Skip site navigation (1)Skip section navigation (2)
Date:      Wed, 20 Mar 2002 18:32:11 +1100 (EST)
From:      "Tim J. Robbins" <tim@robbins.dropbear.id.au>
To:        FreeBSD-gnats-submit@FreeBSD.org
Subject:   standards/36128: Reimplementation of who utility
Message-ID:  <200203200732.g2K7WBZ04802@descent.robbins.dropbear.id.au>

next in thread | raw e-mail | index | archive | help

>Number:         36128
>Category:       standards
>Synopsis:       Reimplementation of who utility
>Confidential:   no
>Severity:       non-critical
>Priority:       low
>Responsible:    freebsd-standards
>State:          open
>Quarter:        
>Keywords:       
>Date-Required:
>Class:          sw-bug
>Submitter-Id:   current-users
>Arrival-Date:   Tue Mar 19 23:40:05 PST 2002
>Closed-Date:
>Last-Modified:
>Originator:     Tim J. Robbins
>Release:        FreeBSD 4.5-STABLE i386
>Organization:
>Environment:
System: FreeBSD descent.robbins.dropbear.id.au 4.5-STABLE FreeBSD 4.5-STABLE #8: Tue Mar 19 08:46:39 EST 2002 tim@descent.robbins.dropbear.id.au:/usr/obj/usr/src/sys/DESCENT i386


	
>Description:
FreeBSD's who(1) utility does not comply with P1003.1-2001. It is missing
every single command line option specified by the standard.
>How-To-Repeat:
who -H
>Fix:

This implementation is as close to conformance as I could get it; concepts
like "runlevels" don't exist on BSD.

