17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate * CDDL HEADER START
37c478bd9Sstevel@tonic-gate *
47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the
5b11e536cSjg * Common Development and Distribution License (the "License").
6b11e536cSjg * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate *
87c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate * and limitations under the License.
127c478bd9Sstevel@tonic-gate *
137c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate *
197c478bd9Sstevel@tonic-gate * CDDL HEADER END
207c478bd9Sstevel@tonic-gate */
217c478bd9Sstevel@tonic-gate /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
227c478bd9Sstevel@tonic-gate /* All Rights Reserved */
237c478bd9Sstevel@tonic-gate
247c478bd9Sstevel@tonic-gate
257c478bd9Sstevel@tonic-gate /*
260a1278f2SGary Mills * Copyright (c) 2013 Gary Mills
270a1278f2SGary Mills *
28b11e536cSjg * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
297c478bd9Sstevel@tonic-gate * Use is subject to license terms.
307c478bd9Sstevel@tonic-gate */
317c478bd9Sstevel@tonic-gate
32*6062513aSJohn Levon /*
33*6062513aSJohn Levon * Copyright (c) 2018, Joyent, Inc.
34*6062513aSJohn Levon */
35*6062513aSJohn Levon
367c478bd9Sstevel@tonic-gate /*
377c478bd9Sstevel@tonic-gate * This program analyzes information found in /var/adm/utmpx
387c478bd9Sstevel@tonic-gate *
397c478bd9Sstevel@tonic-gate * Additionally information is gathered from /etc/inittab
407c478bd9Sstevel@tonic-gate * if requested.
417c478bd9Sstevel@tonic-gate *
427c478bd9Sstevel@tonic-gate *
437c478bd9Sstevel@tonic-gate * Syntax:
447c478bd9Sstevel@tonic-gate *
457c478bd9Sstevel@tonic-gate * who am i Displays info on yourself
467c478bd9Sstevel@tonic-gate *
477c478bd9Sstevel@tonic-gate * who -a Displays information about All
487c478bd9Sstevel@tonic-gate * entries in /var/adm/utmpx
497c478bd9Sstevel@tonic-gate *
507c478bd9Sstevel@tonic-gate * who -b Displays info on last boot
517c478bd9Sstevel@tonic-gate *
527c478bd9Sstevel@tonic-gate * who -d Displays info on DEAD PROCESSES
537c478bd9Sstevel@tonic-gate *
547c478bd9Sstevel@tonic-gate * who -H Displays HEADERS for output
557c478bd9Sstevel@tonic-gate *
567c478bd9Sstevel@tonic-gate * who -l Displays info on LOGIN entries
577c478bd9Sstevel@tonic-gate *
587c478bd9Sstevel@tonic-gate * who -m Same as who am i
597c478bd9Sstevel@tonic-gate *
607c478bd9Sstevel@tonic-gate * who -p Displays info on PROCESSES spawned by init
617c478bd9Sstevel@tonic-gate *
627c478bd9Sstevel@tonic-gate * who -q Displays short information on
637c478bd9Sstevel@tonic-gate * current users who LOGGED ON
647c478bd9Sstevel@tonic-gate *
657c478bd9Sstevel@tonic-gate * who -r Displays info of current run-level
667c478bd9Sstevel@tonic-gate *
677c478bd9Sstevel@tonic-gate * who -s Displays requested info in SHORT form
687c478bd9Sstevel@tonic-gate *
697c478bd9Sstevel@tonic-gate * who -t Displays info on TIME changes
707c478bd9Sstevel@tonic-gate *
717c478bd9Sstevel@tonic-gate * who -T Displays writeability of each user
727c478bd9Sstevel@tonic-gate * (+ writeable, - non-writeable, ? hung)
737c478bd9Sstevel@tonic-gate *
747c478bd9Sstevel@tonic-gate * who -u Displays LONG info on users
757c478bd9Sstevel@tonic-gate * who have LOGGED ON
767c478bd9Sstevel@tonic-gate */
777c478bd9Sstevel@tonic-gate
787c478bd9Sstevel@tonic-gate #define DATE_FMT "%b %e %H:%M"
797c478bd9Sstevel@tonic-gate
807c478bd9Sstevel@tonic-gate /*
817c478bd9Sstevel@tonic-gate * %b Abbreviated month name
827c478bd9Sstevel@tonic-gate * %e Day of month
837c478bd9Sstevel@tonic-gate * %H hour (24-hour clock)
847c478bd9Sstevel@tonic-gate * %M minute
857c478bd9Sstevel@tonic-gate */
867c478bd9Sstevel@tonic-gate #include <errno.h>
877c478bd9Sstevel@tonic-gate #include <fcntl.h>
887c478bd9Sstevel@tonic-gate #include <stdio.h>
897c478bd9Sstevel@tonic-gate #include <string.h>
907c478bd9Sstevel@tonic-gate #include <sys/types.h>
917c478bd9Sstevel@tonic-gate #include <unistd.h>
927c478bd9Sstevel@tonic-gate #include <stdlib.h>
937c478bd9Sstevel@tonic-gate #include <sys/stat.h>
947c478bd9Sstevel@tonic-gate #include <time.h>
957c478bd9Sstevel@tonic-gate #include <utmpx.h>
967c478bd9Sstevel@tonic-gate #include <locale.h>
977c478bd9Sstevel@tonic-gate #include <pwd.h>
987c478bd9Sstevel@tonic-gate #include <limits.h>
997c478bd9Sstevel@tonic-gate
1007c478bd9Sstevel@tonic-gate static void process(void);
1017c478bd9Sstevel@tonic-gate static void ck_file(char *);
1027c478bd9Sstevel@tonic-gate static void dump(void);
1037c478bd9Sstevel@tonic-gate
1047c478bd9Sstevel@tonic-gate static struct utmpx *utmpp; /* pointer for getutxent() */
1057c478bd9Sstevel@tonic-gate
1067c478bd9Sstevel@tonic-gate /*
1070a1278f2SGary Mills * Use the full lengths from utmpx for user and line.
1087c478bd9Sstevel@tonic-gate */
1097c478bd9Sstevel@tonic-gate #define NMAX (sizeof (utmpp->ut_user))
1107c478bd9Sstevel@tonic-gate #define LMAX (sizeof (utmpp->ut_line))
1110a1278f2SGary Mills
1120a1278f2SGary Mills /* Print minimum field widths. */
1130a1278f2SGary Mills #define LOGIN_WIDTH 8
1140a1278f2SGary Mills #define LINE_WIDTH 12
1157c478bd9Sstevel@tonic-gate
1167c478bd9Sstevel@tonic-gate static char comment[BUFSIZ]; /* holds inittab comment */
1177c478bd9Sstevel@tonic-gate static char errmsg[BUFSIZ]; /* used in snprintf for errors */
1187c478bd9Sstevel@tonic-gate static int fildes; /* file descriptor for inittab */
1197c478bd9Sstevel@tonic-gate static int Hopt = 0; /* 1 = who -H */
1207c478bd9Sstevel@tonic-gate static char *inittab; /* ptr to inittab contents */
1217c478bd9Sstevel@tonic-gate static char *iinit; /* index into inittab */
1227c478bd9Sstevel@tonic-gate static int justme = 0; /* 1 = who am i */
1237c478bd9Sstevel@tonic-gate static struct tm *lptr; /* holds user login time */
1247c478bd9Sstevel@tonic-gate static char *myname; /* pointer to invoker's name */
1257c478bd9Sstevel@tonic-gate static char *mytty; /* holds device user is on */
1267c478bd9Sstevel@tonic-gate static char nameval[sizeof (utmpp->ut_user) + 1]; /* invoker's name */
1277c478bd9Sstevel@tonic-gate static int number = 8; /* number of users per -q line */
1287c478bd9Sstevel@tonic-gate static int optcnt = 0; /* keeps count of options */
1297c478bd9Sstevel@tonic-gate static char outbuf[BUFSIZ]; /* buffer for output */
1307c478bd9Sstevel@tonic-gate static char *program; /* holds name of this program */
1317c478bd9Sstevel@tonic-gate #ifdef XPG4
1327c478bd9Sstevel@tonic-gate static int aopt = 0; /* 1 = who -a */
1337c478bd9Sstevel@tonic-gate static int dopt = 0; /* 1 = who -d */
1347c478bd9Sstevel@tonic-gate #endif /* XPG4 */
1357c478bd9Sstevel@tonic-gate static int qopt = 0; /* 1 = who -q */
1367c478bd9Sstevel@tonic-gate static int sopt = 0; /* 1 = who -s */
1377c478bd9Sstevel@tonic-gate static struct stat stbuf; /* area for stat buffer */
1387c478bd9Sstevel@tonic-gate static struct stat *stbufp; /* ptr to structure */
1397c478bd9Sstevel@tonic-gate static int terse = 1; /* 1 = print terse msgs */
1407c478bd9Sstevel@tonic-gate static int Topt = 0; /* 1 = who -T */
1417c478bd9Sstevel@tonic-gate static time_t timnow; /* holds current time */
1427c478bd9Sstevel@tonic-gate static int totlusrs = 0; /* cntr for users on system */
1437c478bd9Sstevel@tonic-gate static int uopt = 0; /* 1 = who -u */
1447c478bd9Sstevel@tonic-gate static char user[sizeof (utmpp->ut_user) + 1]; /* holds user name */
1457c478bd9Sstevel@tonic-gate static int validtype[UTMAXTYPE+1]; /* holds valid types */
1467c478bd9Sstevel@tonic-gate static int wrap; /* flag to indicate wrap */
1477c478bd9Sstevel@tonic-gate static char time_buf[128]; /* holds date and time string */
1487c478bd9Sstevel@tonic-gate static char *end; /* used in strtol for end pointer */
1497c478bd9Sstevel@tonic-gate
1507c478bd9Sstevel@tonic-gate int
main(int argc,char ** argv)1517c478bd9Sstevel@tonic-gate main(int argc, char **argv)
1527c478bd9Sstevel@tonic-gate {
1537c478bd9Sstevel@tonic-gate int goerr = 0; /* non-zero indicates cmd error */
1547c478bd9Sstevel@tonic-gate int i;
1557c478bd9Sstevel@tonic-gate int optsw; /* switch for while of getopt() */
1567c478bd9Sstevel@tonic-gate
1577c478bd9Sstevel@tonic-gate (void) setlocale(LC_ALL, "");
1587c478bd9Sstevel@tonic-gate
1597c478bd9Sstevel@tonic-gate #if !defined(TEXT_DOMAIN) /* Should be defined by cc -D */
1607c478bd9Sstevel@tonic-gate #define TEXT_DOMAIN "SYS_TEST" /* Use this only if it weren't */
1617c478bd9Sstevel@tonic-gate #endif
1627c478bd9Sstevel@tonic-gate (void) textdomain(TEXT_DOMAIN);
1637c478bd9Sstevel@tonic-gate
1647c478bd9Sstevel@tonic-gate validtype[USER_PROCESS] = 1;
1657c478bd9Sstevel@tonic-gate validtype[EMPTY] = 0;
1667c478bd9Sstevel@tonic-gate stbufp = &stbuf;
1677c478bd9Sstevel@tonic-gate
1687c478bd9Sstevel@tonic-gate /*
1697c478bd9Sstevel@tonic-gate * Strip off path name of this command
1707c478bd9Sstevel@tonic-gate */
1710a1278f2SGary Mills for (i = strlen(argv[0]); i >= 0 && argv[0][i] != '/'; --i)
1720a1278f2SGary Mills ;
1737c478bd9Sstevel@tonic-gate if (i >= 0)
1747c478bd9Sstevel@tonic-gate argv[0] += i+1;
1757c478bd9Sstevel@tonic-gate program = argv[0];
1767c478bd9Sstevel@tonic-gate
1777c478bd9Sstevel@tonic-gate /*
1787c478bd9Sstevel@tonic-gate * Buffer stdout for speed
1797c478bd9Sstevel@tonic-gate */
1807c478bd9Sstevel@tonic-gate setbuf(stdout, outbuf);
1817c478bd9Sstevel@tonic-gate
1827c478bd9Sstevel@tonic-gate /*
1837c478bd9Sstevel@tonic-gate * Retrieve options specified on command line
1847c478bd9Sstevel@tonic-gate * XCU4 - add -m option
1857c478bd9Sstevel@tonic-gate */
1867c478bd9Sstevel@tonic-gate while ((optsw = getopt(argc, argv, "abdHlmn:pqrstTu")) != EOF) {
1877c478bd9Sstevel@tonic-gate optcnt++;
1887c478bd9Sstevel@tonic-gate switch (optsw) {
1897c478bd9Sstevel@tonic-gate
1907c478bd9Sstevel@tonic-gate case 'a':
1917c478bd9Sstevel@tonic-gate optcnt += 7;
1927c478bd9Sstevel@tonic-gate validtype[BOOT_TIME] = 1;
1937c478bd9Sstevel@tonic-gate validtype[DEAD_PROCESS] = 1;
1947c478bd9Sstevel@tonic-gate validtype[LOGIN_PROCESS] = 1;
1957c478bd9Sstevel@tonic-gate validtype[INIT_PROCESS] = 1;
1967c478bd9Sstevel@tonic-gate validtype[RUN_LVL] = 1;
1977c478bd9Sstevel@tonic-gate validtype[OLD_TIME] = 1;
1987c478bd9Sstevel@tonic-gate validtype[NEW_TIME] = 1;
1997c478bd9Sstevel@tonic-gate validtype[USER_PROCESS] = 1;
2007c478bd9Sstevel@tonic-gate #ifdef XPG4
2017c478bd9Sstevel@tonic-gate aopt = 1;
2027c478bd9Sstevel@tonic-gate #endif /* XPG4 */
2037c478bd9Sstevel@tonic-gate uopt = 1;
2047c478bd9Sstevel@tonic-gate Topt = 1;
2057c478bd9Sstevel@tonic-gate if (!sopt) terse = 0;
2067c478bd9Sstevel@tonic-gate break;
2077c478bd9Sstevel@tonic-gate
2087c478bd9Sstevel@tonic-gate case 'b':
2097c478bd9Sstevel@tonic-gate validtype[BOOT_TIME] = 1;
2107c478bd9Sstevel@tonic-gate if (!uopt) validtype[USER_PROCESS] = 0;
2117c478bd9Sstevel@tonic-gate break;
2127c478bd9Sstevel@tonic-gate
2137c478bd9Sstevel@tonic-gate case 'd':
2147c478bd9Sstevel@tonic-gate validtype[DEAD_PROCESS] = 1;
2157c478bd9Sstevel@tonic-gate if (!uopt) validtype[USER_PROCESS] = 0;
2167c478bd9Sstevel@tonic-gate #ifdef XPG4
2177c478bd9Sstevel@tonic-gate dopt = 1;
2187c478bd9Sstevel@tonic-gate #endif /* XPG4 */
2197c478bd9Sstevel@tonic-gate break;
2207c478bd9Sstevel@tonic-gate
2217c478bd9Sstevel@tonic-gate case 'H':
2227c478bd9Sstevel@tonic-gate optcnt--; /* Don't count Header */
2237c478bd9Sstevel@tonic-gate Hopt = 1;
2247c478bd9Sstevel@tonic-gate break;
2257c478bd9Sstevel@tonic-gate
2267c478bd9Sstevel@tonic-gate case 'l':
2277c478bd9Sstevel@tonic-gate validtype[LOGIN_PROCESS] = 1;
2287c478bd9Sstevel@tonic-gate if (!uopt) validtype[USER_PROCESS] = 0;
2297c478bd9Sstevel@tonic-gate terse = 0;
2307c478bd9Sstevel@tonic-gate break;
2317c478bd9Sstevel@tonic-gate case 'm': /* New XCU4 option */
2327c478bd9Sstevel@tonic-gate justme = 1;
2337c478bd9Sstevel@tonic-gate break;
2347c478bd9Sstevel@tonic-gate
2357c478bd9Sstevel@tonic-gate case 'n':
2367c478bd9Sstevel@tonic-gate errno = 0;
2377c478bd9Sstevel@tonic-gate number = strtol(optarg, &end, 10);
2387c478bd9Sstevel@tonic-gate if (errno != 0 || *end != '\0') {
2397c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext(
2407c478bd9Sstevel@tonic-gate "%s: Invalid numeric argument\n"),
2417c478bd9Sstevel@tonic-gate program);
2427c478bd9Sstevel@tonic-gate exit(1);
2437c478bd9Sstevel@tonic-gate }
2447c478bd9Sstevel@tonic-gate if (number < 1) {
2457c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext(
2467c478bd9Sstevel@tonic-gate "%s: Number of users per line must "
2470a1278f2SGary Mills "be at least 1\n"), program);
2487c478bd9Sstevel@tonic-gate exit(1);
2497c478bd9Sstevel@tonic-gate }
2507c478bd9Sstevel@tonic-gate break;
2517c478bd9Sstevel@tonic-gate
2527c478bd9Sstevel@tonic-gate case 'p':
2537c478bd9Sstevel@tonic-gate validtype[INIT_PROCESS] = 1;
2547c478bd9Sstevel@tonic-gate if (!uopt) validtype[USER_PROCESS] = 0;
2557c478bd9Sstevel@tonic-gate break;
2567c478bd9Sstevel@tonic-gate
2577c478bd9Sstevel@tonic-gate case 'q':
2587c478bd9Sstevel@tonic-gate qopt = 1;
2597c478bd9Sstevel@tonic-gate break;
2607c478bd9Sstevel@tonic-gate
2617c478bd9Sstevel@tonic-gate case 'r':
2627c478bd9Sstevel@tonic-gate validtype[RUN_LVL] = 1;
2637c478bd9Sstevel@tonic-gate terse = 0;
2647c478bd9Sstevel@tonic-gate if (!uopt) validtype[USER_PROCESS] = 0;
2657c478bd9Sstevel@tonic-gate break;
2667c478bd9Sstevel@tonic-gate
2677c478bd9Sstevel@tonic-gate case 's':
2687c478bd9Sstevel@tonic-gate sopt = 1;
2697c478bd9Sstevel@tonic-gate terse = 1;
2707c478bd9Sstevel@tonic-gate break;
2717c478bd9Sstevel@tonic-gate
2727c478bd9Sstevel@tonic-gate case 't':
2737c478bd9Sstevel@tonic-gate validtype[OLD_TIME] = 1;
2747c478bd9Sstevel@tonic-gate validtype[NEW_TIME] = 1;
2757c478bd9Sstevel@tonic-gate if (!uopt) validtype[USER_PROCESS] = 0;
2767c478bd9Sstevel@tonic-gate break;
2777c478bd9Sstevel@tonic-gate
2787c478bd9Sstevel@tonic-gate case 'T':
2797c478bd9Sstevel@tonic-gate Topt = 1;
2807c478bd9Sstevel@tonic-gate #ifdef XPG4
2817c478bd9Sstevel@tonic-gate terse = 1; /* XPG4 requires -T */
2827c478bd9Sstevel@tonic-gate #else /* XPG4 */
2837c478bd9Sstevel@tonic-gate terse = 0;
2847c478bd9Sstevel@tonic-gate #endif /* XPG4 */
2857c478bd9Sstevel@tonic-gate break;
2867c478bd9Sstevel@tonic-gate
2877c478bd9Sstevel@tonic-gate case 'u':
2887c478bd9Sstevel@tonic-gate uopt = 1;
2897c478bd9Sstevel@tonic-gate validtype[USER_PROCESS] = 1;
2907c478bd9Sstevel@tonic-gate if (!sopt) terse = 0;
2917c478bd9Sstevel@tonic-gate break;
2927c478bd9Sstevel@tonic-gate
2937c478bd9Sstevel@tonic-gate case '?':
2947c478bd9Sstevel@tonic-gate goerr++;
2957c478bd9Sstevel@tonic-gate break;
2967c478bd9Sstevel@tonic-gate default:
2977c478bd9Sstevel@tonic-gate break;
2987c478bd9Sstevel@tonic-gate }
2997c478bd9Sstevel@tonic-gate }
3007c478bd9Sstevel@tonic-gate #ifdef XPG4
3017c478bd9Sstevel@tonic-gate /*
3027c478bd9Sstevel@tonic-gate * XCU4 changes - check for illegal sopt, Topt & aopt combination
3037c478bd9Sstevel@tonic-gate */
3047c478bd9Sstevel@tonic-gate if (sopt == 1) {
3057c478bd9Sstevel@tonic-gate terse = 1;
3067c478bd9Sstevel@tonic-gate if (Topt == 1 || aopt == 1)
307*6062513aSJohn Levon goerr++;
3087c478bd9Sstevel@tonic-gate }
3097c478bd9Sstevel@tonic-gate #endif /* XPG4 */
3107c478bd9Sstevel@tonic-gate
3117c478bd9Sstevel@tonic-gate if (goerr > 0) {
3127c478bd9Sstevel@tonic-gate #ifdef XPG4
3137c478bd9Sstevel@tonic-gate /*
3147c478bd9Sstevel@tonic-gate * XCU4 - slightly different usage with -s -a & -T
3157c478bd9Sstevel@tonic-gate */
3167c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext("\nUsage:\t%s"), program);
3177c478bd9Sstevel@tonic-gate (void) fprintf(stderr,
3187c478bd9Sstevel@tonic-gate gettext(" -s [-bdHlmpqrtu] [utmpx_like_file]\n"));
3197c478bd9Sstevel@tonic-gate
3207c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext(
3217c478bd9Sstevel@tonic-gate "\t%s [-abdHlmpqrtTu] [utmpx_like_file]\n"), program);
3227c478bd9Sstevel@tonic-gate #else /* XPG4 */
3237c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext(
3247c478bd9Sstevel@tonic-gate "\nUsage:\t%s [-abdHlmpqrstTu] [utmpx_like_file]\n"),
3257c478bd9Sstevel@tonic-gate program);
3267c478bd9Sstevel@tonic-gate #endif /* XPG4 */
3277c478bd9Sstevel@tonic-gate (void) fprintf(stderr,
3287c478bd9Sstevel@tonic-gate gettext("\t%s -q [-n x] [utmpx_like_file]\n"), program);
3297c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext("\t%s [am i]\n"), program);
3307c478bd9Sstevel@tonic-gate /*
3317c478bd9Sstevel@tonic-gate * XCU4 changes - be explicit with "am i" options
3327c478bd9Sstevel@tonic-gate */
3337c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext("\t%s [am I]\n"), program);
3347c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext(
3357c478bd9Sstevel@tonic-gate "a\tall (bdlprtu options)\n"));
3367c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext("b\tboot time\n"));
3377c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext("d\tdead processes\n"));
3387c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext("H\tprint header\n"));
3397c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext("l\tlogin processes\n"));
3407c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext(
3417c478bd9Sstevel@tonic-gate "n #\tspecify number of users per line for -q\n"));
3427c478bd9Sstevel@tonic-gate (void) fprintf(stderr,
3437c478bd9Sstevel@tonic-gate gettext("p\tprocesses other than getty or users\n"));
3447c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext("q\tquick %s\n"), program);
3457c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext("r\trun level\n"));
3467c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext(
3477c478bd9Sstevel@tonic-gate "s\tshort form of %s (no time since last output or pid)\n"),
3487c478bd9Sstevel@tonic-gate program);
3497c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext("t\ttime changes\n"));
3507c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext(
3517c478bd9Sstevel@tonic-gate "T\tstatus of tty (+ writable, - not writable, "
3520a1278f2SGary Mills "? hung)\n"));
3537c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext("u\tuseful information\n"));
3547c478bd9Sstevel@tonic-gate (void) fprintf(stderr,
3557c478bd9Sstevel@tonic-gate gettext("m\tinformation only about current terminal\n"));
3567c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext(
3577c478bd9Sstevel@tonic-gate "am i\tinformation about current terminal "
3580a1278f2SGary Mills "(same as -m)\n"));
3597c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext(
3607c478bd9Sstevel@tonic-gate "am I\tinformation about current terminal "
3610a1278f2SGary Mills "(same as -m)\n"));
3627c478bd9Sstevel@tonic-gate exit(1);
3637c478bd9Sstevel@tonic-gate }
3647c478bd9Sstevel@tonic-gate
3657c478bd9Sstevel@tonic-gate /*
3667c478bd9Sstevel@tonic-gate * XCU4: If -q option ignore all other options
3677c478bd9Sstevel@tonic-gate */
3687c478bd9Sstevel@tonic-gate if (qopt == 1) {
3697c478bd9Sstevel@tonic-gate Hopt = 0;
3707c478bd9Sstevel@tonic-gate sopt = 0;
3717c478bd9Sstevel@tonic-gate Topt = 0;
3727c478bd9Sstevel@tonic-gate uopt = 0;
3737c478bd9Sstevel@tonic-gate justme = 0;
3747c478bd9Sstevel@tonic-gate validtype[ACCOUNTING] = 0;
3757c478bd9Sstevel@tonic-gate validtype[BOOT_TIME] = 0;
3767c478bd9Sstevel@tonic-gate validtype[DEAD_PROCESS] = 0;
3777c478bd9Sstevel@tonic-gate validtype[LOGIN_PROCESS] = 0;
3787c478bd9Sstevel@tonic-gate validtype[INIT_PROCESS] = 0;
3797c478bd9Sstevel@tonic-gate validtype[RUN_LVL] = 0;
3807c478bd9Sstevel@tonic-gate validtype[OLD_TIME] = 0;
3817c478bd9Sstevel@tonic-gate validtype[NEW_TIME] = 0;
3827c478bd9Sstevel@tonic-gate validtype[USER_PROCESS] = 1;
3837c478bd9Sstevel@tonic-gate }
3847c478bd9Sstevel@tonic-gate
3857c478bd9Sstevel@tonic-gate if (argc == optind + 1) {
3867c478bd9Sstevel@tonic-gate optcnt++;
3877c478bd9Sstevel@tonic-gate ck_file(argv[optind]);
3887c478bd9Sstevel@tonic-gate (void) utmpxname(argv[optind]);
3897c478bd9Sstevel@tonic-gate }
3907c478bd9Sstevel@tonic-gate
3917c478bd9Sstevel@tonic-gate /*
3927c478bd9Sstevel@tonic-gate * Test for 'who am i' or 'who am I'
3937c478bd9Sstevel@tonic-gate * XCU4 - check if justme was already set by -m option
3947c478bd9Sstevel@tonic-gate */
3957c478bd9Sstevel@tonic-gate if (justme == 1 || (argc == 3 && strcmp(argv[1], "am") == 0 &&
3967c478bd9Sstevel@tonic-gate ((argv[2][0] == 'i' || argv[2][0] == 'I') &&
3970a1278f2SGary Mills argv[2][1] == '\0'))) {
3987c478bd9Sstevel@tonic-gate justme = 1;
3997c478bd9Sstevel@tonic-gate myname = nameval;
4007c478bd9Sstevel@tonic-gate (void) cuserid(myname);
4017c478bd9Sstevel@tonic-gate if ((mytty = ttyname(fileno(stdin))) == NULL &&
4027c478bd9Sstevel@tonic-gate (mytty = ttyname(fileno(stdout))) == NULL &&
4037c478bd9Sstevel@tonic-gate (mytty = ttyname(fileno(stderr))) == NULL) {
4047c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext(
4057c478bd9Sstevel@tonic-gate "Must be attached to terminal for 'am I' option\n"));
4067c478bd9Sstevel@tonic-gate (void) fflush(stderr);
4077c478bd9Sstevel@tonic-gate exit(1);
4087c478bd9Sstevel@tonic-gate } else
4097c478bd9Sstevel@tonic-gate mytty += 5; /* bump past "/dev/" */
4107c478bd9Sstevel@tonic-gate }
4117c478bd9Sstevel@tonic-gate
4127c478bd9Sstevel@tonic-gate if (!terse) {
4137c478bd9Sstevel@tonic-gate if (Hopt)
4147c478bd9Sstevel@tonic-gate (void) printf(gettext(
4157c478bd9Sstevel@tonic-gate "NAME LINE TIME IDLE PID COMMENTS\n"));
4167c478bd9Sstevel@tonic-gate
4177c478bd9Sstevel@tonic-gate timnow = time(0);
4187c478bd9Sstevel@tonic-gate
4197c478bd9Sstevel@tonic-gate if ((fildes = open("/etc/inittab",
4207c478bd9Sstevel@tonic-gate O_NONBLOCK|O_RDONLY)) == -1) {
4217c478bd9Sstevel@tonic-gate (void) snprintf(errmsg, sizeof (errmsg),
4227c478bd9Sstevel@tonic-gate gettext("%s: Cannot open /etc/inittab"), program);
4237c478bd9Sstevel@tonic-gate perror(errmsg);
4247c478bd9Sstevel@tonic-gate exit(errno);
4257c478bd9Sstevel@tonic-gate }
4267c478bd9Sstevel@tonic-gate
4277c478bd9Sstevel@tonic-gate if (fstat(fildes, stbufp) == -1) {
4287c478bd9Sstevel@tonic-gate (void) snprintf(errmsg, sizeof (errmsg),
4297c478bd9Sstevel@tonic-gate gettext("%s: Cannot stat /etc/inittab"), program);
4307c478bd9Sstevel@tonic-gate perror(errmsg);
4317c478bd9Sstevel@tonic-gate exit(errno);
4327c478bd9Sstevel@tonic-gate }
4337c478bd9Sstevel@tonic-gate
4347c478bd9Sstevel@tonic-gate if ((inittab = malloc(stbufp->st_size + 1)) == NULL) {
4357c478bd9Sstevel@tonic-gate (void) snprintf(errmsg, sizeof (errmsg),
4367c478bd9Sstevel@tonic-gate gettext("%s: Cannot allocate %ld bytes"),
4377c478bd9Sstevel@tonic-gate program, stbufp->st_size);
4387c478bd9Sstevel@tonic-gate perror(errmsg);
4397c478bd9Sstevel@tonic-gate exit(errno);
4407c478bd9Sstevel@tonic-gate }
4417c478bd9Sstevel@tonic-gate
4427c478bd9Sstevel@tonic-gate if (read(fildes, inittab, stbufp->st_size)
4437c478bd9Sstevel@tonic-gate != stbufp->st_size) {
4447c478bd9Sstevel@tonic-gate (void) snprintf(errmsg, sizeof (errmsg),
4457c478bd9Sstevel@tonic-gate gettext("%s: Error reading /etc/inittab"),
4467c478bd9Sstevel@tonic-gate program);
4477c478bd9Sstevel@tonic-gate perror(errmsg);
4487c478bd9Sstevel@tonic-gate exit(errno);
4497c478bd9Sstevel@tonic-gate }
4507c478bd9Sstevel@tonic-gate
4517c478bd9Sstevel@tonic-gate inittab[stbufp->st_size] = '\0';
4527c478bd9Sstevel@tonic-gate iinit = inittab;
4537c478bd9Sstevel@tonic-gate } else {
4547c478bd9Sstevel@tonic-gate if (Hopt) {
4557c478bd9Sstevel@tonic-gate #ifdef XPG4
4567c478bd9Sstevel@tonic-gate if (dopt) {
4577c478bd9Sstevel@tonic-gate (void) printf(gettext(
4587c478bd9Sstevel@tonic-gate "NAME LINE TIME COMMENTS\n"));
4597c478bd9Sstevel@tonic-gate } else {
4607c478bd9Sstevel@tonic-gate (void) printf(
4617c478bd9Sstevel@tonic-gate gettext("NAME LINE TIME\n"));
4627c478bd9Sstevel@tonic-gate }
4637c478bd9Sstevel@tonic-gate #else /* XPG4 */
4647c478bd9Sstevel@tonic-gate (void) printf(
4657c478bd9Sstevel@tonic-gate gettext("NAME LINE TIME\n"));
4667c478bd9Sstevel@tonic-gate #endif /* XPG4 */
4677c478bd9Sstevel@tonic-gate }
4687c478bd9Sstevel@tonic-gate }
4697c478bd9Sstevel@tonic-gate process();
4707c478bd9Sstevel@tonic-gate
4717c478bd9Sstevel@tonic-gate /*
4727c478bd9Sstevel@tonic-gate * 'who -q' requires EOL upon exit,
4737c478bd9Sstevel@tonic-gate * followed by total line
4747c478bd9Sstevel@tonic-gate */
4757c478bd9Sstevel@tonic-gate if (qopt)
4767c478bd9Sstevel@tonic-gate (void) printf(gettext("\n# users=%d\n"), totlusrs);
4777c478bd9Sstevel@tonic-gate return (0);
4787c478bd9Sstevel@tonic-gate }
4797c478bd9Sstevel@tonic-gate
4807c478bd9Sstevel@tonic-gate static void
dump()4817c478bd9Sstevel@tonic-gate dump()
4827c478bd9Sstevel@tonic-gate {
4837c478bd9Sstevel@tonic-gate char device[sizeof (utmpp->ut_line) + 1];
4847c478bd9Sstevel@tonic-gate time_t hr;
4857c478bd9Sstevel@tonic-gate time_t idle;
4867c478bd9Sstevel@tonic-gate time_t min;
4877c478bd9Sstevel@tonic-gate char path[sizeof (utmpp->ut_line) + 6];
4887c478bd9Sstevel@tonic-gate int pexit;
4897c478bd9Sstevel@tonic-gate int pterm;
4907c478bd9Sstevel@tonic-gate int rc;
4917c478bd9Sstevel@tonic-gate char w; /* writeability indicator */
4927c478bd9Sstevel@tonic-gate
4937c478bd9Sstevel@tonic-gate /*
4947c478bd9Sstevel@tonic-gate * Get and check user name
4957c478bd9Sstevel@tonic-gate */
4967c478bd9Sstevel@tonic-gate if (utmpp->ut_user[0] == '\0')
4977c478bd9Sstevel@tonic-gate (void) strcpy(user, " .");
4987c478bd9Sstevel@tonic-gate else {
4997c478bd9Sstevel@tonic-gate (void) strncpy(user, utmpp->ut_user, sizeof (user));
5007c478bd9Sstevel@tonic-gate user[sizeof (user) - 1] = '\0';
5017c478bd9Sstevel@tonic-gate }
5027c478bd9Sstevel@tonic-gate totlusrs++;
5037c478bd9Sstevel@tonic-gate
5047c478bd9Sstevel@tonic-gate /*
5057c478bd9Sstevel@tonic-gate * Do print in 'who -q' format
5067c478bd9Sstevel@tonic-gate */
5077c478bd9Sstevel@tonic-gate if (qopt) {
5087c478bd9Sstevel@tonic-gate /*
5097c478bd9Sstevel@tonic-gate * XCU4 - Use non user macro for correct user count
5107c478bd9Sstevel@tonic-gate */
5117c478bd9Sstevel@tonic-gate if (((totlusrs - 1) % number) == 0 && totlusrs > 1)
5127c478bd9Sstevel@tonic-gate (void) printf("\n");
5130a1278f2SGary Mills (void) printf("%-*.*s ", LOGIN_WIDTH, NMAX, user);
5147c478bd9Sstevel@tonic-gate return;
5157c478bd9Sstevel@tonic-gate }
5167c478bd9Sstevel@tonic-gate
5177c478bd9Sstevel@tonic-gate
5187c478bd9Sstevel@tonic-gate pexit = (int)' ';
5197c478bd9Sstevel@tonic-gate pterm = (int)' ';
5207c478bd9Sstevel@tonic-gate
5217c478bd9Sstevel@tonic-gate /*
5227c478bd9Sstevel@tonic-gate * Get exit info if applicable
5237c478bd9Sstevel@tonic-gate */
5247c478bd9Sstevel@tonic-gate if (utmpp->ut_type == RUN_LVL || utmpp->ut_type == DEAD_PROCESS) {
5257c478bd9Sstevel@tonic-gate pterm = utmpp->ut_exit.e_termination;
5267c478bd9Sstevel@tonic-gate pexit = utmpp->ut_exit.e_exit;
5277c478bd9Sstevel@tonic-gate }
5287c478bd9Sstevel@tonic-gate
5297c478bd9Sstevel@tonic-gate /*
5307c478bd9Sstevel@tonic-gate * Massage ut_xtime field
5317c478bd9Sstevel@tonic-gate */
5327c478bd9Sstevel@tonic-gate lptr = localtime(&utmpp->ut_xtime);
5337c478bd9Sstevel@tonic-gate (void) strftime(time_buf, sizeof (time_buf),
5347c478bd9Sstevel@tonic-gate dcgettext(NULL, DATE_FMT, LC_TIME), lptr);
5357c478bd9Sstevel@tonic-gate
5367c478bd9Sstevel@tonic-gate /*
5377c478bd9Sstevel@tonic-gate * Get and massage device
5387c478bd9Sstevel@tonic-gate */
5397c478bd9Sstevel@tonic-gate if (utmpp->ut_line[0] == '\0')
5407c478bd9Sstevel@tonic-gate (void) strcpy(device, " .");
5417c478bd9Sstevel@tonic-gate else {
5427c478bd9Sstevel@tonic-gate (void) strncpy(device, utmpp->ut_line,
5437c478bd9Sstevel@tonic-gate sizeof (utmpp->ut_line));
5447c478bd9Sstevel@tonic-gate device[sizeof (utmpp->ut_line)] = '\0';
5457c478bd9Sstevel@tonic-gate }
5467c478bd9Sstevel@tonic-gate
5477c478bd9Sstevel@tonic-gate /*
5487c478bd9Sstevel@tonic-gate * Get writeability if requested
5497c478bd9Sstevel@tonic-gate * XCU4 - only print + or - for user processes
5507c478bd9Sstevel@tonic-gate */
5517c478bd9Sstevel@tonic-gate if (Topt && (utmpp->ut_type == USER_PROCESS)) {
5527c478bd9Sstevel@tonic-gate w = '-';
5537c478bd9Sstevel@tonic-gate (void) strcpy(path, "/dev/");
5547c478bd9Sstevel@tonic-gate (void) strncpy(path + 5, utmpp->ut_line,
5557c478bd9Sstevel@tonic-gate sizeof (utmpp->ut_line));
5567c478bd9Sstevel@tonic-gate path[5 + sizeof (utmpp->ut_line)] = '\0';
5577c478bd9Sstevel@tonic-gate
5587c478bd9Sstevel@tonic-gate if ((rc = stat(path, stbufp)) == -1) w = '?';
5597c478bd9Sstevel@tonic-gate else if ((stbufp->st_mode & S_IWOTH) ||
5607c478bd9Sstevel@tonic-gate (stbufp->st_mode & S_IWGRP)) /* Check group & other */
5617c478bd9Sstevel@tonic-gate w = '+';
5627c478bd9Sstevel@tonic-gate
5637c478bd9Sstevel@tonic-gate } else
5647c478bd9Sstevel@tonic-gate w = ' ';
5657c478bd9Sstevel@tonic-gate
5667c478bd9Sstevel@tonic-gate /*
5677c478bd9Sstevel@tonic-gate * Print the TERSE portion of the output
5687c478bd9Sstevel@tonic-gate */
5690a1278f2SGary Mills (void) printf("%-*.*s %c %-12s %s", LOGIN_WIDTH, NMAX, user,
5700a1278f2SGary Mills w, device, time_buf);
5717c478bd9Sstevel@tonic-gate
5727c478bd9Sstevel@tonic-gate if (!terse) {
5737c478bd9Sstevel@tonic-gate /*
5747c478bd9Sstevel@tonic-gate * Stat device for idle time
5757c478bd9Sstevel@tonic-gate * (Don't complain if you can't)
5767c478bd9Sstevel@tonic-gate */
577b11e536cSjg rc = -1;
578b11e536cSjg if (utmpp->ut_type == USER_PROCESS) {
579b11e536cSjg (void) strcpy(path, "/dev/");
580b11e536cSjg (void) strncpy(path + 5, utmpp->ut_line,
581b11e536cSjg sizeof (utmpp->ut_line));
582b11e536cSjg path[5 + sizeof (utmpp->ut_line)] = '\0';
583b11e536cSjg rc = stat(path, stbufp);
584b11e536cSjg }
585b11e536cSjg if (rc != -1) {
5867c478bd9Sstevel@tonic-gate idle = timnow - stbufp->st_mtime;
5877c478bd9Sstevel@tonic-gate hr = idle/3600;
5887c478bd9Sstevel@tonic-gate min = (unsigned)(idle/60)%60;
5897c478bd9Sstevel@tonic-gate if (hr == 0 && min == 0)
5907c478bd9Sstevel@tonic-gate (void) printf(gettext(" . "));
5917c478bd9Sstevel@tonic-gate else {
5927c478bd9Sstevel@tonic-gate if (hr < 24)
5937c478bd9Sstevel@tonic-gate (void) printf(" %2d:%2.2d", (int)hr,
5947c478bd9Sstevel@tonic-gate (int)min);
5957c478bd9Sstevel@tonic-gate else
5967c478bd9Sstevel@tonic-gate (void) printf(gettext(" old "));
5977c478bd9Sstevel@tonic-gate }
5987c478bd9Sstevel@tonic-gate }
5997c478bd9Sstevel@tonic-gate
6007c478bd9Sstevel@tonic-gate /*
6017c478bd9Sstevel@tonic-gate * Add PID for verbose output
6027c478bd9Sstevel@tonic-gate */
6037c478bd9Sstevel@tonic-gate if (utmpp->ut_type != BOOT_TIME &&
6047c478bd9Sstevel@tonic-gate utmpp->ut_type != RUN_LVL &&
6057c478bd9Sstevel@tonic-gate utmpp->ut_type != ACCOUNTING)
6067c478bd9Sstevel@tonic-gate (void) printf(" %5ld", utmpp->ut_pid);
6077c478bd9Sstevel@tonic-gate
6087c478bd9Sstevel@tonic-gate /*
6097c478bd9Sstevel@tonic-gate * Handle /etc/inittab comment
6107c478bd9Sstevel@tonic-gate */
6117c478bd9Sstevel@tonic-gate if (utmpp->ut_type == DEAD_PROCESS) {
6127c478bd9Sstevel@tonic-gate (void) printf(gettext(" id=%4.4s "),
6137c478bd9Sstevel@tonic-gate utmpp->ut_id);
6147c478bd9Sstevel@tonic-gate (void) printf(gettext("term=%-3d "), pterm);
6157c478bd9Sstevel@tonic-gate (void) printf(gettext("exit=%d "), pexit);
6167c478bd9Sstevel@tonic-gate } else if (utmpp->ut_type != INIT_PROCESS) {
6177c478bd9Sstevel@tonic-gate /*
6187c478bd9Sstevel@tonic-gate * Search for each entry in inittab
6197c478bd9Sstevel@tonic-gate * string. Keep our place from
6207c478bd9Sstevel@tonic-gate * search to search to try and
6217c478bd9Sstevel@tonic-gate * minimize the work. Wrap once if needed
6227c478bd9Sstevel@tonic-gate * for each entry.
6237c478bd9Sstevel@tonic-gate */
6247c478bd9Sstevel@tonic-gate wrap = 0;
6257c478bd9Sstevel@tonic-gate /*
6267c478bd9Sstevel@tonic-gate * Look for a line beginning with
6277c478bd9Sstevel@tonic-gate * utmpp->ut_id
6287c478bd9Sstevel@tonic-gate */
6297c478bd9Sstevel@tonic-gate while ((rc = strncmp(utmpp->ut_id, iinit,
6307c478bd9Sstevel@tonic-gate strcspn(iinit, ":"))) != 0) {
6310a1278f2SGary Mills for (; *iinit != '\n'; iinit++)
6320a1278f2SGary Mills ;
6337c478bd9Sstevel@tonic-gate iinit++;
6347c478bd9Sstevel@tonic-gate
6357c478bd9Sstevel@tonic-gate /*
6367c478bd9Sstevel@tonic-gate * Wrap once if necessary to
6377c478bd9Sstevel@tonic-gate * find entry in inittab
6387c478bd9Sstevel@tonic-gate */
6397c478bd9Sstevel@tonic-gate if (*iinit == '\0') {
6407c478bd9Sstevel@tonic-gate if (!wrap) {
6417c478bd9Sstevel@tonic-gate iinit = inittab;
6427c478bd9Sstevel@tonic-gate wrap = 1;
6437c478bd9Sstevel@tonic-gate }
6447c478bd9Sstevel@tonic-gate }
6457c478bd9Sstevel@tonic-gate }
6467c478bd9Sstevel@tonic-gate
6477c478bd9Sstevel@tonic-gate if (*iinit != '\0') {
6487c478bd9Sstevel@tonic-gate /*
6497c478bd9Sstevel@tonic-gate * We found our entry
6507c478bd9Sstevel@tonic-gate */
6517c478bd9Sstevel@tonic-gate for (iinit++; *iinit != '#' &&
6520a1278f2SGary Mills *iinit != '\n'; iinit++)
6530a1278f2SGary Mills ;
6547c478bd9Sstevel@tonic-gate if (*iinit == '#') {
6557c478bd9Sstevel@tonic-gate for (iinit++; *iinit == ' ' ||
6560a1278f2SGary Mills *iinit == '\t'; iinit++)
6570a1278f2SGary Mills ;
6587c478bd9Sstevel@tonic-gate for (rc = 0; *iinit != '\n'; iinit++)
6597c478bd9Sstevel@tonic-gate comment[rc++] = *iinit;
6607c478bd9Sstevel@tonic-gate comment[rc] = '\0';
6617c478bd9Sstevel@tonic-gate } else
6627c478bd9Sstevel@tonic-gate (void) strcpy(comment, " ");
6637c478bd9Sstevel@tonic-gate
6647c478bd9Sstevel@tonic-gate (void) printf(" %s", comment);
6657c478bd9Sstevel@tonic-gate } else
6667c478bd9Sstevel@tonic-gate iinit = inittab; /* Reset pointer */
6677c478bd9Sstevel@tonic-gate }
6687c478bd9Sstevel@tonic-gate if (utmpp->ut_type == INIT_PROCESS)
6697c478bd9Sstevel@tonic-gate (void) printf(gettext(" id=%4.4s"), utmpp->ut_id);
6707c478bd9Sstevel@tonic-gate }
6717c478bd9Sstevel@tonic-gate #ifdef XPG4
6727c478bd9Sstevel@tonic-gate else
6737c478bd9Sstevel@tonic-gate if (dopt && utmpp->ut_type == DEAD_PROCESS) {
6747c478bd9Sstevel@tonic-gate (void) printf(gettext("\tterm=%-3d "), pterm);
6757c478bd9Sstevel@tonic-gate (void) printf(gettext("exit=%d "), pexit);
6767c478bd9Sstevel@tonic-gate }
6777c478bd9Sstevel@tonic-gate #endif /* XPG4 */
6787c478bd9Sstevel@tonic-gate
6797c478bd9Sstevel@tonic-gate
6807c478bd9Sstevel@tonic-gate /*
6817c478bd9Sstevel@tonic-gate * Handle RUN_LVL process - If no alt. file - Only one!
6827c478bd9Sstevel@tonic-gate */
6837c478bd9Sstevel@tonic-gate if (utmpp->ut_type == RUN_LVL) {
6847c478bd9Sstevel@tonic-gate (void) printf(" %c %5ld %c", pterm, utmpp->ut_pid,
6857c478bd9Sstevel@tonic-gate pexit);
6867c478bd9Sstevel@tonic-gate if (optcnt == 1 && !validtype[USER_PROCESS]) {
6877c478bd9Sstevel@tonic-gate (void) printf("\n");
6887c478bd9Sstevel@tonic-gate exit(0);
6897c478bd9Sstevel@tonic-gate }
6907c478bd9Sstevel@tonic-gate }
6917c478bd9Sstevel@tonic-gate
6927c478bd9Sstevel@tonic-gate /*
6937c478bd9Sstevel@tonic-gate * Handle BOOT_TIME process - If no alt. file - Only one!
6947c478bd9Sstevel@tonic-gate */
6957c478bd9Sstevel@tonic-gate if (utmpp->ut_type == BOOT_TIME) {
6967c478bd9Sstevel@tonic-gate if (optcnt == 1 && !validtype[USER_PROCESS]) {
6977c478bd9Sstevel@tonic-gate (void) printf("\n");
6987c478bd9Sstevel@tonic-gate exit(0);
6997c478bd9Sstevel@tonic-gate }
7007c478bd9Sstevel@tonic-gate }
7017c478bd9Sstevel@tonic-gate
7027c478bd9Sstevel@tonic-gate /*
7037c478bd9Sstevel@tonic-gate * Get remote host from utmpx structure
7047c478bd9Sstevel@tonic-gate */
705*6062513aSJohn Levon if (utmpp->ut_host[0])
7067c478bd9Sstevel@tonic-gate (void) printf("\t(%.*s)", sizeof (utmpp->ut_host),
7077c478bd9Sstevel@tonic-gate utmpp->ut_host);
7087c478bd9Sstevel@tonic-gate
7097c478bd9Sstevel@tonic-gate /*
7107c478bd9Sstevel@tonic-gate * Now, put on the trailing EOL
7117c478bd9Sstevel@tonic-gate */
7127c478bd9Sstevel@tonic-gate (void) printf("\n");
7137c478bd9Sstevel@tonic-gate }
7147c478bd9Sstevel@tonic-gate
7157c478bd9Sstevel@tonic-gate static void
process()7167c478bd9Sstevel@tonic-gate process()
7177c478bd9Sstevel@tonic-gate {
7187c478bd9Sstevel@tonic-gate struct passwd *pwp;
7197c478bd9Sstevel@tonic-gate int i = 0;
7207c478bd9Sstevel@tonic-gate char *ttname;
7217c478bd9Sstevel@tonic-gate
7227c478bd9Sstevel@tonic-gate /*
7237c478bd9Sstevel@tonic-gate * Loop over each entry in /var/adm/utmpx
7247c478bd9Sstevel@tonic-gate */
7257c478bd9Sstevel@tonic-gate
7267c478bd9Sstevel@tonic-gate setutxent();
7277c478bd9Sstevel@tonic-gate while ((utmpp = getutxent()) != NULL) {
7287c478bd9Sstevel@tonic-gate #ifdef DEBUG
7297c478bd9Sstevel@tonic-gate (void) printf(
7307c478bd9Sstevel@tonic-gate "ut_user '%s'\nut_id '%s'\nut_line '%s'\nut_type '%d'\n\n",
7317c478bd9Sstevel@tonic-gate utmpp->ut_user, utmpp->ut_id, utmpp->ut_line, utmpp->ut_type);
7327c478bd9Sstevel@tonic-gate #endif
7337c478bd9Sstevel@tonic-gate if (utmpp->ut_type <= UTMAXTYPE) {
7347c478bd9Sstevel@tonic-gate /*
7357c478bd9Sstevel@tonic-gate * Handle "am i"
7367c478bd9Sstevel@tonic-gate */
7377c478bd9Sstevel@tonic-gate if (justme) {
7387c478bd9Sstevel@tonic-gate if (strncmp(myname, utmpp->ut_user,
7397c478bd9Sstevel@tonic-gate sizeof (utmpp->ut_user)) == 0 &&
7407c478bd9Sstevel@tonic-gate strncmp(mytty, utmpp->ut_line,
7410a1278f2SGary Mills sizeof (utmpp->ut_line)) == 0 &&
7427c478bd9Sstevel@tonic-gate utmpp->ut_type == USER_PROCESS) {
7437c478bd9Sstevel@tonic-gate /*
7447c478bd9Sstevel@tonic-gate * we have have found ourselves
7457c478bd9Sstevel@tonic-gate * in the utmp file and the entry
7467c478bd9Sstevel@tonic-gate * is a user process, this is not
7477c478bd9Sstevel@tonic-gate * meaningful otherwise
7487c478bd9Sstevel@tonic-gate *
7497c478bd9Sstevel@tonic-gate */
7507c478bd9Sstevel@tonic-gate
7517c478bd9Sstevel@tonic-gate dump();
7527c478bd9Sstevel@tonic-gate exit(0);
7537c478bd9Sstevel@tonic-gate }
7547c478bd9Sstevel@tonic-gate continue;
7557c478bd9Sstevel@tonic-gate }
7567c478bd9Sstevel@tonic-gate
7577c478bd9Sstevel@tonic-gate /*
7587c478bd9Sstevel@tonic-gate * Print the line if we want it
7597c478bd9Sstevel@tonic-gate */
7607c478bd9Sstevel@tonic-gate if (validtype[utmpp->ut_type]) {
7617c478bd9Sstevel@tonic-gate #ifdef XPG4
7627c478bd9Sstevel@tonic-gate if (utmpp->ut_type == LOGIN_PROCESS) {
7637c478bd9Sstevel@tonic-gate if ((utmpp->ut_line[0] == '\0') ||
7640a1278f2SGary Mills (strcmp(utmpp->ut_user,
7650a1278f2SGary Mills "LOGIN") != 0))
7667c478bd9Sstevel@tonic-gate continue;
7677c478bd9Sstevel@tonic-gate }
7687c478bd9Sstevel@tonic-gate #endif /* XPG4 */
7697c478bd9Sstevel@tonic-gate dump();
7707c478bd9Sstevel@tonic-gate }
7717c478bd9Sstevel@tonic-gate } else {
7727c478bd9Sstevel@tonic-gate (void) fprintf(stderr,
7737c478bd9Sstevel@tonic-gate gettext("%s: Error --- entry has ut_type "
7740a1278f2SGary Mills "of %d\n"), program, utmpp->ut_type);
7757c478bd9Sstevel@tonic-gate (void) fprintf(stderr,
7767c478bd9Sstevel@tonic-gate gettext(" when maximum is %d\n"), UTMAXTYPE);
7777c478bd9Sstevel@tonic-gate }
7787c478bd9Sstevel@tonic-gate }
7797c478bd9Sstevel@tonic-gate
7807c478bd9Sstevel@tonic-gate /*
7817c478bd9Sstevel@tonic-gate * If justme is set at this point than the utmp entry
7827c478bd9Sstevel@tonic-gate * was not found.
7837c478bd9Sstevel@tonic-gate */
7847c478bd9Sstevel@tonic-gate if (justme) {
7857c478bd9Sstevel@tonic-gate static struct utmpx utmpt;
7867c478bd9Sstevel@tonic-gate
7877c478bd9Sstevel@tonic-gate pwp = getpwuid(geteuid());
7887c478bd9Sstevel@tonic-gate if (pwp != NULL)
7897c478bd9Sstevel@tonic-gate while (i < (int)sizeof (utmpt.ut_user) &&
7907c478bd9Sstevel@tonic-gate *pwp->pw_name != 0)
7917c478bd9Sstevel@tonic-gate utmpt.ut_user[i++] = *pwp->pw_name++;
7927c478bd9Sstevel@tonic-gate
7937c478bd9Sstevel@tonic-gate ttname = ttyname(1);
7947c478bd9Sstevel@tonic-gate
7957c478bd9Sstevel@tonic-gate i = 0;
7967c478bd9Sstevel@tonic-gate if (ttname != NULL)
7977c478bd9Sstevel@tonic-gate while (i < (int)sizeof (utmpt.ut_line) &&
7987c478bd9Sstevel@tonic-gate *ttname != 0)
7997c478bd9Sstevel@tonic-gate utmpt.ut_line[i++] = *ttname++;
8007c478bd9Sstevel@tonic-gate
8017c478bd9Sstevel@tonic-gate utmpt.ut_id[0] = 0;
8027c478bd9Sstevel@tonic-gate utmpt.ut_pid = getpid();
8037c478bd9Sstevel@tonic-gate utmpt.ut_type = USER_PROCESS;
8047c478bd9Sstevel@tonic-gate (void) time(&utmpt.ut_xtime);
8057c478bd9Sstevel@tonic-gate utmpp = &utmpt;
8067c478bd9Sstevel@tonic-gate dump();
8077c478bd9Sstevel@tonic-gate exit(0);
8087c478bd9Sstevel@tonic-gate }
8097c478bd9Sstevel@tonic-gate }
8107c478bd9Sstevel@tonic-gate
8117c478bd9Sstevel@tonic-gate /*
8127c478bd9Sstevel@tonic-gate * This routine checks the following:
8137c478bd9Sstevel@tonic-gate *
8147c478bd9Sstevel@tonic-gate * 1. File exists
8157c478bd9Sstevel@tonic-gate *
8167c478bd9Sstevel@tonic-gate * 2. We have read permissions
8177c478bd9Sstevel@tonic-gate *
8187c478bd9Sstevel@tonic-gate * 3. It is a multiple of utmp entries in size
8197c478bd9Sstevel@tonic-gate *
8207c478bd9Sstevel@tonic-gate * Failing any of these conditions causes who(1) to
8217c478bd9Sstevel@tonic-gate * abort processing.
8227c478bd9Sstevel@tonic-gate *
8237c478bd9Sstevel@tonic-gate * 4. If file is empty we exit right away as there
8247c478bd9Sstevel@tonic-gate * is no info to report on.
8257c478bd9Sstevel@tonic-gate *
8267c478bd9Sstevel@tonic-gate * This routine does not check utmpx files.
8277c478bd9Sstevel@tonic-gate */
8287c478bd9Sstevel@tonic-gate static void
ck_file(char * name)8297c478bd9Sstevel@tonic-gate ck_file(char *name)
8307c478bd9Sstevel@tonic-gate {
8317c478bd9Sstevel@tonic-gate struct stat sbuf;
8327c478bd9Sstevel@tonic-gate int rc;
8337c478bd9Sstevel@tonic-gate
8347c478bd9Sstevel@tonic-gate /*
8357c478bd9Sstevel@tonic-gate * Does file exist? Do stat to check, and save structure
8367c478bd9Sstevel@tonic-gate * so that we can check on the file's size later on.
8377c478bd9Sstevel@tonic-gate */
8387c478bd9Sstevel@tonic-gate if ((rc = stat(name, &sbuf)) == -1) {
8397c478bd9Sstevel@tonic-gate (void) snprintf(errmsg, sizeof (errmsg),
8407c478bd9Sstevel@tonic-gate gettext("%s: Cannot stat file '%s'"), program, name);
8417c478bd9Sstevel@tonic-gate perror(errmsg);
8427c478bd9Sstevel@tonic-gate exit(1);
8437c478bd9Sstevel@tonic-gate }
8447c478bd9Sstevel@tonic-gate
8457c478bd9Sstevel@tonic-gate /*
8467c478bd9Sstevel@tonic-gate * The only real way we can be sure we can access the
8477c478bd9Sstevel@tonic-gate * file is to try. If we succeed then we close it.
8487c478bd9Sstevel@tonic-gate */
8497c478bd9Sstevel@tonic-gate if (access(name, R_OK) < 0) {
8507c478bd9Sstevel@tonic-gate (void) snprintf(errmsg, sizeof (errmsg),
8517c478bd9Sstevel@tonic-gate gettext("%s: Cannot open file '%s'"), program, name);
8527c478bd9Sstevel@tonic-gate perror(errmsg);
8537c478bd9Sstevel@tonic-gate exit(1);
8547c478bd9Sstevel@tonic-gate }
8557c478bd9Sstevel@tonic-gate
8567c478bd9Sstevel@tonic-gate /*
8577c478bd9Sstevel@tonic-gate * If the file is empty, we are all done.
8587c478bd9Sstevel@tonic-gate */
8597c478bd9Sstevel@tonic-gate if (!sbuf.st_size)
8607c478bd9Sstevel@tonic-gate exit(0);
8617c478bd9Sstevel@tonic-gate
8627c478bd9Sstevel@tonic-gate /*
8637c478bd9Sstevel@tonic-gate * Make sure the file is a utmp file.
8647c478bd9Sstevel@tonic-gate * We can only check for size being a multiple of
8657c478bd9Sstevel@tonic-gate * utmp structures in length.
8667c478bd9Sstevel@tonic-gate */
8677c478bd9Sstevel@tonic-gate rc = sbuf.st_size % (int)sizeof (struct utmpx);
8687c478bd9Sstevel@tonic-gate if (rc) {
8697c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext("%s: File '%s' is not "
8707c478bd9Sstevel@tonic-gate "a utmpx file\n"), program, name);
8717c478bd9Sstevel@tonic-gate exit(1);
8727c478bd9Sstevel@tonic-gate }
8737c478bd9Sstevel@tonic-gate }
874