xref: /original-bsd/usr.bin/last/last.c (revision 264c46cb)
1 #ifndef lint
2 static	char *sccsid = "@(#)last.c	4.5 (Berkeley) 05/22/83";
3 #endif
4 
5 /*
6  * last
7  */
8 #include <sys/types.h>
9 #include <stdio.h>
10 #include <signal.h>
11 #include <stat.h>
12 #include <utmp.h>
13 
14 #define NMAX	sizeof(buf[0].ut_name)
15 #define LMAX	sizeof(buf[0].ut_line)
16 #define	HMAX	sizeof(buf[0].ut_host)
17 #define	SECDAY	(24*60*60)
18 
19 #define	lineq(a,b)	(!strncmp(a,b,LMAX))
20 #define	nameq(a,b)	(!strncmp(a,b,NMAX))
21 #define	hosteq(a,b)	(!strncmp(a,b,HMAX))
22 
23 #define MAXTTYS 256
24 
25 char	**argv;
26 int	argc;
27 int	nameargs;
28 
29 struct	utmp buf[128];
30 char	ttnames[MAXTTYS][LMAX+1];
31 long	logouts[MAXTTYS];
32 
33 char	*ctime(), *strspl();
34 int	onintr();
35 
36 main(ac, av)
37 	char **av;
38 {
39 	register int i, k;
40 	int bl, wtmp;
41 	char *ct;
42 	register struct utmp *bp;
43 	long otime;
44 	struct stat stb;
45 	int print;
46 	char * crmsg = (char *)0;
47 	long crtime;
48 	long outrec = 0;
49 	long maxrec = 0x7fffffffL;
50 
51 	time(&buf[0].ut_time);
52 	ac--, av++;
53 	nameargs = argc = ac;
54 	argv = av;
55 	for (i = 0; i < argc; i++) {
56 		if (argv[i][0] == '-' &&
57 		    argv[i][1] >= '0' && argv[i][1] <= '9') {
58 			maxrec = atoi(argv[i]+1);
59 			nameargs--;
60 			continue;
61 		}
62 		if (strlen(argv[i])>2)
63 			continue;
64 		if (!strcmp(argv[i], "~"))
65 			continue;
66 		if (getpwnam(argv[i]))
67 			continue;
68 		argv[i] = strspl("tty", argv[i]);
69 	}
70 	wtmp = open("/usr/adm/wtmp", 0);
71 	if (wtmp < 0) {
72 		perror("/usr/adm/wtmp");
73 		exit(1);
74 	}
75 	fstat(wtmp, &stb);
76 	bl = (stb.st_size + sizeof (buf)-1) / sizeof (buf);
77 	if (signal(SIGINT, SIG_IGN) != SIG_IGN) {
78 		signal(SIGINT, onintr);
79 		signal(SIGQUIT, onintr);
80 	}
81 	for (bl--; bl >= 0; bl--) {
82 		lseek(wtmp, bl * sizeof (buf), 0);
83 		bp = &buf[read(wtmp, buf, sizeof (buf)) / sizeof(buf[0]) - 1];
84 		for ( ; bp >= buf; bp--) {
85 			print = want(bp);
86 			if (print) {
87 				ct = ctime(&bp->ut_time);
88 				printf("%-*.*s  %-*.*s %-*.*s %10.10s %5.5s",
89 				    NMAX, NMAX, bp->ut_name,
90 				    LMAX, LMAX, bp->ut_line,
91 				    HMAX, HMAX, bp->ut_host,
92 				    ct, 11+ct);
93 			}
94 			for (i = 0; i < MAXTTYS; i++) {
95 				if (ttnames[i][0] == 0) {
96 					strncpy(ttnames[i], bp->ut_line,
97 					    sizeof(bp->ut_line));
98 					otime = logouts[i];
99 					logouts[i] = bp->ut_time;
100 					break;
101 				}
102 				if (lineq(ttnames[i], bp->ut_line)) {
103 					otime = logouts[i];
104 					logouts[i] = bp->ut_time;
105 					break;
106 				}
107 			}
108 			if (print) {
109 				if (otime == 0)
110 					printf("  still logged in\n");
111 				else {
112 					long delta;
113 					if (otime < 0) {
114 						otime = -otime;
115 						printf("- %s", crmsg);
116 					} else
117 						printf("- %5.5s",
118 						    ctime(&otime)+11);
119 					delta = otime - bp->ut_time;
120 					if (delta < SECDAY)
121 					    printf("  (%5.5s)\n",
122 						asctime(gmtime(&delta))+11);
123 					else
124 					    printf(" (%ld+%5.5s)\n",
125 						delta / SECDAY,
126 						asctime(gmtime(&delta))+11);
127 				}
128 				fflush(stdout);
129 				if (++outrec >= maxrec)
130 					exit(0);
131 			}
132 			if (lineq(bp->ut_line, "~")) {
133 				for (i = 0; i < MAXTTYS; i++)
134 					logouts[i] = -bp->ut_time;
135 				if (nameq(bp->ut_name, "shutdown"))
136 					crmsg = "down ";
137 				else
138 					crmsg = "crash";
139 			}
140 		}
141 	}
142 	ct = ctime(&buf[0].ut_time);
143 	printf("\nwtmp begins %10.10s %5.5s \n", ct, ct + 11);
144 	exit(0);
145 }
146 
147 onintr(signo)
148 	int signo;
149 {
150 	char *ct;
151 
152 	if (signo == SIGQUIT)
153 		signal(SIGQUIT, onintr);
154 	ct = ctime(&buf[0].ut_time);
155 	printf("\ninterrupted %10.10s %5.5s \n", ct, ct + 11);
156 	if (signo == SIGINT)
157 		exit(1);
158 }
159 
160 want(bp)
161 	struct utmp *bp;
162 {
163 	register char **av;
164 	register int ac;
165 
166 	if (bp->ut_line[0] == '~' && bp->ut_name[0] == '\0')
167 		strcpy(bp->ut_name, "reboot");		/* bandaid */
168 	if (bp->ut_name[0] == 0)
169 		return (0);
170 	if (nameargs == 0)
171 		return (1);
172 	av = argv;
173 	for (ac = 0; ac < argc; ac++, av++) {
174 		if (av[0][0] == '-')
175 			continue;
176 		if (nameq(*av, bp->ut_name) || lineq(*av, bp->ut_line))
177 			return (1);
178 	}
179 	return (0);
180 }
181 
182 char *
183 strspl(left, right)
184 	char *left, *right;
185 {
186 	char *res = (char *)malloc(strlen(left)+strlen(right)+1);
187 
188 	strcpy(res, left);
189 	strcat(res, right);
190 	return (res);
191 }
192