BSD 4_4_Lite2 release
[unix-history] / usr / src / usr.bin / w / w.c
index d11377e..501938a 100644 (file)
-static char *sccsid = "@(#)w.c 4.7 (Berkeley) %G%";
+/*-
+ * Copyright (c) 1980, 1991, 1993, 1994
+ *     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
+static char copyright[] =
+"@(#) Copyright (c) 1980, 1991, 1993, 1994\n\
+       The Regents of the University of California.  All rights reserved.\n";
+#endif /* not lint */
+
+#ifndef lint
+static char sccsid[] = "@(#)w.c        8.6 (Berkeley) 6/30/94";
+#endif /* not lint */
+
 /*
  * w - print system status (who and what)
  *
  * This program is similar to the systat command on Tenex/Tops 10/20
 /*
  * w - print system status (who and what)
  *
  * This program is similar to the systat command on Tenex/Tops 10/20
- * It needs read permission on /dev/mem, /dev/kmem, and /dev/drum.
+ *
  */
 #include <sys/param.h>
  */
 #include <sys/param.h>
-#include <nlist.h>
-#include <stdio.h>
-#include <ctype.h>
-#include <utmp.h>
+#include <sys/time.h>
 #include <sys/stat.h>
 #include <sys/stat.h>
-#include <sys/dir.h>
-#include <sys/user.h>
+#include <sys/sysctl.h>
 #include <sys/proc.h>
 #include <sys/proc.h>
