BSD 4_4 release
[unix-history] / usr / src / usr.bin / w / w.c
index 254505a..855948b 100644 (file)
@@ -1,18 +1,45 @@
-/*
- * Copyright (c) 1980 Regents of the University of California.
- * All rights reserved.  The Berkeley software License Agreement
- * specifies the terms and conditions for redistribution.
+/*-
+ * Copyright (c) 1980, 1991, 1993
+ *     The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
  */
 
 #ifndef lint
  */
 
 #ifndef lint
-char copyright[] =
-"@(#) Copyright (c) 1980 Regents of the University of California.\n\
- All rights reserved.\n";
-#endif not lint
+static char copyright[] =
+"@(#) Copyright (c) 1980, 1991, 1993\n\
      The Regents of the University of California.  All rights reserved.\n";
+#endif /* not lint */
 
 #ifndef lint
 
 #ifndef lint
-static char sccsid[] = "@(#)w.c        5.24 (Berkeley) 7/27/90";
-#endif not lint
+static char sccsid[] = "@(#)w.c        8.1 (Berkeley) 6/6/93";
+#endif /* not lint */
 
 /*
  * w - print system status (who and what)
 
 /*
  * w - print system status (who and what)
@@ -21,237 +48,204 @@ static char sccsid[] = "@(#)w.c   5.24 (Berkeley) 7/27/90";
  *
  */
 #include <sys/param.h>
  *
  */
 #include <sys/param.h>
-#include <utmp.h>
+#include <sys/time.h>
 #include <sys/stat.h>
 #include <sys/stat.h>
-#include <sys/user.h>
+#include <sys/sysctl.h>
 #include <sys/proc.h>
 #include <sys/proc.h>
+#include <sys/user.h>
 #include <sys/ioctl.h>
 #include <sys/ioctl.h>
-#include <machine/pte.h>
-#include <sys/vm.h>
+#include <sys/socket.h>
 #include <sys/tty.h>
 #include <sys/tty.h>
-#include <nlist.h>
-#include <kvm.h>
+
+#include <machine/cpu.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
 #include <ctype.h>
 #include <ctype.h>
+#include <err.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <kvm.h>
+#include <netdb.h>
+#include <nlist.h>
 #include <paths.h>
 #include <paths.h>
-#include <string.h>
 #include <stdio.h>
 #include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <tzfile.h>
+#include <unistd.h>
+#include <utmp.h>
 
 
-char   *program;
-int    ttywidth;               /* width of tty */
-int    argwidth;               /* width of tty */
-int    header = 1;             /* true if -h flag: don't print heading */
-int    wcmd = 1;               /* true if this is w(1), and not uptime(1) */
-int    nusers;                 /* number of users logged in now */
-char * sel_user;               /* login of particular user selected */
-time_t now;                    /* the current time of day */
-struct timeval boottime;
-time_t uptime;                 /* time of last reboot & elapsed time since */
-struct utmp utmp;
-struct winsize ws;
-int    sortidle;               /* sort bu idle time */
-
+#include "extern.h"
+
+struct timeval boottime;
+struct utmp utmp;
+struct winsize ws;
+kvm_t *kd;
+time_t now;                    /* the current time of day */
+time_t uptime;                 /* time of last reboot & elapsed time since */
+int ttywidth;                  /* width of tty */
+int argwidth;                  /* width of tty */
+int header = 1;                        /* true if -h flag: don't print heading */
+int nflag;                     /* true if -n flag: don't convert addrs */
+int sortidle;                  /* sort bu idle time */
+char *sel_user;                        /* login of particular user selected */
+char *program;
+char domain[MAXHOSTNAMELEN];
 
 /*
 
 /*
- * One of these per active utmp entry.  
+ * One of these per active utmp entry.
  */
 struct entry {
        struct  entry *next;
        struct  utmp utmp;
        dev_t   tdev;           /* dev_t of terminal */
  */
 struct entry {
        struct  entry *next;
        struct  utmp utmp;
        dev_t   tdev;           /* dev_t of terminal */
-       int     idle;           /* idle time of terminal in minutes */
-       struct  proc *proc;     /* list of procs in foreground */
+       time_t  idle;           /* idle time of terminal in seconds */
+       struct  kinfo_proc *kp; /* `most interesting' proc */
        char    *args;          /* arg list of interesting process */
 } *ep, *ehead = NULL, **nextp = &ehead;
 
        char    *args;          /* arg list of interesting process */
 } *ep, *ehead = NULL, **nextp = &ehead;
 
