]> git.saurik.com Git - apple/shell_cmds.git/blame - w/w.c
shell_cmds-116.tar.gz
[apple/shell_cmds.git] / w / w.c
CommitLineData
44bd5ea7
A
1/*-
2 * Copyright (c) 1980, 1991, 1993, 1994
3 * The Regents of the University of California. All rights reserved.
e1a085ba 4 * Portions copyright (c) 2007 Apple Inc. All rights reserved.
44bd5ea7
A
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
e1a085ba 14 * 3. Neither the name of the University nor the names of its contributors
44bd5ea7
A
15 * may be used to endorse or promote products derived from this software
16 * without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
19 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
22 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28 * SUCH DAMAGE.
29 */
30
31#include <sys/cdefs.h>
9bafe280 32
e1a085ba
A
33#ifndef __APPLE__
34__FBSDID("$FreeBSD: src/usr.bin/w/w.c,v 1.58 2005/06/04 23:40:09 gad Exp $");
35#endif
36
44bd5ea7 37#ifndef lint
9bafe280
A
38static const char copyright[] =
39"@(#) Copyright (c) 1980, 1991, 1993, 1994\n\
40 The Regents of the University of California. All rights reserved.\n";
41#endif
44bd5ea7
A
42
43#ifndef lint
9bafe280 44static const char sccsid[] = "@(#)w.c 8.4 (Berkeley) 4/16/94";
44bd5ea7 45#endif
44bd5ea7
A
46
47/*
48 * w - print system status (who and what)
49 *
50 * This program is similar to the systat command on Tenex/Tops 10/20
51 *
52 */
53#include <sys/param.h>
54#include <sys/time.h>
55#include <sys/stat.h>
56#include <sys/sysctl.h>
57#include <sys/proc.h>
58#include <sys/user.h>
59#include <sys/ioctl.h>
60#include <sys/socket.h>
9bafe280 61#include <sys/tty.h>
44bd5ea7 62
e1a085ba
A
63#ifndef __APPLE__
64#include <machine/cpu.h>
65#endif
44bd5ea7
A
66#include <netinet/in.h>
67#include <arpa/inet.h>
9bafe280 68#include <arpa/nameser.h>
44bd5ea7
A
69
70#include <ctype.h>
71#include <err.h>
72#include <errno.h>
73#include <fcntl.h>
e1a085ba 74#if HAVE_KVM
44bd5ea7 75#include <kvm.h>
e1a085ba
A
76#endif
77#include <langinfo.h>
78#include <libutil.h>
44bd5ea7 79#include <limits.h>
9bafe280 80#include <locale.h>
44bd5ea7
A
81#include <netdb.h>
82#include <nlist.h>
83#include <paths.h>
9bafe280 84#include <resolv.h>
44bd5ea7
A
85#include <stdio.h>
86#include <stdlib.h>
87#include <string.h>
e1a085ba 88#include <timeconv.h>
44bd5ea7 89#include <unistd.h>
e1a085ba
A
90#if HAVE_UTMPX
91#include <utmpx.h>
92/* use utmp values so formatting is the same */
93#define UT_NAMESIZE 8
94#define UT_LINESIZE 8
95#else /* HAVE_UTMPX */
44bd5ea7 96#include <utmp.h>
e1a085ba 97#endif /* HAVE_UTMPX */
44bd5ea7
A
98#include <vis.h>
99
100#include "extern.h"
101
102struct timeval boottime;
e1a085ba 103#if !HAVE_UTMPX
44bd5ea7 104struct utmp utmp;
e1a085ba 105#endif
44bd5ea7 106struct winsize ws;
e1a085ba 107#if HAVE_KVM
44bd5ea7 108kvm_t *kd;
e1a085ba 109#endif
44bd5ea7 110time_t now; /* the current time of day */
44bd5ea7
A
111int ttywidth; /* width of tty */
112int argwidth; /* width of tty */
113int header = 1; /* true if -h flag: don't print heading */
e1a085ba 114#if !HAVE_UTMPX
44bd5ea7 115int nflag; /* true if -n flag: don't convert addrs */
e1a085ba
A
116#endif
117#ifndef __APPLE__
9bafe280 118int dflag; /* true if -d flag: output debug info */
e1a085ba 119#endif
9bafe280
A
120int sortidle; /* sort by idle time */
121int use_ampm; /* use AM/PM time */
122int use_comma; /* use comma as floats separator */
123char **sel_users; /* login array of particular users selected */
44bd5ea7
A
124
125/*
126 * One of these per active utmp entry.
127 */
128struct entry {
129 struct entry *next;
e1a085ba
A
130#if HAVE_UTMPX
131 struct utmpx utmp;
132#else
44bd5ea7 133 struct utmp utmp;
e1a085ba 134#endif
9bafe280
A
135 dev_t tdev; /* dev_t of terminal */
136 time_t idle; /* idle time of terminal in seconds */
137 struct kinfo_proc *kp; /* `most interesting' proc */
138 char *args; /* arg list of interesting process */
139 struct kinfo_proc *dkp; /* debug option proc list */
44bd5ea7
A
140} *ep, *ehead = NULL, **nextp = &ehead;
141
e1a085ba
A
142#ifndef __APPLE__
143#define debugproc(p) *((struct kinfo_proc **)&(p)->ki_udata)
144#else
9bafe280 145#define debugproc(p) *((struct kinfo_proc **)&(p)->ki_spare[0])
e1a085ba 146#endif
9bafe280
A
147
148/* W_DISPHOSTSIZE should not be greater than UT_HOSTSIZE */
149#define W_DISPHOSTSIZE 16
150
151static void pr_header(time_t *, int);
152static struct stat *ttystat(char *, int);
153static void usage(int);
154static int this_is_uptime(const char *s);
e1a085ba 155#if !HAVE_KVM
9bafe280 156static void w_getargv(void);
e1a085ba 157#endif
9bafe280
A
158
159char *fmt_argv(char **, char *, int); /* ../../bin/ps/fmt.c */
44bd5ea7
A
160
161int
e1a085ba 162main(int argc, char *argv[])
44bd5ea7 163{
e1a085ba
A
164 struct kinfo_proc *kp;
165 struct kinfo_proc *kprocbuf;
9bafe280 166 struct kinfo_proc *dkp;
44bd5ea7 167 struct stat *stp;
e1a085ba
A
168#if HAVE_UTMPX
169 struct utmpx *ux;
170#else
44bd5ea7 171 FILE *ut;
e1a085ba 172#endif
9bafe280 173 time_t touched;
e1a085ba 174#if HAVE_KVM
9bafe280
A
175 int ch, i, nentries, nusers, wcmd, longidle, dropgid;
176 const char *memf, *nlistf, *p;
e1a085ba
A
177#else
178 int ch, i, nentries, nusers, wcmd, longidle;
179 const char *p;
180#endif /* HAVE_KVM */
9bafe280 181 char *x_suffix;
e1a085ba
A
182#ifdef __APPLE__
183 char buf[MAXHOSTNAMELEN];
184#else
44bd5ea7 185 char buf[MAXHOSTNAMELEN], errbuf[_POSIX2_LINE_MAX];
9bafe280 186 char fn[MAXHOSTNAMELEN];
e1a085ba 187#endif /* __APPLE__ */
9bafe280 188 char *dot;
e1a085ba 189#if !HAVE_KVM
9bafe280
A
190 int local_error = 0, retry_count = 0;
191 size_t bufSize = 0;
192 size_t orig_bufSize = 0;
193 int mib[4] = {CTL_KERN, KERN_PROC, KERN_PROC_ALL, 0 };
e1a085ba 194#endif
9bafe280
A
195
196 (void)setlocale(LC_ALL, "");
e1a085ba 197#ifndef __APPLE__
9bafe280
A
198 use_ampm = (*nl_langinfo(T_FMT_AMPM) != '\0');
199 use_comma = (*nl_langinfo(RADIXCHAR) != ',');
e1a085ba 200#endif
44bd5ea7
A
201
202 /* Are we w(1) or uptime(1)? */
9bafe280 203 if (this_is_uptime(argv[0]) == 0) {
44bd5ea7
A
204 wcmd = 0;
205 p = "";
206 } else {
207 wcmd = 1;
9bafe280 208 p = "dhiflM:N:nsuw";
44bd5ea7
A
209 }
210
e1a085ba 211#if HAVE_KVM
9bafe280 212 dropgid = 0;
e1a085ba
A
213 memf = nlistf = _PATH_DEVNULL;
214#endif
44bd5ea7
A
215 while ((ch = getopt(argc, argv, p)) != -1)
216 switch (ch) {
e1a085ba 217#ifndef __APPLE__
9bafe280
A
218 case 'd':
219 dflag = 1;
220 break;
e1a085ba 221#endif
44bd5ea7
A
222 case 'h':
223 header = 0;
224 break;
225 case 'i':
226 sortidle = 1;
227 break;
e1a085ba 228#if HAVE_KVM
44bd5ea7
A
229 case 'M':
230 header = 0;
231 memf = optarg;
9bafe280 232 dropgid = 1;
44bd5ea7
A
233 break;
234 case 'N':
235 nlistf = optarg;
9bafe280 236 dropgid = 1;
44bd5ea7 237 break;
e1a085ba
A
238#endif /* HAVE_KVM */
239#if !HAVE_UTMPX
44bd5ea7
A
240 case 'n':
241 nflag = 1;
242 break;
e1a085ba
A
243#else /* !HAVE_UTMPX */
244 case 'n':
245#endif /* !HAVE_UTMPX */
44bd5ea7 246 case 'f': case 'l': case 's': case 'u': case 'w':
e1a085ba
A
247#if !HAVE_KVM
248 case 'M': case 'N':
249#endif
250#ifdef __APPLE__
251 case 'd':
252 warnx("[-MNdflnsuw] no longer supported");
253#else
44bd5ea7 254 warnx("[-flsuw] no longer supported");
e1a085ba 255#endif
44bd5ea7
A
256 /* FALLTHROUGH */
257 case '?':
258 default:
259 usage(wcmd);
260 }
261 argc -= optind;
262 argv += optind;
263
9bafe280
A
264 if (!(_res.options & RES_INIT))
265 res_init();
266 _res.retrans = 2; /* resolver timeout to 2 seconds per try */
267 _res.retry = 1; /* only try once.. */
268
e1a085ba 269#if HAVE_KVM
44bd5ea7 270 /*
9bafe280
A
271 * Discard setgid privileges if not the running kernel so that bad
272 * guys can't print interesting stuff from kernel memory.
44bd5ea7 273 */
9bafe280
A
274 if (dropgid)
275 setgid(getgid());
44bd5ea7 276
c0fcf4e1 277 if ((kd = kvm_openfiles(nlistf, memf, NULL, O_RDONLY, errbuf)) == NULL)
44bd5ea7 278 errx(1, "%s", errbuf);
9bafe280 279#endif
44bd5ea7
A
280
281 (void)time(&now);
e1a085ba
A
282#if HAVE_UTMPX
283 setutxent();
284#else
44bd5ea7
A
285 if ((ut = fopen(_PATH_UTMP, "r")) == NULL)
286 err(1, "%s", _PATH_UTMP);
e1a085ba 287#endif
44bd5ea7
A
288
289 if (*argv)
9bafe280 290 sel_users = argv;
44bd5ea7 291
e1a085ba
A
292#if HAVE_UTMPX
293 for (nusers = 0; (ux = getutxent());) {
294 if (ux->ut_user[0] == '\0' || ux->ut_type != USER_PROCESS)
295 continue;
296 if (!(stp = ttystat(ux->ut_line, sizeof(ux->ut_line))))
297 continue; /* corrupted record */
298#else
44bd5ea7
A
299 for (nusers = 0; fread(&utmp, sizeof(utmp), 1, ut);) {
300 if (utmp.ut_name[0] == '\0')
301 continue;
9bafe280
A
302 if (!(stp = ttystat(utmp.ut_line, UT_LINESIZE)))
303 continue; /* corrupted record */
e1a085ba 304#endif
44bd5ea7 305 ++nusers;
9bafe280 306 if (wcmd == 0)
44bd5ea7 307 continue;
9bafe280
A
308 if (sel_users) {
309 int usermatch;
310 char **user;
311
312 usermatch = 0;
313 for (user = sel_users; !usermatch && *user; user++)
e1a085ba
A
314#if HAVE_UTMPX
315 if (!strncmp(ux->ut_user, *user, sizeof(ux->ut_user)))
316#else
9bafe280 317 if (!strncmp(utmp.ut_name, *user, UT_NAMESIZE))
e1a085ba 318#endif
9bafe280
A
319 usermatch = 1;
320 if (!usermatch)
321 continue;
322 }
44bd5ea7 323 if ((ep = calloc(1, sizeof(struct entry))) == NULL)
9bafe280 324 errx(1, "calloc");
44bd5ea7 325 *nextp = ep;
9bafe280 326 nextp = &ep->next;
e1a085ba
A
327#if HAVE_UTMPX
328 memmove(&ep->utmp, ux, sizeof(*ux));
329#else
9bafe280 330 memmove(&ep->utmp, &utmp, sizeof(struct utmp));
e1a085ba 331#endif
44bd5ea7
A
332 ep->tdev = stp->st_rdev;
333#ifdef CPU_CONSDEV
334 /*
335 * If this is the console device, attempt to ascertain
336 * the true console device dev_t.
337 */
338 if (ep->tdev == 0) {
339 int mib[2];
340 size_t size;
341
342 mib[0] = CTL_MACHDEP;
343 mib[1] = CPU_CONSDEV;
344 size = sizeof(dev_t);
9bafe280 345 (void)sysctl(mib, 2, &ep->tdev, &size, NULL, 0);
44bd5ea7
A
346 }
347#endif
9bafe280 348 touched = stp->st_atime;
e1a085ba
A
349#ifdef __APPLE__
350 if (touched < ep->utmp.ut_tv.tv_sec) {
351 /* tty untouched since before login */
352 touched = ep->utmp.ut_tv.tv_sec;
353 }
354#else
9bafe280
A
355 if (touched < ep->utmp.ut_time) {
356 /* tty untouched since before login */
357 touched = ep->utmp.ut_time;
358 }
e1a085ba 359#endif
9bafe280 360 if ((ep->idle = now - touched) < 0)
44bd5ea7
A
361 ep->idle = 0;
362 }
e1a085ba
A
363#if HAVE_UTMPX
364 endutxent();
365#else
44bd5ea7 366 (void)fclose(ut);
e1a085ba 367#endif
44bd5ea7
A
368
369 if (header || wcmd == 0) {
370 pr_header(&now, nusers);
9bafe280 371 if (wcmd == 0) {
e1a085ba 372#if HAVE_KVM
9bafe280
A
373 (void)kvm_close(kd);
374#endif
375 exit(0);
376 }
44bd5ea7 377
9bafe280
A
378#define HEADER_USER "USER"
379#define HEADER_TTY "TTY"
380#define HEADER_FROM "FROM"
381#define HEADER_LOGIN_IDLE "LOGIN@ IDLE "
382#define HEADER_WHAT "WHAT\n"
383#define WUSED (UT_NAMESIZE + UT_LINESIZE + W_DISPHOSTSIZE + \
384 sizeof(HEADER_LOGIN_IDLE) + 3) /* header width incl. spaces */
385 (void)printf("%-*.*s %-*.*s %-*.*s %s",
386 UT_NAMESIZE, UT_NAMESIZE, HEADER_USER,
387 UT_LINESIZE, UT_LINESIZE, HEADER_TTY,
388 W_DISPHOSTSIZE, W_DISPHOSTSIZE, HEADER_FROM,
389 HEADER_LOGIN_IDLE HEADER_WHAT);
390 }
44bd5ea7 391
e1a085ba 392#if HAVE_KVM
44bd5ea7 393 if ((kp = kvm_getprocs(kd, KERN_PROC_ALL, 0, &nentries)) == NULL)
9bafe280 394 err(1, "%s", kvm_geterr(kd));
44bd5ea7 395#else
9bafe280
A
396 mib[0] = CTL_KERN;
397 mib[1] = KERN_PROC;
398 mib[2] = KERN_PROC_ALL;
399 mib[3] = 0;
400
401 if (sysctl(mib, 4, NULL, &bufSize, NULL, 0) < 0) {
402 perror("Failure calling sysctl");
403 exit(1);
404 }
44bd5ea7 405
9bafe280
A
406 kprocbuf = kp = (struct kinfo_proc *)malloc(bufSize);
407
408 retry_count = 0;
409 orig_bufSize = bufSize;
410 for (retry_count = 0; ; retry_count++) {
411 local_error = 0;
412 bufSize = orig_bufSize;
413 if ((local_error = sysctl(mib, 4, kp, &bufSize, NULL, 0)) < 0) {
414 if (retry_count < 1000) {
415 sleep(1);
416 continue;
417 }
418 perror("Failure calling sysctl");
419 exit(1);
420 } else if (local_error == 0) {
421 break;
422 }
423 sleep(1);
424 }
425 nentries = bufSize / sizeof(struct kinfo_proc);
e1a085ba
A
426#endif /* !HAVE_KVM */
427
428#if !HAVE_KVM
429#define ki_stat kp_proc.p_stat
430#define ki_pgid kp_eproc.e_pgid
431#define ki_tpgid kp_eproc.e_tpgid
432#define ki_tdev kp_eproc.e_tdev
433#endif /* !HAVE_KVM */
9bafe280 434 for (i = 0; i < nentries; i++, kp++) {
e1a085ba 435 if (kp->ki_stat == SIDL || kp->ki_stat == SZOMB)
44bd5ea7 436 continue;
44bd5ea7 437 for (ep = ehead; ep != NULL; ep = ep->next) {
e1a085ba 438 if (ep->tdev == kp->ki_tdev) {
44bd5ea7 439 /*
9bafe280 440 * proc is associated with this terminal
44bd5ea7 441 */
e1a085ba 442 if (ep->kp == NULL && kp->ki_pgid == kp->ki_tpgid) {
9bafe280
A
443 /*
444 * Proc is 'most interesting'
445 */
e1a085ba 446 if (proc_compare(ep->kp, kp))
9bafe280
A
447 ep->kp = kp;
448 }
449 /*
450 * Proc debug option info; add to debug
451 * list using kinfo_proc ki_spare[0]
452 * as next pointer; ptr to ptr avoids the
453 * ptr = long assumption.
454 */
455 dkp = ep->dkp;
456 ep->dkp = kp;
e1a085ba 457#ifndef __APPLE__
9bafe280 458 debugproc(kp) = dkp;
e1a085ba 459#endif
44bd5ea7
A
460 }
461 }
462 }
463 if ((ioctl(STDOUT_FILENO, TIOCGWINSZ, &ws) == -1 &&
464 ioctl(STDERR_FILENO, TIOCGWINSZ, &ws) == -1 &&
465 ioctl(STDIN_FILENO, TIOCGWINSZ, &ws) == -1) || ws.ws_col == 0)
466 ttywidth = 79;
467 else
468 ttywidth = ws.ws_col - 1;
469 argwidth = ttywidth - WUSED;
470 if (argwidth < 4)
471 argwidth = 8;
9bafe280
A
472 for (ep = ehead; ep != NULL; ep = ep->next) {
473 if (ep->kp == NULL) {
474 ep->args = strdup("-");
475 continue;
476 }
e1a085ba 477#if HAVE_KVM
9bafe280 478 ep->args = fmt_argv(kvm_getargv(kd, ep->kp, argwidth),
e1a085ba 479 ep->kp->ki_comm, MAXCOMLEN);
9bafe280
A
480#else
481 w_getargv();
e1a085ba 482#endif /* HAVE_KVM */
9bafe280
A
483 if (ep->args == NULL)
484 err(1, NULL);
485 }
44bd5ea7
A
486 /* sort by idle time */
487 if (sortidle && ehead != NULL) {
9bafe280
A
488 struct entry *from, *save;
489
490 from = ehead;
44bd5ea7
A
491 ehead = NULL;
492 while (from != NULL) {
493 for (nextp = &ehead;
494 (*nextp) && from->idle >= (*nextp)->idle;
495 nextp = &(*nextp)->next)
496 continue;
497 save = from;
498 from = from->next;
499 save->next = *nextp;
500 *nextp = save;
501 }
502 }
44bd5ea7
A
503
504 for (ep = ehead; ep != NULL; ep = ep->next) {
e1a085ba
A
505#if HAVE_UTMPX
506 char host_buf[sizeof(ep->utmp.ut_host) + 1];
507 strlcpy(host_buf, ep->utmp.ut_host, sizeof(host_buf));
508#else
9bafe280
A
509 char host_buf[UT_HOSTSIZE + 1];
510 struct sockaddr_storage ss;
511 struct sockaddr *sa = (struct sockaddr *)&ss;
512 struct sockaddr_in *lsin = (struct sockaddr_in *)&ss;
9bafe280 513 struct sockaddr_in6 *lsin6 = (struct sockaddr_in6 *)&ss;
e1a085ba 514 time_t t;
9bafe280
A
515 int isaddr;
516
517 host_buf[UT_HOSTSIZE] = '\0';
518 strncpy(host_buf, ep->utmp.ut_host, UT_HOSTSIZE);
e1a085ba 519#endif /* HAVE_UTMPX */
9bafe280
A
520 p = *host_buf ? host_buf : "-";
521 if ((x_suffix = strrchr(p, ':')) != NULL) {
522 if ((dot = strchr(x_suffix, '.')) != NULL &&
523 strchr(dot+1, '.') == NULL)
524 *x_suffix++ = '\0';
525 else
526 x_suffix = NULL;
527 }
e1a085ba 528#if !HAVE_UTMPX
9bafe280
A
529 if (!nflag) {
530 /* Attempt to change an IP address into a name */
531 isaddr = 0;
532 memset(&ss, '\0', sizeof(ss));
9bafe280
A
533 if (inet_pton(AF_INET6, p, &lsin6->sin6_addr) == 1) {
534 lsin6->sin6_len = sizeof(*lsin6);
535 lsin6->sin6_family = AF_INET6;
536 isaddr = 1;
537 } else if (inet_pton(AF_INET, p, &lsin->sin_addr) == 1) {
538 lsin->sin_len = sizeof(*lsin);
539 lsin->sin_family = AF_INET;
540 isaddr = 1;
541 }
542 if (isaddr && realhostname_sa(fn, sizeof(fn), sa,
543 sa->sa_len) == HOSTNAME_FOUND)
544 p = fn;
44bd5ea7 545 }
e1a085ba 546#endif /* !HAVE_UTMPX */
9bafe280
A
547 if (x_suffix) {
548 (void)snprintf(buf, sizeof(buf), "%s:%s", p, x_suffix);
44bd5ea7
A
549 p = buf;
550 }
e1a085ba 551#ifndef __APPLE__
9bafe280
A
552 if (dflag) {
553 for (dkp = ep->dkp; dkp != NULL; dkp = debugproc(dkp)) {
554 const char *ptr;
555
556 ptr = fmt_argv(kvm_getargv(kd, dkp, argwidth),
557 dkp->ki_comm, MAXCOMLEN);
558 if (ptr == NULL)
559 ptr = "-";
560 (void)printf("\t\t%-9d %s\n",
561 dkp->ki_pid, ptr);
562 }
563 }
e1a085ba 564#endif /* !__APPLE__ */
9bafe280 565 (void)printf("%-*.*s %-*.*s %-*.*s ",
e1a085ba
A
566#if HAVE_UTMPX
567 UT_NAMESIZE, (int)sizeof(ep->utmp.ut_user), ep->utmp.ut_user,
568 UT_LINESIZE, (int)sizeof(ep->utmp.ut_line),
569#else
44bd5ea7 570 UT_NAMESIZE, UT_NAMESIZE, ep->utmp.ut_name,
9bafe280 571 UT_LINESIZE, UT_LINESIZE,
e1a085ba 572#endif
9bafe280
A
573 strncmp(ep->utmp.ut_line, "tty", 3) &&
574 strncmp(ep->utmp.ut_line, "cua", 3) ?
44bd5ea7 575 ep->utmp.ut_line : ep->utmp.ut_line + 3,
9bafe280 576 W_DISPHOSTSIZE, W_DISPHOSTSIZE, *p ? p : "-");
e1a085ba
A
577#ifdef __APPLE__
578 pr_attime(&ep->utmp.ut_tv.tv_sec, &now);
579#else
580 t = _time_to_time32(ep->utmp.ut_time);
581 pr_attime(&t, &now);
582#endif
9bafe280
A
583 longidle = pr_idle(ep->idle);
584 (void)printf("%.*s\n", argwidth - longidle, ep->args);
e1a085ba 585#ifdef __APPLE__
9bafe280
A
586 free(ep->args);
587#endif
44bd5ea7 588 }
e1a085ba 589#if HAVE_KVM
9bafe280
A
590 (void)kvm_close(kd);
591#else
592 free(kprocbuf);
e1a085ba 593#endif /* HAVE_KVM */
44bd5ea7
A
594 exit(0);
595}
596
44bd5ea7 597static void
e1a085ba 598pr_header(time_t *nowp, int nusers)
44bd5ea7
A
599{
600 double avenrun[3];
601 time_t uptime;
9bafe280 602 int days, hrs, i, mins, secs;
44bd5ea7
A
603 int mib[2];
604 size_t size;
605 char buf[256];
606
607 /*
608 * Print time of day.
44bd5ea7 609 */
e1a085ba
A
610 if (strftime(buf, sizeof(buf),
611 use_ampm ? "%l:%M%p" : "%k:%M", localtime(nowp)) != 0)
612 (void)printf("%s ", buf);
44bd5ea7
A
613 /*
614 * Print how long system has been up.
615 * (Found by looking getting "boottime" from the kernel)
616 */
617 mib[0] = CTL_KERN;
618 mib[1] = KERN_BOOTTIME;
619 size = sizeof(boottime);
620 if (sysctl(mib, 2, &boottime, &size, NULL, 0) != -1 &&
621 boottime.tv_sec != 0) {
622 uptime = now - boottime.tv_sec;
9bafe280
A
623 if (uptime > 60)
624 uptime += 30;
625 days = uptime / 86400;
626 uptime %= 86400;
627 hrs = uptime / 3600;
628 uptime %= 3600;
629 mins = uptime / 60;
630 secs = uptime % 60;
631 (void)printf(" up");
632 if (days > 0)
633 (void)printf(" %d day%s,", days, days > 1 ? "s" : "");
634 if (hrs > 0 && mins > 0)
635 (void)printf(" %2d:%02d,", hrs, mins);
636 else if (hrs > 0)
637 (void)printf(" %d hr%s,", hrs, hrs > 1 ? "s" : "");
638 else if (mins > 0)
639 (void)printf(" %d min%s,", mins, mins > 1 ? "s" : "");
640 else
641 (void)printf(" %d sec%s,", secs, secs > 1 ? "s" : "");
44bd5ea7
A
642 }
643
644 /* Print number of users logged in to system */
9bafe280 645 (void)printf(" %d user%s", nusers, nusers == 1 ? "" : "s");
44bd5ea7
A
646
647 /*
648 * Print 1, 5, and 15 minute load averages.
649 */
650 if (getloadavg(avenrun, sizeof(avenrun) / sizeof(avenrun[0])) == -1)
651 (void)printf(", no load average information available\n");
652 else {
653 (void)printf(", load averages:");
9bafe280
A
654 for (i = 0; i < (int)(sizeof(avenrun) / sizeof(avenrun[0])); i++) {
655 if (use_comma && i > 0)
44bd5ea7
A
656 (void)printf(",");
657 (void)printf(" %.2f", avenrun[i]);
658 }
659 (void)printf("\n");
660 }
661}
662
663static struct stat *
e1a085ba 664ttystat(char *line, int sz)
44bd5ea7
A
665{
666 static struct stat sb;
667 char ttybuf[MAXPATHLEN];
668
9bafe280 669 (void)snprintf(ttybuf, sizeof(ttybuf), "%s%.*s", _PATH_DEV, sz, line);
e1a085ba
A
670 if (stat(ttybuf, &sb) == 0) {
671 return (&sb);
672 } else {
9bafe280 673 warn("%s", ttybuf);
44bd5ea7 674 return (NULL);
9bafe280 675 }
44bd5ea7
A
676}
677
678static void
e1a085ba 679usage(int wcmd)
44bd5ea7
A
680{
681 if (wcmd)
682 (void)fprintf(stderr,
e1a085ba 683 "usage: w [hi] [user ...]\n");
44bd5ea7 684 else
9bafe280 685 (void)fprintf(stderr, "usage: uptime\n");
44bd5ea7
A
686 exit(1);
687}
9bafe280
A
688
689static int
e1a085ba 690this_is_uptime(const char *s)
9bafe280
A
691{
692 const char *u;
693
694 if ((u = strrchr(s, '/')) != NULL)
695 ++u;
696 else
697 u = s;
698 if (strcmp(u, "uptime") == 0)
699 return (0);
700 return (-1);
701}
702
e1a085ba 703#if !HAVE_KVM
9bafe280
A
704static void
705w_getargv(void)
706{
707 int mib[3], argmax;
708 size_t size;
709 char *procargs, *sp, *np, *cp;
710
711 mib[0] = CTL_KERN;
712 mib[1] = KERN_ARGMAX;
713
714 size = sizeof(argmax);
715 if (sysctl(mib, 2, &argmax, &size, NULL, 0) == -1) {
716 goto ERROR;
717 }
718
719 procargs = malloc(argmax);
720 if (procargs == NULL) {
721 goto ERROR;
722 }
723
724 mib[0] = CTL_KERN;
725 mib[1] = KERN_PROCARGS;
726 mib[2] = KI_PROC(ep)->p_pid;
727
728 size = (size_t)argmax;
729 if (sysctl(mib, 3, procargs, &size, NULL, 0) == -1) {
730 goto ERROR_FREE;
731 }
732
733 for (cp = procargs; cp < &procargs[size]; cp++) {
734 if (*cp == '\0') {
735 break;
736 }
737 }
738 if (cp == &procargs[size]) {
739 goto ERROR_FREE;
740 }
741
742 sp = cp;
743
744 for (np = NULL; cp < &procargs[size]; cp++) {
745 if (*cp == '\0') {
746 if (np != NULL) {
747 *np = ' ';
748 }
749 np = cp;
750 } else if (*cp == '=') {
751 break;
752 }
753 }
754
755 for (np = sp; (np < &procargs[size]) && (*np == ' '); np++);
756
757 ep->args = strdup(np);
758 free(procargs);
759 return;
760
761ERROR_FREE:
762 free(procargs);
763ERROR:
764/*
765 ep->args = malloc(2);
766 ep->args[0] = '-';
767 ep->args[1] = '\0';
768*/
769 asprintf(&ep->args, "%s", KI_PROC(ep)->p_comm);
770 return;
771}
e1a085ba 772#endif /* HAVE_KVM */