-#include <sys/pte.h>
-#include <sys/vm.h>
-
-#define NMAX sizeof(utmp.ut_name)
-#define LMAX sizeof(utmp.ut_line)
-
-#define ARGWIDTH       33      /* # chars left on 80 col crt for args */
-
-struct pr {
-       short   w_pid;                  /* proc.p_pid */
-       char    w_flag;                 /* proc.p_flag */
-       short   w_size;                 /* proc.p_size */
-       long    w_seekaddr;             /* where to find args */
-       long    w_lastpg;               /* disk address of stack */
-       int     w_igintr;               /* INTR+3*QUIT, 0=die, 1=ign, 2=catch */
-       time_t  w_time;                 /* CPU time used by this process */
-       time_t  w_ctime;                /* CPU time used by children */
-       dev_t   w_tty;                  /* tty device of process */
-       char    w_comm[15];             /* user.u_comm, null terminated */
-       char    w_args[ARGWIDTH+1];     /* args if interesting process */
-} *pr;
-int    nproc;
-
-struct nlist nl[] = {
-       { "_proc" },
-#define        X_PROC          0
-       { "_swapdev" },
-#define        X_SWAPDEV       1
-       { "_Usrptmap" },
-#define        X_USRPTMA       2
-       { "_usrpt" },
-#define        X_USRPT         3
-       { "_nswap" },
-#define        X_NSWAP         4
-       { "_avenrun" },
-#define        X_AVENRUN       5
-       { "_boottime" },
-#define        X_BOOTTIME      6
-       { "_nproc" },
-#define        X_NPROC         7
-       { 0 },
-};
-
-FILE   *ps;
-FILE   *ut;
-FILE   *bootfd;
-int    kmem;
-int    mem;
-int    swap;                   /* /dev/kmem, mem, and swap */
-int    nswap;
-dev_t  tty;
-char   doing[520];             /* process attached to terminal */
-time_t proctime;               /* cpu time of process in doing */
-double avenrun[3];
-struct proc *aproc;
-
-#define        DIV60(t)        ((t+30)/60)    /* x/60 rounded */ 
-#define        TTYEQ           (tty == pr[i].w_tty)
-#define IGINT          (1+3*1)         /* ignoring both SIGINT & SIGQUIT */
+#include <sys/user.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <sys/tty.h>
 
 
-char   *getargs();
-char   *fread();
-char   *ctime();
-char   *rindex();
-FILE   *popen();
-struct tm *localtime();
+#include <machine/cpu.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
 
 
-int    debug;                  /* true if -d flag: debugging output */
-int    header = 1;             /* true if -h flag: don't print heading */
-int    lflag = 1;              /* true if -l flag: long style output */
-int    login;                  /* true if invoked as login shell */
-int    idle;                   /* number of minutes user is idle */
-int    nusers;                 /* number of users logged in now */
-char * sel_user;               /* login of particular user selected */
-char firstchar;                        /* first char of name of prog invoked as */
-time_t jobtime;                /* total cpu time visible */
-time_t now;                    /* the current time of day */
-struct tm *nowt;               /* current time as time struct */
-struct timeval boottime;
-time_t uptime;                 /* time of last reboot & elapsed time since */
-int    np;                     /* number of processes currently active */
-struct utmp utmp;
-struct proc mproc;
-struct user up;
-char   fill[512];
+#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 <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <tzfile.h>
+#include <unistd.h>
+#include <utmp.h>
+#include <vis.h>
+
+#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           domain[MAXHOSTNAMELEN];
 
 
+/*
+ * One of these per active utmp entry.
+ */
+struct entry {
+       struct  entry *next;
+       struct  utmp utmp;
+       dev_t   tdev;           /* dev_t of terminal */
+       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;
+
+static void     pr_header __P((time_t *, int));
+static struct stat
+               *ttystat __P((char *));
+static void     usage __P((int));
+
+char *fmt_argv __P((char **, char *, int));    /* ../../bin/ps/fmt.c */
+
+int
 main(argc, argv)
 main(argc, argv)
+       int argc;
        char **argv;
 {
        char **argv;
 {
-       int days, hrs, mins;
-       register int i, j;
-       char *cp;
-       register int curpid, empty;
-       char obuf[BUFSIZ];
-
-       setbuf(stdout, obuf);
-       login = (argv[0][0] == '-');
-       cp = rindex(argv[0], '/');
-       firstchar = login ? argv[0][1] : (cp==0) ? argv[0][0] : cp[1];
-       cp = argv[0];   /* for Usage */
-
-       while (argc > 1) {
-               if (argv[1][0] == '-') {
-                       for (i=1; argv[1][i]; i++) {
-                               switch(argv[1][i]) {
-
-                               case 'd':
-                                       debug++;
-                                       break;
-
-                               case 'h':
-                                       header = 0;
-                                       break;
-
-                               case 'l':
-                                       lflag++;
-                                       break;
-
-                               case 's':
-                                       lflag = 0;
-                                       break;
-
-                               case 'u':
-                               case 'w':
-                                       firstchar = argv[1][i];
-                                       break;
-
-                               default:
-                                       printf("Bad flag %s\n", argv[1]);
-                                       exit(1);
-                               }
-                       }
-               } else {
-                       if (!isalnum(argv[1][0]) || argc > 2) {
-                               printf("Usage: %s [ -hlsuw ] [ user ]\n", cp);
-                               exit(1);
-                       } else
-                               sel_user = argv[1];
-               }
-               argc--; argv++;
-       }
-
-       if ((kmem = open("/dev/kmem", 0)) < 0) {
-               fprintf(stderr, "No kmem\n");
-               exit(1);
-       }
-       nlist("/vmunix", nl);
-       if (nl[0].n_type==0) {
-               fprintf(stderr, "No namelist\n");
-               exit(1);
+       extern char *__progname;
+       struct kinfo_proc *kp;
+       struct hostent *hp;
+       struct stat *stp;
+       FILE *ut;
+       u_long l;
+       size_t arglen;
+       int ch, i, nentries, nusers, wcmd;
+       char *memf, *nlistf, *p, *vis_args, *x;
+       char buf[MAXHOSTNAMELEN], errbuf[256];
+
+       /* Are we w(1) or uptime(1)? */
+       p = __progname;
+       if (*p == '-')
+               p++;
+       if (*p == 'u') {
+               wcmd = 0;
+               p = "";
+       } else {
+               wcmd = 1;
+               p = "hiflM:N:nsuw";
        }
 
        }
 
-       if (firstchar != 'u')
-               readpr();
+       memf = nlistf = NULL;
+       while ((ch = getopt(argc, argv, p)) != EOF)
+               switch (ch) {
+               case 'h':
+                       header = 0;
+                       break;
+               case 'i':
+                       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':
+                       warnx("[-flsuw] no longer supported");
+                       /* FALLTHROUGH */
+               case '?':
+               default:
+                       usage(wcmd);
+               }
+       argc -= optind;
+       argv += optind;
 
 
-       ut = fopen("/etc/utmp","r");
-       if (header) {
-               /* Print time of day */
-               time(&now);
-               nowt = localtime(&now);
-               prtat(nowt);
+       if ((kd = kvm_openfiles(nlistf, memf, NULL, O_RDONLY, errbuf)) == NULL)
+               errx(1, "%s", errbuf);
 
 
-               /*
-                * Print how long system has been up.
-                * (Found by looking for "boottime" in kernel)
-                */
-               lseek(kmem, (long)nl[X_BOOTTIME].n_value, 0);
-               read(kmem, &boottime, sizeof (boottime));
+       (void)time(&now);
+       if ((ut = fopen(_PATH_UTMP, "r")) == NULL)
+               err(1, "%s", _PATH_UTMP);
 
 
-               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 */
-               while (fread(&utmp, sizeof(utmp), 1, ut)) {
-                       if (utmp.ut_name[0] != '\0')
-                               nusers++;
-               }
-               rewind(ut);
-               printf("  %d users", nusers);
+       if (*argv)
+               sel_user = *argv;
 
 
+       for (nusers = 0; fread(&utmp, sizeof(utmp), 1, ut);) {
+               if (utmp.ut_name[0] == '\0')
+                       continue;
+               ++nusers;
+               if (wcmd == 0 || (sel_user &&
+                   strncmp(utmp.ut_name, sel_user, UT_NAMESIZE) != 0))
+                       continue;
+               if ((ep = calloc(1, sizeof(struct entry))) == NULL)
+                       err(1, NULL);
+               *nextp = ep;
+               nextp = &(ep->next);
+               memmove(&(ep->utmp), &utmp, sizeof(struct utmp));
+               if (!(stp = ttystat(ep->utmp.ut_line)))
+                       continue;
+               ep->tdev = stp->st_rdev;
+#ifdef CPU_CONSDEV
                /*
                /*
-                * Print 1, 5, and 15 minute load averages.
-                * (Found by looking in kernel for avenrun).
+                * If this is the console device, attempt to ascertain
+                * the true console device dev_t.
                 */
                 */
-               printf(",  load average:");
-               lseek(kmem, (long)nl[X_AVENRUN].n_value, 0);
-               read(kmem, avenrun, sizeof(avenrun));
-               for (i = 0; i < (sizeof(avenrun)/sizeof(avenrun[0])); i++) {
-                       if (i > 0)
-                               printf(",");
-                       printf(" %.2f", avenrun[i]);
+               if (ep->tdev == 0) {
+                       int mib[2];
+                       size_t size;
+
+                       mib[0] = CTL_MACHDEP;
+                       mib[1] = CPU_CONSDEV;
+                       size = sizeof(dev_t);
+                       (void) sysctl(mib, 2, &ep->tdev, &size, NULL, 0);
                }
                }
-               printf("\n");
-               if (firstchar == 'u')
-                       exit(0);
+#endif
+               if ((ep->idle = now - stp->st_atime) < 0)
+                       ep->idle = 0;
+       }
+       (void)fclose(ut);
 
 
-               /* Headers for rest of output */
-               if (lflag)
-                       printf("User     tty       login@  idle   JCPU   PCPU  what\n");
-               else
-                       printf("User    tty  idle  what\n");
-               fflush(stdout);
+       if (header || wcmd == 0) {
+               pr_header(&now, nusers);
+               if (wcmd == 0)
+                       exit (0);
        }
 
        }
 
+#define HEADER "USER    TTY FROM              LOGIN@  IDLE WHAT\n"
+#define WUSED  (sizeof (HEADER) - sizeof ("WHAT\n"))
+       (void)printf(HEADER);
 
 
-       for (;;) {      /* for each entry in utmp */
-               if (fread(&utmp, sizeof(utmp), 1, ut) == NULL) {
-                       fclose(ut);
-                       exit(0);
-               }
-               if (utmp.ut_name[0] == '\0')
-                       continue;       /* that tty is free */
-               if (sel_user && strcmpn(utmp.ut_name, sel_user, NMAX) != 0)
-                       continue;       /* we wanted only somebody else */
+       if ((kp = kvm_getprocs(kd, KERN_PROC_ALL, 0, &nentries)) == NULL)
+               err(1, "%s", kvm_geterr(kd));
+       for (i = 0; i < nentries; i++, kp++) {
+               struct proc *p = &kp->kp_proc;
+               struct eproc *e;
 
 
-               gettty();
-               jobtime = 0;
-               proctime = 0;
-               strcpy(doing, "-");     /* default act: normally never prints */
-               empty = 1;
-               curpid = -1;
-               idle = findidle();
-               for (i=0; i<np; i++) {  /* for each process on this tty */
-                       if (!(TTYEQ))
-                               continue;
-                       jobtime += pr[i].w_time + pr[i].w_ctime;
-                       proctime += pr[i].w_time;
-                       if (debug) {
-                               printf("\t\t%d\t%s", pr[i].w_pid, pr[i].w_args);
-                               if ((j=pr[i].w_igintr) > 0)
-                                       if (j==IGINT)
-                                               printf(" &");
-                                       else
-                                               printf(" & %d %d", j%3, j/3);
-                               printf("\n");
-                       }
-                       if (empty && pr[i].w_igintr!=IGINT) {
-                               empty = 0;
-                               curpid = -1;
-                       }
-                       if(pr[i].w_pid>curpid && (pr[i].w_igintr!=IGINT || empty)){
-                               curpid = pr[i].w_pid;
-                               strcpy(doing, lflag ? pr[i].w_args : pr[i].w_comm);
-#ifdef notdef
-                               if (doing[0]==0 || doing[0]=='-' && doing[1]<=' ' || doing[0] == '?') {
-                                       strcat(doing, " (");
-                                       strcat(doing, pr[i].w_comm);
-                                       strcat(doing, ")");
-                               }
-#endif
+               if (p->p_stat == SIDL || p->p_stat == SZOMB)
+                       continue;
+               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
+                                */
+                               if (proc_compare(&ep->kp->kp_proc, p))
+                                       ep->kp = kp;
+                               break;
                        }
                }
                        }
                }
-               putline();
        }
        }
-}
-
-/* figure out the major/minor device # pair for this tty */
-gettty()
-{
-       char ttybuf[20];
-       struct stat statbuf;
-
-       ttybuf[0] = 0;
-       strcpy(ttybuf, "/dev/");
-       strcat(ttybuf, utmp.ut_line);
-       stat(ttybuf, &statbuf);
-       tty = statbuf.st_rdev;
-}
-
-/*
- * putline: print out the accumulated line of info about one user.
- */
-putline()
-{
-       register int tm;
-
-       /* print login name of the user */
-       printf("%-*.*s ", NMAX, NMAX, utmp.ut_name);
-
-       /* print tty user is on */
-       if (lflag)
-               /* long form: all (up to) LMAX chars */
-               printf("%-*.*s", LMAX, LMAX, utmp.ut_line);
-       else {
-               /* short form: 2 chars, skipping 'tty' if there */
-               if (utmp.ut_line[0]=='t' && utmp.ut_line[1]=='t' && utmp.ut_line[2]=='y')
-                       printf("%-2.2s", &utmp.ut_line[3]);
-               else
-                       printf("%-2.2s", utmp.ut_line);
+       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;
+       argwidth = ttywidth - WUSED;
+       if (argwidth < 4)
+               argwidth = 8;
+       for (ep = ehead; ep != NULL; ep = ep->next) {
+               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);
        }
        }
