LCOV - code coverage report
Current view: top level - src - who.c (source / functions) Hit Total Coverage
Test: coreutils.info Lines: 159 298 53.4 %
Date: 2018-01-30 Functions: 7 17 41.2 %

          Line data    Source code
       1             : /* GNU's who.
       2             :    Copyright (C) 1992-2007 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 3 of the License, or
       7             :    (at your option) 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, see <http://www.gnu.org/licenses/>.  */
      16             : 
      17             : /* Written by jla; revised by djm; revised again by mstone */
      18             : 
      19             : /* Output format:
      20             :    name [state] line time [activity] [pid] [comment] [exit]
      21             :    state: -T
      22             :    name, line, time: not -q
      23             :    idle: -u
      24             : */
      25             : 
      26             : #include <config.h>
      27             : #include <getopt.h>
      28             : #include <stdio.h>
      29             : 
      30             : #include <sys/types.h>
      31             : #include "system.h"
      32             : 
      33             : #include "canon-host.h"
      34             : #include "readutmp.h"
      35             : #include "error.h"
      36             : #include "hard-locale.h"
      37             : #include "inttostr.h"
      38             : #include "quote.h"
      39             : 
      40             : /* The official name of this program (e.g., no `g' prefix).  */
      41             : #define PROGRAM_NAME "who"
      42             : 
      43             : #define AUTHORS "Joseph Arceneaux", "David MacKenzie", "Michael Stone"
      44             : 
      45             : #ifndef MAXHOSTNAMELEN
      46             : # define MAXHOSTNAMELEN 64
      47             : #endif
      48             : 
      49             : #ifdef RUN_LVL
      50             : # define UT_TYPE_RUN_LVL(U) UT_TYPE_EQ (U, RUN_LVL)
      51             : #else
      52             : # define UT_TYPE_RUN_LVL(U) false
      53             : #endif
      54             : 
      55             : #ifdef INIT_PROCESS
      56             : # define UT_TYPE_INIT_PROCESS(U) UT_TYPE_EQ (U, INIT_PROCESS)
      57             : #else
      58             : # define UT_TYPE_INIT_PROCESS(U) false
      59             : #endif
      60             : 
      61             : #ifdef LOGIN_PROCESS
      62             : # define UT_TYPE_LOGIN_PROCESS(U) UT_TYPE_EQ (U, LOGIN_PROCESS)
      63             : #else
      64             : # define UT_TYPE_LOGIN_PROCESS(U) false
      65             : #endif
      66             : 
      67             : #ifdef DEAD_PROCESS
      68             : # define UT_TYPE_DEAD_PROCESS(U) UT_TYPE_EQ (U, DEAD_PROCESS)
      69             : #else
      70             : # define UT_TYPE_DEAD_PROCESS(U) false
      71             : #endif
      72             : 
      73             : #ifdef NEW_TIME
      74             : # define UT_TYPE_NEW_TIME(U) UT_TYPE_EQ (U, NEW_TIME)
      75             : #else
      76             : # define UT_TYPE_NEW_TIME(U) false
      77             : #endif
      78             : 
      79             : #define IDLESTR_LEN 6
      80             : 
      81             : #if HAVE_STRUCT_XTMP_UT_PID
      82             : # define PIDSTR_DECL_AND_INIT(Var, Utmp_ent) \
      83             :   char Var[INT_STRLEN_BOUND (Utmp_ent->ut_pid) + 1]; \
      84             :   sprintf (Var, "%ld", (long int) (Utmp_ent->ut_pid))
      85             : #else
      86             : # define PIDSTR_DECL_AND_INIT(Var, Utmp_ent) \
      87             :   const char *Var = ""
      88             : #endif
      89             : 
      90             : #if HAVE_STRUCT_XTMP_UT_ID
      91             : # define UT_ID(U) ((U)->ut_id)
      92             : #else
      93             : # define UT_ID(U) "??"
      94             : #endif
      95             : 
      96             : char *ttyname ();
      97             : 
      98             : /* The name this program was run with. */
      99             : char *program_name;
     100             : 
     101             : /* If true, attempt to canonicalize hostnames via a DNS lookup. */
     102             : static bool do_lookup;
     103             : 
     104             : /* If true, display only a list of usernames and count of
     105             :    the users logged on.
     106             :    Ignored for `who am i'.  */
     107             : static bool short_list;
     108             : 
     109             : /* If true, display only name, line, and time fields.  */
     110             : static bool short_output;
     111             : 
     112             : /* If true, display the hours:minutes since each user has touched
     113             :    the keyboard, or "." if within the last minute, or "old" if
     114             :    not within the last day.  */
     115             : static bool include_idle;
     116             : 
     117             : /* If true, display a line at the top describing each field.  */
     118             : static bool include_heading;
     119             : 
     120             : /* If true, display a `+' for each user if mesg y, a `-' if mesg n,
     121             :    or a `?' if their tty cannot be statted. */
     122             : static bool include_mesg;
     123             : 
     124             : /* If true, display process termination & exit status.  */
     125             : static bool include_exit;
     126             : 
     127             : /* If true, display the last boot time.  */
     128             : static bool need_boottime;
     129             : 
     130             : /* If true, display dead processes.  */
     131             : static bool need_deadprocs;
     132             : 
     133             : /* If true, display processes waiting for user login.  */
     134             : static bool need_login;
     135             : 
     136             : /* If true, display processes started by init.  */
     137             : static bool need_initspawn;
     138             : 
     139             : /* If true, display the last clock change.  */
     140             : static bool need_clockchange;
     141             : 
     142             : /* If true, display the current runlevel.  */
     143             : static bool need_runlevel;
     144             : 
     145             : /* If true, display user processes.  */
     146             : static bool need_users;
     147             : 
     148             : /* If true, display info only for the controlling tty.  */
     149             : static bool my_line_only;
     150             : 
     151             : /* The strftime format to use for login times, and its expected
     152             :    output width.  */
     153             : static char const *time_format;
     154             : static int time_format_width;
     155             : 
     156             : /* for long options with no corresponding short option, use enum */
     157             : enum
     158             : {
     159             :   LOOKUP_OPTION = CHAR_MAX + 1
     160             : };
     161             : 
     162             : static struct option const longopts[] = {
     163             :   {"all", no_argument, NULL, 'a'},
     164             :   {"boot", no_argument, NULL, 'b'},
     165             :   {"count", no_argument, NULL, 'q'},
     166             :   {"dead", no_argument, NULL, 'd'},
     167             :   {"heading", no_argument, NULL, 'H'},
     168             :   {"login", no_argument, NULL, 'l'},
     169             :   {"lookup", no_argument, NULL, LOOKUP_OPTION},
     170             :   {"message", no_argument, NULL, 'T'},
     171             :   {"mesg", no_argument, NULL, 'T'},
     172             :   {"process", no_argument, NULL, 'p'},
     173             :   {"runlevel", no_argument, NULL, 'r'},
     174             :   {"short", no_argument, NULL, 's'},
     175             :   {"time", no_argument, NULL, 't'},
     176             :   {"users", no_argument, NULL, 'u'},
     177             :   {"writable", no_argument, NULL, 'T'},
     178             :   {GETOPT_HELP_OPTION_DECL},
     179             :   {GETOPT_VERSION_OPTION_DECL},
     180             :   {NULL, 0, NULL, 0}
     181             : };
     182             : 
     183             : /* Return a string representing the time between WHEN and now.
     184             :    BOOTTIME is the time of last reboot.
     185             :    FIXME: locale? */
     186             : static const char *
     187           0 : idle_string (time_t when, time_t boottime)
     188             : {
     189             :   static time_t now = TYPE_MINIMUM (time_t);
     190             : 
     191           0 :   if (now == TYPE_MINIMUM (time_t))
     192           0 :     time (&now);
     193             : 
     194           0 :   if (boottime < when && now - 24 * 60 * 60 < when && when <= now)
     195             :     {
     196           0 :       int seconds_idle = now - when;
     197           0 :       if (seconds_idle < 60)
     198           0 :         return "  .  ";
     199             :       else
     200             :         {
     201             :           static char idle_hhmm[IDLESTR_LEN];
     202           0 :           sprintf (idle_hhmm, "%02d:%02d",
     203             :                    seconds_idle / (60 * 60),
     204           0 :                    (seconds_idle % (60 * 60)) / 60);
     205           0 :           return idle_hhmm;
     206             :         }
     207             :     }
     208             : 
     209           0 :   return _(" old ");
     210             : }
     211             : 
     212             : /* Return a time string.  */
     213             : static const char *
     214           0 : time_string (const STRUCT_UTMP *utmp_ent)
     215             : {
     216             :   static char buf[INT_STRLEN_BOUND (intmax_t) + sizeof "-%m-%d %H:%M"];
     217             : 
     218             :   /* Don't take the address of UT_TIME_MEMBER directly.
     219             :      Ulrich Drepper wrote:
     220             :      ``... GNU libc (and perhaps other libcs as well) have extended
     221             :      utmp file formats which do not use a simple time_t ut_time field.
     222             :      In glibc, ut_time is a macro which selects for backward compatibility
     223             :      the tv_sec member of a struct timeval value.''  */
     224           0 :   time_t t = UT_TIME_MEMBER (utmp_ent);
     225           0 :   struct tm *tmp = localtime (&t);
     226             : 
     227           0 :   if (tmp)
     228             :     {
     229           0 :       strftime (buf, sizeof buf, time_format, tmp);
     230           0 :       return buf;
     231             :     }
     232             :   else
     233           0 :     return TYPE_SIGNED (time_t) ? imaxtostr (t, buf) : umaxtostr (t, buf);
     234             : }
     235             : 
     236             : /* Print formatted output line. Uses mostly arbitrary field sizes, probably
     237             :    will need tweaking if any of the localization stuff is done, or for 64 bit
     238             :    pids, etc. */
     239             : static void
     240           3 : print_line (int userlen, const char *user, const char state,
     241             :             int linelen, const char *line,
     242             :             const char *time_str, const char *idle, const char *pid,
     243             :             const char *comment, const char *exitstr)
     244             : {
     245             :   static char mesg[3] = { ' ', 'x', '\0' };
     246             :   char *buf;
     247             :   char x_idle[1 + IDLESTR_LEN + 1];
     248             :   char x_pid[1 + INT_STRLEN_BOUND (pid_t) + 1];
     249             :   char *x_exitstr;
     250             :   int err;
     251             : 
     252           3 :   mesg[1] = state;
     253             : 
     254           3 :   if (include_idle && !short_output && strlen (idle) < sizeof x_idle - 1)
     255           1 :     sprintf (x_idle, " %-6s", idle);
     256             :   else
     257           2 :     *x_idle = '\0';
     258             : 
     259           3 :   if (!short_output && strlen (pid) < sizeof x_pid - 1)
     260           1 :     sprintf (x_pid, " %10s", pid);
     261             :   else
     262           2 :     *x_pid = '\0';
     263             : 
     264           3 :   x_exitstr = xmalloc (include_exit ? 1 + MAX (12, strlen (exitstr)) + 1 : 1);
     265           3 :   if (include_exit)
     266           1 :     sprintf (x_exitstr, " %-12s", exitstr);
     267             :   else
     268           2 :     *x_exitstr = '\0';
     269             : 
     270           6 :   err = asprintf (&buf,
     271             :                   "%-8.*s"
     272             :                   "%s"
     273             :                   " %-12.*s"
     274             :                   " %-*s"
     275             :                   "%s"
     276             :                   "%s"
     277             :                   " %-8s"
     278             :                   "%s"
     279             :                   ,
     280             :                   userlen, user ? user : "   .",
     281           3 :                   include_mesg ? mesg : "",
     282             :                   linelen, line,
     283             :                   time_format_width,
     284             :                   time_str,
     285             :                   x_idle,
     286             :                   x_pid,
     287             :                   /* FIXME: it's not really clear whether the following
     288             :                      field should be in the short_output.  A strict reading
     289             :                      of SUSv2 would suggest not, but I haven't seen any
     290             :                      implementations that actually work that way... */
     291             :                   comment,
     292             :                   x_exitstr
     293             :                   );
     294           3 :   if (err == -1)
     295           0 :     xalloc_die ();
     296             : 
     297             :   {
     298             :     /* Remove any trailing spaces.  */
     299           3 :     char *p = buf + strlen (buf);
     300           3 :     while (*--p == ' ')
     301             :       /* empty */;
     302           3 :     *(p + 1) = '\0';
     303             :   }
     304             : 
     305           3 :   puts (buf);
     306           3 :   free (buf);
     307           3 :   free (x_exitstr);
     308           3 : }
     309             : 
     310             : /* Send properly parsed USER_PROCESS info to print_line.  The most
     311             :    recent boot time is BOOTTIME. */
     312             : static void
     313           0 : print_user (const STRUCT_UTMP *utmp_ent, time_t boottime)
     314             : {
     315             :   struct stat stats;
     316             :   time_t last_change;
     317             :   char mesg;
     318             :   char idlestr[IDLESTR_LEN + 1];
     319             :   static char *hoststr;
     320             : #if HAVE_UT_HOST
     321             :   static size_t hostlen;
     322             : #endif
     323             : 
     324             : #define DEV_DIR_WITH_TRAILING_SLASH "/dev/"
     325             : #define DEV_DIR_LEN (sizeof (DEV_DIR_WITH_TRAILING_SLASH) - 1)
     326             : 
     327             :   char line[sizeof (utmp_ent->ut_line) + DEV_DIR_LEN + 1];
     328           0 :   PIDSTR_DECL_AND_INIT (pidstr, utmp_ent);
     329             : 
     330             :   /* Copy ut_line into LINE, prepending `/dev/' if ut_line is not
     331             :      already an absolute file name.  Some systems may put the full,
     332             :      absolute file name in ut_line.  */
     333           0 :   if (utmp_ent->ut_line[0] == '/')
     334             :     {
     335           0 :       strncpy (line, utmp_ent->ut_line, sizeof (utmp_ent->ut_line));
     336           0 :       line[sizeof (utmp_ent->ut_line)] = '\0';
     337             :     }
     338             :   else
     339             :     {
     340           0 :       strcpy (line, DEV_DIR_WITH_TRAILING_SLASH);
     341           0 :       strncpy (line + DEV_DIR_LEN, utmp_ent->ut_line,
     342             :                sizeof (utmp_ent->ut_line));
     343           0 :       line[DEV_DIR_LEN + sizeof (utmp_ent->ut_line)] = '\0';
     344             :     }
     345             : 
     346           0 :   if (stat (line, &stats) == 0)
     347             :     {
     348           0 :       mesg = (stats.st_mode & S_IWGRP) ? '+' : '-';
     349           0 :       last_change = stats.st_atime;
     350             :     }
     351             :   else
     352             :     {
     353           0 :       mesg = '?';
     354           0 :       last_change = 0;
     355             :     }
     356             : 
     357           0 :   if (last_change)
     358           0 :     sprintf (idlestr, "%.*s", IDLESTR_LEN, idle_string (last_change, boottime));
     359             :   else
     360           0 :     sprintf (idlestr, "  ?");
     361             : 
     362             : #if HAVE_UT_HOST
     363           0 :   if (utmp_ent->ut_host[0])
     364             :     {
     365             :       char ut_host[sizeof (utmp_ent->ut_host) + 1];
     366           0 :       char *host = NULL;
     367           0 :       char *display = NULL;
     368             : 
     369             :       /* Copy the host name into UT_HOST, and ensure it's nul terminated. */
     370           0 :       strncpy (ut_host, utmp_ent->ut_host, sizeof (utmp_ent->ut_host));
     371           0 :       ut_host[sizeof (utmp_ent->ut_host)] = '\0';
     372             : 
     373             :       /* Look for an X display.  */
     374           0 :       display = strchr (ut_host, ':');
     375           0 :       if (display)
     376           0 :         *display++ = '\0';
     377             : 
     378           0 :       if (*ut_host && do_lookup)
     379             :         {
     380             :           /* See if we can canonicalize it.  */
     381           0 :           host = canon_host (ut_host);
     382             :         }
     383             : 
     384           0 :       if (! host)
     385           0 :         host = ut_host;
     386             : 
     387           0 :       if (display)
     388             :         {
     389           0 :           if (hostlen < strlen (host) + strlen (display) + 4)
     390             :             {
     391           0 :               hostlen = strlen (host) + strlen (display) + 4;
     392           0 :               hoststr = xrealloc (hoststr, hostlen);
     393             :             }
     394           0 :           sprintf (hoststr, "(%s:%s)", host, display);
     395             :         }
     396             :       else
     397             :         {
     398           0 :           if (hostlen < strlen (host) + 3)
     399             :             {
     400           0 :               hostlen = strlen (host) + 3;
     401           0 :               hoststr = xrealloc (hoststr, hostlen);
     402             :             }
     403           0 :           sprintf (hoststr, "(%s)", host);
     404             :         }
     405             : 
     406           0 :       if (host != ut_host)
     407           0 :         free (host);
     408             :     }
     409             :   else
     410             :     {
     411           0 :       if (hostlen < 1)
     412             :         {
     413           0 :           hostlen = 1;
     414           0 :           hoststr = xrealloc (hoststr, hostlen);
     415             :         }
     416           0 :       *hoststr = '\0';
     417             :     }
     418             : #endif
     419             : 
     420           0 :   print_line (sizeof UT_USER (utmp_ent), UT_USER (utmp_ent), mesg,
     421           0 :               sizeof utmp_ent->ut_line, utmp_ent->ut_line,
     422             :               time_string (utmp_ent), idlestr, pidstr,
     423           0 :               hoststr ? hoststr : "", "");
     424           0 : }
     425             : 
     426             : static void
     427           0 : print_boottime (const STRUCT_UTMP *utmp_ent)
     428             : {
     429           0 :   print_line (-1, "", ' ', -1, "system boot",
     430             :               time_string (utmp_ent), "", "", "", "");
     431           0 : }
     432             : 
     433             : static char *
     434           0 : make_id_equals_comment (STRUCT_UTMP const *utmp_ent)
     435             : {
     436           0 :   char *comment = xmalloc (strlen (_("id=")) + sizeof UT_ID (utmp_ent) + 1);
     437             : 
     438           0 :   strcpy (comment, _("id="));
     439           0 :   strncat (comment, UT_ID (utmp_ent), sizeof UT_ID (utmp_ent));
     440           0 :   return comment;
     441             : }
     442             : 
     443             : static void
     444           0 : print_deadprocs (const STRUCT_UTMP *utmp_ent)
     445             : {
     446             :   static char *exitstr;
     447           0 :   char *comment = make_id_equals_comment (utmp_ent);
     448           0 :   PIDSTR_DECL_AND_INIT (pidstr, utmp_ent);
     449             : 
     450           0 :   if (!exitstr)
     451           0 :     exitstr = xmalloc (strlen (_("term="))
     452             :                        + INT_STRLEN_BOUND (UT_EXIT_E_TERMINATION (utmp_ent)) + 1
     453             :                        + strlen (_("exit="))
     454             :                        + INT_STRLEN_BOUND (UT_EXIT_E_EXIT (utmp_ent))
     455             :                        + 1);
     456           0 :   sprintf (exitstr, "%s%d %s%d", _("term="), UT_EXIT_E_TERMINATION (utmp_ent),
     457           0 :            _("exit="), UT_EXIT_E_EXIT (utmp_ent));
     458             : 
     459             :   /* FIXME: add idle time? */
     460             : 
     461           0 :   print_line (-1, "", ' ', sizeof utmp_ent->ut_line, utmp_ent->ut_line,
     462             :               time_string (utmp_ent), "", pidstr, comment, exitstr);
     463           0 :   free (comment);
     464           0 : }
     465             : 
     466             : static void
     467           0 : print_login (const STRUCT_UTMP *utmp_ent)
     468             : {
     469           0 :   char *comment = make_id_equals_comment (utmp_ent);
     470           0 :   PIDSTR_DECL_AND_INIT (pidstr, utmp_ent);
     471             : 
     472             :   /* FIXME: add idle time? */
     473             : 
     474           0 :   print_line (-1, "LOGIN", ' ', sizeof utmp_ent->ut_line, utmp_ent->ut_line,
     475             :               time_string (utmp_ent), "", pidstr, comment, "");
     476           0 :   free (comment);
     477           0 : }
     478             : 
     479             : static void
     480           0 : print_initspawn (const STRUCT_UTMP *utmp_ent)
     481             : {
     482           0 :   char *comment = make_id_equals_comment (utmp_ent);
     483           0 :   PIDSTR_DECL_AND_INIT (pidstr, utmp_ent);
     484             : 
     485           0 :   print_line (-1, "", ' ', sizeof utmp_ent->ut_line, utmp_ent->ut_line,
     486             :               time_string (utmp_ent), "", pidstr, comment, "");
     487           0 :   free (comment);
     488           0 : }
     489             : 
     490             : static void
     491           0 : print_clockchange (const STRUCT_UTMP *utmp_ent)
     492             : {
     493             :   /* FIXME: handle NEW_TIME & OLD_TIME both */
     494           0 :   print_line (-1, "", ' ', -1, _("clock change"),
     495             :               time_string (utmp_ent), "", "", "", "");
     496           0 : }
     497             : 
     498             : static void
     499           0 : print_runlevel (const STRUCT_UTMP *utmp_ent)
     500             : {
     501             :   static char *runlevline, *comment;
     502           0 :   unsigned char last = UT_PID (utmp_ent) / 256;
     503           0 :   unsigned char curr = UT_PID (utmp_ent) % 256;
     504             : 
     505           0 :   if (!runlevline)
     506           0 :     runlevline = xmalloc (strlen (_("run-level")) + 3);
     507           0 :   sprintf (runlevline, "%s %c", _("run-level"), curr);
     508             : 
     509           0 :   if (!comment)
     510           0 :     comment = xmalloc (strlen (_("last=")) + 2);
     511           0 :   sprintf (comment, "%s%c", _("last="), (last == 'N') ? 'S' : last);
     512             : 
     513           0 :   print_line (-1, "", ' ', -1, runlevline, time_string (utmp_ent),
     514             :               "", "", comment, "");
     515             : 
     516           0 :   return;
     517             : }
     518             : 
     519             : /* Print the username of each valid entry and the number of valid entries
     520             :    in UTMP_BUF, which should have N elements. */
     521             : static void
     522           1 : list_entries_who (size_t n, const STRUCT_UTMP *utmp_buf)
     523             : {
     524           1 :   unsigned long int entries = 0;
     525           1 :   char const *separator = "";
     526             : 
     527           2 :   while (n--)
     528             :     {
     529           0 :       if (IS_USER_PROCESS (utmp_buf))
     530             :         {
     531             :           char *trimmed_name;
     532             : 
     533           0 :           trimmed_name = extract_trimmed_name (utmp_buf);
     534             : 
     535           0 :           printf ("%s%s", separator, trimmed_name);
     536           0 :           free (trimmed_name);
     537           0 :           separator = " ";
     538           0 :           entries++;
     539             :         }
     540           0 :       utmp_buf++;
     541             :     }
     542           1 :   printf (_("\n# users=%lu\n"), entries);
     543           1 : }
     544             : 
     545             : static void
     546           3 : print_heading (void)
     547             : {
     548           3 :   print_line (-1, _("NAME"), ' ', -1, _("LINE"), _("TIME"), _("IDLE"),
     549             :               _("PID"), _("COMMENT"), _("EXIT"));
     550           3 : }
     551             : 
     552             : /* Display UTMP_BUF, which should have N entries. */
     553             : static void
     554          40 : scan_entries (size_t n, const STRUCT_UTMP *utmp_buf)
     555             : {
     556             :   char *ttyname_b IF_LINT ( = NULL);
     557          40 :   time_t boottime = TYPE_MINIMUM (time_t);
     558             : 
     559          40 :   if (include_heading)
     560           3 :     print_heading ();
     561             : 
     562          40 :   if (my_line_only)
     563             :     {
     564          12 :       ttyname_b = ttyname (STDIN_FILENO);
     565          12 :       if (!ttyname_b)
     566           1 :         return;
     567          11 :       if (strncmp (ttyname_b, DEV_DIR_WITH_TRAILING_SLASH, DEV_DIR_LEN) == 0)
     568          11 :         ttyname_b += DEV_DIR_LEN;       /* Discard /dev/ prefix.  */
     569             :     }
     570             : 
     571          78 :   while (n--)
     572             :     {
     573           0 :       if (!my_line_only ||
     574           0 :           strncmp (ttyname_b, utmp_buf->ut_line,
     575             :                    sizeof (utmp_buf->ut_line)) == 0)
     576             :         {
     577           0 :           if (need_users && IS_USER_PROCESS (utmp_buf))
     578           0 :             print_user (utmp_buf, boottime);
     579           0 :           else if (need_runlevel && UT_TYPE_RUN_LVL (utmp_buf))
     580           0 :             print_runlevel (utmp_buf);
     581           0 :           else if (need_boottime && UT_TYPE_BOOT_TIME (utmp_buf))
     582           0 :             print_boottime (utmp_buf);
     583             :           /* I've never seen one of these, so I don't know what it should
     584             :              look like :^)
     585             :              FIXME: handle OLD_TIME also, perhaps show the delta? */
     586           0 :           else if (need_clockchange && UT_TYPE_NEW_TIME (utmp_buf))
     587           0 :             print_clockchange (utmp_buf);
     588           0 :           else if (need_initspawn && UT_TYPE_INIT_PROCESS (utmp_buf))
     589           0 :             print_initspawn (utmp_buf);
     590           0 :           else if (need_login && UT_TYPE_LOGIN_PROCESS (utmp_buf))
     591           0 :             print_login (utmp_buf);
     592           0 :           else if (need_deadprocs && UT_TYPE_DEAD_PROCESS (utmp_buf))
     593           0 :             print_deadprocs (utmp_buf);
     594             :         }
     595             : 
     596           0 :       if (UT_TYPE_BOOT_TIME (utmp_buf))
     597           0 :         boottime = UT_TIME_MEMBER (utmp_buf);
     598             : 
     599           0 :       utmp_buf++;
     600             :     }
     601             : }
     602             : 
     603             : /* Display a list of who is on the system, according to utmp file FILENAME.
     604             :    Use read_utmp OPTIONS to read the file.  */
     605             : static void
     606          41 : who (const char *filename, int options)
     607             : {
     608             :   size_t n_users;
     609             :   STRUCT_UTMP *utmp_buf;
     610             : 
     611          41 :   if (read_utmp (filename, &n_users, &utmp_buf, options) != 0)
     612           0 :     error (EXIT_FAILURE, errno, "%s", filename);
     613             : 
     614          41 :   if (short_list)
     615           1 :     list_entries_who (n_users, utmp_buf);
     616             :   else
     617          40 :     scan_entries (n_users, utmp_buf);
     618             : 
     619          41 :   free (utmp_buf);
     620          41 : }
     621             : 
     622             : void
     623          22 : usage (int status)
     624             : {
     625          22 :   if (status != EXIT_SUCCESS)
     626          21 :     fprintf (stderr, _("Try `%s --help' for more information.\n"),
     627             :              program_name);
     628             :   else
     629             :     {
     630           1 :       printf (_("Usage: %s [OPTION]... [ FILE | ARG1 ARG2 ]\n"), program_name);
     631           1 :       fputs (_("\
     632             : \n\
     633             :   -a, --all         same as -b -d --login -p -r -t -T -u\n\
     634             :   -b, --boot        time of last system boot\n\
     635             :   -d, --dead        print dead processes\n\
     636             :   -H, --heading     print line of column headings\n\
     637             : "), stdout);
     638           1 :       fputs (_("\
     639             :   -l, --login       print system login processes\n\
     640             : "), stdout);
     641           1 :       fputs (_("\
     642             :       --lookup      attempt to canonicalize hostnames via DNS\n\
     643             :   -m                only hostname and user associated with stdin\n\
     644             :   -p, --process     print active processes spawned by init\n\
     645             : "), stdout);
     646           1 :       fputs (_("\
     647             :   -q, --count       all login names and number of users logged on\n\
     648             :   -r, --runlevel    print current runlevel\n\
     649             :   -s, --short       print only name, line, and time (default)\n\
     650             :   -t, --time        print last system clock change\n\
     651             : "), stdout);
     652           1 :       fputs (_("\
     653             :   -T, -w, --mesg    add user's message status as +, - or ?\n\
     654             :   -u, --users       list users logged in\n\
     655             :       --message     same as -T\n\
     656             :       --writable    same as -T\n\
     657             : "), stdout);
     658           1 :       fputs (HELP_OPTION_DESCRIPTION, stdout);
     659           1 :       fputs (VERSION_OPTION_DESCRIPTION, stdout);
     660           1 :       printf (_("\
     661             : \n\
     662             : If FILE is not specified, use %s.  %s as FILE is common.\n\
     663             : If ARG1 ARG2 given, -m presumed: `am i' or `mom likes' are usual.\n\
     664             : "), UTMP_FILE, WTMP_FILE);
     665           1 :       emit_bug_reporting_address ();
     666             :     }
     667          22 :   exit (status);
     668             : }
     669             : 
     670             : int
     671          64 : main (int argc, char **argv)
     672             : {
     673             :   int optc;
     674          64 :   bool assumptions = true;
     675             : 
     676             :   initialize_main (&argc, &argv);
     677          64 :   program_name = argv[0];
     678          64 :   setlocale (LC_ALL, "");
     679             :   bindtextdomain (PACKAGE, LOCALEDIR);
     680             :   textdomain (PACKAGE);
     681             : 
     682          64 :   atexit (close_stdout);
     683             : 
     684         159 :   while ((optc = getopt_long (argc, argv, "abdlmpqrstuwHT", longopts, NULL))
     685             :          != -1)
     686             :     {
     687          38 :       switch (optc)
     688             :         {
     689          10 :         case 'a':
     690          10 :           need_boottime = true;
     691          10 :           need_deadprocs = true;
     692          10 :           need_login = true;
     693          10 :           need_initspawn = true;
     694          10 :           need_runlevel = true;
     695          10 :           need_clockchange = true;
     696          10 :           need_users = true;
     697          10 :           include_mesg = true;
     698          10 :           include_idle = true;
     699          10 :           include_exit = true;
     700          10 :           assumptions = false;
     701          10 :           break;
     702             : 
     703           3 :         case 'b':
     704           3 :           need_boottime = true;
     705           3 :           assumptions = false;
     706           3 :           break;
     707             : 
     708           1 :         case 'd':
     709           1 :           need_deadprocs = true;
     710           1 :           include_idle = true;
     711           1 :           include_exit = true;
     712           1 :           assumptions = false;
     713           1 :           break;
     714             : 
     715           3 :         case 'H':
     716           3 :           include_heading = true;
     717           3 :           break;
     718             : 
     719           2 :         case 'l':
     720           2 :           need_login = true;
     721           2 :           include_idle = true;
     722           2 :           assumptions = false;
     723           2 :           break;
     724             : 
     725           2 :         case 'm':
     726           2 :           my_line_only = true;
     727           2 :           break;
     728             : 
     729           1 :         case 'p':
     730           1 :           need_initspawn = true;
     731           1 :           assumptions = false;
     732           1 :           break;
     733             : 
     734           1 :         case 'q':
     735           1 :           short_list = true;
     736           1 :           break;
     737             : 
     738           1 :         case 'r':
     739           1 :           need_runlevel = true;
     740           1 :           include_idle = true;
     741           1 :           assumptions = false;
     742           1 :           break;
     743             : 
     744           2 :         case 's':
     745           2 :           short_output = true;
     746           2 :           break;
     747             : 
     748           1 :         case 't':
     749           1 :           need_clockchange = true;
     750           1 :           assumptions = false;
     751           1 :           break;
     752             : 
     753           2 :         case 'T':
     754             :         case 'w':
     755           2 :           include_mesg = true;
     756           2 :           break;
     757             : 
     758           1 :         case 'u':
     759           1 :           need_users = true;
     760           1 :           include_idle = true;
     761           1 :           assumptions = false;
     762           1 :           break;
     763             : 
     764           1 :         case LOOKUP_OPTION:
     765           1 :           do_lookup = true;
     766           1 :           break;
     767             : 
     768           1 :           case_GETOPT_HELP_CHAR;
     769             : 
     770           1 :           case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS);
     771             : 
     772           5 :         default:
     773           5 :           usage (EXIT_FAILURE);
     774             :         }
     775             :     }
     776             : 
     777          57 :   if (assumptions)
     778             :     {
     779          40 :       need_users = true;
     780          40 :       short_output = true;
     781             :     }
     782             : 
     783          57 :   if (include_exit)
     784             :     {
     785           9 :       short_output = false;
     786             :     }
     787             : 
     788          57 :   if (hard_locale (LC_TIME))
     789             :     {
     790           0 :       time_format = "%Y-%m-%d %H:%M";
     791           0 :       time_format_width = 4 + 1 + 2 + 1 + 2 + 1 + 2 + 1 + 2;
     792             :     }
     793             :   else
     794             :     {
     795          57 :       time_format = "%b %e %H:%M";
     796          57 :       time_format_width = 3 + 1 + 2 + 1 + 2 + 1 + 2;
     797             :     }
     798             : 
     799          57 :   switch (argc - optind)
     800             :     {
     801          10 :     case 2:                     /* who <blurf> <glop> */
     802          10 :       my_line_only = true;
     803             :       /* Fall through.  */
     804          28 :     case -1:
     805             :     case 0:                     /* who */
     806          28 :       who (UTMP_FILE, READ_UTMP_CHECK_PIDS);
     807          28 :       break;
     808             : 
     809          13 :     case 1:                     /* who <utmp file> */
     810          13 :       who (argv[optind], 0);
     811          13 :       break;
     812             : 
     813          16 :     default:                    /* lose */
     814          16 :       error (0, 0, _("extra operand %s"), quote (argv[optind + 2]));
     815          16 :       usage (EXIT_FAILURE);
     816             :     }
     817             : 
     818          41 :   exit (EXIT_SUCCESS);
     819             : }

Generated by: LCOV version 1.10