11590Srgrimes/*- 21590Srgrimes * Copyright (c) 1980, 1991, 1993, 1994 31590Srgrimes * The Regents of the University of California. All rights reserved. 41590Srgrimes * 51590Srgrimes * Redistribution and use in source and binary forms, with or without 61590Srgrimes * modification, are permitted provided that the following conditions 71590Srgrimes * are met: 81590Srgrimes * 1. Redistributions of source code must retain the above copyright 91590Srgrimes * notice, this list of conditions and the following disclaimer. 101590Srgrimes * 2. Redistributions in binary form must reproduce the above copyright 111590Srgrimes * notice, this list of conditions and the following disclaimer in the 121590Srgrimes * documentation and/or other materials provided with the distribution. 131590Srgrimes * 4. Neither the name of the University nor the names of its contributors 141590Srgrimes * may be used to endorse or promote products derived from this software 151590Srgrimes * without specific prior written permission. 161590Srgrimes * 171590Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 181590Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 191590Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 201590Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 211590Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 221590Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 231590Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 241590Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 251590Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 261590Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 271590Srgrimes * SUCH DAMAGE. 281590Srgrimes */ 291590Srgrimes 3087674Smarkm#include <sys/cdefs.h> 3187674Smarkm 3287674Smarkm__FBSDID("$FreeBSD$"); 3387674Smarkm 341590Srgrimes#ifndef lint 3528694Scharnierstatic const char copyright[] = 361590Srgrimes"@(#) Copyright (c) 1980, 1991, 1993, 1994\n\ 371590Srgrimes The Regents of the University of California. All rights reserved.\n"; 3887674Smarkm#endif 391590Srgrimes 401590Srgrimes#ifndef lint 4187674Smarkmstatic const char sccsid[] = "@(#)w.c 8.4 (Berkeley) 4/16/94"; 4228694Scharnier#endif 431590Srgrimes 441590Srgrimes/* 451590Srgrimes * w - print system status (who and what) 461590Srgrimes * 471590Srgrimes * This program is similar to the systat command on Tenex/Tops 10/20 481590Srgrimes * 491590Srgrimes */ 501590Srgrimes#include <sys/param.h> 511590Srgrimes#include <sys/time.h> 521590Srgrimes#include <sys/stat.h> 531590Srgrimes#include <sys/sysctl.h> 541590Srgrimes#include <sys/proc.h> 551590Srgrimes#include <sys/user.h> 561590Srgrimes#include <sys/ioctl.h> 571590Srgrimes#include <sys/socket.h> 581590Srgrimes#include <sys/tty.h> 591590Srgrimes 60253750Savg#include <machine/cpu.h> 611590Srgrimes#include <netinet/in.h> 621590Srgrimes#include <arpa/inet.h> 6387674Smarkm#include <arpa/nameser.h> 641590Srgrimes 65200462Sdelphij#include <ctype.h> 661590Srgrimes#include <err.h> 671590Srgrimes#include <errno.h> 681590Srgrimes#include <fcntl.h> 691590Srgrimes#include <kvm.h> 7073365Sache#include <langinfo.h> 7180407Sbrian#include <libutil.h> 7277212Stmm#include <limits.h> 7373365Sache#include <locale.h> 741590Srgrimes#include <netdb.h> 751590Srgrimes#include <nlist.h> 761590Srgrimes#include <paths.h> 7787674Smarkm#include <resolv.h> 781590Srgrimes#include <stdio.h> 791590Srgrimes#include <stdlib.h> 801590Srgrimes#include <string.h> 81200462Sdelphij#include <timeconv.h> 821590Srgrimes#include <unistd.h> 83202199Sed#include <utmpx.h> 84200462Sdelphij#include <vis.h> 851590Srgrimes 861590Srgrimes#include "extern.h" 871590Srgrimes 88227199Sedstatic struct utmpx *utmp; 89227199Sedstatic struct winsize ws; 90227199Sedstatic kvm_t *kd; 91227199Sedstatic time_t now; /* the current time of day */ 92227199Sedstatic int ttywidth; /* width of tty */ 93227199Sedstatic int argwidth; /* width of tty */ 94227199Sedstatic int header = 1; /* true if -h flag: don't print heading */ 95227199Sedstatic int nflag; /* true if -n flag: don't convert addrs */ 96227199Sedstatic int dflag; /* true if -d flag: output debug info */ 97227199Sedstatic int sortidle; /* sort by idle time */ 9873365Sacheint use_ampm; /* use AM/PM time */ 99227199Sedstatic int use_comma; /* use comma as floats separator */ 100227199Sedstatic char **sel_users; /* login array of particular users selected */ 1011590Srgrimes 1021590Srgrimes/* 1031590Srgrimes * One of these per active utmp entry. 1041590Srgrimes */ 105227199Sedstatic struct entry { 1061590Srgrimes struct entry *next; 107200172Sed struct utmpx utmp; 10829310Sache dev_t tdev; /* dev_t of terminal */ 10929310Sache time_t idle; /* idle time of terminal in seconds */ 11029310Sache struct kinfo_proc *kp; /* `most interesting' proc */ 11129310Sache char *args; /* arg list of interesting process */ 11229310Sache struct kinfo_proc *dkp; /* debug option proc list */ 1131590Srgrimes} *ep, *ehead = NULL, **nextp = &ehead; 1141590Srgrimes 115201611Sdwmalone#define debugproc(p) *(&((struct kinfo_proc *)p)->ki_udata) 1161590Srgrimes 117200172Sed#define W_DISPUSERSIZE 10 118200172Sed#define W_DISPLINESIZE 8 119200172Sed#define W_DISPHOSTSIZE 24 12080407Sbrian 12192922Simpstatic void pr_header(time_t *, int); 122200172Sedstatic struct stat *ttystat(char *); 12392922Simpstatic void usage(int); 12492922Simpstatic int this_is_uptime(const char *s); 12549177Sgreen 126245635Sjhbchar *fmt_argv(char **, char *, char *, size_t); /* ../../bin/ps/fmt.c */ 1271590Srgrimes 1281590Srgrimesint 12997981Sjmallettmain(int argc, char *argv[]) 1301590Srgrimes{ 1311590Srgrimes struct kinfo_proc *kp; 13229310Sache struct kinfo_proc *dkp; 1331590Srgrimes struct stat *stp; 13470242Sbrian time_t touched; 135288139Sdelphij int ch, i, nentries, nusers, wcmd, longidle, longattime; 13687674Smarkm const char *memf, *nlistf, *p; 13787674Smarkm char *x_suffix; 13877212Stmm char buf[MAXHOSTNAMELEN], errbuf[_POSIX2_LINE_MAX]; 13980407Sbrian char fn[MAXHOSTNAMELEN]; 14080407Sbrian char *dot; 1411590Srgrimes 14249177Sgreen (void)setlocale(LC_ALL, ""); 14373365Sache use_ampm = (*nl_langinfo(T_FMT_AMPM) != '\0'); 14473385Sache use_comma = (*nl_langinfo(RADIXCHAR) != ','); 14511755Sache 1461590Srgrimes /* Are we w(1) or uptime(1)? */ 14742055Sdillon if (this_is_uptime(argv[0]) == 0) { 1481590Srgrimes wcmd = 0; 1491590Srgrimes p = ""; 1501590Srgrimes } else { 1511590Srgrimes wcmd = 1; 15229310Sache p = "dhiflM:N:nsuw"; 1531590Srgrimes } 1541590Srgrimes 155203688Sbrucec memf = _PATH_DEVNULL; 156203688Sbrucec nlistf = NULL; 15724360Simp while ((ch = getopt(argc, argv, p)) != -1) 1581590Srgrimes switch (ch) { 15929310Sache case 'd': 16029310Sache dflag = 1; 16129310Sache break; 1621590Srgrimes case 'h': 1631590Srgrimes header = 0; 1641590Srgrimes break; 1651590Srgrimes case 'i': 1661590Srgrimes sortidle = 1; 1671590Srgrimes break; 1681590Srgrimes case 'M': 1691590Srgrimes header = 0; 1701590Srgrimes memf = optarg; 1711590Srgrimes break; 1721590Srgrimes case 'N': 1731590Srgrimes nlistf = optarg; 1741590Srgrimes break; 1751590Srgrimes case 'n': 1761590Srgrimes nflag = 1; 1771590Srgrimes break; 1781590Srgrimes case 'f': case 'l': case 's': case 'u': case 'w': 1791590Srgrimes warnx("[-flsuw] no longer supported"); 1801590Srgrimes /* FALLTHROUGH */ 1811590Srgrimes case '?': 1821590Srgrimes default: 1831590Srgrimes usage(wcmd); 1841590Srgrimes } 1851590Srgrimes argc -= optind; 1861590Srgrimes argv += optind; 1871590Srgrimes 1889573Speter if (!(_res.options & RES_INIT)) 1899573Speter res_init(); 1909573Speter _res.retrans = 2; /* resolver timeout to 2 seconds per try */ 1919573Speter _res.retry = 1; /* only try once.. */ 1929573Speter 1931590Srgrimes if ((kd = kvm_openfiles(nlistf, memf, NULL, O_RDONLY, errbuf)) == NULL) 1941590Srgrimes errx(1, "%s", errbuf); 1951590Srgrimes 1961590Srgrimes (void)time(&now); 1971590Srgrimes 1981590Srgrimes if (*argv) 19949177Sgreen sel_users = argv; 2001590Srgrimes 201200172Sed setutxent(); 202200172Sed for (nusers = 0; (utmp = getutxent()) != NULL;) { 203200172Sed if (utmp->ut_type != USER_PROCESS) 2041590Srgrimes continue; 205200172Sed if (!(stp = ttystat(utmp->ut_line))) 20645201Sbrian continue; /* corrupted record */ 2071590Srgrimes ++nusers; 20849177Sgreen if (wcmd == 0) 2091590Srgrimes continue; 21049177Sgreen if (sel_users) { 21149177Sgreen int usermatch; 21249177Sgreen char **user; 21349177Sgreen 21449177Sgreen usermatch = 0; 21549177Sgreen for (user = sel_users; !usermatch && *user; user++) 216200172Sed if (!strcmp(utmp->ut_user, *user)) 21749177Sgreen usermatch = 1; 21849177Sgreen if (!usermatch) 21949177Sgreen continue; 22049177Sgreen } 2211590Srgrimes if ((ep = calloc(1, sizeof(struct entry))) == NULL) 22228694Scharnier errx(1, "calloc"); 2231590Srgrimes *nextp = ep; 22449177Sgreen nextp = &ep->next; 225200172Sed memmove(&ep->utmp, utmp, sizeof *utmp); 2261590Srgrimes ep->tdev = stp->st_rdev; 2271590Srgrimes /* 2281590Srgrimes * If this is the console device, attempt to ascertain 2291590Srgrimes * the true console device dev_t. 2301590Srgrimes */ 2311590Srgrimes if (ep->tdev == 0) { 2321590Srgrimes size_t size; 2331590Srgrimes 2341590Srgrimes size = sizeof(dev_t); 235158444Sphk (void)sysctlbyname("machdep.consdev", &ep->tdev, &size, NULL, 0); 2361590Srgrimes } 23770242Sbrian touched = stp->st_atime; 238200172Sed if (touched < ep->utmp.ut_tv.tv_sec) { 23970242Sbrian /* tty untouched since before login */ 240200172Sed touched = ep->utmp.ut_tv.tv_sec; 24170242Sbrian } 24270242Sbrian if ((ep->idle = now - touched) < 0) 2431590Srgrimes ep->idle = 0; 2441590Srgrimes } 245200172Sed endutxent(); 2461590Srgrimes 2471590Srgrimes if (header || wcmd == 0) { 2481590Srgrimes pr_header(&now, nusers); 24977367Sphk if (wcmd == 0) { 25077367Sphk (void)kvm_close(kd); 25149177Sgreen exit(0); 25277367Sphk } 2531590Srgrimes 25436276Sjkoshy#define HEADER_USER "USER" 25536276Sjkoshy#define HEADER_TTY "TTY" 25636276Sjkoshy#define HEADER_FROM "FROM" 25736276Sjkoshy#define HEADER_LOGIN_IDLE "LOGIN@ IDLE " 25836276Sjkoshy#define HEADER_WHAT "WHAT\n" 259200172Sed#define WUSED (W_DISPUSERSIZE + W_DISPLINESIZE + W_DISPHOSTSIZE + \ 26036276Sjkoshy sizeof(HEADER_LOGIN_IDLE) + 3) /* header width incl. spaces */ 26136276Sjkoshy (void)printf("%-*.*s %-*.*s %-*.*s %s", 262200172Sed W_DISPUSERSIZE, W_DISPUSERSIZE, HEADER_USER, 263200172Sed W_DISPLINESIZE, W_DISPLINESIZE, HEADER_TTY, 26480407Sbrian W_DISPHOSTSIZE, W_DISPHOSTSIZE, HEADER_FROM, 26536276Sjkoshy HEADER_LOGIN_IDLE HEADER_WHAT); 2669555Speter } 2671590Srgrimes 2681590Srgrimes if ((kp = kvm_getprocs(kd, KERN_PROC_ALL, 0, &nentries)) == NULL) 2691590Srgrimes err(1, "%s", kvm_geterr(kd)); 2701590Srgrimes for (i = 0; i < nentries; i++, kp++) { 271202199Sed if (kp->ki_stat == SIDL || kp->ki_stat == SZOMB || 272202199Sed kp->ki_tdev == NODEV) 2731590Srgrimes continue; 2741590Srgrimes for (ep = ehead; ep != NULL; ep = ep->next) { 27569896Smckusick if (ep->tdev == kp->ki_tdev) { 2761590Srgrimes /* 27729310Sache * proc is associated with this terminal 2781590Srgrimes */ 27969896Smckusick if (ep->kp == NULL && kp->ki_pgid == kp->ki_tpgid) { 28029310Sache /* 28129310Sache * Proc is 'most interesting' 28229310Sache */ 28369896Smckusick if (proc_compare(ep->kp, kp)) 28429310Sache ep->kp = kp; 28529310Sache } 28629310Sache /* 28729310Sache * Proc debug option info; add to debug 28869896Smckusick * list using kinfo_proc ki_spare[0] 28929310Sache * as next pointer; ptr to ptr avoids the 29029310Sache * ptr = long assumption. 29129310Sache */ 29229310Sache dkp = ep->dkp; 29329310Sache ep->dkp = kp; 29449177Sgreen debugproc(kp) = dkp; 2951590Srgrimes } 2961590Srgrimes } 2971590Srgrimes } 2981590Srgrimes if ((ioctl(STDOUT_FILENO, TIOCGWINSZ, &ws) == -1 && 2991590Srgrimes ioctl(STDERR_FILENO, TIOCGWINSZ, &ws) == -1 && 3001590Srgrimes ioctl(STDIN_FILENO, TIOCGWINSZ, &ws) == -1) || ws.ws_col == 0) 3011590Srgrimes ttywidth = 79; 3021590Srgrimes else 3031590Srgrimes ttywidth = ws.ws_col - 1; 3041590Srgrimes argwidth = ttywidth - WUSED; 3051590Srgrimes if (argwidth < 4) 3061590Srgrimes argwidth = 8; 3071590Srgrimes for (ep = ehead; ep != NULL; ep = ep->next) { 3081590Srgrimes if (ep->kp == NULL) { 30987674Smarkm ep->args = strdup("-"); 3101590Srgrimes continue; 3111590Srgrimes } 3121590Srgrimes ep->args = fmt_argv(kvm_getargv(kd, ep->kp, argwidth), 313245635Sjhb ep->kp->ki_comm, NULL, MAXCOMLEN); 3141590Srgrimes if (ep->args == NULL) 3151590Srgrimes err(1, NULL); 3161590Srgrimes } 3171590Srgrimes /* sort by idle time */ 3181590Srgrimes if (sortidle && ehead != NULL) { 31949177Sgreen struct entry *from, *save; 3208874Srgrimes 32149177Sgreen from = ehead; 3221590Srgrimes ehead = NULL; 3231590Srgrimes while (from != NULL) { 3241590Srgrimes for (nextp = &ehead; 3251590Srgrimes (*nextp) && from->idle >= (*nextp)->idle; 3261590Srgrimes nextp = &(*nextp)->next) 3271590Srgrimes continue; 3281590Srgrimes save = from; 3291590Srgrimes from = from->next; 3301590Srgrimes save->next = *nextp; 3311590Srgrimes *nextp = save; 3321590Srgrimes } 3331590Srgrimes } 3348874Srgrimes 3351590Srgrimes for (ep = ehead; ep != NULL; ep = ep->next) { 336199655Sume struct addrinfo hints, *res; 33780407Sbrian struct sockaddr_storage ss; 33880407Sbrian struct sockaddr *sa = (struct sockaddr *)&ss; 33987674Smarkm struct sockaddr_in *lsin = (struct sockaddr_in *)&ss; 34087674Smarkm struct sockaddr_in6 *lsin6 = (struct sockaddr_in6 *)&ss; 341116998Speter time_t t; 34280407Sbrian int isaddr; 34345946Sache 344200172Sed p = *ep->utmp.ut_host ? ep->utmp.ut_host : "-"; 34580407Sbrian if ((x_suffix = strrchr(p, ':')) != NULL) { 34680407Sbrian if ((dot = strchr(x_suffix, '.')) != NULL && 34780407Sbrian strchr(dot+1, '.') == NULL) 34880407Sbrian *x_suffix++ = '\0'; 34980407Sbrian else 35080407Sbrian x_suffix = NULL; 3511590Srgrimes } 352199655Sume 353199655Sume isaddr = 0; 354199655Sume memset(&ss, '\0', sizeof(ss)); 355199655Sume if (inet_pton(AF_INET6, p, &lsin6->sin6_addr) == 1) { 356199655Sume lsin6->sin6_len = sizeof(*lsin6); 357199655Sume lsin6->sin6_family = AF_INET6; 358199655Sume isaddr = 1; 359199655Sume } else if (inet_pton(AF_INET, p, &lsin->sin_addr) == 1) { 360199655Sume lsin->sin_len = sizeof(*lsin); 361199655Sume lsin->sin_family = AF_INET; 362199655Sume isaddr = 1; 363199655Sume } 36480407Sbrian if (!nflag) { 36580407Sbrian /* Attempt to change an IP address into a name */ 36680407Sbrian if (isaddr && realhostname_sa(fn, sizeof(fn), sa, 36780407Sbrian sa->sa_len) == HOSTNAME_FOUND) 36880407Sbrian p = fn; 369199655Sume } else if (!isaddr) { 370199655Sume /* 371199655Sume * If a host has only one A/AAAA RR, change a 372199655Sume * name into an IP address 373199655Sume */ 374199655Sume memset(&hints, 0, sizeof(hints)); 375199655Sume hints.ai_flags = AI_PASSIVE; 376199655Sume hints.ai_family = AF_UNSPEC; 377199655Sume hints.ai_socktype = SOCK_STREAM; 378199655Sume if (getaddrinfo(p, NULL, &hints, &res) == 0) { 379199655Sume if (res->ai_next == NULL && 380199655Sume getnameinfo(res->ai_addr, res->ai_addrlen, 381199655Sume fn, sizeof(fn), NULL, 0, 382199655Sume NI_NUMERICHOST) == 0) 383199655Sume p = fn; 384199655Sume freeaddrinfo(res); 385199655Sume } 38616436Sache } 387199655Sume 38880407Sbrian if (x_suffix) { 38980407Sbrian (void)snprintf(buf, sizeof(buf), "%s:%s", p, x_suffix); 3901590Srgrimes p = buf; 3911590Srgrimes } 39242481Speter if (dflag) { 39349177Sgreen for (dkp = ep->dkp; dkp != NULL; dkp = debugproc(dkp)) { 39487674Smarkm const char *ptr; 39549177Sgreen 39645201Sbrian ptr = fmt_argv(kvm_getargv(kd, dkp, argwidth), 397245635Sjhb dkp->ki_comm, NULL, MAXCOMLEN); 39845201Sbrian if (ptr == NULL) 39945201Sbrian ptr = "-"; 40049177Sgreen (void)printf("\t\t%-9d %s\n", 40169896Smckusick dkp->ki_pid, ptr); 40229310Sache } 40329310Sache } 40435309Sphk (void)printf("%-*.*s %-*.*s %-*.*s ", 405200172Sed W_DISPUSERSIZE, W_DISPUSERSIZE, ep->utmp.ut_user, 406200172Sed W_DISPLINESIZE, W_DISPLINESIZE, 407202199Sed *ep->utmp.ut_line ? 408202199Sed (strncmp(ep->utmp.ut_line, "tty", 3) && 4093138Sache strncmp(ep->utmp.ut_line, "cua", 3) ? 410202199Sed ep->utmp.ut_line : ep->utmp.ut_line + 3) : "-", 41180407Sbrian W_DISPHOSTSIZE, W_DISPHOSTSIZE, *p ? p : "-"); 412200172Sed t = ep->utmp.ut_tv.tv_sec; 413196652Sume longattime = pr_attime(&t, &now); 41442481Speter longidle = pr_idle(ep->idle); 415196652Sume (void)printf("%.*s\n", argwidth - longidle - longattime, 416196652Sume ep->args); 4171590Srgrimes } 41877367Sphk (void)kvm_close(kd); 4191590Srgrimes exit(0); 4201590Srgrimes} 4211590Srgrimes 4221590Srgrimesstatic void 42397981Sjmallettpr_header(time_t *nowp, int nusers) 4241590Srgrimes{ 4251590Srgrimes double avenrun[3]; 42691837Sobrien time_t uptime; 427151417Sandre struct timespec tp; 42830389Sache int days, hrs, i, mins, secs; 4291590Srgrimes char buf[256]; 4301590Srgrimes 4311590Srgrimes /* 4321590Srgrimes * Print time of day. 4331590Srgrimes */ 434119854Scharnier if (strftime(buf, sizeof(buf), 435119854Scharnier use_ampm ? "%l:%M%p" : "%k:%M", localtime(nowp)) != 0) 436119854Scharnier (void)printf("%s ", buf); 4371590Srgrimes /* 4381590Srgrimes * Print how long system has been up. 4391590Srgrimes */ 440241484Semaste if (clock_gettime(CLOCK_UPTIME, &tp) != -1) { 441151417Sandre uptime = tp.tv_sec; 44291837Sobrien if (uptime > 60) 44391837Sobrien uptime += 30; 44491837Sobrien days = uptime / 86400; 44591837Sobrien uptime %= 86400; 44691837Sobrien hrs = uptime / 3600; 44791837Sobrien uptime %= 3600; 44891837Sobrien mins = uptime / 60; 44991837Sobrien secs = uptime % 60; 4501590Srgrimes (void)printf(" up"); 4511590Srgrimes if (days > 0) 4521590Srgrimes (void)printf(" %d day%s,", days, days > 1 ? "s" : ""); 4531590Srgrimes if (hrs > 0 && mins > 0) 4541590Srgrimes (void)printf(" %2d:%02d,", hrs, mins); 45530389Sache else if (hrs > 0) 45649177Sgreen (void)printf(" %d hr%s,", hrs, hrs > 1 ? "s" : ""); 45730389Sache else if (mins > 0) 45849177Sgreen (void)printf(" %d min%s,", mins, mins > 1 ? "s" : ""); 45930389Sache else 46049177Sgreen (void)printf(" %d sec%s,", secs, secs > 1 ? "s" : ""); 4611590Srgrimes } 4621590Srgrimes 4631590Srgrimes /* Print number of users logged in to system */ 4646542Ssmace (void)printf(" %d user%s", nusers, nusers == 1 ? "" : "s"); 4651590Srgrimes 4661590Srgrimes /* 4671590Srgrimes * Print 1, 5, and 15 minute load averages. 4681590Srgrimes */ 4691590Srgrimes if (getloadavg(avenrun, sizeof(avenrun) / sizeof(avenrun[0])) == -1) 4701590Srgrimes (void)printf(", no load average information available\n"); 4711590Srgrimes else { 4721590Srgrimes (void)printf(", load averages:"); 47387674Smarkm for (i = 0; i < (int)(sizeof(avenrun) / sizeof(avenrun[0])); i++) { 47473385Sache if (use_comma && i > 0) 47573385Sache (void)printf(","); 47673385Sache (void)printf(" %.2f", avenrun[i]); 47773385Sache } 4781590Srgrimes (void)printf("\n"); 4791590Srgrimes } 4801590Srgrimes} 4811590Srgrimes 4821590Srgrimesstatic struct stat * 483200172Sedttystat(char *line) 4841590Srgrimes{ 4851590Srgrimes static struct stat sb; 4861590Srgrimes char ttybuf[MAXPATHLEN]; 4871590Srgrimes 488200172Sed (void)snprintf(ttybuf, sizeof(ttybuf), "%s%s", _PATH_DEV, line); 489223786Sed if (stat(ttybuf, &sb) == 0 && S_ISCHR(sb.st_mode)) { 490102300Sseanc return (&sb); 491102300Sseanc } else 49249177Sgreen return (NULL); 4931590Srgrimes} 4941590Srgrimes 4951590Srgrimesstatic void 49697981Sjmallettusage(int wcmd) 4971590Srgrimes{ 4981590Srgrimes if (wcmd) 4991590Srgrimes (void)fprintf(stderr, 50049177Sgreen "usage: w [-dhin] [-M core] [-N system] [user ...]\n"); 5011590Srgrimes else 50249177Sgreen (void)fprintf(stderr, "usage: uptime\n"); 50349177Sgreen exit(1); 5041590Srgrimes} 50542055Sdillon 50642055Sdillonstatic int 50797981Sjmallettthis_is_uptime(const char *s) 50842055Sdillon{ 50942055Sdillon const char *u; 51042055Sdillon 51142055Sdillon if ((u = strrchr(s, '/')) != NULL) 51242055Sdillon ++u; 51342055Sdillon else 51442055Sdillon u = s; 51542055Sdillon if (strcmp(u, "uptime") == 0) 51649177Sgreen return (0); 51749177Sgreen return (-1); 51842055Sdillon} 519