-
-       if (lflag)
-               /* print when the user logged in */
-               prtat(localtime(&utmp.ut_time));
-
-       /* print idle time */
-       prttime(idle," ");
-
-       if (lflag) {
-               /* print CPU time for all processes & children */
-               prttime(DIV60(jobtime)," ");
-               /* print cpu time for interesting process */
-               prttime(DIV60(proctime)," ");
+       /* sort by idle time */
+       if (sortidle && ehead != NULL) {
+               struct entry *from = ehead, *save;
+               
+               ehead = NULL;
+               while (from != NULL) {
+                       for (nextp = &ehead;
+                           (*nextp) && from->idle >= (*nextp)->idle;
+                           nextp = &(*nextp)->next)
+                               continue;
+                       save = from;
+                       from = from->next;
+                       save->next = *nextp;
+                       *nextp = save;
+               }
        }
        }
+                       
+       if (!nflag)
+               if (gethostname(domain, sizeof(domain) - 1) < 0 ||
+                   (p = strchr(domain, '.')) == 0)
+                       domain[0] = '\0';
+               else {
+                       domain[sizeof(domain) - 1] = '\0';
+                       memmove(domain, p, strlen(p) + 1);
+               }
 
 
-       /* what user is doing, either command tail or args */
-       printf(" %-.32s\n",doing);
-       fflush(stdout);
-}
-
-/* find & return number of minutes current tty has been idle */
-findidle()
-{
-       struct stat stbuf;
-       long lastaction, diff;
-       char ttyname[20];
-
-       strcpy(ttyname, "/dev/");
-       strcatn(ttyname, utmp.ut_line, LMAX);
-       stat(ttyname, &stbuf);
-       time(&now);
-       lastaction = stbuf.st_atime;
-       diff = now - lastaction;
-       diff = DIV60(diff);
-       if (diff < 0) diff = 0;
-       return(diff);
-}
-
-/*
- * prttime prints a time in hours and minutes.
- * The character string tail is printed at the end, obvious
- * strings to pass are "", " ", or "am".
- */
-prttime(tim, tail)
-       time_t tim;
-       char *tail;
-{
-       register int didhrs = 0;
-
-       if (tim >= 60) {
-               printf("%3d:", tim/60);
-               didhrs++;
-       } else {
-               printf("    ");
-       }
-       tim %= 60;
-       if (tim > 0 || didhrs) {
-               printf(didhrs&&tim<10 ? "%02d" : "%2d", tim);
-       } else {
-               printf("  ");
+       if ((vis_args = malloc(argwidth * 4 + 1)) == NULL)
+               err(1, NULL);
+       for (ep = ehead; ep != NULL; ep = ep->next) {
+               p = *ep->utmp.ut_host ? ep->utmp.ut_host : "-";
+               if ((x = strchr(p, ':')) != NULL)
+                       *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) == 0)
+                                       *p = '\0';
+                       }
+                       p = hp->h_name;
+               }
+               if (x) {
+                       (void)snprintf(buf, sizeof(buf), "%s:%.*s", p,
+                               ep->utmp.ut_host + UT_HOSTSIZE - x, 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);
+               if (ep->args != NULL) {
+                       arglen = strlen(ep->args);
+                       strvisx(vis_args, ep->args,
+                           arglen > argwidth ? argwidth : arglen,
+                           VIS_TAB | VIS_NL | VIS_NOSLASH);
+               }
+               (void)printf("%.*s\n", argwidth, ep->args);
        }
        }
