]> git.saurik.com Git - apple/shell_cmds.git/blame_incremental - w/w.c
shell_cmds-116.tar.gz
[apple/shell_cmds.git] / w / w.c
... / ...
CommitLineData
1/*-
2 * Copyright (c) 1980, 1991, 1993, 1994
3 * The Regents of the University of California. All rights reserved.
4 * Portions copyright (c) 2007 Apple Inc. All rights reserved.
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.
14 * 3. Neither the name of the University nor the names of its contributors
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>
32
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
37#ifndef lint
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
42
43#ifndef lint
44static const char sccsid[] = "@(#)w.c 8.4 (Berkeley) 4/16/94";
45#endif
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>
61#include <sys/tty.h>
62
63#ifndef __APPLE__
64#include <machine/cpu.h>
65#endif
66#include <netinet/in.h>
67#include <arpa/inet.h>
68#include <arpa/nameser.h>
69
70#include <ctype.h>
71#include <err.h>
72#include <errno.h>
73#include <fcntl.h>
74#if HAVE_KVM
75#include <kvm.h>
76#endif
77#include <langinfo.h>
78#include <libutil.h>
79#include <limits.h>
80#include <locale.h>
81#include <netdb.h>
82#include <nlist.h>
83#include <paths.h>
84#include <resolv.h>
85#include <stdio.h>
86#include <stdlib.h>
87#include <string.h>
88#include <timeconv.h>
89#include <unistd.h>
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 */
96#include <utmp.h>
97#endif /* HAVE_UTMPX */
98#include <vis.h>
99
100#include "extern.h"
101
102struct timeval boottime;
103#if !HAVE_UTMPX
104struct utmp utmp;
105#endif
106struct winsize ws;
107#if HAVE_KVM
108kvm_t *kd;
109#endif
110time_t now; /* the current time of day */
111int ttywidth; /* width of tty */
112int argwidth; /* width of tty */
113int header = 1; /* true if -h flag: don't print heading */
114#if !HAVE_UTMPX
115int nflag; /* true if -n flag: don't convert addrs */
116#endif
117#ifndef __APPLE__
118int dflag; /* true if -d flag: output debug info */
119#endif
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 */
124
125/*
126 * One of these per active utmp entry.
127 */
128struct entry {
129 struct entry *next;
130#if HAVE_UTMPX
131 struct utmpx utmp;
132#else
133 struct utmp utmp;
134#endif
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 */
140} *ep, *ehead = NULL, **nextp = &ehead;
141
142#ifndef __APPLE__
143#define debugproc(p) *((struct kinfo_proc **)&(p)->ki_udata)
144#else
145#define debugproc(p) *((struct kinfo_proc **)&(p)->ki_spare[0])
146#endif
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);
155#if !HAVE_KVM
156static void w_getargv(void);
157#endif
158
159char *fmt_argv(char **, char *, int); /* ../../bin/ps/fmt.c */
160
161int
162main(int argc, char *argv[])
163{
164 struct kinfo_proc *kp;
165 struct kinfo_proc *kprocbuf;
166 struct kinfo_proc *dkp;
167 struct stat *stp;
168#if HAVE_UTMPX
169 struct utmpx *ux;
170#else
171 FILE *ut;
172#endif
173 time_t touched;
174#if HAVE_KVM
175 int ch, i, nentries, nusers, wcmd, longidle, dropgid;
176 const char *memf, *nlistf, *p;
177#else
178 int ch, i, nentries, nusers, wcmd, longidle;
179 const char *p;
180#endif /* HAVE_KVM */
181 char *x_suffix;
182#ifdef __APPLE__
183 char buf[MAXHOSTNAMELEN];
184#else
185 char buf[MAXHOSTNAMELEN], errbuf[_POSIX2_LINE_MAX];
186 char fn[MAXHOSTNAMELEN];
187#endif /* __APPLE__ */
188 char *dot;
189#if !HAVE_KVM
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 };
194#endif
195
196 (void)setlocale(LC_ALL, "");
197#ifndef __APPLE__
198 use_ampm = (*nl_langinfo(T_FMT_AMPM) != '\0');
199 use_comma = (*nl_langinfo(RADIXCHAR) != ',');
200#endif
201
202 /* Are we w(1) or uptime(1)? */
203 if (this_is_uptime(argv[0]) == 0) {
204 wcmd = 0;
205 p = "";
206 } else {
207 wcmd = 1;
208 p = "dhiflM:N:nsuw";
209 }
210
211#if HAVE_KVM
212 dropgid = 0;
213 memf = nlistf = _PATH_DEVNULL;
214#endif
215 while ((ch = getopt(argc, argv, p)) != -1)
216 switch (ch) {
217#ifndef __APPLE__
218 case 'd':
219 dflag = 1;
220 break;
221#endif
222 case 'h':
223 header = 0;
224 break;
225 case 'i':
226 sortidle = 1;
227 break;
228#if HAVE_KVM
229 case 'M':
230 header = 0;
231 memf = optarg;
232 dropgid = 1;
233 break;
234 case 'N':
235 nlistf = optarg;
236 dropgid = 1;
237 break;
238#endif /* HAVE_KVM */
239#if !HAVE_UTMPX
240 case 'n':
241 nflag = 1;
242 break;
243#else /* !HAVE_UTMPX */
244 case 'n':
245#endif /* !HAVE_UTMPX */
246 case 'f': case 'l': case 's': case 'u': case 'w':
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
254 warnx("[-flsuw] no longer supported");
255#endif
256 /* FALLTHROUGH */
257 case '?':
258 default:
259 usage(wcmd);
260 }
261 argc -= optind;
262 argv += optind;
263
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
269#if HAVE_KVM
270 /*
271 * Discard setgid privileges if not the running kernel so that bad
272 * guys can't print interesting stuff from kernel memory.
273 */
274 if (dropgid)
275 setgid(getgid());
276
277 if ((kd = kvm_openfiles(nlistf, memf, NULL, O_RDONLY, errbuf)) == NULL)
278 errx(1, "%s", errbuf);
279#endif
280
281 (void)time(&now);
282#if HAVE_UTMPX
283 setutxent();
284#else
285 if ((ut = fopen(_PATH_UTMP, "r")) == NULL)
286 err(1, "%s", _PATH_UTMP);
287#endif
288
289 if (*argv)
290 sel_users = argv;
291
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
299 for (nusers = 0; fread(&utmp, sizeof(utmp), 1, ut);) {
300 if (utmp.ut_name[0] == '\0')
301 continue;
302 if (!(stp = ttystat(utmp.ut_line, UT_LINESIZE)))
303 continue; /* corrupted record */
304#endif
305 ++nusers;
306 if (wcmd == 0)
307 continue;
308 if (sel_users) {
309 int usermatch;
310 char **user;
311
312 usermatch = 0;
313 for (user = sel_users; !usermatch && *user; user++)
314#if HAVE_UTMPX
315 if (!strncmp(ux->ut_user, *user, sizeof(ux->ut_user)))
316#else
317 if (!strncmp(utmp.ut_name, *user, UT_NAMESIZE))
318#endif
319 usermatch = 1;
320 if (!usermatch)
321 continue;
322 }
323 if ((ep = calloc(1, sizeof(struct entry))) == NULL)
324 errx(1, "calloc");
325 *nextp = ep;
326 nextp = &ep->next;
327#if HAVE_UTMPX
328 memmove(&ep->utmp, ux, sizeof(*ux));
329#else
330 memmove(&ep->utmp, &utmp, sizeof(struct utmp));
331#endif
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);
345 (void)sysctl(mib, 2, &ep->tdev, &size, NULL, 0);
346 }
347#endif
348 touched = stp->st_atime;
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
355 if (touched < ep->utmp.ut_time) {
356 /* tty untouched since before login */
357 touched = ep->utmp.ut_time;
358 }
359#endif
360 if ((ep->idle = now - touched) < 0)
361 ep->idle = 0;
362 }
363#if HAVE_UTMPX
364 endutxent();
365#else
366 (void)fclose(ut);
367#endif
368
369 if (header || wcmd == 0) {
370 pr_header(&now, nusers);
371 if (wcmd == 0) {
372#if HAVE_KVM
373 (void)kvm_close(kd);
374#endif
375 exit(0);
376 }
377
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 }
391
392#if HAVE_KVM
393 if ((kp = kvm_getprocs(kd, KERN_PROC_ALL, 0, &nentries)) == NULL)
394 err(1, "%s", kvm_geterr(kd));
395#else
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 }
405
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);
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 */
434 for (i = 0; i < nentries; i++, kp++) {
435 if (kp->ki_stat == SIDL || kp->ki_stat == SZOMB)
436 continue;
437 for (ep = ehead; ep != NULL; ep = ep->next) {
438 if (ep->tdev == kp->ki_tdev) {
439 /*
440 * proc is associated with this terminal
441 */
442 if (ep->kp == NULL && kp->ki_pgid == kp->ki_tpgid) {
443 /*
444 * Proc is 'most interesting'
445 */
446 if (proc_compare(ep->kp, kp))
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;
457#ifndef __APPLE__
458 debugproc(kp) = dkp;
459#endif
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;
472 for (ep = ehead; ep != NULL; ep = ep->next) {
473 if (ep->kp == NULL) {
474 ep->args = strdup("-");
475 continue;
476 }
477#if HAVE_KVM
478 ep->args = fmt_argv(kvm_getargv(kd, ep->kp, argwidth),
479 ep->kp->ki_comm, MAXCOMLEN);
480#else
481 w_getargv();
482#endif /* HAVE_KVM */
483 if (ep->args == NULL)
484 err(1, NULL);
485 }
486 /* sort by idle time */
487 if (sortidle && ehead != NULL) {
488 struct entry *from, *save;
489
490 from = ehead;
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 }
503
504 for (ep = ehead; ep != NULL; ep = ep->next) {
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
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;
513 struct sockaddr_in6 *lsin6 = (struct sockaddr_in6 *)&ss;
514 time_t t;
515 int isaddr;
516
517 host_buf[UT_HOSTSIZE] = '\0';
518 strncpy(host_buf, ep->utmp.ut_host, UT_HOSTSIZE);
519#endif /* HAVE_UTMPX */
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 }
528#if !HAVE_UTMPX
529 if (!nflag) {
530 /* Attempt to change an IP address into a name */
531 isaddr = 0;
532 memset(&ss, '\0', sizeof(ss));
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;
545 }
546#endif /* !HAVE_UTMPX */
547 if (x_suffix) {
548 (void)snprintf(buf, sizeof(buf), "%s:%s", p, x_suffix);
549 p = buf;
550 }
551#ifndef __APPLE__
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 }
564#endif /* !__APPLE__ */
565 (void)printf("%-*.*s %-*.*s %-*.*s ",
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
570 UT_NAMESIZE, UT_NAMESIZE, ep->utmp.ut_name,
571 UT_LINESIZE, UT_LINESIZE,
572#endif
573 strncmp(ep->utmp.ut_line, "tty", 3) &&
574 strncmp(ep->utmp.ut_line, "cua", 3) ?
575 ep->utmp.ut_line : ep->utmp.ut_line + 3,
576 W_DISPHOSTSIZE, W_DISPHOSTSIZE, *p ? p : "-");
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
583 longidle = pr_idle(ep->idle);
584 (void)printf("%.*s\n", argwidth - longidle, ep->args);
585#ifdef __APPLE__
586 free(ep->args);
587#endif
588 }
589#if HAVE_KVM
590 (void)kvm_close(kd);
591#else
592 free(kprocbuf);
593#endif /* HAVE_KVM */
594 exit(0);
595}
596
597static void
598pr_header(time_t *nowp, int nusers)
599{
600 double avenrun[3];
601 time_t uptime;
602 int days, hrs, i, mins, secs;
603 int mib[2];
604 size_t size;
605 char buf[256];
606
607 /*
608 * Print time of day.
609 */
610 if (strftime(buf, sizeof(buf),
611 use_ampm ? "%l:%M%p" : "%k:%M", localtime(nowp)) != 0)
612 (void)printf("%s ", buf);
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;
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" : "");
642 }
643
644 /* Print number of users logged in to system */
645 (void)printf(" %d user%s", nusers, nusers == 1 ? "" : "s");
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:");
654 for (i = 0; i < (int)(sizeof(avenrun) / sizeof(avenrun[0])); i++) {
655 if (use_comma && i > 0)
656 (void)printf(",");
657 (void)printf(" %.2f", avenrun[i]);
658 }
659 (void)printf("\n");
660 }
661}
662
663static struct stat *
664ttystat(char *line, int sz)
665{
666 static struct stat sb;
667 char ttybuf[MAXPATHLEN];
668
669 (void)snprintf(ttybuf, sizeof(ttybuf), "%s%.*s", _PATH_DEV, sz, line);
670 if (stat(ttybuf, &sb) == 0) {
671 return (&sb);
672 } else {
673 warn("%s", ttybuf);
674 return (NULL);
675 }
676}
677
678static void
679usage(int wcmd)
680{
681 if (wcmd)
682 (void)fprintf(stderr,
683 "usage: w [hi] [user ...]\n");
684 else
685 (void)fprintf(stderr, "usage: uptime\n");
686 exit(1);
687}
688
689static int
690this_is_uptime(const char *s)
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
703#if !HAVE_KVM
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}
772#endif /* HAVE_KVM */