|
|
1.1 root 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.24 (Berkeley) 7/27/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: */
23: #include <sys/param.h>
24: #include <utmp.h>
25: #include <sys/stat.h>
26: #include <sys/user.h>
27: #include <sys/proc.h>
28: #include <sys/ioctl.h>
29: #include <machine/pte.h>
30: #include <sys/vm.h>
31: #include <sys/tty.h>
32: #include <nlist.h>
33: #include <kvm.h>
34: #include <ctype.h>
35: #include <paths.h>
36: #include <string.h>
37: #include <stdio.h>
38:
39: char *program;
40: int ttywidth; /* width of tty */
41: int argwidth; /* width of tty */
42: int header = 1; /* true if -h flag: don't print heading */
43: int wcmd = 1; /* true if this is w(1), and not uptime(1) */
44: int nusers; /* number of users logged in now */
45: char * sel_user; /* login of particular user selected */
46: time_t now; /* the current time of day */
47: struct timeval boottime;
48: time_t uptime; /* time of last reboot & elapsed time since */
49: struct utmp utmp;
50: struct winsize ws;
51: int sortidle; /* sort bu idle time */
52:
53:
54: /*
55: * One of these per active utmp entry.
56: */
57: struct entry {
58: struct entry *next;
59: struct utmp utmp;
60: dev_t tdev; /* dev_t of terminal */
61: int idle; /* idle time of terminal in minutes */
62: struct proc *proc; /* list of procs in foreground */
63: char *args; /* arg list of interesting process */
64: } *ep, *ehead = NULL, **nextp = &ehead;
65:
66: struct nlist nl[] = {
67: { "_boottime" },
68: #define X_BOOTTIME 0
69: #if defined(hp300)
70: { "_cn_tty" },
71: #define X_CNTTY 1
72: #endif
73: { "" },
74: };
75:
76: #define USAGE "[ -hi ] [ user ]"
77: #define usage() fprintf(stderr, "usage: %s: %s\n", program, USAGE)
78:
79: main(argc, argv)
80: char **argv;
81: {
82: register int i;
83: struct winsize win;
84: register struct proc *p;
85: struct eproc *e;
86: struct stat *stp, *ttystat();
87: FILE *ut;
88: char *cp;
89: int ch;
90: extern char *optarg;
91: extern int optind;
92: char *strsave();
93:
94: program = argv[0];
95: /*
96: * are we w(1) or uptime(1)
97: */
98: if ((cp = rindex(program, '/')) || *(cp = program) == '-')
99: cp++;
100: if (*cp == 'u')
101: wcmd = 0;
102:
103: while ((ch = getopt(argc, argv, "hiflsuw")) != EOF)
104: switch((char)ch) {
105: case 'h':
106: header = 0;
107: break;
108: case 'i':
109: sortidle++;
110: break;
111: case 'f': case 'l': case 's': case 'u': case 'w':
112: error("[-flsuw] no longer supported");
113: usage();
114: exit(1);
115: case '?':
116: default:
117: usage();
118: exit(1);
119: }
120: argc -= optind;
121: argv += optind;
122: if (argc == 1) {
123: sel_user = argv[0];
124: argv++, argc--;
125: }
126: if (argc) {
127: usage();
128: exit(1);
129: }
130:
131: if (header && kvm_nlist(nl) != 0) {
132: error("can't get namelist");
133: exit (1);
134: }
135: time(&now);
136: ut = fopen(_PATH_UTMP, "r");
137: while (fread(&utmp, sizeof(utmp), 1, ut)) {
138: if (utmp.ut_name[0] == '\0')
139: continue;
140: nusers++;
141: if (wcmd == 0 || (sel_user &&
142: strncmp(utmp.ut_name, sel_user, UT_NAMESIZE) != 0))
143: continue;
144: if ((ep = (struct entry *)
145: calloc(1, sizeof (struct entry))) == NULL) {
146: error("out of memory");
147: exit(1);
148: }
149: *nextp = ep;
150: nextp = &(ep->next);
151: bcopy(&utmp, &(ep->utmp), sizeof (struct utmp));
152: stp = ttystat(ep->utmp.ut_line);
153: ep->tdev = stp->st_rdev;
154: #if defined(hp300)
155: /*
156: * XXX If this is the console device, attempt to ascertain
157: * the true console device dev_t.
158: */
159: if (ep->tdev == 0) {
160: static dev_t cn_dev;
161:
162: if (nl[X_CNTTY].n_value) {
163: struct tty cn_tty, *cn_ttyp;
164:
165: if (kvm_read(nl[X_CNTTY].n_value,
166: &cn_ttyp, sizeof (cn_ttyp)) > 0) {
167: (void)kvm_read(cn_ttyp, &cn_tty,
168: sizeof (cn_tty));
169: cn_dev = cn_tty.t_dev;
170: }
171: nl[X_CNTTY].n_value = 0;
172: }
173: ep->tdev = cn_dev;
174: }
175: #endif
176: ep->idle = ((now - stp->st_atime) + 30) / 60; /* secs->mins */
177: if (ep->idle < 0)
178: ep->idle = 0;
179: }
180: fclose(ut);
181:
182: if (header || wcmd == 0) {
183: double avenrun[3];
184: int days, hrs, mins;
185:
186: /*
187: * Print time of day
188: */
189: fputs(attime(&now), stdout);
190: /*
191: * Print how long system has been up.
192: * (Found by looking for "boottime" in kernel)
193: */
194: (void)kvm_read((off_t)nl[X_BOOTTIME].n_value, &boottime,
195: sizeof (boottime));
196: uptime = now - boottime.tv_sec;
197: uptime += 30;
198: days = uptime / (60*60*24);
199: uptime %= (60*60*24);
200: hrs = uptime / (60*60);
201: uptime %= (60*60);
202: mins = uptime / 60;
203:
204: printf(" up");
205: if (days > 0)
206: printf(" %d day%s,", days, days>1?"s":"");
207: if (hrs > 0 && mins > 0) {
208: printf(" %2d:%02d,", hrs, mins);
209: } else {
210: if (hrs > 0)
211: printf(" %d hr%s,", hrs, hrs>1?"s":"");
212: if (mins > 0)
213: printf(" %d min%s,", mins, mins>1?"s":"");
214: }
215:
216: /* Print number of users logged in to system */
217: printf(" %d user%s", nusers, nusers>1?"s":"");
218:
219: /*
220: * Print 1, 5, and 15 minute load averages.
221: */
222: printf(", load average:");
223: (void)getloadavg(avenrun, sizeof(avenrun) / sizeof(avenrun[0]));
224: for (i = 0; i < (sizeof(avenrun)/sizeof(avenrun[0])); i++) {
225: if (i > 0)
226: printf(",");
227: printf(" %.2f", avenrun[i]);
228: }
229: printf("\n");
230: if (wcmd == 0) /* if uptime(1) then done */
231: exit(0);
232: #define HEADER "USER TTY FROM LOGIN@ IDLE WHAT\n"
233: #define WUSED (sizeof (HEADER) - sizeof ("WHAT\n"))
234: printf(HEADER);
235: }
236:
237: while ((p = kvm_nextproc()) != NULL) {
238: if (p->p_stat == SZOMB || (p->p_flag & SCTTY) == 0)
239: continue;
240: e = kvm_geteproc(p);
241: for (ep = ehead; ep != NULL; ep = ep->next) {
242: if (ep->tdev == e->e_tdev && e->e_pgid == e->e_tpgid) {
243: /*
244: * Proc is in foreground of this terminal
245: */
246: if (proc_compare(ep->proc, p))
247: ep->proc = p;
248: break;
249: }
250: }
251: }
252: if ((ioctl(1, TIOCGWINSZ, &ws) == -1 &&
253: ioctl(2, TIOCGWINSZ, &ws) == -1 &&
254: ioctl(0, TIOCGWINSZ, &ws) == -1) || ws.ws_col == 0)
255: ttywidth = 79;
256: else
257: ttywidth = ws.ws_col - 1;
258: argwidth = ttywidth - WUSED;
259: if (argwidth < 4)
260: argwidth = 8;
261: for (ep = ehead; ep != NULL; ep = ep->next) {
262: ep->args = strsave(kvm_getargs(ep->proc, kvm_getu(ep->proc)));
263: if (ep->args == NULL) {
264: error("out of memory");
265: exit(1);
266: }
267: }
268: /* sort by idle time */
269: if (sortidle && ehead != NULL) {
270: struct entry *from = ehead, *save;
271:
272: ehead = NULL;
273: while (from != NULL) {
274: for (nextp = &ehead;
275: (*nextp) && from->idle >= (*nextp)->idle;
276: nextp = &(*nextp)->next)
277: ;
278: save = from;
279: from = from->next;
280: save->next = *nextp;
281: *nextp = save;
282: }
283: }
284:
285: for (ep = ehead; ep != NULL; ep = ep->next) {
286: printf("%-*.*s %-2.2s %-*.*s %s",
287: UT_NAMESIZE, UT_NAMESIZE, ep->utmp.ut_name,
288: strncmp(ep->utmp.ut_line, "tty", 3) == 0 ?
289: ep->utmp.ut_line+3 : ep->utmp.ut_line,
290: UT_HOSTSIZE, UT_HOSTSIZE, *ep->utmp.ut_host ?
291: ep->utmp.ut_host : "-",
292: attime(&ep->utmp.ut_time));
293: if (ep->idle >= 36 * 60)
294: printf(" %ddays ", (ep->idle + 12 * 60) / (24 * 60));
295: else
296: prttime(ep->idle, " ");
297: printf("%.*s\n", argwidth, ep->args);
298: }
299: }
300:
301: struct stat *
302: ttystat(line)
303: {
304: static struct stat statbuf;
305: char ttybuf[sizeof (_PATH_DEV) + UT_LINESIZE + 1];
306:
307: sprintf(ttybuf, "%s/%.*s", _PATH_DEV, UT_LINESIZE, line);
308: (void) stat(ttybuf, &statbuf);
309:
310: return (&statbuf);
311: }
312:
313: char *
314: strsave(cp)
315: char *cp;
316: {
317: register unsigned len;
318: register char *dp;
319:
320: len = strlen(cp);
321: dp = (char *)calloc(len+1, sizeof (char));
322: (void) strcpy(dp, cp);
323: return (dp);
324: }
325: /*
326: * prttime prints a time in hours and minutes or minutes and seconds.
327: * The character string tail is printed at the end, obvious
328: * strings to pass are "", " ", or "am".
329: */
330: prttime(tim, tail)
331: time_t tim;
332: char *tail;
333: {
334:
335: if (tim >= 60) {
336: printf(" %2d:", tim/60);
337: tim %= 60;
338: printf("%02d", tim);
339: } else if (tim >= 0)
340: printf(" %2d", tim);
341: printf("%s", tail);
342: }
343:
344: #include <varargs.h>
345:
346: warning(va_alist)
347: va_dcl
348: {
349: char *fmt;
350: va_list ap;
351:
352: fprintf(stderr, "%s: warning: ", program);
353: va_start(ap);
354: fmt = va_arg(ap, char *);
355: (void) vfprintf(stderr, fmt, ap);
356: va_end(ap);
357: fprintf(stderr, "\n");
358: }
359:
360: error(va_alist)
361: va_dcl
362: {
363: char *fmt;
364: va_list ap;
365:
366: fprintf(stderr, "%s: ", program);
367: va_start(ap);
368: fmt = va_arg(ap, char *);
369: (void) vfprintf(stderr, fmt, ap);
370: va_end(ap);
371: fprintf(stderr, "\n");
372: }
373:
374: syserror(va_alist)
375: va_dcl
376: {
377: char *fmt;
378: va_list ap;
379: extern errno;
380:
381: fprintf(stderr, "%s: ", program);
382: va_start(ap);
383: fmt = va_arg(ap, char *);
384: (void) vfprintf(stderr, fmt, ap);
385: va_end(ap);
386: fprintf(stderr, ": %s\n", strerror(errno));
387: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.