-       printf("%s", tail);
-}
-
-/* prtat prints a 12 hour time given a pointer to a time of day */
-prtat(p)
-       struct tm *p;
-{
-       register int t, pm;
-
-       t = p -> tm_hour;
-       pm = (t > 11);
-       if (t > 11)
-               t -= 12;
-       if (t == 0)
-               t = 12;
-       prttime(t*60 + p->tm_min, pm ? "pm" : "am");
+       exit(0);
 }
 
 }
 
-/*
- * readpr finds and reads in the array pr, containing the interesting
- * parts of the proc and user tables for each live process.
- */
-readpr()
+static void
+pr_header(nowp, nusers)
+       time_t *nowp;
+       int nusers;
 {
 {
-       int pn, mf, addr, c;
-       int szpt, pfnum, i;
-       struct pte *Usrptma, *usrpt, *pte, apte;
-       struct dblock db;
+       double avenrun[3];
+       time_t uptime;
+       int days, hrs, i, mins;
+       int mib[2];
+       size_t size;
+       char buf[256];
 
 
-       Usrptma = (struct pte *) nl[X_USRPTMA].n_value;
-       usrpt = (struct pte *) nl[X_USRPT].n_value;
-       if((mem = open("/dev/mem", 0)) < 0) {
-               fprintf(stderr, "No mem\n");
-               exit(1);
-       }
-       if ((swap = open("/dev/drum", 0)) < 0) {
-               fprintf(stderr, "No drum\n");
-               exit(1);
-       }
-       /*
-        * read mem to find swap dev.
-        */
-       lseek(kmem, (long)nl[X_SWAPDEV].n_value, 0);
-       read(kmem, &nl[X_SWAPDEV].n_value, sizeof(nl[X_SWAPDEV].n_value));
        /*
        /*
-        * Find base of swap
+        * Print time of day.
+        *
+        * SCCS forces the string manipulation below, as it replaces
+        * %, M, and % in a character string with the file name.
         */
         */
-       lseek(kmem, (long)nl[X_NSWAP].n_value, 0);
-       read(kmem, &nswap, sizeof(nswap));
+       (void)strftime(buf, sizeof(buf),
+           __CONCAT("%l:%","M%p"), localtime(nowp));
+       (void)printf("%s ", buf);
+
        /*
        /*
-        * Locate proc table
+        * Print how long system has been up.
+        * (Found by looking getting "boottime" from the kernel)
         */
         */
-       lseek(kmem, (long)nl[X_NPROC].n_value, 0);
-       read(kmem, &nproc, sizeof(nproc));
-       pr = (struct pr *)calloc(nproc, sizeof (struct pr));
-       np = 0;
-       lseek(kmem, (long)nl[X_PROC].n_value, 0);
-       read(kmem, &aproc, sizeof(aproc));
-       for (pn=0; pn<nproc; pn++) {
-               lseek(kmem, (int)(aproc + pn), 0);
-               read(kmem, &mproc, sizeof mproc);
-               /* decide if it's an interesting process */
-               if (mproc.p_stat==0 || mproc.p_pgrp==0)
-                       continue;
-               /* find & read in the user structure */
-               if ((mproc.p_flag & SLOAD) == 0) {
-                       /* not in memory - get from swap device */
-                       addr = mproc.p_swaddr<<9;
-                       lseek(swap, (long)addr, 0);
-                       if (read(swap, &up, sizeof(up)) != sizeof(up)) {
-                               continue;
-                       }
-               } else {
-                       int p0br, cc;
-#define INTPPG (NBPG / sizeof (int))
-                       struct pte pagetbl[NBPG / sizeof (struct pte)];
-                       /* loaded, get each page from memory separately */
-                       szpt = mproc.p_szpt;
-                       p0br = (int)mproc.p_p0br;
-                       pte = &Usrptma[btokmx(mproc.p_p0br) + szpt-1];
-                       lseek(kmem, (long)pte, 0);
-                       if (read(kmem, &apte, sizeof(apte)) != sizeof(apte))
-                               continue;
-                       lseek(mem, ctob(apte.pg_pfnum), 0);
-                       if (read(mem,pagetbl,sizeof(pagetbl)) != sizeof(pagetbl))   
-cont:
-                               continue;
-                       for(cc=0; cc<UPAGES; cc++) {    /* get u area */
-                               int upage = pagetbl[NPTEPG-UPAGES+cc].pg_pfnum;
-                               lseek(mem,ctob(upage),0);
-                               if (read(mem,((int *)&up)+INTPPG*cc,NBPG) != NBPG)
-                                       goto cont;
-                       }
-                       szpt = up.u_pcb.pcb_szpt;
-                       pr[np].w_seekaddr = ctob(apte.pg_pfnum);
-               }
-               vstodb(0, CLSIZE, &up.u_smap, &db, 1);
-               pr[np].w_lastpg = ctob(db.db_base);
-               if (up.u_ttyp == NULL)
-                       continue;
-
-               /* save the interesting parts */
-               pr[np].w_pid = mproc.p_pid;
-               pr[np].w_flag = mproc.p_flag;
-               pr[np].w_size = mproc.p_dsize + mproc.p_ssize;
-               pr[np].w_igintr = (((int)up.u_signal[2]==1) + 2*((int)up.u_signal[2]>1) + 3*((int)up.u_signal[3]==1)) + 6*((int)up.u_signal[3]>1);
-               pr[np].w_time =
-                   up.u_ru.ru_utime.tv_sec + up.u_ru.ru_stime.tv_sec;
-               pr[np].w_ctime =
-                   up.u_cru.ru_utime.tv_sec + up.u_cru.ru_stime.tv_sec;
-               pr[np].w_tty = up.u_ttyd;
-               up.u_comm[14] = 0;      /* Bug: This bombs next field. */
-               strcpy(pr[np].w_comm, up.u_comm);
-               /*
-                * Get args if there's a chance we'll print it.
-                * Cant just save pointer: getargs returns static place.
-                * Cant use strcpyn: that crock blank pads.
-                */
-               pr[np].w_args[0] = 0;
-               strcatn(pr[np].w_args,getargs(&pr[np]),ARGWIDTH);
-               if (pr[np].w_args[0]==0 || pr[np].w_args[0]=='-' && pr[np].w_args[1]<=' ' || pr[np].w_args[0] == '?') {
-                       strcat(pr[np].w_args, " (");
-                       strcat(pr[np].w_args, pr[np].w_comm);
-                       strcat(pr[np].w_args, ")");
+       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" : "");
                }
                }
-               np++;
        }
        }
