|
|
1.1 root 1: /*
2: * Copyright (c) 1987 Regents of the University of California.
3: * All rights reserved.
4: *
5: * Redistribution and use in source and binary forms are permitted
6: * provided that the above copyright notice and this paragraph are
7: * duplicated in all such forms and that any documentation,
8: * advertising materials, and other materials related to such
9: * distribution and use acknowledge that the software was developed
10: * by the University of California, Berkeley. The name of the
11: * University may not be used to endorse or promote products derived
12: * from this software without specific prior written permission.
13: * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
14: * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
15: * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
16: */
17:
18: #ifndef lint
19: char copyright[] =
20: "@(#) Copyright (c) 1987 Regents of the University of California.\n\
21: All rights reserved.\n";
22: #endif /* not lint */
23:
24: #ifndef lint
25: static char sccsid[] = "@(#)last.c 5.11 (Berkeley) 6/29/88";
26: #endif /* not lint */
27:
28: /*
29: * last
30: */
31: #include <sys/param.h>
32: #include <sys/stat.h>
33: #include <sys/file.h>
34: #include <signal.h>
35: #include <time.h>
36: #include <utmp.h>
37: #include <stdio.h>
38:
39: #define SECDAY (24*60*60) /* seconds in a day */
40: #define NO 0 /* false/no */
41: #define YES 1 /* true/yes */
42:
43: static struct utmp buf[1024]; /* utmp read buffer */
44:
45: #define HMAX sizeof(buf[0].ut_host) /* size of utmp host field */
46: #define LMAX sizeof(buf[0].ut_line) /* size of utmp tty field */
47: #define NMAX sizeof(buf[0].ut_name) /* size of utmp name field */
48:
49: typedef struct arg {
50: char *name; /* argument */
51: #define HOST_TYPE -2
52: #define TTY_TYPE -3
53: #define USER_TYPE -4
54: int type; /* type of arg */
55: struct arg *next; /* linked list pointer */
56: } ARG;
57: ARG *arglist; /* head of linked list */
58:
59: typedef struct ttytab {
60: long logout; /* log out time */
61: char tty[LMAX + 1]; /* terminal name */
62: struct ttytab *next; /* linked list pointer */
63: } TTY;
64: TTY *ttylist; /* head of linked list */
65:
66: static long currentout, /* current logout value */
67: maxrec; /* records to display */
68: static char *file = "/usr/adm/wtmp"; /* wtmp file */
69:
70: main(argc, argv)
71: int argc;
72: char **argv;
73: {
74: extern int optind;
75: extern char *optarg;
76: int ch;
77: long atol();
78: char *ttyconv();
79:
80: while ((ch = getopt(argc, argv, "0123456789f:h:t:")) != EOF)
81: switch((char)ch) {
82: case '0': case '1': case '2': case '3': case '4':
83: case '5': case '6': case '7': case '8': case '9':
84: /*
85: * kludge: last was originally designed to take
86: * a number after a dash.
87: */
88: if (!maxrec)
89: maxrec = atol(argv[optind - 1] + 1);
90: break;
91: case 'f':
92: file = optarg;
93: break;
94: case 'h':
95: hostconv(optarg);
96: addarg(HOST_TYPE, optarg);
97: break;
98: case 't':
99: addarg(TTY_TYPE, ttyconv(optarg));
100: break;
101: case '?':
102: default:
103: fputs("usage: last [-#] [-f file] [-t tty] [-h hostname] [user ...]\n", stderr);
104: exit(1);
105: }
106: for (argv += optind; *argv; ++argv) {
107: #define COMPATIBILITY
108: #ifdef COMPATIBILITY
109: /* code to allow "last p5" to work */
110: addarg(TTY_TYPE, ttyconv(*argv));
111: #endif
112: addarg(USER_TYPE, *argv);
113: }
114: wtmp();
115: exit(0);
116: }
117:
118: /*
119: * wtmp --
120: * read through the wtmp file
121: */
122: static
123: wtmp()
124: {
125: register struct utmp *bp; /* current structure */
126: register TTY *T; /* tty list entry */
127: struct stat stb; /* stat of file for size */
128: long bl, delta, /* time difference */
129: lseek(), time();
130: int bytes, wfd,
131: onintr();
132: char *ct, *crmsg,
133: *asctime(), *ctime(), *strcpy();
134: TTY *addtty();
135:
136: if ((wfd = open(file, O_RDONLY, 0)) < 0 || fstat(wfd, &stb) == -1) {
137: perror(file);
138: exit(1);
139: }
140: bl = (stb.st_size + sizeof(buf) - 1) / sizeof(buf);
141:
142: (void)time(&buf[0].ut_time);
143: (void)signal(SIGINT, onintr);
144: (void)signal(SIGQUIT, onintr);
145:
146: while (--bl >= 0) {
147: if (lseek(wfd, (long)(bl * sizeof(buf)), L_SET) == -1 ||
148: (bytes = read(wfd, (char *)buf, sizeof(buf))) == -1) {
149: fprintf(stderr, "last: %s: ", file);
150: perror((char *)NULL);
151: exit(1);
152: }
153: for (bp = &buf[bytes / sizeof(buf[0]) - 1]; bp >= buf; --bp) {
154: /*
155: * if the terminal line is '~', the machine stopped.
156: * see utmp(5) for more info.
157: */
158: if (!strncmp(bp->ut_line, "~", LMAX)) {
159: /* everybody just logged out */
160: for (T = ttylist; T; T = T->next)
161: T->logout = -bp->ut_time;
162: currentout = -bp->ut_time;
163: crmsg = strncmp(bp->ut_name, "shutdown", NMAX) ? "crash" : "down ";
164: if (!bp->ut_name[0])
165: (void)strcpy(bp->ut_name, "reboot");
166: if (want(bp, NO)) {
167: ct = ctime(&bp->ut_time);
168: printf("%-*.*s %-*.*s %-*.*s %10.10s %5.5s \n", NMAX, NMAX, bp->ut_name, LMAX, LMAX, bp->ut_line, HMAX, HMAX, bp->ut_host, ct, ct + 11);
169: if (maxrec && !--maxrec)
170: return;
171: }
172: continue;
173: }
174: /* find associated tty */
175: for (T = ttylist;; T = T->next) {
176: if (!T) {
177: /* add new one */
178: T = addtty(bp->ut_line);
179: break;
180: }
181: if (!strncmp(T->tty, bp->ut_line, LMAX))
182: break;
183: }
184: if (bp->ut_name[0] && want(bp, YES)) {
185: ct = ctime(&bp->ut_time);
186: printf("%-*.*s %-*.*s %-*.*s %10.10s %5.5s ", NMAX, NMAX, bp->ut_name, LMAX, LMAX, bp->ut_line, HMAX, HMAX, bp->ut_host, ct, ct + 11);
187: if (!T->logout)
188: puts(" still logged in");
189: else {
190: if (T->logout < 0) {
191: T->logout = -T->logout;
192: printf("- %s", crmsg);
193: }
194: else
195: printf("- %5.5s", ctime(&T->logout)+11);
196: delta = T->logout - bp->ut_time;
197: if (delta < SECDAY)
198: printf(" (%5.5s)\n", asctime(gmtime(&delta))+11);
199: else
200: printf(" (%ld+%5.5s)\n", delta / SECDAY, asctime(gmtime(&delta))+11);
201: }
202: if (maxrec != -1 && !--maxrec)
203: return;
204: }
205: T->logout = bp->ut_time;
206: }
207: }
208: ct = ctime(&buf[0].ut_time);
209: printf("\nwtmp begins %10.10s %5.5s \n", ct, ct + 11);
210: }
211:
212: /*
213: * want --
214: * see if want this entry
215: */
216: static
217: want(bp, check)
218: register struct utmp *bp;
219: int check;
220: {
221: register ARG *step;
222:
223: if (check)
224: /*
225: * when uucp and ftp log in over a network, the entry in
226: * the utmp file is the name plus their process id. See
227: * etc/ftpd.c and usr.bin/uucp/uucpd.c for more information.
228: */
229: if (!strncmp(bp->ut_line, "ftp", sizeof("ftp") - 1))
230: bp->ut_line[3] = '\0';
231: else if (!strncmp(bp->ut_line, "uucp", sizeof("uucp") - 1))
232: bp->ut_line[4] = '\0';
233: if (!arglist)
234: return(YES);
235:
236: for (step = arglist; step; step = step->next)
237: switch(step->type) {
238: case HOST_TYPE:
239: if (!strncasecmp(step->name, bp->ut_host, HMAX))
240: return(YES);
241: break;
242: case TTY_TYPE:
243: if (!strncmp(step->name, bp->ut_line, LMAX))
244: return(YES);
245: break;
246: case USER_TYPE:
247: if (!strncmp(step->name, bp->ut_name, NMAX))
248: return(YES);
249: break;
250: }
251: return(NO);
252: }
253:
254: /*
255: * addarg --
256: * add an entry to a linked list of arguments
257: */
258: static
259: addarg(type, arg)
260: int type;
261: char *arg;
262: {
263: register ARG *cur;
264: char *malloc();
265:
266: if (!(cur = (ARG *)malloc((u_int)sizeof(ARG)))) {
267: fputs("last: malloc failure.\n", stderr);
268: exit(1);
269: }
270: cur->next = arglist;
271: cur->type = type;
272: cur->name = arg;
273: arglist = cur;
274: }
275:
276: /*
277: * addtty --
278: * add an entry to a linked list of ttys
279: */
280: static TTY *
281: addtty(ttyname)
282: char *ttyname;
283: {
284: register TTY *cur;
285: char *malloc();
286:
287: if (!(cur = (TTY *)malloc((u_int)sizeof(TTY)))) {
288: fputs("last: malloc failure.\n", stderr);
289: exit(1);
290: }
291: cur->next = ttylist;
292: cur->logout = currentout;
293: bcopy(ttyname, cur->tty, LMAX);
294: return(ttylist = cur);
295: }
296:
297: /*
298: * hostconv --
299: * convert the hostname to search pattern; if the supplied host name
300: * has a domain attached that is the same as the current domain, rip
301: * off the domain suffix since that's what login(1) does.
302: */
303: static
304: hostconv(arg)
305: char *arg;
306: {
307: static int first = 1;
308: static char *hostdot,
309: name[MAXHOSTNAMELEN];
310: char *argdot, *index();
311:
312: if (!(argdot = index(arg, '.')))
313: return;
314: if (first) {
315: first = 0;
316: if (gethostname(name, sizeof(name))) {
317: perror("last: gethostname");
318: exit(1);
319: }
320: hostdot = index(name, '.');
321: }
322: if (hostdot && !strcasecmp(hostdot, argdot))
323: *argdot = '\0';
324: }
325:
326: /*
327: * ttyconv --
328: * convert tty to correct name.
329: */
330: static char *
331: ttyconv(arg)
332: char *arg;
333: {
334: char *mval,
335: *malloc(), *strcpy();
336:
337: /*
338: * kludge -- we assume that all tty's end with
339: * a two character suffix.
340: */
341: if (strlen(arg) == 2) {
342: /* either 6 for "ttyxx" or 8 for "console" */
343: if (!(mval = malloc((u_int)8))) {
344: fputs("last: malloc failure.\n", stderr);
345: exit(1);
346: }
347: if (!strcmp(arg, "co"))
348: (void)strcpy(mval, "console");
349: else {
350: (void)strcpy(mval, "tty");
351: (void)strcpy(mval + 3, arg);
352: }
353: return(mval);
354: }
355: if (!strncmp(arg, "/dev/", sizeof("/dev/") - 1))
356: return(arg + 5);
357: return(arg);
358: }
359:
360: /*
361: * onintr --
362: * on interrupt, we inform the user how far we've gotten
363: */
364: static
365: onintr(signo)
366: int signo;
367: {
368: char *ct, *ctime();
369:
370: ct = ctime(&buf[0].ut_time);
371: printf("\ninterrupted %10.10s %5.5s \n", ct, ct + 11);
372: if (signo == SIGINT)
373: exit(1);
374: (void)fflush(stdout); /* fix required for rsh */
375: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.