Annotation of src/usr.bin/who/who.c, Revision 1.26
1.26 ! naddy 1: /* $OpenBSD: who.c,v 1.25 2015/10/11 23:29:56 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.26 ! naddy 77: if (pledge("stdio rpath getpw", NULL) == -1)
1.23 deraadt 78: err(1, "pledge");
1.21 semarie 79:
1.25 deraadt 80: if (mytty = ttyname(0)) {
81: /* strip any directory component */
82: if ((t = strrchr(mytty, '/')))
83: mytty = t + 1;
84: }
1.21 semarie 85:
1.5 flipk 86: only_current_term = show_term = show_idle = show_labels = 0;
1.6 denny 87: show_quick = 0;
88: while ((c = getopt(argc, argv, "HmqTu")) != -1) {
1.1 deraadt 89: switch (c) {
1.6 denny 90: case 'H':
91: show_labels = 1;
92: break;
1.1 deraadt 93: case 'm':
94: only_current_term = 1;
95: break;
1.6 denny 96: case 'q':
97: show_quick = 1;
98: break;
1.1 deraadt 99: case 'T':
100: show_term = 1;
101: break;
102: case 'u':
103: show_idle = 1;
104: break;
105: default:
106: usage();
107: /* NOTREACHED */
108: }
109: }
110: argc -= optind;
111: argv += optind;
112:
1.6 denny 113: if (show_quick) {
114: only_current_term = show_term = show_idle = show_labels = 0;
115: }
1.19 otto 116:
117: if (show_term)
118: hostwidth -= 2;
119: if (show_idle)
120: hostwidth -= 6;
1.6 denny 121:
1.5 flipk 122: if (show_labels)
123: output_labels();
124:
1.1 deraadt 125: switch (argc) {
126: case 0: /* who */
127: ufp = file(_PATH_UTMP);
128:
129: if (only_current_term) {
130: who_am_i(ufp);
1.6 denny 131: } else if (show_quick) {
132: int count = 0;
133:
134: while (fread((char *)&usr, sizeof(usr), 1, ufp) == 1) {
135: if (*usr.ut_name && *usr.ut_line) {
1.10 deraadt 136: (void)printf("%-*.*s ", NAME_WIDTH,
1.6 denny 137: UT_NAMESIZE, usr.ut_name);
138: if ((++count % 8) == 0)
139: (void) printf("\n");
140: }
141: }
142: if (count % 8)
143: (void) printf("\n");
144: (void) printf ("# users=%d\n", count);
1.1 deraadt 145: } else {
146: /* only entries with both name and line fields */
147: while (fread((char *)&usr, sizeof(usr), 1, ufp) == 1)
148: if (*usr.ut_name && *usr.ut_line)
149: output(&usr);
150: }
151: break;
152: case 1: /* who utmp_file */
153: ufp = file(*argv);
154:
155: if (only_current_term) {
156: who_am_i(ufp);
1.6 denny 157: } else if (show_quick) {
158: int count = 0;
159:
160: while (fread((char *)&usr, sizeof(usr), 1, ufp) == 1) {
161: if (*usr.ut_name && *usr.ut_line) {
1.10 deraadt 162: (void)printf("%-*.*s ", NAME_WIDTH,
1.6 denny 163: UT_NAMESIZE, usr.ut_name);
164: if ((++count % 8) == 0)
165: (void) printf("\n");
166: }
167: }
168: if (count % 8)
169: (void) printf("\n");
170: (void) printf ("# users=%d\n", count);
1.1 deraadt 171: } else {
172: /* all entries */
173: while (fread((char *)&usr, sizeof(usr), 1, ufp) == 1)
174: output(&usr);
175: }
176: break;
177: case 2: /* who am i */
178: ufp = file(_PATH_UTMP);
179: who_am_i(ufp);
180: break;
181: default:
182: usage();
183: /* NOTREACHED */
184: }
185: exit(0);
186: }
187:
188: void
1.16 deraadt 189: who_am_i(FILE *ufp)
1.1 deraadt 190: {
191: struct utmp usr;
192: struct passwd *pw;
193:
194: /* search through the utmp and find an entry for this tty */
1.21 semarie 195: if (mytty) {
1.1 deraadt 196: while (fread((char *)&usr, sizeof(usr), 1, ufp) == 1)
1.21 semarie 197: if (*usr.ut_name && !strcmp(usr.ut_line, mytty)) {
1.1 deraadt 198: output(&usr);
199: return;
200: }
201: /* well, at least we know what the tty is */
1.21 semarie 202: (void)strncpy(usr.ut_line, mytty, UT_LINESIZE);
1.1 deraadt 203: } else
1.13 deraadt 204: (void)strncpy(usr.ut_line, "tty??", UT_LINESIZE);
1.1 deraadt 205:
206: pw = getpwuid(getuid());
207: (void)strncpy(usr.ut_name, pw ? pw->pw_name : "?", UT_NAMESIZE);
208: (void)time(&usr.ut_time);
209: *usr.ut_host = '\0';
210: output(&usr);
211: }
212:
213: void
1.16 deraadt 214: output(struct utmp *up)
1.1 deraadt 215: {
216: struct stat sb;
1.9 millert 217: char line[sizeof(_PATH_DEV) + sizeof (up->ut_line)];
1.5 flipk 218: char state = '?';
1.1 deraadt 219: static time_t now = 0;
1.5 flipk 220: time_t idle = 0;
1.1 deraadt 221:
222: if (show_term || show_idle) {
223: if (now == 0)
224: time(&now);
225:
1.14 deraadt 226: memset(line, 0, sizeof line);
227: strlcpy(line, _PATH_DEV, sizeof line);
228: strlcat(line, up->ut_line, sizeof line);
1.1 deraadt 229:
230: if (stat(line, &sb) == 0) {
231: state = (sb.st_mode & 020) ? '+' : '-';
232: idle = now - sb.st_atime;
233: } else {
234: state = '?';
235: idle = 0;
236: }
237:
238: }
239:
1.10 deraadt 240: (void)printf("%-*.*s ", NAME_WIDTH, UT_NAMESIZE, up->ut_name);
1.1 deraadt 241:
242: if (show_term) {
243: (void)printf("%c ", state);
244: }
245:
246: (void)printf("%-*.*s ", UT_LINESIZE, UT_LINESIZE, up->ut_line);
247: (void)printf("%.12s ", ctime(&up->ut_time) + 4);
248:
249: if (show_idle) {
250: if (idle < 60)
251: (void)printf(" . ");
252: else if (idle < (24 * 60 * 60))
253: (void)printf("%02d:%02d ",
1.20 guenther 254: ((int)idle / (60 * 60)),
255: ((int)idle % (60 * 60)) / 60);
1.1 deraadt 256: else
257: (void)printf(" old ");
258: }
259:
260: if (*up->ut_host)
1.19 otto 261: printf(" (%.*s)", hostwidth, up->ut_host);
1.1 deraadt 262: (void)putchar('\n');
263: }
264:
1.5 flipk 265: void
1.16 deraadt 266: output_labels(void)
1.5 flipk 267: {
1.10 deraadt 268: (void)printf("%-*.*s ", NAME_WIDTH, UT_NAMESIZE, "USER");
1.5 flipk 269:
270: if (show_term)
271: (void)printf("S ");
272:
273: (void)printf("%-*.*s ", UT_LINESIZE, UT_LINESIZE, "LINE");
274: (void)printf("WHEN ");
275:
276: if (show_idle)
277: (void)printf("IDLE ");
278:
1.19 otto 279: (void)printf(" %.*s", hostwidth, "FROM");
1.5 flipk 280:
281: (void)putchar('\n');
282: }
283:
1.1 deraadt 284: FILE *
1.16 deraadt 285: file(char *name)
1.1 deraadt 286: {
287: FILE *ufp;
288:
289: if (!(ufp = fopen(name, "r"))) {
290: err(1, "%s", name);
291: /* NOTREACHED */
1.21 semarie 292: }
293: if (show_term || show_idle) {
1.24 deraadt 294: if (pledge("stdio rpath getpw", NULL) == -1)
1.23 deraadt 295: err(1, "pledge");
1.21 semarie 296: } else {
1.23 deraadt 297: if (pledge("stdio getpw", NULL) == -1)
298: err(1, "pledge");
1.1 deraadt 299: }
300: return(ufp);
301: }
302:
303: void
1.16 deraadt 304: usage(void)
1.1 deraadt 305: {
1.17 jmc 306: (void)fprintf(stderr, "usage: who [-HmqTu] [file]\n who am i\n");
1.1 deraadt 307: exit(1);
308: }