-}
 
 
-/*
- * getargs: given a pointer to a proc structure, this looks at the swap area
- * and tries to reconstruct the arguments. This is straight out of ps.
- */
-char *
-getargs(p)
-       struct pr *p;
-{
-       int c, addr, nbad;
-       static int abuf[CLSIZE*NBPG/sizeof(int)];
-       struct pte pagetbl[NPTEPG];
-       register int *ip;
-       register char *cp, *cp1;
+       /* Print number of users logged in to system */
+       (void)printf(" %d user%s", nusers, nusers > 1 ? "s" : "");
 
 
-       if ((p->w_flag & SLOAD) == 0) {
-               lseek(swap, p->w_lastpg, 0);
-               if (read(swap, abuf, sizeof(abuf)) != sizeof(abuf))
-                       return(p->w_comm);
-       } else {
-               c = p->w_seekaddr;
-               lseek(mem,c,0);
-               if (read(mem,pagetbl,NBPG) != NBPG)
-                       return(p->w_comm);
-               if (pagetbl[NPTEPG-CLSIZE-UPAGES].pg_fod==0 && pagetbl[NPTEPG-CLSIZE-UPAGES].pg_pfnum) {
-                       lseek(mem,ctob(pagetbl[NPTEPG-CLSIZE-UPAGES].pg_pfnum),0);
-                       if (read(mem,abuf,sizeof(abuf)) != sizeof(abuf))
-                               return(p->w_comm);
-               } else {
-                       lseek(swap, p->w_lastpg, 0);
-                       if (read(swap, abuf, sizeof(abuf)) != sizeof(abuf))
-                               return(p->w_comm);
-               }
-       }
-       abuf[sizeof(abuf)/sizeof(abuf[0])-1] = 0;
-       for (ip = &abuf[sizeof(abuf)/sizeof(abuf[0])-2]; ip > abuf;) {
-               /* Look from top for -1 or 0 as terminator flag. */
-               if (*--ip == -1 || *ip == 0) {
-                       cp = (char *)(ip+1);
-                       if (*cp==0)
-                               cp++;
-                       nbad = 0;       /* up to 5 funny chars as ?'s */
-                       for (cp1 = cp; cp1 < (char *)&abuf[sizeof(abuf)/sizeof(abuf[0])]; cp1++) {
-                               c = *cp1&0177;
-                               if (c==0)  /* nulls between args => spaces */
-                                       *cp1 = ' ';
-                               else if (c < ' ' || c > 0176) {
-                                       if (++nbad >= 5) {
-                                               *cp1++ = ' ';
-                                               break;
-                                       }
-                                       *cp1 = '?';
-                               } else if (c=='=') {    /* Oops - found an
-                                                        * environment var, back
-                                                        * over & erase it. */
-                                       *cp1 = 0;
-                                       while (cp1>cp && *--cp1!=' ')
-                                               *cp1 = 0;
-                                       break;
-                               }
-                       }
-                       while (*--cp1==' ')     /* strip trailing spaces */
-                               *cp1 = 0;
-                       return(cp);
+       /*
+        * 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");
        }
        }
-       return (p->w_comm);
 }
 
 }
 
-/*
- * Given a base/size pair in virtual swap area,
- * return a physical base/size pair which is the
- * (largest) initial, physically contiguous block.
- */
-vstodb(vsbase, vssize, dmp, dbp, rev)
-       register int vsbase;
-       int vssize;
-       struct dmap *dmp;
-       register struct dblock *dbp;
+static struct stat *
+ttystat(line)
+       char *line;
 {
 {
-       register int blk = DMMIN;
-       register swblk_t *ip = dmp->dm_map;
+       static struct stat sb;
+       char ttybuf[MAXPATHLEN];
 
 
-       if (vsbase < 0 || vsbase + vssize > dmp->dm_size)
-               panic("vstodb");
-       while (vsbase >= blk) {
-               vsbase -= blk;
-               if (blk < DMMAX)
-                       blk *= 2;
-               ip++;
-       }
-       if (*ip <= 0 || *ip + blk > nswap)
-               panic("vstodb *ip");
-       dbp->db_size = min(vssize, blk - vsbase);
-       dbp->db_base = *ip + (rev ? blk - (vsbase + dbp->db_size) : vsbase);
+       (void)snprintf(ttybuf, sizeof(ttybuf), "%s/%s", _PATH_DEV, line);
+       if (stat(ttybuf, &sb))
+               return (NULL);
+       return (&sb);
 }
 
 }
 
-panic(cp)
-       char *cp;
+static void
+usage(wcmd)
+       int wcmd;
 {
 {
-
-       /* printf("%s\n", cp); */
-}
-
-min(a, b)
-{
-
-       return (a < b ? a : b);
+       if (wcmd)
+               (void)fprintf(stderr,
+                   "usage: w: [-hin] [-M core] [-N system] [user]\n");
+       else
+               (void)fprintf(stderr, "uptime\n");
+       exit (1);
 }
 }