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