# This is a shell archive.  Save it in a file, remove anything before
# this line, and then unpack it by entering "sh file".  Note, it may
# create directories; files and directories will be owned by you and
# have default permissions.
#
# This archive contains:
#
#	Makefile
#	who.c
#	who.1
#
echo x - Makefile
sed 's/^X//' >Makefile << 'END-of-Makefile'
X# $FreeBSD$
X# $Id: Makefile,v 1.1 2002/02/17 23:12:22 tim Exp $
X
XPROG=	who
X
X.include <bsd.prog.mk>
END-of-Makefile
echo x - who.c
sed 's/^X//' >who.c << 'END-of-who.c'
X/*-
X * Copyright (c) 2002 Tim J. Robbins.
X * All rights reserved.
X *
X * Redistribution and use in source and binary forms, with or without
X * modification, are permitted provided that the following conditions
X * are met:
X * 1. Redistributions of source code must retain the above copyright
X *    notice, this list of conditions and the following disclaimer.
X * 2. Redistributions in binary form must reproduce the above copyright
X *    notice, this list of conditions and the following disclaimer in the
X *    documentation and/or other materials provided with the distribution.
X *
X * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
X * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
X * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
X * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
X * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
X * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
X * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
X * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
X * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
X * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
X * SUCH DAMAGE.
X */
X
X#include <sys/cdefs.h>
X__FBSDID("$FreeBSD$");
X__RCSID("$Id: who.c,v 1.5 2002/03/19 11:17:35 tim Exp $");
X
X#include <sys/stat.h>
X#include <sys/types.h>
X
X#include <err.h>
X#include <errno.h>
X#include <limits.h>
X#include <locale.h>
X#include <paths.h>
X#include <stdio.h>
X#include <stdlib.h>
X#include <string.h>
X#include <time.h>
X#include <unistd.h>
X#include <utmp.h>
X
Xvoid heading(void);
Xvoid usage(void);
Xvoid process_utmp(const char *fn);
Xvoid process_wtmp(const char *fn);
Xvoid quick(const char *fn);
Xvoid row(const char *name, char state, const char *line, time_t utime,
X    time_t idle);
Xvoid wtmp(void);
X
Xint Hflag, Tflag, aflag, bflag, dflag, lflag, mflag, pflag, qflag, rflag;
Xint sflag, tflag, uflag;
X
Xint
Xmain(int argc, char *argv[])
X{
X	int ch;
X
X	setlocale(LC_TIME, "");
X
X	Hflag = Tflag = aflag = bflag = dflag = lflag = mflag = 0;
X	pflag = qflag = rflag = sflag = tflag = uflag = 0;
X	while ((ch = getopt(argc, argv, "HTabdlmpqrstu")) != -1) {
X		switch (ch) {
X		case 'H':		/* Write column headings */
X			Hflag = 1;
X			break;
X		case 'T':		/* Show terminal state */
X			Tflag = 1;
X			break;
X		case 'a':		/* Show all info */
X			aflag = bflag = dflag = lflag = tflag = Tflag = 1;
X			pflag = rflag = uflag = 1;
X			break;
X		case 'b':		/* Write time&date of last reboot */
X			bflag = 1;
X			break;
X		case 'd':		/* Show dead processes */
X			warnx("cannot show dead processes");
X			dflag = 1;
X			break;
X		case 'l':		/* Show only lines waiting for login */
X			lflag = 1;
X			break;
X		case 'm':		/* Show info about current terminal */
X			mflag = 1;
X			break;
X		case 'q':		/* "Quick" mode */
X			qflag = 1;
X			break;
X		case 'r':		/* Show run-level of init process */
X			warnx("cannot show runlevel");
X			rflag = 1;
X			break;
X		case 'p':		/* Show other procs spawned by init */
X			warnx("cannot show `other' processes");
X			pflag = 1;
X			break;
X		case 's':		/* Show name, line, time */
X			sflag = 1;
X			break;
X		case 't':		/* Show last change to system clock */
X			tflag = 1;
X			break;
X		case 'u':		/* Show idle time */
X			uflag = 1;
X			break;
X		default:
X			usage();
X			/*NOTREACHED*/
X		}
X	}
X	argc -= optind;
X	argv += optind;
X
X	if (argc > 2 && strcmp(argv[0], "am") == 0 &&
X	    (strcmp(argv[1], "i") == 0 || strcmp(argv[1], "I") == 0)) {
X		/* "who am i" or "who am I", equivalent to -m */
X		mflag = 1;
X		argc -= 2;
X		argv += 2;
X	}
X	if (argc > 1)
X		usage();
X
X	if (sflag)
X		Tflag = uflag = 0;	
X	if (Hflag)
X		heading();
X	if (qflag)
X		quick(*argv != NULL ? *argv : _PATH_UTMP);
X	else {
X		if (aflag || (!bflag && !dflag && !pflag && !rflag && !tflag))
X			process_utmp(*argv != NULL ? *argv : _PATH_UTMP);
X		if (bflag || tflag)
X			process_wtmp(_PATH_WTMP);
X	}
X
X	return (0);
X}
X
Xvoid
Xusage(void)
X{
X	fprintf(stderr, "usage: who [-HTabdlmpqrstu] [am I] [file]\n");
X	exit(1);
X}
X
Xvoid
Xheading(void)
X{
X	printf("%-*s ", UT_NAMESIZE, "NAME");
X	if (Tflag)
X		printf("S ");
X	printf("%-*s ", UT_LINESIZE, "LINE");
X	printf("%-*s ", 12, "TIME");
X	if (uflag)
X		printf("IDLE ");
X	printf("\n");
X}
X
Xvoid
Xrow(const char *name, char state, const char *line, time_t utime, time_t idle)
X{
X	char buf[80];
X	struct tm *tm;
X
X	printf("%-*.*s ", UT_NAMESIZE, UT_NAMESIZE, name);
X	if (Tflag)
X		printf("%c ", state);
X	printf("%-*.*s ", UT_LINESIZE, UT_LINESIZE, line);
X	tm = localtime(&utime);
X	strftime(buf, sizeof(buf), "%b %e %H:%M", tm);
X	printf("%-*s ", 12, buf);
X	if (uflag) {
X		if (idle < 60)
X			printf("  .   ");
X		else if (idle < 24 * 60 * 60)
X			printf("%02d:%02d ", idle / 60 / 60, idle / 60 % 60);
X		else
X			printf(" old  ");
X	}
X	printf("\n");
X}
X
Xvoid
Xprocess_utmp(const char *fn)
X{
X	FILE *fp;
X	struct utmp ut;
X	struct stat sb;
X	char tty[PATH_MAX], *ttyn;
X	time_t idle, now;
X	char state;
X
X	now = time(NULL);
X	if (mflag && (ttyn = ttyname(0)) == NULL)
X		return;
X
X	if ((fp = fopen(fn, "r")) == NULL)
X		err(1, "%s", fn);
X
X	while (fread(&ut, sizeof(ut), 1, fp) == 1) { 
X		strcpy(tty, _PATH_DEV);
X		strncat(tty, ut.ut_line, sizeof(ut.ut_line));
X		tty[strlen(_PATH_DEV) + UT_LINESIZE] = '\0';
X		state = '?';
X		idle = 0;
X		if (Tflag || uflag) {
X			if (stat(tty, &sb) == 0) {
X				state = sb.st_mode & (S_IWOTH|S_IWGRP) ?
X				    '+' : '-';
X				idle = now - sb.st_mtime;
X			}
X		}
X		if ((!lflag || aflag) && *ut.ut_name != '\0' &&
X		    (!mflag || strcmp(ttyn, tty) == 0))
X			row(ut.ut_name, state, ut.ut_line, ut.ut_time, idle);
X		else if (lflag && *ut.ut_name == '\0' && *ut.ut_line != '\0')
X			row("LOGIN", ' ', ut.ut_line, ut.ut_time, idle);
X	}
X
X	fclose(fp);
X}
X
Xvoid
Xprocess_wtmp(const char *fn)
X{
X	FILE *fp;
X	struct utmp ut;
X	time_t lastboot, lasttime;
X
X	if ((fp = fopen(fn, "r")) == NULL)
X		err(1, "%s", fn);
X
X	lastboot = lasttime = (time_t)-1;
X	while (fread(&ut, sizeof(ut), 1, fp) == 1) { 
X		if (bflag && *ut.ut_line == '~')
X			lastboot = ut.ut_time;
X		if (tflag && *ut.ut_line == '{')
X			lasttime = ut.ut_time;
X	}
X
X	if (bflag) {
X		if (lastboot != (time_t)-1)
X			row("reboot", ' ', "-", lastboot, 0);
X		else
X			warnx("couldn't find time of last reboot");
X			
X	}
X	if (tflag) {
X		if (lasttime != (time_t)-1)
X			row("date", ' ', "-", lasttime, 0);
X		else
X			warnx("couldn't find time of last date change");
X			
X	}
X}
X
Xvoid
Xquick(const char *fn)
X{
X	FILE *fp;
X	struct utmp ut;
X	int n;
X
X	if ((fp = fopen(fn, "r")) == NULL)
X		err(1, "%s", fn);
X
X	n = 0;
X	while (fread(&ut, sizeof(ut), 1, fp) == 1) { 
X		if (*ut.ut_name == '\0')
X			continue;
X		printf("%-.*s\n", UT_NAMESIZE, ut.ut_name);
X		n++;
X	}
X	printf("# users = %d\n", n);
X}
END-of-who.c
echo x - who.1
sed 's/^X//' >who.1 << 'END-of-who.1'
X.\" Copyright (c) 2002 Tim J. Robbins.
X.\" All rights reserved.
X.\"
X.\" Redistribution and use in source and binary forms, with or without
X.\" modification, are permitted provided that the following conditions
X.\" are met:
X.\" 1. Redistributions of source code must retain the above copyright
X.\"    notice, this list of conditions and the following disclaimer.
X.\" 2. Redistributions in binary form must reproduce the above copyright
X.\"    notice, this list of conditions and the following disclaimer in the
X.\"    documentation and/or other materials provided with the distribution.
X.\"
X.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
X.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
X.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
X.\" ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
X.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
X.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
X.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
X.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
X.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
X.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
X.\" SUCH DAMAGE.
X.\"
X.\" $FreeBSD$
X.\" $Id: who.1,v 1.3 2002/03/19 10:55:50 tim Exp $
X.\"
X.Dd January 24, 2002
X.Dt WHO 1
X.Os
X.Sh NAME
X.Nm who
X.Nd display who is on the system
X.Sh SYNOPSIS
X.Nm
X.Op Fl HTabdlmpqrstu
X.Op Cm am I
X.Op Ar file
X.Sh DESCRIPTION
XThe
X.Nm
Xutility displays information about currently logged in users.
X.Pp
XA
X.Xr utmp 5
Xformat
X.Ar file
Xargument may be specified instead of the default
X.Pa utmp
Xfile.
X.Pp
XThe options are as follows:
X.Bl -tag -width indent
X.It Fl H
XWrite column headings.
X.It Fl T
XIndicate whether each user is accepting messages.
XOne of the following characters is written:
X.Bl -tag -width x -compact
X.It +
XUser is accepting messages.
X.It \&-
XUser is not accepting messages.
X.It ?
XAn error occurred.
X.El
X.It Fl a
XEquivalent to
X.Fl Tbdlprtu .
X.It Fl b
XWrite the time and date of the last reboot.
X.It Fl l
XList only lines that are waiting for a user to log in.
X.It Fl m
XWrite information about the current terminal only.
X.It Fl q
XList the names and number of logged in users.
XAll command line options are ignored.
X.It Fl s
XWrite the name, line and time fields only.
X.It Fl t
XShow the time the system clock was last changed.
X.It Fl u
XShow idle time for each user in hours and minutes as
X.Ql hh:mm ,
X.Ql \&.
Xif the user has been idle less that a minute and
X.Ql old
Xif the user has been idle more than 24 hours.
X.It Cm am I
XEquivalent to
X.Fl m .
X.El
X.Pp
XThe
X.Fl d ,
X.Fl r
Xand
X.Fl p
Xoptions are accepted but ignored for compatibility with
X.At V.4
Xsystems.
X.Sh FILES
X.Pa /var/run/utmp
X.Sh DIAGNOSTICS
X.Ex -std
X.Sh SEE ALSO
X.Xr last 1 ,
X.Xr users 1 ,
X.Xr w 1 ,
X.Xr utmp 5 ,
X.Xr init 8
X.Sh STANDARDS
XThe
X.Nm
Xutility is designed to comply with the
X.St -p1003.1-2001
Xspecification.
X.Pp
XThe
X.Fl r
Xoption is ignored because
X.Bx Ns 's
X.Xr init 8
Xdoes not use runlevels, nor does it keep track of the relevant information
Xto implement the
X.Fl d
Xand
X.Fl p
Xoptions.
END-of-who.1
exit

>Release-Note:
>Audit-Trail:
>Unformatted:

To Unsubscribe: send mail to majordomo@FreeBSD.org
with "unsubscribe freebsd-standards" in the body of the message




Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200203200732.g2K7WBZ04802>