home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Source Code 1993 July / THE_SOURCE_CODE_CD_ROM.iso / bsd_srcs / usr.bin / w / w.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-04-23  |  9.4 KB  |  378 lines

  1. /*-
  2.  * Copyright (c) 1980, 1991 The Regents of the University of California.
  3.  * All rights reserved.
  4.  *
  5.  * Redistribution and use in source and binary forms, with or without
  6.  * modification, are permitted provided that the following conditions
  7.  * are met:
  8.  * 1. Redistributions of source code must retain the above copyright
  9.  *    notice, this list of conditions and the following disclaimer.
  10.  * 2. Redistributions in binary form must reproduce the above copyright
  11.  *    notice, this list of conditions and the following disclaimer in the
  12.  *    documentation and/or other materials provided with the distribution.
  13.  * 3. All advertising materials mentioning features or use of this software
  14.  *    must display the following acknowledgement:
  15.  *    This product includes software developed by the University of
  16.  *    California, Berkeley and its contributors.
  17.  * 4. Neither the name of the University nor the names of its contributors
  18.  *    may be used to endorse or promote products derived from this software
  19.  *    without specific prior written permission.
  20.  *
  21.  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  22.  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  23.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  24.  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  25.  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  26.  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  27.  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  28.  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  29.  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  30.  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  31.  * SUCH DAMAGE.
  32.  */
  33.  
  34. #ifndef lint
  35. char copyright[] =
  36. "@(#) Copyright (c) 1980, 1991 The Regents of the University of California.\n\
  37.  All rights reserved.\n";
  38. #endif /* not lint */
  39.  
  40. #ifndef lint
  41. static char sccsid[] = "@(#)w.c    5.29 (Berkeley) 4/23/91";
  42. #endif /* not lint */
  43.  
  44. /*
  45.  * w - print system status (who and what)
  46.  *
  47.  * This program is similar to the systat command on Tenex/Tops 10/20
  48.  *
  49.  */
  50. #include <sys/param.h>
  51. #include <utmp.h>
  52. #include <sys/time.h>
  53. #include <sys/stat.h>
  54. #include <sys/proc.h>
  55. #include <sys/user.h>
  56. #include <sys/ioctl.h>
  57. #include <sys/tty.h>
  58. #include <nlist.h>
  59. #include <kvm.h>
  60. #include <ctype.h>
  61. #include <paths.h>
  62. #include <string.h>
  63. #include <stdio.h>
  64.  
  65. #ifdef SPPWAIT
  66. #define NEWVM
  67. #endif
  68. #ifndef NEWVM
  69. #include <machine/pte.h>
  70. #include <sys/vm.h>
  71. #endif
  72.  
  73. char    *program;
  74. int    ttywidth;        /* width of tty */
  75. int    argwidth;        /* width of tty */
  76. int    header = 1;        /* true if -h flag: don't print heading */
  77. int    wcmd = 1;        /* true if this is w(1), and not uptime(1) */
  78. int    nusers;            /* number of users logged in now */
  79. char *    sel_user;        /* login of particular user selected */
  80. time_t    now;            /* the current time of day */
  81. struct    timeval boottime;
  82. time_t    uptime;            /* time of last reboot & elapsed time since */
  83. struct    utmp utmp;
  84. struct    winsize ws;
  85. int    sortidle;        /* sort bu idle time */
  86.  
  87.  
  88. /*
  89.  * One of these per active utmp entry.  
  90.  */
  91. struct    entry {
  92.     struct    entry *next;
  93.     struct    utmp utmp;
  94.     dev_t    tdev;        /* dev_t of terminal */
  95.     int    idle;        /* idle time of terminal in minutes */
  96.     struct    proc *proc;    /* list of procs in foreground */
  97.     char    *args;        /* arg list of interesting process */
  98. } *ep, *ehead = NULL, **nextp = &ehead;
  99.  
  100. struct nlist nl[] = {
  101.     { "_boottime" },
  102. #define X_BOOTTIME    0
  103. #if defined(hp300)
  104.     { "_cn_tty" },
  105. #define X_CNTTY        1
  106. #endif
  107.     { "" },
  108. };
  109.  
  110. #define USAGE "[ -hi ] [ user ]"
  111. #define usage()    fprintf(stderr, "usage: %s: %s\n", program, USAGE)
  112.  
  113. main(argc, argv)
  114.     int argc;
  115.     char **argv;
  116. {
  117.     register int i;
  118.     struct winsize win;
  119.     register struct proc *p;
  120.     struct eproc *e;
  121.     struct stat *stp, *ttystat();
  122.     FILE *ut;
  123.     char *cp;
  124.     int ch;
  125.     extern char *optarg;
  126.     extern int optind;
  127.     char *attime();
  128.  
  129.     program = argv[0];
  130.     /*
  131.      * are we w(1) or uptime(1)
  132.      */
  133.     if ((cp = rindex(program, '/')) || *(cp = program) == '-')
  134.         cp++;
  135.     if (*cp == 'u')
  136.         wcmd = 0;
  137.  
  138.     while ((ch = getopt(argc, argv, "hiflsuw")) != EOF)
  139.         switch((char)ch) {
  140.         case 'h':
  141.             header = 0;
  142.             break;
  143.         case 'i':
  144.             sortidle++;
  145.             break;
  146.         case 'f': case 'l': case 's': case 'u': case 'w':
  147.             error("[-flsuw] no longer supported");
  148.             usage();
  149.             exit(1);
  150.         case '?':
  151.         default:
  152.             usage();
  153.             exit(1);
  154.         }
  155.     argc -= optind;
  156.     argv += optind;
  157.  
  158.     if (*argv)
  159.         sel_user = *argv;
  160.  
  161.     if (header && kvm_nlist(nl) != 0) {
  162.         error("can't get namelist");
  163.         exit (1);
  164.     }
  165.     time(&now);
  166.     ut = fopen(_PATH_UTMP, "r");
  167.     while (fread(&utmp, sizeof(utmp), 1, ut)) {
  168.         if (utmp.ut_name[0] == '\0')
  169.             continue;
  170.         nusers++;
  171.         if (wcmd == 0 || (sel_user && 
  172.             strncmp(utmp.ut_name, sel_user, UT_NAMESIZE) != 0))
  173.             continue;
  174.         if ((ep = (struct entry *)
  175.              calloc(1, sizeof (struct entry))) == NULL) {
  176.             error("out of memory");
  177.             exit(1);
  178.         }
  179.         *nextp = ep;
  180.         nextp = &(ep->next);
  181.         bcopy(&utmp, &(ep->utmp), sizeof (struct utmp));
  182.         stp = ttystat(ep->utmp.ut_line);
  183.         ep->tdev = stp->st_rdev;
  184. #if defined(hp300)
  185.         /*
  186.          * XXX  If this is the console device, attempt to ascertain
  187.          * the true console device dev_t.
  188.          */
  189.         if (ep->tdev == 0) {
  190.             static dev_t cn_dev;
  191.  
  192.             if (nl[X_CNTTY].n_value) {
  193.                 struct tty cn_tty, *cn_ttyp;
  194.                 
  195.                 if (kvm_read((void *)nl[X_CNTTY].n_value,
  196.                     &cn_ttyp, sizeof(cn_ttyp)) > 0) {
  197.                     (void)kvm_read(cn_ttyp, &cn_tty,
  198.                         sizeof (cn_tty));
  199.                     cn_dev = cn_tty.t_dev;
  200.                 }
  201.                 nl[X_CNTTY].n_value = 0;
  202.             }
  203.             ep->tdev = cn_dev;
  204.         }
  205. #endif
  206.         ep->idle = ((now - stp->st_atime) + 30) / 60; /* secs->mins */
  207.         if (ep->idle < 0)
  208.             ep->idle = 0;
  209.     }
  210.     fclose(ut);
  211.  
  212.     if (header || wcmd == 0) {
  213.         double    avenrun[3];
  214.         int days, hrs, mins;
  215.  
  216.         /*
  217.          * Print time of day 
  218.          */
  219.         fputs(attime(&now), stdout);
  220.         /*
  221.          * Print how long system has been up.
  222.          * (Found by looking for "boottime" in kernel)
  223.          */
  224.         (void)kvm_read((void *)nl[X_BOOTTIME].n_value, &boottime, 
  225.             sizeof (boottime));
  226.         uptime = now - boottime.tv_sec;
  227.         uptime += 30;
  228.         days = uptime / (60*60*24);
  229.         uptime %= (60*60*24);
  230.         hrs = uptime / (60*60);
  231.         uptime %= (60*60);
  232.         mins = uptime / 60;
  233.  
  234.         printf("  up");
  235.         if (days > 0)
  236.             printf(" %d day%s,", days, days>1?"s":"");
  237.         if (hrs > 0 && mins > 0) {
  238.             printf(" %2d:%02d,", hrs, mins);
  239.         } else {
  240.             if (hrs > 0)
  241.                 printf(" %d hr%s,", hrs, hrs>1?"s":"");
  242.             if (mins > 0)
  243.                 printf(" %d min%s,", mins, mins>1?"s":"");
  244.         }
  245.  
  246.         /* Print number of users logged in to system */
  247.         printf("  %d user%s", nusers, nusers>1?"s":"");
  248.  
  249.         /*
  250.          * Print 1, 5, and 15 minute load averages.
  251.          */
  252.         printf(",  load average:");
  253.         (void)getloadavg(avenrun, sizeof(avenrun) / sizeof(avenrun[0]));
  254.         for (i = 0; i < (sizeof(avenrun)/sizeof(avenrun[0])); i++) {
  255.             if (i > 0)
  256.                 printf(",");
  257.             printf(" %.2f", avenrun[i]);
  258.         }
  259.         printf("\n");
  260.         if (wcmd == 0)        /* if uptime(1) then done */
  261.             exit(0);
  262. #define HEADER    "USER    TTY FROM              LOGIN@  IDLE WHAT\n"
  263. #define WUSED    (sizeof (HEADER) - sizeof ("WHAT\n"))
  264.         printf(HEADER);
  265.     }
  266.  
  267.     while ((p = kvm_nextproc()) != NULL) {
  268.         if (p->p_stat == SZOMB || (p->p_flag & SCTTY) == 0)
  269.             continue;
  270.         e = kvm_geteproc(p);
  271.         for (ep = ehead; ep != NULL; ep = ep->next) {
  272.             if (ep->tdev == e->e_tdev && e->e_pgid == e->e_tpgid) {
  273.                 /*
  274.                  * Proc is in foreground of this terminal
  275.                  */
  276.                 if (proc_compare(ep->proc, p))
  277.                     ep->proc = p;
  278.                 break;
  279.             }
  280.         }
  281.     }
  282.     if ((ioctl(1, TIOCGWINSZ, &ws) == -1 &&
  283.          ioctl(2, TIOCGWINSZ, &ws) == -1 &&
  284.          ioctl(0, TIOCGWINSZ, &ws) == -1) || ws.ws_col == 0)
  285.            ttywidth = 79;
  286.         else
  287.            ttywidth = ws.ws_col - 1;
  288.     argwidth = ttywidth - WUSED;
  289.     if (argwidth < 4)
  290.         argwidth = 8;
  291.     for (ep = ehead; ep != NULL; ep = ep->next) {
  292.         ep->args = strdup(kvm_getargs(ep->proc, kvm_getu(ep->proc)));
  293.         if (ep->args == NULL) {
  294.             error("out of memory");
  295.             exit(1);
  296.         }
  297.     }
  298.     /* sort by idle time */
  299.     if (sortidle && ehead != NULL) {
  300.         struct entry *from = ehead, *save;
  301.         
  302.         ehead = NULL;
  303.         while (from != NULL) {
  304.             for (nextp = &ehead; 
  305.                 (*nextp) && from->idle >= (*nextp)->idle;
  306.                 nextp = &(*nextp)->next)
  307.                 ;
  308.             save = from;
  309.             from = from->next;
  310.             save->next = *nextp;
  311.             *nextp = save;
  312.         }
  313.     }
  314.             
  315.     for (ep = ehead; ep != NULL; ep = ep->next) {
  316.         printf("%-*.*s %-2.2s %-*.*s %s",
  317.             UT_NAMESIZE, UT_NAMESIZE, ep->utmp.ut_name,
  318.             strncmp(ep->utmp.ut_line, "tty", 3) == 0 ? 
  319.                 ep->utmp.ut_line+3 : ep->utmp.ut_line,
  320.             UT_HOSTSIZE, UT_HOSTSIZE, *ep->utmp.ut_host ?
  321.                 ep->utmp.ut_host : "-",
  322.             attime(&ep->utmp.ut_time));
  323.         if (ep->idle >= 36 * 60)
  324.             printf(" %ddays ", (ep->idle + 12 * 60) / (24 * 60));
  325.         else
  326.             prttime(ep->idle, " ");
  327.         printf("%.*s\n", argwidth, ep->args);
  328.     }
  329.     exit(0);
  330. }
  331.  
  332. struct stat *
  333. ttystat(line)
  334. {
  335.     static struct stat statbuf;
  336.     char ttybuf[sizeof (_PATH_DEV) + UT_LINESIZE + 1];
  337.  
  338.     sprintf(ttybuf, "%s/%.*s", _PATH_DEV, UT_LINESIZE, line);
  339.     (void) stat(ttybuf, &statbuf);
  340.  
  341.     return (&statbuf);
  342. }
  343.  
  344. /*
  345.  * prttime prints a time in hours and minutes or minutes and seconds.
  346.  * The character string tail is printed at the end, obvious
  347.  * strings to pass are "", " ", or "am".
  348.  */
  349. prttime(tim, tail)
  350.     time_t tim;
  351.     char *tail;
  352. {
  353.  
  354.     if (tim >= 60) {
  355.         printf(" %2d:", tim/60);
  356.         tim %= 60;
  357.         printf("%02d", tim);
  358.     } else if (tim >= 0)
  359.         printf("    %2d", tim);
  360.     printf("%s", tail);
  361. }
  362.  
  363. #include <varargs.h>
  364.  
  365. error(va_alist)
  366.     va_dcl
  367. {
  368.     char *fmt;
  369.     va_list ap;
  370.  
  371.     fprintf(stderr, "%s: ", program);
  372.     va_start(ap);
  373.     fmt = va_arg(ap, char *);
  374.     (void) vfprintf(stderr, fmt, ap);
  375.     va_end(ap);
  376.     fprintf(stderr, "\n");
  377. }
  378.