-struct nlist nl[] = {
-       { "_boottime" },
-#define X_BOOTTIME     0
-#if defined(hp300)
-       { "_cn_tty" },
-#define X_CNTTY                1
-#endif
-       { "" },
-};
+static void     pr_header __P((time_t *, int));
+static struct stat
+               *ttystat __P((char *));
+static void     usage __P((int));
 
 
-#define USAGE "[ -hi ] [ user ]"
-#define usage()        fprintf(stderr, "usage: %s: %s\n", program, USAGE)
+char *fmt_argv __P((char **, char *, int));
 
 
+int
 main(argc, argv)
 main(argc, argv)
+       int argc;
        char **argv;
 {
        char **argv;
 {
-       register int i;
-       struct winsize win;
-       register struct proc *p;
-       struct eproc *e;
-       struct stat *stp, *ttystat();
-       FILE *ut;
-       char *cp;
-       int ch;
        extern char *optarg;
        extern int optind;
        extern char *optarg;
        extern int optind;
-       char *strsave();
+       struct kinfo_proc *kp;
+       struct hostent *hp;
+       struct stat *stp;
+       FILE *ut;
+       u_long l;
+       int ch, i, nentries, nusers, wcmd;
+       char *memf, *nlistf, *p, *x;
+       char buf[MAXHOSTNAMELEN], errbuf[256];
 
 
+       /* Are we w(1) or uptime(1)? */
        program = argv[0];
        program = argv[0];
-       /*
-        * are we w(1) or uptime(1)
-        */
-       if ((cp = rindex(program, '/')) || *(cp = program) == '-')
-               cp++;
-       if (*cp == 'u')
+       if ((p = rindex(program, '/')) || *(p = program) == '-')
+               p++;
+       if (*p == 'u') {
                wcmd = 0;
                wcmd = 0;
+               p = "";
+       } else {
+               wcmd = 1;
+               p = "hiflM:N:nsuw";
+       }
 
 
-       while ((ch = getopt(argc, argv, "hiflsuw")) != EOF)
-               switch((char)ch) {
+       memf = nlistf = NULL;
+       while ((ch = getopt(argc, argv, p)) != EOF)
+               switch (ch) {
                case 'h':
                        header = 0;
                        break;
                case 'i':
                case 'h':
                        header = 0;
                        break;
                case 'i':
-                       sortidle++;
+                       sortidle = 1;
+                       break;
+               case 'M':
+                       header = 0;
+                       memf = optarg;
+                       break;
+               case 'N':
+                       nlistf = optarg;
+                       break;
+               case 'n':
+                       nflag = 1;
                        break;
                case 'f': case 'l': case 's': case 'u': case 'w':
                        break;
                case 'f': case 'l': case 's': case 'u': case 'w':
-                       error("[-flsuw] no longer supported");
-                       usage();
-                       exit(1);
+                       warnx("[-flsuw] no longer supported");
+                       /* FALLTHROUGH */
                case '?':
                default:
                case '?':
                default:
-                       usage();
-                       exit(1);
+                       usage(wcmd);
                }
        argc -= optind;
        argv += optind;
                }
        argc -= optind;
        argv += optind;
-       if (argc == 1) {
-               sel_user = argv[0];
-               argv++, argc--;
-       }
-       if (argc) {
-               usage();
-               exit(1);
-       }
 
 
-       if (header && kvm_nlist(nl) != 0) {
-               error("can't get namelist");
-               exit (1);
-       }
-       time(&now);
-       ut = fopen(_PATH_UTMP, "r");
-       while (fread(&utmp, sizeof(utmp), 1, ut)) {
+       if ((kd = kvm_openfiles(nlistf, memf, NULL, O_RDONLY, errbuf)) == NULL)
+               err(1, "%s", errbuf);
+
+       (void)time(&now);
+       if ((ut = fopen(_PATH_UTMP, "r")) == NULL)
+               err(1, "%s", _PATH_UTMP);
+
+       if (*argv)
+               sel_user = *argv;
+
+       for (nusers = 0; fread(&utmp, sizeof(utmp), 1, ut);) {
                if (utmp.ut_name[0] == '\0')
                        continue;
                if (utmp.ut_name[0] == '\0')
                        continue;
-               nusers++;
-               if (wcmd == 0 || (sel_user && 
+               ++nusers;
+               if (wcmd == 0 || (sel_user &&
                    strncmp(utmp.ut_name, sel_user, UT_NAMESIZE) != 0))
                        continue;
                    strncmp(utmp.ut_name, sel_user, UT_NAMESIZE) != 0))
                        continue;
-               if ((ep = (struct entry *)
-                    calloc(1, sizeof (struct entry))) == NULL) {
-                       error("out of memory");
-                       exit(1);
-               }
+               if ((ep = calloc(1, sizeof(struct entry))) == NULL)
+                       err(1, NULL);
                *nextp = ep;
                nextp = &(ep->next);
                bcopy(&utmp, &(ep->utmp), sizeof (struct utmp));
                stp = ttystat(ep->utmp.ut_line);
                ep->tdev = stp->st_rdev;
                *nextp = ep;
                nextp = &(ep->next);
                bcopy(&utmp, &(ep->utmp), sizeof (struct utmp));
                stp = ttystat(ep->utmp.ut_line);
                ep->tdev = stp->st_rdev;
-#if defined(hp300)
+#ifdef CPU_CONSDEV
                /*
                /*
-                * XXX  If this is the console device, attempt to ascertain
+                * If this is the console device, attempt to ascertain
                 * the true console device dev_t.
                 */
                if (ep->tdev == 0) {
                 * the true console device dev_t.
                 */
                if (ep->tdev == 0) {
-                       static dev_t cn_dev;
+                       int mib[2];
+                       size_t size;
 
 
-                       if (nl[X_CNTTY].n_value) {
-                               struct tty cn_tty, *cn_ttyp;
-                               
-                               if (kvm_read(nl[X_CNTTY].n_value,
-                                            &cn_ttyp, sizeof (cn_ttyp)) > 0) {
-                                       (void)kvm_read(cn_ttyp, &cn_tty,
-                                                      sizeof (cn_tty));
-                                       cn_dev = cn_tty.t_dev;
-                               }
-                               nl[X_CNTTY].n_value = 0;
-                       }
-                       ep->tdev = cn_dev;
+                       mib[0] = CTL_MACHDEP;
+                       mib[1] = CPU_CONSDEV;
+                       size = sizeof(dev_t);
+                       (void) sysctl(mib, 2, &ep->tdev, &size, NULL, 0);
                }
 #endif
                }
 #endif
-               ep->idle = ((now - stp->st_atime) + 30) / 60; /* secs->mins */
-               if (ep->idle < 0)
+               if ((ep->idle = now - stp->st_atime) < 0)
                        ep->idle = 0;
        }
                        ep->idle = 0;
        }
-       fclose(ut);
+       (void)fclose(ut);
 
        if (header || wcmd == 0) {
 
        if (header || wcmd == 0) {
-               double  avenrun[3];
-               int days, hrs, mins;
-
-               /*
-                * Print time of day 
-                */
-               fputs(attime(&now), stdout);
-               /*
-                * Print how long system has been up.
-                * (Found by looking for "boottime" in kernel)
-                */
-               (void)kvm_read((off_t)nl[X_BOOTTIME].n_value, &boottime, 
-                       sizeof (boottime));
-               uptime = now - boottime.tv_sec;
-               uptime += 30;
-               days = uptime / (60*60*24);
-               uptime %= (60*60*24);
-               hrs = uptime / (60*60);
-               uptime %= (60*60);
-               mins = uptime / 60;
-
-               printf("  up");
-               if (days > 0)
-                       printf(" %d day%s,", days, days>1?"s":"");
-               if (hrs > 0 && mins > 0) {
-                       printf(" %2d:%02d,", hrs, mins);
-               } else {
-                       if (hrs > 0)
-                               printf(" %d hr%s,", hrs, hrs>1?"s":"");
-                       if (mins > 0)
-                               printf(" %d min%s,", mins, mins>1?"s":"");
-               }
-
-               /* Print number of users logged in to system */
-               printf("  %d user%s", nusers, nusers>1?"s":"");
+               pr_header(&now, nusers);
+               if (wcmd == 0)
+                       exit (0);
+       }
 
 
-               /*
-                * Print 1, 5, and 15 minute load averages.
-                */
-               printf(",  load average:");
-               (void)getloadavg(avenrun, sizeof(avenrun) / sizeof(avenrun[0]));
-               for (i = 0; i < (sizeof(avenrun)/sizeof(avenrun[0])); i++) {
-                       if (i > 0)
-                               printf(",");
-                       printf(" %.2f", avenrun[i]);
-               }
-               printf("\n");
-               if (wcmd == 0)          /* if uptime(1) then done */
-                       exit(0);
 #define HEADER "USER    TTY FROM              LOGIN@  IDLE WHAT\n"
 #define WUSED  (sizeof (HEADER) - sizeof ("WHAT\n"))
 #define HEADER "USER    TTY FROM              LOGIN@  IDLE WHAT\n"
 #define WUSED  (sizeof (HEADER) - sizeof ("WHAT\n"))
-               printf(HEADER);
-       }
+       (void)printf(HEADER);
+
+       if ((kp = kvm_getprocs(kd, KERN_PROC_ALL, 0, &nentries)) == NULL)
+               err(1, "%s", kvm_geterr(kd));
+       for (i = 0; i < nentries; i++, kp++) {
+               register struct proc *p = &kp->kp_proc;
+               register struct eproc *e;
 
 
-       while ((p = kvm_nextproc()) != NULL) {
-               if (p->p_stat == SZOMB || (p->p_flag & SCTTY) == 0)
+               if (p->p_stat == SIDL || p->p_stat == SZOMB)
                        continue;
                        continue;
-               e = kvm_geteproc(p);
+               e = &kp->kp_eproc;
                for (ep = ehead; ep != NULL; ep = ep->next) {
                        if (ep->tdev == e->e_tdev && e->e_pgid == e->e_tpgid) {
                                /*
                                 * Proc is in foreground of this terminal
                                 */
                for (ep = ehead; ep != NULL; ep = ep->next) {
                        if (ep->tdev == e->e_tdev && e->e_pgid == e->e_tpgid) {
                                /*
                                 * Proc is in foreground of this terminal
                                 */
-                               if (proc_compare(ep->proc, p))
-                                       ep->proc = p;
+                               if (proc_compare(&ep->kp->kp_proc, p))
+                                       ep->kp = kp;
                                break;
                        }
                }
        }
                                break;
                        }
                }
        }
-       if ((ioctl(1, TIOCGWINSZ, &ws) == -1 &&
-            ioctl(2, TIOCGWINSZ, &ws) == -1 &&
-            ioctl(0, TIOCGWINSZ, &ws) == -1) || ws.ws_col == 0)
+       if ((ioctl(STDOUT_FILENO, TIOCGWINSZ, &ws) == -1 &&
+            ioctl(STDERR_FILENO, TIOCGWINSZ, &ws) == -1 &&
+            ioctl(STDIN_FILENO, TIOCGWINSZ, &ws) == -1) || ws.ws_col == 0)
               ttywidth = 79;
         else
               ttywidth = ws.ws_col - 1;
               ttywidth = 79;
         else
               ttywidth = ws.ws_col - 1;
@@ -259,11 +253,14 @@ main(argc, argv)
        if (argwidth < 4)
                argwidth = 8;
        for (ep = ehead; ep != NULL; ep = ep->next) {
        if (argwidth < 4)
                argwidth = 8;
        for (ep = ehead; ep != NULL; ep = ep->next) {
-               ep->args = strsave(kvm_getargs(ep->proc, kvm_getu(ep->proc)));
-               if (ep->args == NULL) {
-                       error("out of memory");
-                       exit(1);
+               if (ep->kp == NULL) {
+                       ep->args = "-";
+                       continue;
                }
                }
+               ep->args = fmt_argv(kvm_getargv(kd, ep->kp, argwidth),
+                   ep->kp->kp_proc.p_comm, MAXCOMLEN);
+               if (ep->args == NULL)
+                       err(1, NULL);
        }
        /* sort by idle time */
        if (sortidle && ehead != NULL) {
        }
        /* sort by idle time */
        if (sortidle && ehead != NULL) {
@@ -271,10 +268,10 @@ main(argc, argv)
                
                ehead = NULL;
                while (from != NULL) {
                
                ehead = NULL;
                while (from != NULL) {
-                       for (nextp = &ehead; 
+                       for (nextp = &ehead;
                            (*nextp) && from->idle >= (*nextp)->idle;
                            nextp = &(*nextp)->next)
                            (*nextp) && from->idle >= (*nextp)->idle;
                            nextp = &(*nextp)->next)
-                               ;
+                               continue;
                        save = from;
                        from = from->next;
                        save->next = *nextp;
                        save = from;
                        from = from->next;
                        save->next = *nextp;
@@ -282,106 +279,141 @@ main(argc, argv)
                }
        }
                        
                }
        }
                        
+       if (!nflag)
+               if (gethostname(domain, sizeof(domain) - 1) < 0 ||
+                   (p = index(domain, '.')) == 0)
+                       domain[0] = '\0';
+               else {
+                       domain[sizeof(domain) - 1] = '\0';
+                       bcopy(p, domain, strlen(p) + 1);
+               }
+
        for (ep = ehead; ep != NULL; ep = ep->next) {
        for (ep = ehead; ep != NULL; ep = ep->next) {
-               printf("%-*.*s %-2.2s %-*.*s %s",
-                       UT_NAMESIZE, UT_NAMESIZE, ep->utmp.ut_name,
-                       strncmp(ep->utmp.ut_line, "tty", 3) == 0 ? 
-                               ep->utmp.ut_line+3 : ep->utmp.ut_line,
-                       UT_HOSTSIZE, UT_HOSTSIZE, *ep->utmp.ut_host ?
-                               ep->utmp.ut_host : "-",
-                       attime(&ep->utmp.ut_time));
-               if (ep->idle >= 36 * 60)
-                       printf(" %ddays ", (ep->idle + 12 * 60) / (24 * 60));
-               else
-                       prttime(ep->idle, " ");
-               printf("%.*s\n", argwidth, ep->args);
+               p = *ep->utmp.ut_host ? ep->utmp.ut_host : "-";
+               if (x = index(p, ':'))
+                       *x++ = '\0';
+               if (!nflag && isdigit(*p) &&
+                   (long)(l = inet_addr(p)) != -1 &&
+                   (hp = gethostbyaddr((char *)&l, sizeof(l), AF_INET))) {
+                       if (domain[0] != '\0') {
+                               p = hp->h_name;
+                               p += strlen(hp->h_name);
+                               p -= strlen(domain);
+                               if (p > hp->h_name && !strcmp(p, domain))
+                                       *p = '\0';
+                       }
+                       p = hp->h_name;
+               }
+               if (x) {
+                       (void)snprintf(buf, sizeof(buf), "%s:%s", p, x);
+                       p = buf;
+               }
+               (void)printf("%-*.*s %-2.2s %-*.*s ",
+                   UT_NAMESIZE, UT_NAMESIZE, ep->utmp.ut_name,
+                   strncmp(ep->utmp.ut_line, "tty", 3) ?
+                   ep->utmp.ut_line : ep->utmp.ut_line + 3,
+                   UT_HOSTSIZE, UT_HOSTSIZE, *p ? p : "-");
+               pr_attime(&ep->utmp.ut_time, &now);
+               pr_idle(ep->idle);
+               (void)printf("%.*s\n", argwidth, ep->args);
        }
        }
+       exit(0);
 }
 
 }
 
