home *** CD-ROM | disk | FTP | other *** search
/ Fresh Fish 8 / FreshFishVol8-CD2.bin / bbs / gnu / sh-utils-1.12-src.lha / sh-utils-1.12 / src / who.c < prev    next >
C/C++ Source or Header  |  1994-11-12  |  13KB  |  594 lines

  1. /* GNU's users/who.
  2.    Copyright (C) 92, 93, 1994 Free Software Foundation, Inc.
  3.  
  4.    This program is free software; you can redistribute it and/or modify
  5.    it under the terms of the GNU General Public License as published by
  6.    the Free Software Foundation; either version 2, or (at your option)
  7.    any later version.
  8.  
  9.    This program is distributed in the hope that it will be useful,
  10.    but WITHOUT ANY WARRANTY; without even the implied warranty of
  11.    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12.    GNU General Public License for more details.
  13.  
  14.    You should have received a copy of the GNU General Public License
  15.    along with this program; if not, write to the Free Software
  16.    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
  17.  
  18. /* Written by jla; revised by djm */
  19.  
  20. /* Output format:
  21.    name [state] line time [idle] host
  22.    state: -T
  23.    name, line, time: not -q
  24.    idle: -u
  25.  
  26.    Options:
  27.    -m        Same as 'who am i', for POSIX.
  28.    -q        Only user names and # logged on; overrides all other options.
  29.    -s        Name, line, time (default).
  30.    -i, -u    Idle hours and minutes; '.' means active in last minute;
  31.         'old' means idle for >24 hours.
  32.    -H        Print column headings at top.
  33.    -w, -T    -s plus mesg (+ or -, or ? if bad line). */
  34.  
  35. #include <config.h>
  36. #include <stdio.h>
  37. #include <sys/types.h>
  38.  
  39. #ifdef HAVE_UTMPX_H
  40. #include <utmpx.h>
  41. #define STRUCT_UTMP struct utmpx
  42. #else
  43. #include <utmp.h>
  44. #define STRUCT_UTMP struct utmp
  45. #endif
  46.  
  47. #include <time.h>
  48. #include <getopt.h>
  49. #ifdef HAVE_SYS_PARAM_H
  50. #include <sys/param.h>
  51. #endif
  52.  
  53. #include "system.h"
  54. #include "version.h"
  55. #include "safe-stat.h"
  56.  
  57. #if !defined (UTMP_FILE) && defined (_PATH_UTMP)    /* 4.4BSD.  */
  58. #define UTMP_FILE _PATH_UTMP
  59. #endif
  60.  
  61. #if defined (UTMPX_FILE)    /* Solaris, SysVr4 */
  62. #undef  UTMP_FILE
  63. #define UTMP_FILE UTMPX_FILE
  64. #endif
  65.  
  66. #ifndef UTMP_FILE
  67. #define UTMP_FILE "/etc/utmp"
  68. #endif
  69.  
  70. #ifndef MAXHOSTNAMELEN
  71. #define MAXHOSTNAMELEN 64
  72. #endif
  73.  
  74. #ifndef S_IWGRP
  75. #define S_IWGRP 020
  76. #endif
  77.  
  78. #ifdef WHO
  79. #define COMMAND_NAME "who"
  80. #else
  81. #ifdef USERS
  82. #define COMMAND_NAME "users"
  83. #else
  84.  error You must define one of WHO and USERS.
  85. #endif /* USERS */
  86. #endif /* WHO */
  87.  
  88. char *xmalloc ();
  89. void error ();
  90. char *ttyname ();
  91. int gethostname ();
  92.  
  93. static int read_utmp ();
  94. #ifdef WHO
  95. static const char *idle_string ();
  96. static STRUCT_UTMP *search_entries ();
  97. static void print_entry ();
  98. static void print_heading ();
  99. static void scan_entries ();
  100. static void who_am_i ();
  101. #endif /* WHO */
  102. static void list_entries ();
  103. static void usage ();
  104. static void who ();
  105.  
  106. /* The name this program was run with. */
  107. char *program_name;
  108.  
  109. /* If non-zero, display usage information and exit.  */
  110. static int show_help;
  111.  
  112. /* If non-zero, print the version on standard output and exit.  */
  113. static int show_version;
  114.  
  115. #ifdef WHO
  116. /* If nonzero, display only a list of usernames and count of
  117.    the users logged on.
  118.    Ignored for `who am i'. */
  119. static int short_list;
  120.  
  121. /* If nonzero, display the hours:minutes since each user has touched
  122.    the keyboard, or "." if within the last minute, or "old" if
  123.    not within the last day. */
  124. static int include_idle;
  125.  
  126. /* If nonzero, display a line at the top describing each field. */
  127. static int include_heading;
  128.  
  129. /* If nonzero, display a `+' for each user if mesg y, a `-' if mesg n,
  130.    or a `?' if their tty cannot be statted. */
  131. static int include_mesg;
  132. #endif /* WHO */
  133.  
  134. static struct option const longopts[] =
  135. {
  136. #ifdef WHO
  137.   {"count", no_argument, NULL, 'q'},
  138.   {"idle", no_argument, NULL, 'u'},
  139.   {"heading", no_argument, NULL, 'H'},
  140.   {"message", no_argument, NULL, 'T'},
  141.   {"mesg", no_argument, NULL, 'T'},
  142.   {"writable", no_argument, NULL, 'T'},
  143. #endif /* WHO */
  144.   {"help", no_argument, &show_help, 1},
  145.   {"version", no_argument, &show_version, 1},
  146.   {NULL, 0, NULL, 0}
  147. };
  148.  
  149. main (argc, argv)
  150.      int argc;
  151.      char **argv;
  152. {
  153.   int optc, longind;
  154. #ifdef WHO
  155.   int my_line_only = 0;
  156. #endif /* WHO */
  157.  
  158.   program_name = argv[0];
  159.  
  160. #ifdef WHO
  161.   while ((optc = getopt_long (argc, argv, "imqsuwHT", longopts, &longind))
  162. #else
  163.   while ((optc = getopt_long (argc, argv, "", longopts, &longind))
  164. #endif /* WHO */
  165.      != EOF)
  166.     {
  167.       switch (optc)
  168.     {
  169.     case 0:
  170.       break;
  171.  
  172. #ifdef WHO
  173.     case 'm':
  174.       my_line_only = 1;
  175.       break;
  176.  
  177.     case 'q':
  178.       short_list = 1;
  179.       break;
  180.  
  181.     case 's':
  182.       break;
  183.  
  184.     case 'i':
  185.     case 'u':
  186.       include_idle = 1;
  187.       break;
  188.  
  189.     case 'H':
  190.       include_heading = 1;
  191.       break;
  192.  
  193.     case 'w':
  194.     case 'T':
  195.       include_mesg = 1;
  196.       break;
  197. #endif /* WHO */
  198.  
  199.     default:
  200.       error (0, 0, "too many arguments");
  201.       usage (1);
  202.     }
  203.     }
  204.  
  205.   if (show_version)
  206.     {
  207.       printf ("%s - %s\n", COMMAND_NAME, version_string);
  208.       exit (0);
  209.     }
  210.  
  211.   if (show_help)
  212.     usage (0);
  213.  
  214.   switch (argc - optind)
  215.     {
  216.     case 0:            /* who */
  217. #ifdef WHO
  218.       if (my_line_only)
  219.     who_am_i (UTMP_FILE);
  220.       else
  221. #endif /* WHO */
  222.     who (UTMP_FILE);
  223.       break;
  224.  
  225.     case 1:            /* who <utmp file> */
  226. #ifdef WHO
  227.       if (my_line_only)
  228.     who_am_i (argv[optind]);
  229.       else
  230. #endif /* WHO */
  231.     who (argv[optind]);
  232.       break;
  233.  
  234. #ifdef WHO
  235.     case 2:            /* who <blurf> <glop> */
  236.       who_am_i (UTMP_FILE);
  237.       break;
  238. #endif /* WHO */
  239.  
  240.     default:            /* lose */
  241.       usage (1);
  242.     }
  243.  
  244.   exit (0);
  245. }
  246.  
  247. static STRUCT_UTMP *utmp_contents;
  248.  
  249. /* Display a list of who is on the system, according to utmp file FILENAME. */
  250.  
  251. static void
  252. who (filename)
  253.      char *filename;
  254. {
  255.   int users;
  256.  
  257.   users = read_utmp (filename);
  258. #ifdef WHO
  259.   if (short_list)
  260.     list_entries (users);
  261.   else
  262.     scan_entries (users);
  263. #else
  264. #ifdef USERS
  265.   list_entries (users);
  266. #endif /* USERS */
  267. #endif /* WHO */
  268. }
  269.  
  270. /* Read the utmp file FILENAME into UTMP_CONTENTS and return the
  271.    number of entries it contains. */
  272.  
  273. static int
  274. read_utmp (filename)
  275.      char *filename;
  276. {
  277.   FILE *utmp;
  278.   struct stat file_stats;
  279.   int n_read;
  280.   size_t size;
  281.  
  282.   utmp = fopen (filename, "r");
  283.   if (utmp == NULL)
  284.     error (1, errno, "%s", filename);
  285.  
  286.   fstat (fileno (utmp), &file_stats);
  287.   size = file_stats.st_size;
  288.   if (size > 0)
  289.     utmp_contents = (STRUCT_UTMP *) xmalloc (size);
  290.   else
  291.     {
  292.       fclose (utmp);
  293.       return 0;
  294.     }
  295.  
  296.   /* Use < instead of != in case the utmp just grew.  */
  297.   n_read = fread (utmp_contents, 1, size, utmp);
  298.   if (ferror (utmp) || fclose (utmp) == EOF
  299.       || n_read < size)
  300.     error (1, errno, "%s", filename);
  301.  
  302.   return size / sizeof (STRUCT_UTMP);
  303. }
  304.  
  305. #ifdef WHO
  306. /* Display a line of information about entry THIS. */
  307.  
  308. static void
  309. print_entry (this)
  310.      STRUCT_UTMP *this;
  311. {
  312.   struct stat stats;
  313.   time_t last_change;
  314.   char mesg;
  315.  
  316. #define DEV_DIR_WITH_TRAILING_SLASH "/dev/"
  317. #define DEV_DIR_LEN (sizeof (DEV_DIR_WITH_TRAILING_SLASH) - 1)
  318.  
  319.   char line[sizeof (this->ut_line) + DEV_DIR_LEN + 1];
  320.  
  321.   /* Copy ut_line into LINE, prepending `/dev/' if ut_line is not
  322.      already an absolute pathname.  Some system may put the full,
  323.      absolute pathname in ut_line.  */
  324.   if (this->ut_line[0] == '/')
  325.     {
  326.       strncpy (line, this->ut_line, sizeof (this->ut_line));
  327.       line[sizeof (this->ut_line)] = '\0';
  328.     }
  329.   else
  330.     {
  331.       strcpy(line, DEV_DIR_WITH_TRAILING_SLASH);
  332.       strncpy (line + DEV_DIR_LEN, this->ut_line, sizeof (this->ut_line));
  333.       line[DEV_DIR_LEN + sizeof (this->ut_line)] = '\0';
  334.     }
  335.  
  336.   if (SAFE_STAT (line, &stats) == 0)
  337.     {
  338.       mesg = (stats.st_mode & S_IWGRP) ? '+' : '-';
  339.       last_change = stats.st_atime;
  340.     }
  341.   else
  342.     {
  343.       mesg = '?';
  344.       last_change = 0;
  345.     }
  346.   
  347.   printf ("%-8.*s", (int) sizeof (this->ut_name), this->ut_name);
  348.   if (include_mesg)
  349.     printf ("  %c  ", mesg);
  350.   printf (" %-8.*s", (int) sizeof (this->ut_line), this->ut_line);
  351.  
  352. #ifdef HAVE_UTMPX_H
  353.   printf (" %-12.12s", ctime (&this->ut_tv.tv_sec) + 4);
  354. #else
  355.   printf (" %-12.12s", ctime (&this->ut_time) + 4);
  356. #endif
  357.  
  358.   if (include_idle)
  359.     {
  360.       if (last_change)
  361.     printf (" %s", idle_string (last_change));
  362.       else
  363.     printf ("   .  ");
  364.     }
  365. #ifdef HAVE_UT_HOST
  366.   if (this->ut_host[0])
  367.     printf (" (%-.*s)", (int) sizeof (this->ut_host), this->ut_host);
  368. #endif
  369.  
  370.   putchar ('\n');
  371. }
  372. #endif /* WHO */
  373.  
  374. #if defined (WHO) || defined (USERS)
  375. /* Print the username of each valid entry and the number of valid entries
  376.    in `utmp_contents', which should have N elements. */
  377.  
  378. static void
  379. list_entries (n)