BSD 2 development
[unix-history] / src / last.c
CommitLineData
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
21char 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
35long logouts [48];
36
37struct utmp buf;
38
39main (argc, argv)
40char **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
210equal (a, b)
211char *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
224intrp ()
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
253char *next;
254
255int nl, nr, i, j, k;
256
257bread (file, buff, nbytes)
258char *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
309brseek (file, offset, flag)
310{
311 nl = nr = 0;
312 return (lseek (file, (long) offset, flag));
313}
314
315blseek (file, offset, flag)
316long offset;
317{
318 nl = nr = 0;
319 return (lseek (file, offset, flag));
320}
321
322char *
323rmchar (c, s)
324char 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
337length (a)
338char *a;
339{
340 char *b;
341
342 for (b = a; *b; b++);
343 return (b - a);
344}
345
346char *
347move (a, b)
348char *a, *b;
349{
350 while (*b++ = *a++);
351 return (b - 1);
352}
353
354should_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}