/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
/* All Rights Reserved */
/*
* Copyright (c) 2013 Gary Mills
*
* Copyright 2006 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
/*
*
* if requested.
*
*
* Syntax:
*
* who am i Displays info on yourself
*
* who -a Displays information about All
*
* who -b Displays info on last boot
*
* who -d Displays info on DEAD PROCESSES
*
* who -H Displays HEADERS for output
*
* who -l Displays info on LOGIN entries
*
* who -m Same as who am i
*
* who -p Displays info on PROCESSES spawned by init
*
* who -q Displays short information on
* current users who LOGGED ON
*
* who -r Displays info of current run-level
*
* who -s Displays requested info in SHORT form
*
* who -t Displays info on TIME changes
*
* who -T Displays writeability of each user
* (+ writeable, - non-writeable, ? hung)
*
* who -u Displays LONG info on users
* who have LOGGED ON
*/
/*
* %b Abbreviated month name
* %e Day of month
* %H hour (24-hour clock)
* %M minute
*/
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include <time.h>
#include <utmpx.h>
#include <locale.h>
#include <pwd.h>
#include <limits.h>
static void process(void);
static void ck_file(char *);
static void dump(void);
/*
* Use the full lengths from utmpx for user and line.
*/
/* Print minimum field widths. */
#ifdef XPG4
#endif /* XPG4 */
int
{
int i;
#if !defined(TEXT_DOMAIN) /* Should be defined by cc -D */
#endif
(void) textdomain(TEXT_DOMAIN);
/*
* Strip off path name of this command
*/
;
if (i >= 0)
argv[0] += i+1;
/*
* Buffer stdout for speed
*/
/*
* Retrieve options specified on command line
* XCU4 - add -m option
*/
optcnt++;
switch (optsw) {
case 'a':
optcnt += 7;
#ifdef XPG4
aopt = 1;
#endif /* XPG4 */
uopt = 1;
Topt = 1;
break;
case 'b':
break;
case 'd':
#ifdef XPG4
dopt = 1;
#endif /* XPG4 */
break;
case 'H':
optcnt--; /* Don't count Header */
Hopt = 1;
break;
case 'l':
terse = 0;
break;
case 'm': /* New XCU4 option */
justme = 1;
break;
case 'n':
errno = 0;
"%s: Invalid numeric argument\n"),
program);
exit(1);
}
if (number < 1) {
"%s: Number of users per line must "
"be at least 1\n"), program);
exit(1);
}
break;
case 'p':
break;
case 'q':
qopt = 1;
break;
case 'r':
terse = 0;
break;
case 's':
sopt = 1;
terse = 1;
break;
case 't':
break;
case 'T':
Topt = 1;
#ifdef XPG4
#else /* XPG4 */
terse = 0;
#endif /* XPG4 */
break;
case 'u':
uopt = 1;
break;
case '?':
goerr++;
break;
default:
break;
}
}
#ifdef XPG4
/*
* XCU4 changes - check for illegal sopt, Topt & aopt combination
*/
if (sopt == 1) {
terse = 1;
goerr++;
}
#endif /* XPG4 */
if (goerr > 0) {
#ifdef XPG4
/*
* XCU4 - slightly different usage with -s -a & -T
*/
gettext(" -s [-bdHlmpqrtu] [utmpx_like_file]\n"));
"\t%s [-abdHlmpqrtTu] [utmpx_like_file]\n"), program);
#else /* XPG4 */
"\nUsage:\t%s [-abdHlmpqrstTu] [utmpx_like_file]\n"),
program);
#endif /* XPG4 */
/*
* XCU4 changes - be explicit with "am i" options
*/
"a\tall (bdlprtu options)\n"));
"n #\tspecify number of users per line for -q\n"));
gettext("p\tprocesses other than getty or users\n"));
"s\tshort form of %s (no time since last output or pid)\n"),
program);
"T\tstatus of tty (+ writable, - not writable, "
"? hung)\n"));
gettext("m\tinformation only about current terminal\n"));
"am i\tinformation about current terminal "
"(same as -m)\n"));
"am I\tinformation about current terminal "
"(same as -m)\n"));
exit(1);
}
/*
* XCU4: If -q option ignore all other options
*/
if (qopt == 1) {
Hopt = 0;
sopt = 0;
Topt = 0;
uopt = 0;
justme = 0;
validtype[ACCOUNTING] = 0;
validtype[DEAD_PROCESS] = 0;
validtype[LOGIN_PROCESS] = 0;
validtype[INIT_PROCESS] = 0;
}
optcnt++;
}
/*
* Test for 'who am i' or 'who am I'
* XCU4 - check if justme was already set by -m option
*/
justme = 1;
"Must be attached to terminal for 'am I' option\n"));
exit(1);
} else
}
if (!terse) {
if (Hopt)
"NAME LINE TIME IDLE PID COMMENTS\n"));
}
}
gettext("%s: Cannot allocate %ld bytes"),
}
program);
}
} else {
if (Hopt) {
#ifdef XPG4
if (dopt) {
"NAME LINE TIME COMMENTS\n"));
} else {
(void) printf(
gettext("NAME LINE TIME\n"));
}
#else /* XPG4 */
(void) printf(
gettext("NAME LINE TIME\n"));
#endif /* XPG4 */
}
}
process();
/*
* 'who -q' requires EOL upon exit,
* followed by total line
*/
if (qopt)
return (0);
}
static void
dump()
{
int pexit;
int pterm;
int rc;
char w; /* writeability indicator */
/*
* Get and check user name
*/
else {
}
totlusrs++;
/*
* Do print in 'who -q' format
*/
if (qopt) {
/*
* XCU4 - Use non user macro for correct user count
*/
(void) printf("\n");
return;
}
pexit = (int)' ';
pterm = (int)' ';
/*
* Get exit info if applicable
*/
}
/*
* Massage ut_xtime field
*/
/*
* Get and massage device
*/
else {
}
/*
* Get writeability if requested
* XCU4 - only print + or - for user processes
*/
w = '-';
w = '+';
} else
w = ' ';
/*
* Print the TERSE portion of the output
*/
if (!terse) {
/*
* Stat device for idle time
* (Don't complain if you can't)
*/
rc = -1;
}
if (rc != -1) {
else {
if (hr < 24)
(int)min);
else
}
}
/*
* Add PID for verbose output
*/
/*
*/
/*
* Search for each entry in inittab
* string. Keep our place from
* search to search to try and
* minimize the work. Wrap once if needed
* for each entry.
*/
wrap = 0;
/*
* Look for a line beginning with
* utmpp->ut_id
*/
;
iinit++;
/*
* Wrap once if necessary to
* find entry in inittab
*/
if (*iinit == '\0') {
if (!wrap) {
wrap = 1;
}
}
}
if (*iinit != '\0') {
/*
* We found our entry
*/
;
if (*iinit == '#') {
;
} else
} else
}
}
#ifdef XPG4
else
}
#endif /* XPG4 */
/*
* Handle RUN_LVL process - If no alt. file - Only one!
*/
pexit);
(void) printf("\n");
exit(0);
}
}
/*
* Handle BOOT_TIME process - If no alt. file - Only one!
*/
(void) printf("\n");
exit(0);
}
}
/*
* Get remote host from utmpx structure
*/
/*
* Now, put on the trailing EOL
*/
(void) printf("\n");
}
static void
process()
{
int i = 0;
char *ttname;
/*
*/
setutxent();
#ifdef DEBUG
(void) printf(
"ut_user '%s'\nut_id '%s'\nut_line '%s'\nut_type '%d'\n\n",
#endif
/*
* Handle "am i"
*/
if (justme) {
/*
* we have have found ourselves
* in the utmp file and the entry
* is a user process, this is not
* meaningful otherwise
*
*/
dump();
exit(0);
}
continue;
}
/*
* Print the line if we want it
*/
#ifdef XPG4
"LOGIN") != 0))
continue;
}
#endif /* XPG4 */
dump();
}
} else {
gettext("%s: Error --- entry has ut_type "
}
}
/*
* If justme is set at this point than the utmp entry
* was not found.
*/
if (justme) {
i = 0;
*ttname != 0)
dump();
exit(0);
}
}
/*
* This routine checks the following:
*
* 1. File exists
*
* 2. We have read permissions
*
* 3. It is a multiple of utmp entries in size
*
* Failing any of these conditions causes who(1) to
* abort processing.
*
* 4. If file is empty we exit right away as there
* is no info to report on.
*
* This routine does not check utmpx files.
*/
static void
{
int rc;
/*
* Does file exist? Do stat to check, and save structure
* so that we can check on the file's size later on.
*/
exit(1);
}
/*
* The only real way we can be sure we can access the
* file is to try. If we succeed then we close it.
*/
exit(1);
}
/*
* If the file is empty, we are all done.
*/
exit(0);
/*
* Make sure the file is a utmp file.
* We can only check for size being a multiple of
* utmp structures in length.
*/
if (rc) {
exit(1);
}
}