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