+
+/*
+ * since we can't init unions, the cleanest way to use a.out.h instead
+ * of nlist.h (required since nlist() uses some defines) is to do a
+ * runtime copy into the nl array -- sigh
+ */
+init_nlist()
+{
+ register struct nlist *np;
+ register char **namep;
+
+ nllen = sizeof nl_names / sizeof (char *);
+ np = nl = (struct nlist *) malloc(nllen * sizeof (struct nlist));
+ if (np == NULL) {
+ fprintf(stderr, "ps: out of memory allocating namelist\n");
+ exit(1);
+ }
+ namep = &nl_names[0];
+ while (nllen > 0) {
+ np->n_un.n_name = *namep;
+ if (**namep == '\0')
+ break;
+ namep++;
+ np++;
+ }
+}
+
+/*
+ * nlist - retreive attributes from name list (string table version)
+ * modified to add wait channels - Charles R. LaBrec 8/85
+ */
+nlist(name, list)
+ char *name;
+ struct nlist *list;
+{
+ register struct nlist *p, *q;
+ register char *s1, *s2;
+ register n, m;
+ int maxlen, nreq;
+ FILE *f;
+ FILE *sf;
+ off_t sa; /* symbol address */
+ off_t ss; /* start of strings */
+ int type;
+ struct exec buf;
+ struct nlist space[BUFSIZ/sizeof (struct nlist)];
+ char nambuf[BUFSIZ];
+
+ maxlen = 0;
+ for (q = list, nreq = 0; q->n_un.n_name && q->n_un.n_name[0]; q++, nreq++) {
+ q->n_type = 0;
+ q->n_value = 0;
+ q->n_desc = 0;
+ q->n_other = 0;
+ n = strlen(q->n_un.n_name);
+ if (n > maxlen)
+ maxlen = n;
+ }
+ f = fopen(name, "r");
+ if (f == NULL)
+ return (-1);
+ fread((char *)&buf, sizeof buf, 1, f);
+ if (N_BADMAG(buf)) {
+ fclose(f);
+ return (-1);
+ }
+ sf = fopen(name, "r");
+ if (sf == NULL) {
+ /* ??? */
+ fclose(f);
+ return(-1);
+ }
+ sa = N_SYMOFF(buf);
+ ss = sa + buf.a_syms;
+ n = buf.a_syms;
+ fseek(f, sa, 0);
+ while (n) {
+ m = sizeof (space);
+ if (n < m)
+ m = n;
+ if (fread((char *)space, m, 1, f) != 1)
+ break;
+ n -= m;
+ for (q = space; (m -= sizeof(struct nlist)) >= 0; q++) {
+ if (q->n_un.n_strx == 0 || q->n_type & N_STAB)
+ continue;
+ /*
+ * since we know what type of symbols we will get,
+ * we can make a quick check here -- crl
+ */
+ type = q->n_type & (N_TYPE | N_EXT);
+ if ((q->n_type & N_TYPE) != N_ABS
+ && type != (N_EXT | N_DATA)
+ && type != (N_EXT | N_BSS))
+ continue;
+ fseek(sf, ss+q->n_un.n_strx, 0);
+ fread(nambuf, maxlen+1, 1, sf);
+ /* if using wchans, add it to the list of channels */
+ if (!nflg)
+ addchan(&nambuf[1], (caddr_t) q->n_value);
+ for (p = list; p->n_un.n_name && p->n_un.n_name[0]; p++) {
+ s1 = p->n_un.n_name;
+ s2 = nambuf;
+ if (strcmp(p->n_un.n_name, nambuf) == 0) {
+ p->n_value = q->n_value;
+ p->n_type = q->n_type;
+ p->n_desc = q->n_desc;
+ p->n_other = q->n_other;
+ --nreq;
+ break;
+ }
+ }
+ }
+ }
+alldone:
+ fclose(f);
+ fclose(sf);
+ return (nreq);
+}
+
+/*
+ * add the given channel to the channel list
+ */
+addchan(name, caddr)
+char *name;
+caddr_t caddr;
+{
+ static int left = 0;
+ register struct wchan *wp;
+ register char **p;
+
+ for (p = wchan_stop_list; *p; p++) {
+ if (**p != *name) /* quick check first */
+ continue;
+ if (strncmp(name, *p, WNAMESIZ) == 0)
+ return; /* if found, don't add */
+ }
+ if (left == 0) {
+ if (wchanhd) {
+ left = 100;
+ wchanhd = (struct wchan *) realloc(wchanhd,
+ (nchans + left) * sizeof (struct wchan));
+ } else {
+ left = 600;
+ wchanhd = (struct wchan *) malloc(left
+ * sizeof (struct wchan));
+ }
+ if (wchanhd == NULL) {
+ fprintf(stderr, "ps: out of memory allocating wait channels\n");
+ nflg++;
+ return;
+ }
+ }
+ left--;
+ wp = &wchanhd[nchans++];
+ strncpy(wp->wc_name, name, WNAMESIZ);
+ wp->wc_name[WNAMESIZ] = '\0';
+ wp->wc_caddr = caddr;
+}
+
+/*
+ * returns the symbolic wait channel corresponding to chan
+ */
+char *
+getchan(chan)
+register caddr_t chan;
+{
+ register i, iend;
+ register char *prevsym;
+ register struct wchan *wp;
+
+ prevsym = "???"; /* nothing, to begin with */
+ if (chan) {
+ for (i = 0; i < NWCINDEX; i++)
+ if ((unsigned) chan < (unsigned) wchan_index[i])
+ break;
+ iend = i--;
+ if (i < 0) /* can't be found */
+ return prevsym;
+ iend *= nchans;
+ iend /= NWCINDEX;
+ i *= nchans;
+ i /= NWCINDEX;
+ wp = &wchanhd[i];
+ for ( ; i < iend; i++, wp++) {
+ if ((unsigned) wp->wc_caddr > (unsigned) chan)
+ break;
+ prevsym = wp->wc_name;
+ }
+ }
+ return prevsym;
+}
+
+/*
+ * used in sorting the wait channel array
+ */
+int
+wchancomp (w1, w2)
+struct wchan *w1, *w2;
+{
+ register unsigned c1, c2;
+
+ c1 = (unsigned) w1->wc_caddr;
+ c2 = (unsigned) w2->wc_caddr;
+ if (c1 > c2)
+ return 1;
+ else if (c1 == c2)
+ return 0;
+ else
+ return -1;
+}