Commit | Line | Data |
---|---|---|
9fa3fcf1 HK |
1 | /* Copyright (c) 1979 Regents of the University of California */ |
2 | # | |
3 | /* | |
4 | * NAME: last | |
5 | * | |
6 | * SYNOPSIS: last [list] | |
7 | * | |
8 | * DESCRIPTION: Displays login history of named users or tty's. | |
9 | * Last with no argument prints history for all users. | |
10 | * | |
11 | * EXTERNAL ROUTINES USED: bread.c blseek.c | |
12 | * | |
13 | * AUTHOR - Howard P. Katseff | |
14 | */ | |
15 | ||
16 | # include <sys/types.h> | |
17 | # include <stdio.h> | |
18 | # include <sys/stat.h> | |
19 | # include <utmp.h> | |
20 | ||
21 | char yes = 1, | |
22 | no = 0, | |
23 | ||
24 | *wtmp = "/usr/adm/wtmp", | |
25 | b [512], | |
26 | ||
27 | Arg [25] [9], | |
28 | tty_names [48] [9], | |
29 | ||
30 | *ctime (), | |
31 | *move (), | |
32 | *rmchar (); | |
33 | ||
34 | ||
35 | long logouts [48]; | |
36 | ||
37 | struct utmp buf; | |
38 | ||
39 | main (argc, argv) | |
40 | char **argv; | |
41 | { | |
42 | char f, | |
43 | narg, | |
44 | ||
45 | *bend, | |
46 | *p, | |
47 | *q; | |
48 | ||
49 | short i, | |
50 | nbyte; | |
51 | ||
52 | int lx, | |
53 | ntime, | |
54 | otime, | |
55 | ||
56 | intrp (); | |
57 | ||
58 | struct stat sbuf; | |
59 | ||
60 | for (i = 1; i < argc; i++) | |
61 | { | |
62 | if | |
63 | ( | |
64 | length (argv [i]) > 2 /* long tty or user name */ | |
65 | || | |
66 | equal (argv [i], "~") /* tilde */ | |
67 | || | |
68 | getpwnam (argv [i]) /* user name */ | |
69 | ) | |
70 | { | |
71 | move (argv [i], Arg [narg++]); | |
72 | } | |
73 | else /* short tty name */ | |
74 | { | |
75 | move (argv [i], move ("tty", Arg [narg++])); | |
76 | } | |
77 | } | |
78 | f = open (wtmp, 0); | |
79 | if (f < 0) | |
80 | { | |
81 | perror (wtmp); | |
82 | fflush (stdout); | |
83 | exit (); | |
84 | } | |
85 | if (fstat (f, &sbuf) < 0) | |
86 | { | |
87 | perror ("/usr/adm/wtmp"); | |
88 | fflush (stdout); | |
89 | exit (); | |
90 | } | |
91 | lx = sbuf.st_size; | |
92 | blseek (f, lx, 0); | |
93 | lx -= sizeof buf; | |
94 | signal (2, intrp); | |
95 | for (;;) /* the large loop */ | |
96 | { | |
97 | if (lx < sizeof buf) | |
98 | { | |
99 | q = ctime (&buf.ut_time); | |
100 | printf | |
101 | ( | |
102 | "\nwtmp begins %10.10s %5.5s \n", | |
103 | q, q + 11 | |
104 | ); | |
105 | fflush (stdout); | |
106 | exit (); | |
107 | } | |
108 | /* | |
109 | * read the next login-logout record | |
110 | */ | |
111 | if (bread (f, &buf+1, -sizeof buf) < sizeof buf) | |
112 | { | |
113 | perror ("impossible error\n"); | |
114 | exit (); | |
115 | } | |
116 | if (should_print ()) | |
117 | { | |
118 | q = ctime (&buf.ut_time); | |
119 | printf | |
120 | ( | |
121 | "%-8.8s %-8.8s %10.10s %5.5s ", | |
122 | buf.ut_name, buf.ut_line, q, 11+q | |
123 | ); | |
124 | otime = buf.ut_time; | |
125 | /* | |
126 | * look up the logout time for the tty | |
127 | */ | |
128 | for (i = 0;; i++) | |
129 | { | |
130 | if (!*tty_names [i]) | |
131 | { /* not in the table, therefore add it */ | |
132 | move (buf.ut_line, tty_names [i]); | |
133 | ntime = 0; | |
134 | break; | |
135 | } | |
136 | if (equal (tty_names [i], buf.ut_line)) | |
137 | { | |
138 | ntime = logouts [i]; | |
139 | break; | |
140 | } | |
141 | } | |
142 | if (ntime == 0) | |
143 | { | |
144 | printf (" still logged in\n"); | |
145 | } | |
146 | else | |
147 | { | |
148 | if (ntime < 0) | |
149 | { | |
150 | ntime = -ntime; | |
151 | printf ("- crash"); | |
152 | } | |
153 | else | |
154 | { | |
155 | printf ("- %5.5s", ctime (&ntime) + 11); | |
156 | } | |
157 | /* | |
158 | * calculate how long logged in | |
159 | */ | |
160 | otime = ntime - otime; | |
161 | otime += 231220830 + 10800; | |
162 | if (otime < 231220830 + 86400 + 10800) | |
163 | { | |
164 | printf | |
165 | ( | |
166 | " (%5.5s)\n", | |
167 | ctime (&otime) + 11 | |
168 | ); | |
169 | } | |
170 | else | |
171 | { | |
172 | printf | |
173 | ( | |
174 | " (%ld+%5.5s)\n", | |
175 | (otime - | |
176 | (231330830-86400-10800))/86400, | |
177 | ctime (&otime) + 11 | |
178 | ); | |
179 | } | |
180 | } | |
181 | fflush (stdout); | |
182 | } | |
183 | lx -= sizeof buf; | |
184 | if (equal (buf.ut_line, "~")) | |
185 | { | |
186 | for (i = 0; *tty_names [i]; i++) | |
187 | { | |
188 | logouts [i] = -buf.ut_time; | |
189 | } | |
190 | } | |
191 | else | |
192 | { | |
193 | for (i = 0;; i++) | |
194 | { | |
195 | if (!*tty_names [i]) | |
196 | { | |
197 | move (buf.ut_line, tty_names [i]); | |
198 | break; | |
199 | } | |
200 | if (equal (tty_names [i], buf.ut_line)) | |
201 | { | |
202 | logouts [i] = buf.ut_time; | |
203 | break; | |
204 | } | |
205 | } | |
206 | } | |
207 | } | |
208 | } | |
209 | ||
210 | equal (a, b) | |
211 | char *a, *b; | |
212 | { | |
213 | char i; | |
214 | ||
215 | for (i = 0; i < 8; i++) | |
216 | { | |
217 | if (!*a) return (!*b); | |
218 | if (*a++ != *b++) return (0); | |
219 | } | |
220 | return (1); | |
221 | } | |
222 | ||
223 | ||
224 | intrp () | |
225 | { | |
226 | char *q; | |
227 | ||
228 | signal (2, 1); /* ignore further interrupts */ | |
229 | q = ctime (&buf.ut_time); | |
230 | printf | |
231 | ( | |
232 | "\ninterrupted %10.10s %5.5s \n", | |
233 | q, q + 11 | |
234 | ); | |
235 | exit (); | |
236 | } | |
237 | ||
238 | /* | |
239 | * NAMES: | |
240 | * bread (), brseek (), blseek () | |
241 | * | |
242 | * DESCRIPTION: | |
243 | * This is a buffered read package which simulates | |
244 | * read (), lseek () and lseek (). | |
245 | * | |
246 | * Bread may be called with a negative nbytes which causes it to | |
247 | * read backwards. In this case, buffer should point to the first | |
248 | * byte following the buffer. If only a partial read is possible | |
249 | * (due to beginning of file), only the last bytes of the buffer | |
250 | * will be filled. | |
251 | */ | |
252 | ||
253 | char *next; | |
254 | ||
255 | int nl, nr, i, j, k; | |
256 | ||
257 | bread (file, buff, nbytes) | |
258 | char *buff; | |
259 | { | |
260 | register nb; | |
261 | ||
262 | if (nbytes > 0) | |
263 | { | |
264 | for (nb = nbytes; nb > 0; nb--) | |
265 | { | |
266 | if (!nr) | |
267 | { | |
268 | nr = read (file, next=b, 512); | |
269 | nl = 0; | |
270 | if (nr < 0) return (-1); | |
271 | if (nr == 0) return (nbytes - nb); | |
272 | } | |
273 | *buff++ = *next++; | |
274 | nl++; | |
275 | nr--; | |
276 | } | |
277 | } | |
278 | else | |
279 | { | |
280 | nbytes = -nbytes; | |
281 | for (nb = nbytes; nb > 0; nb--) | |
282 | { | |
283 | if (!nl) | |
284 | { | |
285 | lseek (file, (long) - (512 + nr), 1); | |
286 | nl = read (file, b, 512); | |
287 | if (nl < 0) | |
288 | { | |
289 | for (k = 511; k > 0; k--) | |
290 | { | |
291 | lseek (file, (long) 1, 1); | |
292 | nl = read (file, b, k); | |
293 | if (nl >= 0) break; | |
294 | } | |
295 | if (nl < 0) return (nbytes-nb); | |
296 | } | |
297 | if (nl == 0) return (nbytes-nb); | |
298 | next = b + nl; | |
299 | nr = 0; | |
300 | } | |
301 | *--buff = *--next; | |
302 | nr++; | |
303 | nl--; | |
304 | } | |
305 | } | |
306 | return (nbytes); | |
307 | } | |
308 | ||
309 | brseek (file, offset, flag) | |
310 | { | |
311 | nl = nr = 0; | |
312 | return (lseek (file, (long) offset, flag)); | |
313 | } | |
314 | ||
315 | blseek (file, offset, flag) | |
316 | long offset; | |
317 | { | |
318 | nl = nr = 0; | |
319 | return (lseek (file, offset, flag)); | |
320 | } | |
321 | ||
322 | char * | |
323 | rmchar (c, s) | |
324 | char c, *s; | |
325 | { | |
326 | for (; *s; s++) | |
327 | { | |
328 | if (*s == c) | |
329 | { | |
330 | *s = 0; | |
331 | return (s); | |
332 | } | |
333 | } | |
334 | return (0); | |
335 | } | |
336 | ||
337 | length (a) | |
338 | char *a; | |
339 | { | |
340 | char *b; | |
341 | ||
342 | for (b = a; *b; b++); | |
343 | return (b - a); | |
344 | } | |
345 | ||
346 | char * | |
347 | move (a, b) | |
348 | char *a, *b; | |
349 | { | |
350 | while (*b++ = *a++); | |
351 | return (b - 1); | |
352 | } | |
353 | ||
354 | should_print () | |
355 | { | |
356 | char i; | |
357 | ||
358 | if (buf.ut_name [0] == no) return no; /* a logout entry */ | |
359 | if (!**Arg) return yes; | |
360 | for (i = 0; i < *Arg [i]; i++) | |
361 | { | |
362 | if | |
363 | ( | |
364 | equal (Arg [i], buf.ut_name) | |
365 | || | |
366 | equal (Arg [i], buf.ut_line) | |
367 | ) | |
368 | return yes; | |
369 | } | |
370 | return no; | |
371 | } |