xref: /original-bsd/usr.bin/w/w.c (revision 492c862f)
1 /*
2  * Copyright (c) 1980 Regents of the University of California.
3  * All rights reserved.  The Berkeley software License Agreement
4  * specifies the terms and conditions for redistribution.
5  */
6 
7 #ifndef lint
8 char copyright[] =
9 "@(#) Copyright (c) 1980 Regents of the University of California.\n\
10  All rights reserved.\n";
11 #endif not lint
12 
13 #ifndef lint
14 static char sccsid[] = "@(#)w.c	5.15 (Berkeley) 02/06/90";
15 #endif not lint
16 
17 /*
18  * w - print system status (who and what)
19  *
20  * This program is similar to the systat command on Tenex/Tops 10/20
21  */
22 #include <sys/param.h>
23 #include <nlist.h>
24 #include <stdio.h>
25 #include <ctype.h>
26 #include <utmp.h>
27 #include <sys/stat.h>
28 #include <sys/dir.h>
29 #include <sys/user.h>
30 #include <sys/proc.h>
31 #include <sys/ioctl.h>
32 #include <machine/pte.h>
33 #include <sys/vm.h>
34 #include <sys/tty.h>
35 #include <sys/kinfo.h>
36 #include <paths.h>
37 
38 #define ARGWIDTH	33	/* # chars left on 80 col crt for args */
39 
40 struct pr {
41 	short	w_pid;			/* proc.p_pid */
42 	char	w_flag;			/* proc.p_flag */
43 	short	w_size;			/* proc.p_size */
44 	long	w_seekaddr;		/* where to find args */
45 	long	w_lastpg;		/* disk address of stack */
46 	int	w_igintr;		/* INTR+3*QUIT, 0=die, 1=ign, 2=catch */
47 	time_t	w_time;			/* CPU time used by this process */
48 	time_t	w_ctime;		/* CPU time used by children */
49 	dev_t	w_tty;			/* tty device of process */
50 	int	w_uid;			/* uid of process */
51 	char	w_comm[15];		/* user.u_comm, null terminated */
52 	char	w_args[ARGWIDTH+1];	/* args if interesting process */
53 } *pr;
54 int	nproc;
55 
56 struct	nlist nl[] = {
57 	{ "_nproc" },
58 #define	X_NPROC		0
59 	{ "_boottime" },
60 #define	X_BOOTTIME	1
61 	{ "_proc" },
62 #define	X_PROC		2
63 	{ "_swapdev" },
64 #define	X_SWAPDEV	3
65 	{ "_Usrptmap" },
66 #define	X_USRPTMA	4
67 	{ "_usrpt" },
68 #define	X_USRPT		5
69 	{ "_nswap" },
70 #define	X_NSWAP		6
71 	{ "_dmmin" },
72 #define	X_DMMIN		7
73 	{ "_dmmax" },
74 #define	X_DMMAX		8
75 	{ "" },
76 };
77 
78 FILE	*ps;
79 FILE	*ut;
80 FILE	*bootfd;
81 int	kmem;
82 int	mem;
83 int	swap;			/* kmem, mem, and swap */
84 int	nswap;
85 int	dmmin, dmmax;
86 dev_t	tty;
87 int	uid;
88 char	doing[520];		/* process attached to terminal */
89 time_t	proctime;		/* cpu time of process in doing */
90 double	avenrun[3];
91 struct	proc *aproc;
92 pid_t	pgid;
93 pid_t	tpgid;
94 
95 #define	DIV60(t)	((t+30)/60)    /* x/60 rounded */
96 #define	TTYEQ		(tty == pr[i].w_tty)
97 #define IGINT		(1+3*1)		/* ignoring both SIGINT & SIGQUIT */
98 
99 char	*getargs();
100 char	*ctime();
101 char	*rindex();
102 FILE	*popen();
103 struct	tm *localtime();
104 time_t	findidle();
105 
106 int	debug;			/* true if -d flag: debugging output */
107 int	ttywidth = 80;		/* width of tty */
108 int	header = 1;		/* true if -h flag: don't print heading */
109 int	lflag = 1;		/* true if -l flag: long style output */
110 int	prfrom = 1;		/* true if not -f flag: print host from */
111 int	login;			/* true if invoked as login shell */
112 time_t	idle;			/* number of minutes user is idle */
113 int	nusers;			/* number of users logged in now */
114 char *	sel_user;		/* login of particular user selected */
115 char firstchar;			/* first char of name of prog invoked as */
116 time_t	jobtime;		/* total cpu time visible */
117 time_t	now;			/* the current time of day */
118 struct	timeval boottime;
119 time_t	uptime;			/* time of last reboot & elapsed time since */
120 int	np;			/* number of processes currently active */
121 struct	utmp utmp;
122 union {
123 	struct user U_up;
124 	char	pad[NBPG][UPAGES];
125 } Up;
126 #define	up	Up.U_up
127 
128 main(argc, argv)
129 	char **argv;
130 {
131 	int days, hrs, mins;
132 	register int i, j;
133 	char *cp;
134 	register int curpid, empty;
135 	struct winsize win;
136 
137 	login = (argv[0][0] == '-');
138 	cp = rindex(argv[0], '/');
139 	firstchar = login ? argv[0][1] : (cp==0) ? argv[0][0] : cp[1];
140 	cp = argv[0];	/* for Usage */
141 
142 	while (argc > 1) {
143 		if (argv[1][0] == '-') {
144 			for (i=1; argv[1][i]; i++) {
145 				switch(argv[1][i]) {
146 
147 				case 'd':
148 					debug++;
149 					break;
150 
151 				case 'f':
152 					prfrom = !prfrom;
153 					break;
154 
155 				case 'h':
156 					header = 0;
157 					break;
158 
159 				case 'l':
160 					lflag++;
161 					break;
162 
163 				case 's':
164 					lflag = 0;
165 					break;
166 
167 				case 'u':
168 				case 'w':
169 					firstchar = argv[1][i];
170 					break;
171 
172 				default:
173 					fprintf(stderr, "w: Bad flag %s\n",
174 						argv[1]);
175 					exit(1);
176 				}
177 			}
178 		} else {
179 			if (!isalnum(argv[1][0]) || argc > 2) {
180 				fprintf(stderr,
181 				       "Usage: %s [ -hlsfuw ] [ user ]\n", cp);
182 				exit(1);
183 			} else
184 				sel_user = argv[1];
185 		}
186 		argc--; argv++;
187 	}
188 
189 	if ((kmem = open(_PATH_KMEM, 0)) < 0) {
190 		fprintf(stderr, "w: no %s.\n", _PATH_KMEM);
191 		exit(1);
192 	}
193 	nlist(_PATH_UNIX, nl);
194 	if (nl[0].n_type==0) {
195 		fprintf(stderr, "w: no %s namelist.\n", _PATH_UNIX);
196 		exit(1);
197 	}
198 
199 	if (firstchar == 'u')	/* uptime(1) */
200 		nl[X_BOOTTIME+1].n_name = "";
201 	else {			/* then read in procs, get window size */
202 		readpr();
203 		if (ioctl(1, TIOCGWINSZ, &win) != -1 && win.ws_col > 70)
204 			ttywidth = win.ws_col;
205 	}
206 
207 	ut = fopen(_PATH_UTMP, "r");
208 	time(&now);
209 	if (header) {
210 		/* Print time of day */
211 		prtat(&now);
212 
213 		/*
214 		 * Print how long system has been up.
215 		 * (Found by looking for "boottime" in kernel)
216 		 */
217 		lseek(kmem, (long)nl[X_BOOTTIME].n_value, 0);
218 		read(kmem, &boottime, sizeof (boottime));
219 
220 		uptime = now - boottime.tv_sec;
221 		uptime += 30;
222 		days = uptime / (60*60*24);
223 		uptime %= (60*60*24);
224 		hrs = uptime / (60*60);
225 		uptime %= (60*60);
226 		mins = uptime / 60;
227 
228 		printf("  up");
229 		if (days > 0)
230 			printf(" %d day%s,", days, days>1?"s":"");
231 		if (hrs > 0 && mins > 0) {
232 			printf(" %2d:%02d,", hrs, mins);
233 		} else {
234 			if (hrs > 0)
235 				printf(" %d hr%s,", hrs, hrs>1?"s":"");
236 			if (mins > 0)
237 				printf(" %d min%s,", mins, mins>1?"s":"");
238 		}
239 
240 		/* Print number of users logged in to system */
241 		while (fread(&utmp, sizeof(utmp), 1, ut)) {
242 			if (utmp.ut_name[0] != '\0')
243 				nusers++;
244 		}
245 		rewind(ut);
246 		printf("  %d user%s", nusers, nusers>1?"s":"");
247 
248 		/*
249 		 * Print 1, 5, and 15 minute load averages.
250 		 */
251 		printf(",  load average:");
252 		(void)getloadavg(avenrun, sizeof(avenrun) / sizeof(avenrun[0]));
253 		for (i = 0; i < (sizeof(avenrun)/sizeof(avenrun[0])); i++) {
254 			if (i > 0)
255 				printf(",");
256 			printf(" %.2f", avenrun[i]);
257 		}
258 		printf("\n");
259 		if (firstchar == 'u')	/* if this was uptime(1), finished */
260 			exit(0);
261 
262 		/* Headers for rest of output */
263 		if (lflag && prfrom)
264 			printf("USER    TTY FROM            LOGIN@  IDLE   JCPU   PCPU  WHAT\n");
265 		else if (lflag)
266 			printf("USER     TTY       LOGIN@  IDLE   JCPU   PCPU  WHAT\n");
267 		else if (prfrom)
268 			printf("USER    TTY FROM            IDLE  WHAT\n");
269 		else
270 			printf("USER    TTY  IDLE  WHAT\n");
271 		fflush(stdout);
272 	}
273 
274 
275 	for (;;) {	/* for each entry in utmp */
276 		if (fread(&utmp, sizeof(utmp), 1, ut) == NULL) {
277 			fclose(ut);
278 			exit(0);
279 		}
280 		if (utmp.ut_name[0] == '\0')
281 			continue;	/* that tty is free */
282 		if (sel_user && strncmp(utmp.ut_name, sel_user, UT_NAMESIZE) != 0)
283 			continue;	/* we wanted only somebody else */
284 
285 		gettty();
286 		jobtime = 0;
287 		proctime = 0;
288 		strcpy(doing, "-");	/* default act: normally never prints */
289 		empty = 1;
290 		curpid = -1;
291 		idle = findidle();
292 		for (i=0; i<np; i++) {	/* for each process on this tty */
293 			if (!(TTYEQ))
294 				continue;
295 			jobtime += pr[i].w_time + pr[i].w_ctime;
296 			proctime += pr[i].w_time;
297 			/*
298 			 * Meaning of debug fields following proc name is:
299 			 * & by itself: ignoring both SIGINT and QUIT.
300 			 *		(==> this proc is not a candidate.)
301 			 * & <i> <q>:   i is SIGINT status, q is quit.
302 			 *		0 == DFL, 1 == IGN, 2 == caught.
303 			 * *:		proc pgrp == tty pgrp.
304 			 */
305 			 if (debug) {
306 				printf("\t\t%d\t%s", pr[i].w_pid, pr[i].w_args);
307 				if ((j=pr[i].w_igintr) > 0)
308 					if (j==IGINT)
309 						printf(" &");
310 					else
311 						printf(" & %d %d", j%3, j/3);
312 				printf("\n");
313 			}
314 			if (empty && pr[i].w_igintr!=IGINT) {
315 				empty = 0;
316 				curpid = -1;
317 			}
318 			if(pr[i].w_pid>curpid && (pr[i].w_igintr!=IGINT || empty)){
319 				curpid = pr[i].w_pid;
320 				strcpy(doing, lflag ? pr[i].w_args : pr[i].w_comm);
321 #ifdef notdef
322 				if (doing[0]==0 || doing[0]=='-' && doing[1]<=' ' || doing[0] == '?') {
323 					strcat(doing, " (");
324 					strcat(doing, pr[i].w_comm);
325 					strcat(doing, ")");
326 				}
327 #endif
328 			}
329 		}
330 		putline();
331 	}
332 }
333 
334 /* figure out the major/minor device # pair for this tty */
335 gettty()
336 {
337 	char ttybuf[20];
338 	struct stat statbuf;
339 
340 	ttybuf[0] = 0;
341 	strcpy(ttybuf, _PATH_DEV);
342 	strcat(ttybuf, utmp.ut_line);
343 	stat(ttybuf, &statbuf);
344 	tty = statbuf.st_rdev;
345 	uid = statbuf.st_uid;
346 }
347 
348 /*
349  * putline: print out the accumulated line of info about one user.
350  */
351 putline()
352 {
353 	register int tm;
354 	int width = ttywidth - 1;
355 
356 	/* print login name of the user */
357 	printf("%-*.*s ", UT_NAMESIZE, UT_NAMESIZE, utmp.ut_name);
358 	width -= UT_NAMESIZE + 1;
359 
360 	/* print tty user is on */
361 	if (lflag && !prfrom) {
362 		/* long form: all (up to) UT_LINESIZE chars */
363 		printf("%-*.*s", UT_LINESIZE, UT_LINESIZE, utmp.ut_line);
364 		width -= UT_LINESIZE;
365 	 } else {
366 		/* short form: 2 chars, skipping 'tty' if there */
367 		if (utmp.ut_line[0]=='t' && utmp.ut_line[1]=='t' && utmp.ut_line[2]=='y')
368 			printf("%-2.2s", &utmp.ut_line[3]);
369 		else
370 			printf("%-2.2s", utmp.ut_line);
371 		width -= 2;
372 	}
373 
374 	if (prfrom) {
375 		if (*utmp.ut_host == '\0')
376 			printf(" -             ");
377 		else
378 			printf(" %-14.14s", utmp.ut_host);
379 		width -= 15;
380 	}
381 
382 	if (lflag) {
383 		/* print when the user logged in */
384 		prtat(&utmp.ut_time);
385 		width -= 8;
386 	}
387 
388 	/* print idle time */
389 	if (idle >= 36 * 60)
390 		printf(" %ddays ", (idle + 12 * 60) / (24 * 60));
391 	else
392 		prttime(idle," ");
393 	width -= 7;
394 
395 	if (lflag) {
396 		/* print CPU time for all processes & children */
397 		prttime(jobtime," ");
398 		width -= 7;
399 		/* print cpu time for interesting process */
400 		prttime(proctime," ");
401 		width -= 7;
402 	}
403 
404 	/* what user is doing, either command tail or args */
405 	printf(" %-.*s\n", width-1, doing);
406 	fflush(stdout);
407 }
408 
409 /* find & return number of minutes current tty has been idle */
410 time_t
411 findidle()
412 {
413 	struct stat stbuf;
414 	long lastaction, diff;
415 	char ttyname[20];
416 
417 	strcpy(ttyname, _PATH_DEV);
418 	strncat(ttyname, utmp.ut_line, UT_LINESIZE);
419 	stat(ttyname, &stbuf);
420 	time(&now);
421 	lastaction = stbuf.st_atime;
422 	diff = now - lastaction;
423 	diff = DIV60(diff);
424 	if (diff < 0) diff = 0;
425 	return(diff);
426 }
427 
428 #define	HR	(60 * 60)
429 #define	DAY	(24 * HR)
430 #define	MON	(30 * DAY)
431 
432 /*
433  * prttime prints a time in hours and minutes or minutes and seconds.
434  * The character string tail is printed at the end, obvious
435  * strings to pass are "", " ", or "am".
436  */
437 prttime(tim, tail)
438 	time_t tim;
439 	char *tail;
440 {
441 
442 	if (tim >= 60) {
443 		printf(" %2d:", tim/60);
444 		tim %= 60;
445 		printf("%02d", tim);
446 	} else if (tim >= 0)
447 		printf("    %2d", tim);
448 	printf("%s", tail);
449 }
450 
451 char *weekday[] = { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" };
452 char *month[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun",
453 		"Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
454 
455 /* prtat prints a 12 hour time given a pointer to a time of day */
456 prtat(time)
457 	long *time;
458 {
459 	struct tm *p;
460 	register int hr, pm;
461 
462 	p = localtime(time);
463 	hr = p->tm_hour;
464 	pm = (hr > 11);
465 	if (hr > 11)
466 		hr -= 12;
467 	if (hr == 0)
468 		hr = 12;
469 	if (now - *time <= 18 * HR)
470 		prttime(hr * 60 + p->tm_min, pm ? "pm" : "am");
471 	else if (now - *time <= 7 * DAY)
472 		printf(" %*s%d%s", hr < 10 ? 4 : 3, weekday[p->tm_wday], hr,
473 		   pm ? "pm" : "am");
474 	else
475 		printf(" %2d%s%2d", p->tm_mday, month[p->tm_mon], p->tm_year);
476 }
477 
478 /*
479  * readpr finds and reads in the array pr, containing the interesting
480  * parts of the proc and user tables for each live process.
481  * We only accept procs whos controlling tty has a pgrp equal to the
482  * pgrp of the proc.  This accurately defines the notion of the current
483  * process(s), but because of time skew, we always read in the tty struct
484  * after reading the proc, even though the same tty struct may have been
485  * read earlier on.
486  */
487 readpr()
488 {
489 	int mf, addr, c;
490 	int szpt, pfnum, i;
491 	struct pte *Usrptma, *usrpt, *pte, apte;
492 	struct dblock db;
493 	struct kinfo_proc *kp;
494 	register struct proc *p;
495 	int nentries;
496 
497 	Usrptma = (struct pte *) nl[X_USRPTMA].n_value;
498 	usrpt = (struct pte *) nl[X_USRPT].n_value;
499 	if((mem = open(_PATH_MEM, 0)) < 0) {
500 		fprintf(stderr, "w: no %s.\n", _PATH_MEM);
501 		exit(1);
502 	}
503 	if ((swap = open(_PATH_DRUM, 0)) < 0) {
504 		fprintf(stderr, "w: no %s\n", _PATH_DRUM);
505 		exit(1);
506 	}
507 	/*
508 	 * read mem to find swap dev.
509 	 */
510 	lseek(kmem, (long)nl[X_SWAPDEV].n_value, 0);
511 	read(kmem, &nl[X_SWAPDEV].n_value, sizeof(nl[X_SWAPDEV].n_value));
512 	/*
513 	 * Find base of and parameters of swap
514 	 */
515 	lseek(kmem, (long)nl[X_NSWAP].n_value, 0);
516 	read(kmem, &nswap, sizeof(nswap));
517 	lseek(kmem, (long)nl[X_DMMIN].n_value, 0);
518 	read(kmem, &dmmin, sizeof(dmmin));
519 	lseek(kmem, (long)nl[X_DMMAX].n_value, 0);
520 	read(kmem, &dmmax, sizeof(dmmax));
521 	/*
522 	 * Read proc table.
523 	 */
524 	np = 0;
525 	nentries = kvm_getkproc(&kp);
526 	pr = (struct pr *)calloc(nentries, sizeof (struct pr));
527 	for (i=0; i < nentries; i++, kp++) {
528 		p = &kp->kp_proc;
529 		/* decide if it's an interesting process */
530 		if (p->p_stat==0 || p->p_stat==SZOMB
531 		    || p->p_stat==SSTOP)
532 			continue;
533 		/* find & read in the user structure */
534 		if ((p->p_flag & SLOAD) == 0) {
535 			/* not in memory - get from swap device */
536 			addr = dtob(p->p_swaddr);
537 			lseek(swap, (long)addr, 0);
538 			if (read(swap, &up, sizeof(up)) != sizeof(up)) {
539 				continue;
540 			}
541 		} else {
542 			int p0br, cc;
543 #define INTPPG (NBPG / sizeof (int))
544 			struct pte pagetbl[NBPG / sizeof (struct pte)];
545 			/* loaded, get each page from memory separately */
546 			szpt = p->p_szpt;
547 			p0br = (int)p->p_p0br;
548 			pte = &Usrptma[btokmx(p->p_p0br) + szpt-1];
549 			lseek(kmem, (long)pte, 0);
550 			if (read(kmem, &apte, sizeof(apte)) != sizeof(apte))
551 				continue;
552 			lseek(mem, ctob(apte.pg_pfnum), 0);
553 			if (read(mem,pagetbl,sizeof(pagetbl)) != sizeof(pagetbl))
554 cont:
555 				continue;
556 			for(cc=0; cc<UPAGES; cc++) {	/* get u area */
557 				int upage = pagetbl[NPTEPG-UPAGES+cc].pg_pfnum;
558 				lseek(mem,ctob(upage),0);
559 				if (read(mem,((int *)&up)+INTPPG*cc,NBPG) != NBPG)
560 					goto cont;
561 			}
562 			szpt = up.u_pcb.pcb_szpt;
563 			pr[np].w_seekaddr = ctob(apte.pg_pfnum);
564 		}
565 		vstodb(0, CLSIZE, &up.u_smap, &db, 1);
566 		pr[np].w_lastpg = dtob(db.db_base);
567 		if (kp->kp_eproc.kp_tdev == NODEV)
568 			continue;
569 
570 		/* only include a process whose tty has a pgrp which matchs its own */
571 		if (kp->kp_eproc.kp_pgid != kp->kp_eproc.kp_tpgid)
572 			continue;
573 
574 		/* save the interesting parts */
575 		pr[np].w_pid = p->p_pid;
576 		pr[np].w_flag = p->p_flag;
577 		pr[np].w_size = p->p_dsize + p->p_ssize;
578 		pr[np].w_igintr = (((int)up.u_signal[2]==1) +
579 		    2*((int)up.u_signal[2]>1) + 3*((int)up.u_signal[3]==1)) +
580 		    6*((int)up.u_signal[3]>1);
581 		pr[np].w_time =
582 		    up.u_ru.ru_utime.tv_sec + up.u_ru.ru_stime.tv_sec;
583 		pr[np].w_ctime =
584 		    up.u_cru.ru_utime.tv_sec + up.u_cru.ru_stime.tv_sec;
585 		pr[np].w_tty = kp->kp_eproc.kp_tdev;
586 		pr[np].w_uid = p->p_uid;
587 		strcpy(pr[np].w_comm, p->p_comm, MAXCOMLEN+1);
588 		/*
589 		 * Get args if there's a chance we'll print it.
590 		 * Can't just save pointer: getargs returns static place.
591 		 * Can't use strncpy, it blank pads.
592 		 */
593 		pr[np].w_args[0] = 0;
594 		strncat(pr[np].w_args,getargs(&pr[np]),ARGWIDTH);
595 		if (pr[np].w_args[0]==0 || pr[np].w_args[0]=='-' && pr[np].w_args[1]<=' ' || pr[np].w_args[0] == '?') {
596 			strcat(pr[np].w_args, " (");
597 			strcat(pr[np].w_args, pr[np].w_comm);
598 			strcat(pr[np].w_args, ")");
599 		}
600 		np++;
601 	}
602 }
603 
604 /*
605  * getargs: given a pointer to a proc structure, this looks at the swap area
606  * and tries to reconstruct the arguments. This is straight out of ps.
607  */
608 char *
609 getargs(p)
610 	struct pr *p;
611 {
612 	int c, addr, nbad;
613 	static int abuf[CLSIZE*NBPG/sizeof(int)];
614 	struct pte pagetbl[NPTEPG];
615 	register int *ip;
616 	register char *cp, *cp1;
617 
618 	if ((p->w_flag & SLOAD) == 0) {
619 		lseek(swap, p->w_lastpg, 0);
620 		if (read(swap, abuf, sizeof(abuf)) != sizeof(abuf))
621 			return(p->w_comm);
622 	} else {
623 		c = p->w_seekaddr;
624 		lseek(mem,c,0);
625 		if (read(mem,pagetbl,NBPG) != NBPG)
626 			return(p->w_comm);
627 		if (pagetbl[NPTEPG-CLSIZE-UPAGES].pg_fod==0 && pagetbl[NPTEPG-CLSIZE-UPAGES].pg_pfnum) {
628 			lseek(mem,ctob(pagetbl[NPTEPG-CLSIZE-UPAGES].pg_pfnum),0);
629 			if (read(mem,abuf,sizeof(abuf)) != sizeof(abuf))
630 				return(p->w_comm);
631 		} else {
632 			lseek(swap, p->w_lastpg, 0);
633 			if (read(swap, abuf, sizeof(abuf)) != sizeof(abuf))
634 				return(p->w_comm);
635 		}
636 	}
637 	abuf[sizeof(abuf)/sizeof(abuf[0])-1] = 0;
638 	for (ip = &abuf[sizeof(abuf)/sizeof(abuf[0])-2]; ip > abuf;) {
639 		/* Look from top for -1 or 0 as terminator flag. */
640 		if (*--ip == -1 || *ip == 0) {
641 			cp = (char *)(ip+1);
642 			if (*cp==0)
643 				cp++;
644 			nbad = 0;	/* up to 5 funny chars as ?'s */
645 			for (cp1 = cp; cp1 < (char *)&abuf[sizeof(abuf)/sizeof(abuf[0])]; cp1++) {
646 				c = *cp1&0177;
647 				if (c==0)  /* nulls between args => spaces */
648 					*cp1 = ' ';
649 				else if (c < ' ' || c > 0176) {
650 					if (++nbad >= 5) {
651 						*cp1++ = ' ';
652 						break;
653 					}
654 					*cp1 = '?';
655 				} else if (c=='=') {	/* Oops - found an
656 							 * environment var, back
657 							 * over & erase it. */
658 					*cp1 = 0;
659 					while (cp1>cp && *--cp1!=' ')
660 						*cp1 = 0;
661 					break;
662 				}
663 			}
664 			while (*--cp1==' ')	/* strip trailing spaces */
665 				*cp1 = 0;
666 			return(cp);
667 		}
668 	}
669 	return (p->w_comm);
670 }
671 
672 /*
673  * Given a base/size pair in virtual swap area,
674  * return a physical base/size pair which is the
675  * (largest) initial, physically contiguous block.
676  */
677 vstodb(vsbase, vssize, dmp, dbp, rev)
678 	register int vsbase;
679 	int vssize;
680 	struct dmap *dmp;
681 	register struct dblock *dbp;
682 {
683 	register int blk = dmmin;
684 	register swblk_t *ip = dmp->dm_map;
685 
686 	vsbase = ctod(vsbase);
687 	vssize = ctod(vssize);
688 	if (vsbase < 0 || vsbase + vssize > dmp->dm_size)
689 		panic("vstodb");
690 	while (vsbase >= blk) {
691 		vsbase -= blk;
692 		if (blk < dmmax)
693 			blk *= 2;
694 		ip++;
695 	}
696 	if (*ip <= 0 || *ip + blk > nswap)
697 		panic("vstodb *ip");
698 	dbp->db_size = MIN(vssize, blk - vsbase);
699 	dbp->db_base = *ip + (rev ? blk - (vsbase + dbp->db_size) : vsbase);
700 }
701 
702 panic(cp)
703 	char *cp;
704 {
705 
706 	/* printf("%s\n", cp); */
707 }
708 
709 #define PROCSLOP	(5 * sizeof (struct kinfo_proc))
710 kvm_getkproc(bp)
711 	char **bp;
712 {
713 	int ret;
714 	int copysize;
715 	int need;
716 	char *buff;
717 
718 	if ((ret = syscall(63, KINFO_PROC_ALL, NULL, NULL, 0)) == -1) {
719 		perror("ktable, error getting estimate");
720 		return (0);
721 	}
722 	copysize = ret + PROCSLOP;   /* XXX PROCSLOP should be in header ? */
723 	buff = (char *)malloc(copysize);
724 	if (buff == NULL) {
725 		fprintf(stderr, "out of memory");
726 		exit (1);
727 	}
728 	if ((ret = syscall(63, KINFO_PROC_ALL, buff, &copysize, 0)) == -1) {
729 		perror("ktable");
730 		return (0);
731 	}
732 	*bp = buff;
733 
734 	return (copysize / sizeof (struct kinfo_proc));
735 }
736