summaryrefslogtreecommitdiffstats
path: root/usr.bin/who
diff options
context:
space:
mode:
authortjr <tjr@FreeBSD.org>2002-05-09 23:04:40 +0000
committertjr <tjr@FreeBSD.org>2002-05-09 23:04:40 +0000
commit1894db5ac7af64acc77acfbbc7b98c819dd70e22 (patch)
treee8314d1120a02aeff9fe6adf8d6111767126f210 /usr.bin/who
parentdc4e1bdffacc666da76301235b153d0c63a115f0 (diff)
downloadFreeBSD-src-1894db5ac7af64acc77acfbbc7b98c819dd70e22.zip
FreeBSD-src-1894db5ac7af64acc77acfbbc7b98c819dd70e22.tar.gz
Reimplement the who(1) utility to add some features required by SUSv3:
-H option (show column headings), -T (show mesg(1) state), -m (same as "am I"), -u (show idle time), -q (quick mode; list names in columns). PR: 36128 Reviewed by: mike
Diffstat (limited to 'usr.bin/who')
-rw-r--r--usr.bin/who/who.165
-rw-r--r--usr.bin/who/who.c327
2 files changed, 270 insertions, 122 deletions
diff --git a/usr.bin/who/who.1 b/usr.bin/who/who.1
index 5abded5..f656915 100644
--- a/usr.bin/who/who.1
+++ b/usr.bin/who/who.1
@@ -32,31 +32,60 @@
.\" @(#)who.1 8.2 (Berkeley) 12/30/93
.\" $FreeBSD$
.\"
-.Dd December 30, 1993
+.Dd May 8, 2002
.Dt WHO 1
.Os
.Sh NAME
.Nm who
-.Nd display who is logged in
+.Nd display who is on the system
.Sh SYNOPSIS
.Nm
-.Ar am I
-.Nm
+.Op Fl HmqsTu
+.Op Cm am I
.Op Ar file
.Sh DESCRIPTION
The
.Nm
-utility displays
-a list of all users currently logged on, showing for each user
-the login name,
-tty name, the date and time of login, and hostname if not local.
+utility displays information about currently logged in users.
+By default, this includes the login name, tty name, date and time of login and
+remote hostname if not local.
.Pp
-Available options:
+The options are as follows:
+.Bl -tag -width indent
+.It Fl H
+Write column headings above the output.
+.It Fl m
+Show information about the terminal attached to standard input only.
+.It Fl q
+.Dq Quick mode Ns :
+List the names and number of logged in users in columns.
+All other command line options are ignored.
+.It Fl s
+Show the name, line and time fields only.
+This is the default.
+.It Fl T
+Indicate whether each user is accepting messages.
+One of the following characters is written:
+.Bl -tag -width x -compact
+.It +
+User is accepting messages.
+.It \&-
+User is not accepting messages.
+.It ?
+An error occurred.
+.El
+.It Fl u
+Show idle time for each user in hours and minutes as
+.Ql hh:mm ,
+.Ql \&.
+if the user has been idle less that a minute and
+.Ql old
+if the user has been idle more than 24 hours.
+.It Cm am I
+Equivalent to
+.Fl m .
+.El
.Pp
-.Bl -tag -width file
-.It Ar \&am I
-Returns the invoker's real user name.
-.It Ar file
By default,
.Nm
gathers information from the file
@@ -80,7 +109,6 @@ since
.Pa wtmp
was last truncated or
created.
-.El
.Pp
If
.Pa /var/log/wtmp
@@ -95,11 +123,18 @@ special characters, see
.It Pa /var/log/wtmp
.It Pa /var/log/wtmp.[0-6]
.El
+.Sh DIAGNOSTICS
+.Ex -std
.Sh SEE ALSO
.Xr last 1 ,
.Xr users 1 ,
-.Xr getuid 2 ,
+.Xr w 1 ,
.Xr utmp 5
+.Sh STANDARDS
+The
+.Nm
+utility conforms to
+.St -p1003.1-2001 .
.Sh HISTORY
A
.Nm
diff --git a/usr.bin/who/who.c b/usr.bin/who/who.c
index 02b5e51..6268095 100644
--- a/usr.bin/who/who.c
+++ b/usr.bin/who/who.c
@@ -1,9 +1,6 @@
-/*
- * Copyright (c) 1989, 1993
- * The Regents of the University of California. All rights reserved.
- *
- * This code is derived from software contributed to Berkeley by
- * Michael Fischbein.
+/*-
+ * Copyright (c) 2002 Tim J. Robbins.
+ * All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -13,18 +10,11 @@
* 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
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR 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)
@@ -35,25 +25,16 @@
*/
#include <sys/cdefs.h>
-
__FBSDID("$FreeBSD$");
-#ifndef lint
-static const char copyright[] =
-"@(#) Copyright (c) 1989, 1993\n\
- The Regents of the University of California. All rights reserved.\n";
-#endif
-
-#ifndef lint
-static const char sccsid[] = "@(#)who.c 8.1 (Berkeley) 6/6/93";
-#endif
-
#include <sys/types.h>
-#include <sys/file.h>
+#include <sys/ioctl.h>
+#include <sys/stat.h>
#include <err.h>
#include <langinfo.h>
#include <locale.h>
+#include <paths.h>
#include <pwd.h>
#include <stdio.h>
#include <stdlib.h>
@@ -62,107 +43,239 @@ static const char sccsid[] = "@(#)who.c 8.1 (Berkeley) 6/6/93";
#include <unistd.h>
#include <utmp.h>
-static void usage(void);
-static void output(struct utmp *);
-static FILE *file(const char *);
+static void heading(void);
+static void process_utmp(FILE *);
+static void quick(FILE *);
+static void row(struct utmp *);
+static int ttywidth(void);
+static void usage(void);
+static void whoami(FILE *);
+
+static int Hflag; /* Write column headings */
+static int mflag; /* Show info about current terminal */
+static int qflag; /* "Quick" mode */
+static int sflag; /* Show name, line, time */
+static int Tflag; /* Show terminal state */
+static int uflag; /* Show idle time */
int
-main(argc, argv)
- int argc;
- char **argv;
+main(int argc, char *argv[])
{
- char *p;
- struct utmp usr;
- struct passwd *pw;
- FILE *ufp;
- char *t;
-
- (void) setlocale(LC_TIME, "");
-
- switch (argc) {
- case 1: /* who */
- ufp = file(_PATH_UTMP);
- /* only entries with both name and line fields */
- while (fread((char *)&usr, sizeof(usr), 1, ufp) == 1)
- if (*usr.ut_name && *usr.ut_line)
- output(&usr);
- break;
- case 2: /* who utmp_file */
- ufp = file(argv[1]);
- /* all entries */
- while (fread((char *)&usr, sizeof(usr), 1, ufp) == 1)
- output(&usr);
- break;
- case 3: /* who am i */
- if (strcmp(argv[1], "am")
- || (strcmp(argv[2], "I") && strcmp(argv[2], "i")))
- usage();
-
- ufp = file(_PATH_UTMP);
-
- /* search through the utmp and find an entry for this tty */
- if ((p = ttyname(0))) {
- /* strip any directory component */
- if ((t = rindex(p, '/')))
- p = t + 1;
- while (fread((char *)&usr, sizeof(usr), 1, ufp) == 1)
- if (*usr.ut_name && !strcmp(usr.ut_line, p)) {
- output(&usr);
- exit(0);
- }
- /* well, at least we know what the tty is */
- (void)strncpy(usr.ut_line, p, UT_LINESIZE);
- } else
- (void)strcpy(usr.ut_line, "tty??");
- pw = getpwuid(getuid());
- (void)strncpy(usr.ut_name, pw ? pw->pw_name : "?", UT_NAMESIZE);
- (void)time(&usr.ut_time);
- *usr.ut_host = '\0';
- output(&usr);
- break;
- default:
+ int ch;
+ const char *file;
+ FILE *fp;
+
+ setlocale(LC_TIME, "");
+
+ while ((ch = getopt(argc, argv, "HTabdlmpqrstu")) != -1) {
+ switch (ch) {
+ case 'H': /* Write column headings */
+ Hflag = 1;
+ break;
+ case 'T': /* Show terminal state */
+ Tflag = 1;
+ break;
+ case 'm': /* Show info about current terminal */
+ mflag = 1;
+ break;
+ case 'q': /* "Quick" mode */
+ qflag = 1;
+ break;
+ case 's': /* Show name, line, time */
+ sflag = 1;
+ break;
+ case 'u': /* Show idle time */
+ uflag = 1;
+ break;
+ default:
+ usage();
+ /*NOTREACHED*/
+ }
+ }
+ argc -= optind;
+ argv += optind;
+
+ if (argc >= 2 && strcmp(argv[0], "am") == 0 &&
+ (strcmp(argv[1], "i") == 0 || strcmp(argv[1], "I") == 0)) {
+ /* "who am i" or "who am I", equivalent to -m */
+ mflag = 1;
+ argc -= 2;
+ argv += 2;
+ }
+ if (argc > 1)
usage();
+
+ if (*argv != NULL)
+ file = *argv;
+ else
+ file = _PATH_UTMP;
+ if ((fp = fopen(file, "r")) == NULL)
+ err(1, "%s", file);
+
+ if (qflag)
+ quick(fp);
+ else {
+ if (sflag)
+ Tflag = uflag = 0;
+ if (Hflag)
+ heading();
+ if (mflag)
+ whoami(fp);
+ else
+ process_utmp(fp);
}
+
+ fclose(fp);
+
exit(0);
}
-static void
-usage()
+void
+usage(void)
{
- (void)fprintf(stderr, "%s\n%s\n",
- "usage: who [file]",
- " who am i");
+
+ fprintf(stderr, "usage: who [-HmqsTu] [am I] [file]\n");
exit(1);
}
void
-output(up)
- struct utmp *up;
+heading(void)
{
- char buf[80];
+
+ printf("%-*s ", UT_NAMESIZE, "NAME");
+ if (Tflag)
+ printf("S ");
+ printf("%-*s ", UT_LINESIZE, "LINE");
+ printf("%-*s ", 12, "TIME");
+ if (uflag)
+ printf("IDLE ");
+ putchar('\n');
+}
+
+void
+row(struct utmp *ut)
+{
+ char buf[80], tty[sizeof(_PATH_DEV) + UT_LINESIZE];
+ struct stat sb;
+ time_t idle;
static int d_first = -1;
+ struct tm *tm;
+ char state;
if (d_first < 0)
d_first = (*nl_langinfo(D_MD_ORDER) == 'd');
- (void)printf("%-*.*s %-*.*s", UT_NAMESIZE, UT_NAMESIZE, up->ut_name,
- UT_LINESIZE, UT_LINESIZE, up->ut_line);
- (void)strftime(buf, sizeof(buf),
- d_first ? "%e %b %R" : "%b %e %R",
- localtime(&up->ut_time));
- (void)printf("%s", buf);
- if (*up->ut_host)
- printf("\t(%.*s)", UT_HOSTSIZE, up->ut_host);
- (void)putchar('\n');
+ if (Tflag || uflag) {
+ snprintf(tty, sizeof(tty), "%s%.*s", _PATH_DEV,
+ UT_LINESIZE, ut->ut_line);
+ state = '?';
+ idle = 0;
+ if (stat(tty, &sb) == 0) {
+ state = sb.st_mode & (S_IWOTH|S_IWGRP) ?
+ '+' : '-';
+ idle = time(NULL) - sb.st_mtime;
+ }
+ }
+
+ printf("%-*.*s ", UT_NAMESIZE, UT_NAMESIZE, ut->ut_name);
+ if (Tflag)
+ printf("%c ", state);
+ printf("%-*.*s ", UT_LINESIZE, UT_LINESIZE, ut->ut_line);
+ tm = localtime(&ut->ut_time);
+ strftime(buf, sizeof(buf), d_first ? "%e %b %R" : "%b %e %R", tm);
+ printf("%-*s ", 12, buf);
+ if (uflag) {
+ if (idle < 60)
+ printf(" . ");
+ else if (idle < 24 * 60 * 60)
+ printf("%02d:%02d ", (int)(idle / 60 / 60),
+ (int)(idle / 60 % 60));
+ else
+ printf(" old ");
+ }
+ if (*ut->ut_host != '\0')
+ printf("(%.*s)", UT_HOSTSIZE, ut->ut_host);
+ putchar('\n');
+}
+
+void
+process_utmp(FILE *fp)
+{
+ struct utmp ut;
+
+ while (fread(&ut, sizeof(ut), 1, fp) == 1)
+ if (*ut.ut_name != '\0')
+ row(&ut);
+}
+
+void
+quick(FILE *fp)
+{
+ struct utmp ut;
+ int col, ncols, num;
+
+ ncols = ttywidth();
+ col = num = 0;
+ while (fread(&ut, sizeof(ut), 1, fp) == 1) {
+ if (*ut.ut_name == '\0')
+ continue;
+ printf("%-*.*s", UT_NAMESIZE, UT_NAMESIZE, ut.ut_name);
+ if (++col < ncols / (UT_NAMESIZE + 1))
+ putchar(' ');
+ else {
+ col = 0;
+ putchar('\n');
+ }
+ num++;
+ }
+ if (col != 0)
+ putchar('\n');
+
+ printf("# users = %d\n", num);
}
-static FILE *
-file(name)
- const char *name;
+void
+whoami(FILE *fp)
{
- FILE *ufp;
+ struct utmp ut;
+ struct passwd *pwd;
+ const char *name, *p, *tty;
+
+ if ((tty = ttyname(STDIN_FILENO)) == NULL)
+ tty = "tty??";
+ else if ((p = strrchr(tty, '/')) != NULL)
+ tty = p + 1;
+
+ /* Search utmp for our tty, dump first matching record. */
+ while (fread(&ut, sizeof(ut), 1, fp) == 1)
+ if (*ut.ut_name != '\0' && strncmp(ut.ut_line, tty,
+ UT_LINESIZE) == 0) {
+ row(&ut);
+ return;
+ }
+
+ /* Not found; fill the utmp structure with the information we have. */
+ memset(&ut, 0, sizeof(ut));
+ if ((pwd = getpwuid(getuid())) != NULL)
+ name = pwd->pw_name;
+ else
+ name = "?";
+ strncpy(ut.ut_name, name, UT_NAMESIZE);
+ strncpy(ut.ut_line, tty, UT_LINESIZE);
+ time(&ut.ut_time);
+ row(&ut);
+}
+
+int
+ttywidth(void)
+{
+ struct winsize ws;
+ int width;
+
+ if (ioctl(STDOUT_FILENO, TIOCGWINSZ, &ws) != -1)
+ width = ws.ws_col;
+ else
+ width = 80;
- if (!(ufp = fopen(name, "r")))
- err(1, "%s", name);
- return(ufp);
+ return (width);
}
OpenPOWER on IntegriCloud