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