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