-struct stat *
-ttystat(line)
+static void
+pr_header(nowp, nusers)
+       time_t *nowp;
+       int nusers;
 {
 {
-       static struct stat statbuf;
-       char ttybuf[sizeof (_PATH_DEV) + UT_LINESIZE + 1];
-
-       sprintf(ttybuf, "%s/%.*s", _PATH_DEV, UT_LINESIZE, line);
-       (void) stat(ttybuf, &statbuf);
-
-       return (&statbuf);
-}
+       double avenrun[3];
+       time_t uptime;
+       int days, hrs, i, mins;
+       int mib[2];
+       size_t size;
+       char buf[256], fmt[10];
 
 
-char *
-strsave(cp)
-       char *cp;
-{
-       register unsigned len;
-       register char *dp;
-
-       len = strlen(cp);
-       dp = (char *)calloc(len+1, sizeof (char));
-       (void) strcpy(dp, cp);
-       return (dp);
-}
-/*
- * prttime prints a time in hours and minutes or minutes and seconds.
- * The character string tail is printed at the end, obvious
- * strings to pass are "", " ", or "am".
- */
-prttime(tim, tail)
-       time_t tim;
-       char *tail;
-{
-
-       if (tim >= 60) {
-               printf(" %2d:", tim/60);
-               tim %= 60;
-               printf("%02d", tim);
-       } else if (tim >= 0)
-               printf("    %2d", tim);
-       printf("%s", tail);
-}
+       /*
+        * Print time of day.
+        *
+        * Note, SCCS forces the string manipulation below, as it
+        * replaces w.c with file information.
+        */
+       (void)strcpy(fmt, "%l:%%%p");
+       fmt[4] = 'M';
+       (void)strftime(buf, sizeof(buf), fmt, localtime(nowp));
+       (void)printf("%s ", buf);
 
 
-#include <varargs.h>
+       /*
+        * Print how long system has been up.
+        * (Found by looking getting "boottime" from the kernel)
+        */
+       mib[0] = CTL_KERN;
+       mib[1] = KERN_BOOTTIME;
+       size = sizeof(boottime);
+       if (sysctl(mib, 2, &boottime, &size, NULL, 0) != -1 &&
+           boottime.tv_sec != 0) {
+               uptime = now - boottime.tv_sec;
+               uptime += 30;
+               days = uptime / SECSPERDAY;
+               uptime %= SECSPERDAY;
+               hrs = uptime / SECSPERHOUR;
+               uptime %= SECSPERHOUR;
+               mins = uptime / SECSPERMIN;
+               (void)printf(" up");
+               if (days > 0)
+                       (void)printf(" %d day%s,", days, days > 1 ? "s" : "");
+               if (hrs > 0 && mins > 0)
+                       (void)printf(" %2d:%02d,", hrs, mins);
+               else {
+                       if (hrs > 0)
+                               (void)printf(" %d hr%s,",
+                                   hrs, hrs > 1 ? "s" : "");
+                       if (mins > 0)
+                               (void)printf(" %d min%s,",
+                                   mins, mins > 1 ? "s" : "");
+               }
+       }
 
 
-warning(va_alist)
-       va_dcl
-{
-       char *fmt;
-       va_list ap;
+       /* Print number of users logged in to system */
+       (void)printf(" %d user%s", nusers, nusers > 1 ? "s" : "");
 
 
-       fprintf(stderr, "%s: warning: ", program);
-       va_start(ap);
-       fmt = va_arg(ap, char *);
-       (void) vfprintf(stderr, fmt, ap);
-       va_end(ap);
-       fprintf(stderr, "\n");
+       /*
+        * Print 1, 5, and 15 minute load averages.
+        */
+       if (getloadavg(avenrun, sizeof(avenrun) / sizeof(avenrun[0])) == -1)
+               (void)printf(", no load average information available\n");
+       else {
+               (void)printf(", load averages:");
+               for (i = 0; i < (sizeof(avenrun) / sizeof(avenrun[0])); i++) {
+                       if (i > 0)
+                               (void)printf(",");
+                       (void)printf(" %.2f", avenrun[i]);
+               }
+               (void)printf("\n");
+       }
 }
 
 }
 
