Annotation of src/usr.bin/who/who.c, Revision 1.24
1.24 ! deraadt 1: /* $OpenBSD: who.c,v 1.23 2015/10/09 01:37:09 deraadt Exp $ */
1.1 deraadt 2: /* $NetBSD: who.c,v 1.4 1994/12/07 04:28:49 jtc Exp $ */
3:
4: /*
5: * Copyright (c) 1989, 1993
6: * The Regents of the University of California. All rights reserved.
7: *
8: * This code is derived from software contributed to Berkeley by
9: * Michael Fischbein.
10: *
11: * Redistribution and use in source and binary forms, with or without
12: * modification, are permitted provided that the following conditions
13: * are met:
14: * 1. Redistributions of source code must retain the above copyright
15: * notice, this list of conditions and the following disclaimer.
16: * 2. Redistributions in binary form must reproduce the above copyright
17: * notice, this list of conditions and the following disclaimer in the
18: * documentation and/or other materials provided with the distribution.
1.15 millert 19: * 3. Neither the name of the University nor the names of its contributors
1.1 deraadt 20: * may be used to endorse or promote products derived from this software
21: * without specific prior written permission.
22: *
23: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
24: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33: * SUCH DAMAGE.
34: */
35:
36: #include <sys/types.h>
37: #include <sys/stat.h>
1.9 millert 38: #include <paths.h>
1.1 deraadt 39: #include <pwd.h>
40: #include <utmp.h>
41: #include <stdio.h>
42: #include <string.h>
43: #include <stdlib.h>
44: #include <unistd.h>
45: #include <time.h>
46: #include <err.h>
1.5 flipk 47: #include <locale.h>
48:
1.12 millert 49: void output(struct utmp *);
50: void output_labels(void);
51: void who_am_i(FILE *);
52: void usage(void);
53: FILE *file(char *);
1.1 deraadt 54:
55: int only_current_term; /* show info about the current terminal only */
56: int show_term; /* show term state */
57: int show_idle; /* show idle time */
1.5 flipk 58: int show_labels; /* show column labels */
1.6 denny 59: int show_quick; /* quick, names only */
1.1 deraadt 60:
1.10 deraadt 61: #define NAME_WIDTH 8
1.19 otto 62: #define HOST_WIDTH 45
63:
64: int hostwidth = HOST_WIDTH;
1.21 semarie 65: char *mytty;
1.10 deraadt 66:
1.1 deraadt 67: int
1.16 deraadt 68: main(int argc, char *argv[])
1.1 deraadt 69: {
70: struct utmp usr;
1.5 flipk 71: FILE *ufp;
1.21 semarie 72: char *t;
1.1 deraadt 73: int c;
74:
1.5 flipk 75: setlocale(LC_ALL, "");
76:
1.24 ! deraadt 77: if (pledge("stdio rpath getpw tty", NULL) == -1)
1.23 deraadt 78: err(1, "pledge");
1.21 semarie 79:
80: mytty = ttyname(0);
81: /* strip any directory component */
82: if ((t = strrchr(mytty, '/')))
83: mytty = t + 1;
84:
1.5 flipk 85: only_current_term = show_term = show_idle = show_labels = 0;
1.6 denny 86: show_quick = 0;
87: while ((c = getopt(argc, argv, "HmqTu")) != -1) {
1.1 deraadt 88: switch (c) {
1.6 denny 89: case 'H':
90: show_labels = 1;
91: break;
1.1 deraadt 92: case 'm':
93: only_current_term = 1;
94: break;
1.6 denny 95: case 'q':
96: show_quick = 1;
97: break;
1.1 deraadt 98: case 'T':
99: show_term = 1;
100: break;
101: case 'u':
102: show_idle = 1;
103: break;
104: default:
105: usage();
106: /* NOTREACHED */
107: }
108: }
109: argc -= optind;
110: argv += optind;
111:
1.6 denny 112: if (show_quick) {
113: only_current_term = show_term = show_idle = show_labels = 0;
114: }
1.19 otto 115:
116: if (show_term)
117: hostwidth -= 2;
118: if (show_idle)
119: hostwidth -= 6;
1.6 denny 120:
1.5 flipk 121: if (show_labels)
122: output_labels();
123:
1.1 deraadt 124: switch (argc) {
125: case 0: /* who */
126: ufp = file(_PATH_UTMP);
127:
128: if (only_current_term) {
129: who_am_i(ufp);
1.6 denny 130: } else if (show_quick) {
131: int count = 0;
132:
133: while (fread((char *)&usr, sizeof(usr), 1, ufp) == 1) {
134: if (*usr.ut_name && *usr.ut_line) {
1.10 deraadt 135: (void)printf("%-*.*s ", NAME_WIDTH,
1.6 denny 136: UT_NAMESIZE, usr.ut_name);
137: if ((++count % 8) == 0)
138: (void) printf("\n");
139: }
140: }
141: if (count % 8)
142: (void) printf("\n");
143: (void) printf ("# users=%d\n", count);
1.1 deraadt 144: } else {
145: /* only entries with both name and line fields */
146: while (fread((char *)&usr, sizeof(usr), 1, ufp) == 1)
147: if (*usr.ut_name && *usr.ut_line)
148: output(&usr);
149: }
150: break;
151: case 1: /* who utmp_file */
152: ufp = file(*argv);
153:
154: if (only_current_term) {
155: who_am_i(ufp);
1.6 denny 156: } else if (show_quick) {
157: int count = 0;
158:
159: while (fread((char *)&usr, sizeof(usr), 1, ufp) == 1) {
160: if (*usr.ut_name && *usr.ut_line) {
1.10 deraadt 161: (void)printf("%-*.*s ", NAME_WIDTH,
1.6 denny 162: UT_NAMESIZE, usr.ut_name);
163: if ((++count % 8) == 0)
164: (void) printf("\n");
165: }
166: }
167: if (count % 8)
168: (void) printf("\n");
169: (void) printf ("# users=%d\n", count);
1.1 deraadt 170: } else {
171: /* all entries */
172: while (fread((char *)&usr, sizeof(usr), 1, ufp) == 1)
173: output(&usr);
174: }
175: break;
176: case 2: /* who am i */
177: ufp = file(_PATH_UTMP);
178: who_am_i(ufp);
179: break;
180: default:
181: usage();
182: /* NOTREACHED */
183: }
184: exit(0);
185: }
186:
187: void
1.16 deraadt 188: who_am_i(FILE *ufp)
1.1 deraadt 189: {
190: struct utmp usr;
191: struct passwd *pw;
192:
193: /* search through the utmp and find an entry for this tty */
1.21 semarie 194: if (mytty) {
1.1 deraadt 195: while (fread((char *)&usr, sizeof(usr), 1, ufp) == 1)
1.21 semarie 196: if (*usr.ut_name && !strcmp(usr.ut_line, mytty)) {
1.1 deraadt 197: output(&usr);
198: return;
199: }
200: /* well, at least we know what the tty is */
1.21 semarie 201: (void)strncpy(usr.ut_line, mytty, UT_LINESIZE);
1.1 deraadt 202: } else
1.13 deraadt 203: (void)strncpy(usr.ut_line, "tty??", UT_LINESIZE);
1.1 deraadt 204:
205: pw = getpwuid(getuid());
206: (void)strncpy(usr.ut_name, pw ? pw->pw_name : "?", UT_NAMESIZE);
207: (void)time(&usr.ut_time);
208: *usr.ut_host = '\0';
209: output(&usr);
210: }
211:
212: void
1.16 deraadt 213: output(struct utmp *up)
1.1 deraadt 214: {
215: struct stat sb;
1.9 millert 216: char line[sizeof(_PATH_DEV) + sizeof (up->ut_line)];
1.5 flipk 217: char state = '?';
1.1 deraadt 218: static time_t now = 0;
1.5 flipk 219: time_t idle = 0;
1.1 deraadt 220:
221: if (show_term || show_idle) {
222: if (now == 0)
223: time(&now);
224:
1.14 deraadt 225: memset(line, 0, sizeof line);
226: strlcpy(line, _PATH_DEV, sizeof line);
227: strlcat(line, up->ut_line, sizeof line);
1.1 deraadt 228:
229: if (stat(line, &sb) == 0) {
230: state = (sb.st_mode & 020) ? '+' : '-';
231: idle = now - sb.st_atime;
232: } else {
233: state = '?';
234: idle = 0;
235: }
236:
237: }
238:
1.10 deraadt 239: (void)printf("%-*.*s ", NAME_WIDTH, UT_NAMESIZE, up->ut_name);
1.1 deraadt 240:
241: if (show_term) {
242: (void)printf("%c ", state);
243: }
244:
245: (void)printf("%-*.*s ", UT_LINESIZE, UT_LINESIZE, up->ut_line);
246: (void)printf("%.12s ", ctime(&up->ut_time) + 4);
247:
248: if (show_idle) {
249: if (idle < 60)
250: (void)printf(" . ");
251: else if (idle < (24 * 60 * 60))
252: (void)printf("%02d:%02d ",
1.20 guenther 253: ((int)idle / (60 * 60)),
254: ((int)idle % (60 * 60)) / 60);
1.1 deraadt 255: else
256: (void)printf(" old ");
257: }
258:
259: if (*up->ut_host)
1.19 otto 260: printf(" (%.*s)", hostwidth, up->ut_host);
1.1 deraadt 261: (void)putchar('\n');
262: }
263:
1.5 flipk 264: void
1.16 deraadt 265: output_labels(void)
1.5 flipk 266: {
1.10 deraadt 267: (void)printf("%-*.*s ", NAME_WIDTH, UT_NAMESIZE, "USER");
1.5 flipk 268:
269: if (show_term)
270: (void)printf("S ");
271:
272: (void)printf("%-*.*s ", UT_LINESIZE, UT_LINESIZE, "LINE");
273: (void)printf("WHEN ");
274:
275: if (show_idle)
276: (void)printf("IDLE ");
277:
1.19 otto 278: (void)printf(" %.*s", hostwidth, "FROM");
1.5 flipk 279:
280: (void)putchar('\n');
281: }
282:
1.1 deraadt 283: FILE *
1.16 deraadt 284: file(char *name)
1.1 deraadt 285: {
286: FILE *ufp;
287:
288: if (!(ufp = fopen(name, "r"))) {
289: err(1, "%s", name);
290: /* NOTREACHED */
1.21 semarie 291: }
292: if (show_term || show_idle) {
1.24 ! deraadt 293: if (pledge("stdio rpath getpw", NULL) == -1)
1.23 deraadt 294: err(1, "pledge");
1.21 semarie 295: } else {
1.23 deraadt 296: if (pledge("stdio getpw", NULL) == -1)
297: err(1, "pledge");
1.1 deraadt 298: }
299: return(ufp);
300: }
301:
302: void
1.16 deraadt 303: usage(void)
1.1 deraadt 304: {
1.17 jmc 305: (void)fprintf(stderr, "usage: who [-HmqTu] [file]\n who am i\n");
1.1 deraadt 306: exit(1);
307: }