From: Jim Meyering Date: Sat, 6 Jan 1996 11:13:11 +0000 (+0000) Subject: rename from who.c X-Git-Tag: TEXTUTILS-1_14~60 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=7949927db64dcc0467b047961ddc40c328b6ee63;p=platform%2Fupstream%2Fcoreutils.git rename from who.c --- diff --git a/src/who-users.c b/src/who-users.c new file mode 100644 index 0000000..cb0125f --- /dev/null +++ b/src/who-users.c @@ -0,0 +1,654 @@ +/* GNU's users/who. + Copyright (C) 92, 93, 94, 1995 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + +/* Written by jla; revised by djm */ + +/* Output format: + name [state] line time [idle] host + state: -T + name, line, time: not -q + idle: -u + + Options: + -m Same as 'who am i', for POSIX. + -q Only user names and # logged on; overrides all other options. + -s Name, line, time (default). + -i, -u Idle hours and minutes; '.' means active in last minute; + 'old' means idle for >24 hours. + -H Print column headings at top. + -w, -T -s plus mesg (+ or -, or ? if bad line). */ + +#include +#include +#include + +#ifdef HAVE_UTMPX_H +#include +#define STRUCT_UTMP struct utmpx +#else +#include +#define STRUCT_UTMP struct utmp +#endif + +#include +#include +#ifdef HAVE_SYS_PARAM_H +#include +#endif + +#include "system.h" +#include "version.h" +#include "error.h" + +#if !defined (UTMP_FILE) && defined (_PATH_UTMP) /* 4.4BSD. */ +#define UTMP_FILE _PATH_UTMP +#endif + +#if defined (UTMPX_FILE) /* Solaris, SysVr4 */ +#undef UTMP_FILE +#define UTMP_FILE UTMPX_FILE +#endif + +#ifndef UTMP_FILE +#define UTMP_FILE "/etc/utmp" +#endif + +#ifndef MAXHOSTNAMELEN +#define MAXHOSTNAMELEN 64 +#endif + +#ifndef S_IWGRP +#define S_IWGRP 020 +#endif + +#ifdef WHO +#define COMMAND_NAME "who" +#else +#ifdef USERS +#define COMMAND_NAME "users" +#else + error You must define one of WHO and USERS. +#endif /* USERS */ +#endif /* WHO */ + +int gethostname (); +char *ttyname (); +char *xmalloc (); + +/* The name this program was run with. */ +char *program_name; + +/* If nonzero, display usage information and exit. */ +static int show_help; + +/* If nonzero, print the version on standard output and exit. */ +static int show_version; + +#ifdef WHO +/* If nonzero, display only a list of usernames and count of + the users logged on. + Ignored for `who am i'. */ +static int short_list; + +/* If nonzero, display the hours:minutes since each user has touched + the keyboard, or "." if within the last minute, or "old" if + not within the last day. */ +static int include_idle; + +/* If nonzero, display a line at the top describing each field. */ +static int include_heading; + +/* If nonzero, display a `+' for each user if mesg y, a `-' if mesg n, + or a `?' if their tty cannot be statted. */ +static int include_mesg; +#endif /* WHO */ + +static struct option const longopts[] = +{ +#ifdef WHO + {"count", no_argument, NULL, 'q'}, + {"idle", no_argument, NULL, 'u'}, + {"heading", no_argument, NULL, 'H'}, + {"message", no_argument, NULL, 'T'}, + {"mesg", no_argument, NULL, 'T'}, + {"writable", no_argument, NULL, 'T'}, +#endif /* WHO */ + {"help", no_argument, &show_help, 1}, + {"version", no_argument, &show_version, 1}, + {NULL, 0, NULL, 0} +}; + +static STRUCT_UTMP *utmp_contents; + +#if defined (WHO) || defined (USERS) + +/* Copy UT->ut_name into storage obtained from malloc. Then remove any + trailing spaces from the copy, NUL terminate it, and return the copy. */ + +static char * +extract_trimmed_name (const STRUCT_UTMP *ut) +{ + char *p, *trimmed_name; + + trimmed_name = xmalloc (sizeof (ut->ut_name) + 1); + strncpy (trimmed_name, ut->ut_name, sizeof (ut->ut_name)); + /* Append a trailing space character. Some systems pad names shorter than + the maximum with spaces, others pad with NULs. Remove any spaces. */ + trimmed_name[sizeof (ut->ut_name)] = ' '; + p = strchr (trimmed_name, ' '); + if (p != NULL) + *p = '\0'; + return trimmed_name; +} + +#endif /* WHO || USERS */ + +#if WHO + +/* Return a string representing the time between WHEN and the time + that this function is first run. */ + +static const char * +idle_string (when) + time_t when; +{ + static time_t now = 0; + static char idle[10]; + time_t seconds_idle; + + if (now == 0) + time (&now); + + seconds_idle = now - when; + if (seconds_idle < 60) /* One minute. */ + return " . "; + if (seconds_idle < (24 * 60 * 60)) /* One day. */ + { + sprintf (idle, "%02d:%02d", + (int) (seconds_idle / (60 * 60)), + (int) ((seconds_idle % (60 * 60)) / 60)); + return (const char *) idle; + } + return _(" old "); +} + +/* Display a line of information about entry THIS. */ + +static void +print_entry (this) + STRUCT_UTMP *this; +{ + struct stat stats; + time_t last_change; + char mesg; + +#define DEV_DIR_WITH_TRAILING_SLASH "/dev/" +#define DEV_DIR_LEN (sizeof (DEV_DIR_WITH_TRAILING_SLASH) - 1) + + char line[sizeof (this->ut_line) + DEV_DIR_LEN + 1]; + + /* Copy ut_line into LINE, prepending `/dev/' if ut_line is not + already an absolute pathname. Some system may put the full, + absolute pathname in ut_line. */ + if (this->ut_line[0] == '/') + { + strncpy (line, this->ut_line, sizeof (this->ut_line)); + line[sizeof (this->ut_line)] = '\0'; + } + else + { + strcpy (line, DEV_DIR_WITH_TRAILING_SLASH); + strncpy (line + DEV_DIR_LEN, this->ut_line, sizeof (this->ut_line)); + line[DEV_DIR_LEN + sizeof (this->ut_line)] = '\0'; + } + + if (stat (line, &stats) == 0) + { + mesg = (stats.st_mode & S_IWGRP) ? '+' : '-'; + last_change = stats.st_atime; + } + else + { + mesg = '?'; + last_change = 0; + } + + printf ("%-8.*s", (int) sizeof (this->ut_name), this->ut_name); + if (include_mesg) + printf (" %c ", mesg); + printf (" %-8.*s", (int) sizeof (this->ut_line), this->ut_line); + +#ifdef HAVE_UTMPX_H + printf (" %-12.12s", ctime (&this->ut_tv.tv_sec) + 4); +#else + printf (" %-12.12s", ctime (&this->ut_time) + 4); +#endif + + if (include_idle) + { + if (last_change) + printf (" %s", idle_string (last_change)); + else + printf (" . "); + } +#ifdef HAVE_UT_HOST + if (this->ut_host[0]) + printf (" (%-.*s)", (int) sizeof (this->ut_host), this->ut_host); +#endif + + putchar ('\n'); +} + +/* Print the username of each valid entry and the number of valid entries + in `utmp_contents', which should have N elements. */ + +static void +list_entries_who (n) + int n; +{ + register STRUCT_UTMP *this = utmp_contents; + int entries; + + entries = 0; + while (n--) + { + if (this->ut_name[0] +#ifdef USER_PROCESS + && this->ut_type == USER_PROCESS +#endif + ) + { + char *trimmed_name; + + trimmed_name = extract_trimmed_name (this); + + printf ("%s ", trimmed_name); + free (trimmed_name); + entries++; + } + this++; + } + printf (_("\n# users=%u\n"), entries); +} + +#endif /* WHO */ + +#ifdef USERS + +static int +userid_compare (v_a, v_b) + const void *v_a; + const void *v_b; +{ + char **a = (char **) v_a; + char **b = (char **) v_b; + return strcmp (*a, *b); +} + +static void +list_entries_users (n) + int n; +{ + register STRUCT_UTMP *this = utmp_contents; + char **u; + int i; + int n_entries; + + n_entries = 0; + u = (char **) xmalloc (n * sizeof (u[0])); + for (i=0; iut_name[0] +#ifdef USER_PROCESS + && this->ut_type == USER_PROCESS +#endif + ) + { + char *trimmed_name; + + trimmed_name = extract_trimmed_name (this); + + u[n_entries] = trimmed_name; + ++n_entries; + } + this++; + } + + qsort (u, n_entries, sizeof (u[0]), userid_compare); + + for (i=0; iut_name[0] +#ifdef USER_PROCESS + && this->ut_type == USER_PROCESS +#endif + ) + print_entry (this); + this++; + } +} + +#endif /* WHO */ + +/* Read the utmp file FILENAME into UTMP_CONTENTS and return the + number of entries it contains. */ + +static int +read_utmp (filename) + char *filename; +{ + FILE *utmp; + struct stat file_stats; + int n_read; + size_t size; + + utmp = fopen (filename, "r"); + if (utmp == NULL) + error (1, errno, "%s", filename); + + fstat (fileno (utmp), &file_stats); + size = file_stats.st_size; + if (size > 0) + utmp_contents = (STRUCT_UTMP *) xmalloc (size); + else + { + fclose (utmp); + return 0; + } + + /* Use < instead of != in case the utmp just grew. */ + n_read = fread (utmp_contents, 1, size, utmp); + if (ferror (utmp) || fclose (utmp) == EOF + || n_read < size) + error (1, errno, "%s", filename); + + return size / sizeof (STRUCT_UTMP); +} + +/* Display a list of who is on the system, according to utmp file FILENAME. */ + +static void +who (filename) + char *filename; +{ + int users; + + users = read_utmp (filename); +#ifdef WHO + if (short_list) + list_entries_who (users); + else + scan_entries (users); +#else +#ifdef USERS + list_entries_users (users); +#endif /* USERS */ +#endif /* WHO */ +} + +#ifdef WHO + +/* Search `utmp_contents', which should have N entries, for + an entry with a `ut_line' field identical to LINE. + Return the first matching entry found, or NULL if there + is no matching entry. */ + +static STRUCT_UTMP * +search_entries (n, line) + int n; + char *line; +{ + register STRUCT_UTMP *this = utmp_contents; + + while (n--) + { + if (this->ut_name[0] +#ifdef USER_PROCESS + && this->ut_type == USER_PROCESS +#endif + && !strncmp (line, this->ut_line, sizeof (this->ut_line))) + return this; + this++; + } + return NULL; +} + +/* Display the entry in utmp file FILENAME for this tty on standard input, + or nothing if there is no entry for it. */ + +static void +who_am_i (filename) + char *filename; +{ + register STRUCT_UTMP *utmp_entry; + char hostname[MAXHOSTNAMELEN + 1]; + char *tty; + + if (gethostname (hostname, MAXHOSTNAMELEN + 1)) + *hostname = 0; + + if (include_heading) + { + printf ("%*s ", (int) strlen (hostname), " "); + print_heading (); + } + + tty = ttyname (0); + if (tty == NULL) + return; + tty += 5; /* Remove "/dev/". */ + + utmp_entry = search_entries (read_utmp (filename), tty); + if (utmp_entry == NULL) + return; + + printf ("%s!", hostname); + print_entry (utmp_entry); +} + +static void +usage (status) + int status; +{ + if (status != 0) + fprintf (stderr, _("Try `%s --help' for more information.\n"), + program_name); + else + { + printf (_("Usage: %s [OPTION]... [ FILE | ARG1 ARG2 ]\n"), program_name); + printf (_("\ +\n\ + -H, --heading print line of column headings\n\ + -T, -w, --mesg add user's message status as +, - or ?\n\ + -i, -u, --idle add user idle time as HOURS:MINUTES, . or old\n\ + -m only hostname and user associated with stdin\n\ + -q, --count all login names and number of users logged on\n\ + -s (ignored)\n\ + --help display this help and exit\n\ + --message same as -T\n\ + --version output version information and exit\n\ + --writeable same as -T\n\ +\n\ +If FILE not given, uses /etc/utmp. /etc/wtmp as FILE is common.\n\ +If ARG1 ARG2 given, -m presumed: `am i' or `mom likes' are usual.\n\ +")); + } + exit (status); +} +#endif /* WHO */ + +#ifdef USERS +static void +usage (status) + int status; +{ + if (status != 0) + fprintf (stderr, _("Try `%s --help' for more information.\n"), + program_name); + else + { + printf (_("Usage: %s [OPTION]... [ FILE ]\n"), program_name); + printf (_("\ +Output who is currently logged in according to FILE.\n\ +If FILE not given, uses /etc/utmp. /etc/wtmp as FILE is common.\n\ +\n\ + --help display this help and exit\n\ + --version output version information and exit\n")); + } + exit (status); +} +#endif /* USERS */ + +void +main (argc, argv) + int argc; + char **argv; +{ + int optc, longind; +#ifdef WHO + int my_line_only = 0; +#endif /* WHO */ + + program_name = argv[0]; + +#ifdef WHO + while ((optc = getopt_long (argc, argv, "imqsuwHT", longopts, &longind)) +#else + while ((optc = getopt_long (argc, argv, "", longopts, &longind)) +#endif /* WHO */ + != EOF) + { + switch (optc) + { + case 0: + break; + +#ifdef WHO + case 'm': + my_line_only = 1; + break; + + case 'q': + short_list = 1; + break; + + case 's': + break; + + case 'i': + case 'u': + include_idle = 1; + break; + + case 'H': + include_heading = 1; + break; + + case 'w': + case 'T': + include_mesg = 1; + break; +#endif /* WHO */ + + default: + error (0, 0, _("too many arguments")); + usage (1); + } + } + + if (show_version) + { + printf ("%s - %s\n", COMMAND_NAME, version_string); + exit (0); + } + + if (show_help) + usage (0); + + switch (argc - optind) + { + case 0: /* who */ +#ifdef WHO + if (my_line_only) + who_am_i (UTMP_FILE); + else +#endif /* WHO */ + who (UTMP_FILE); + break; + + case 1: /* who */ +#ifdef WHO + if (my_line_only) + who_am_i (argv[optind]); + else +#endif /* WHO */ + who (argv[optind]); + break; + +#ifdef WHO + case 2: /* who */ + who_am_i (UTMP_FILE); + break; +#endif /* WHO */ + + default: /* lose */ + usage (1); + } + + exit (0); +}