-error(va_alist)
-       va_dcl
+static struct stat *
+ttystat(line)
+       char *line;
 {
 {
-       char *fmt;
-       va_list ap;
+       static struct stat sb;
+       char ttybuf[MAXPATHLEN];
 
 
-       fprintf(stderr, "%s: ", program);
-       va_start(ap);
-       fmt = va_arg(ap, char *);
-       (void) vfprintf(stderr, fmt, ap);
-       va_end(ap);
-       fprintf(stderr, "\n");
+       (void)snprintf(ttybuf, sizeof(ttybuf), "%s/%s", _PATH_DEV, line);
+       if (stat(ttybuf, &sb))
+               err(1, "%s", ttybuf);
+       return (&sb);
 }
 
 }
 
-syserror(va_alist)
-       va_dcl
+static void
+usage(wcmd)
+       int wcmd;
 {
 {
-       char *fmt;
-       va_list ap;
-       extern errno;
-
-       fprintf(stderr, "%s: ", program);
-       va_start(ap);
-       fmt = va_arg(ap, char *);
-       (void) vfprintf(stderr, fmt, ap);
-       va_end(ap);
-       fprintf(stderr, ": %s\n", strerror(errno));
+       if (wcmd)
+               (void)fprintf(stderr,
+                   "usage: w: [-hin] [-M core] [-N system] [user]\n");
+       else
+               (void)fprintf(stderr, "uptime\n");
+       exit (1);
 }
 }