Commit | Line | Data |
---|---|---|
dfbdb50f HK |
1 | # |
2 | /* | |
3 | * NAME: last | |
4 | * | |
5 | * SYNOPSIS: last [list] | |
6 | * | |
7 | * DESCRIPTION: Displays login history of named users or tty's. | |
8 | * Last with no argument prints history for all users. | |
9 | * | |
10 | * AUTHOR - Howard P. Katseff | |
11 | */ | |
12 | ||
13 | # include <sys/types.h> | |
14 | # include <stdio.h> | |
15 | # include <stat.h> | |
16 | # include <utmp.h> | |
17 | ||
18 | char yes = 1, | |
19 | no = 0, | |
20 | ||
21 | *wtmp = "/usr/adm/wtmp", | |
22 | b [512], | |
23 | ||
24 | Arg [25] [9], | |
25 | tty_names [48] [9], | |
26 | ||
27 | *ctime (), | |
28 | *move (), | |
29 | *rmchar (); | |
30 | ||
31 | ||
32 | long logouts [48], | |
33 | bl, | |
34 | rec, | |
35 | nblock; | |
36 | ||
37 | struct utmp buf [128]; /* buf takes exactly 5 blocks */ | |
38 | ||
39 | main (argc, argv) | |
40 | char **argv; | |
41 | { | |
42 | char f, | |
43 | narg, | |
44 | ||
45 | *bend, | |
46 | *p, | |
47 | *q; | |
48 | ||
49 | short n_byte, | |
50 | n_record; | |
51 | ||
52 | long i, | |
53 | k, | |
54 | ntime, | |
55 | otime, | |
56 | ||
57 | intrp (); | |
58 | ||
59 | struct stat sbuf; | |
60 | ||
61 | for (i = 1; i < argc; i++) | |
62 | { | |
63 | if | |
64 | ( | |
65 | length (argv [i]) > 2 /* long tty or user name */ | |
66 | || | |
67 | equal (argv [i], "~") /* tilde */ | |
68 | || | |
69 | getpwnam (argv [i]) /* user name */ | |
70 | ) | |
71 | { | |
72 | move (argv [i], Arg [narg++]); | |
73 | } | |
74 | else /* short tty name */ | |
75 | { | |
76 | move (argv [i], move ("tty", Arg [narg++])); | |
77 | } | |
78 | } | |
79 | f = open (wtmp, 0); | |
80 | if (f < 0) | |
81 | { | |
82 | perror (wtmp); | |
83 | fflush (stdout); | |
84 | exit (); | |
85 | } | |
86 | if (fstat (f, &sbuf) < 0) | |
87 | { | |
88 | perror ("/usr/adm/wtmp"); | |
89 | fflush (stdout); | |
90 | exit (); | |
91 | } | |
92 | nblock = (sbuf.st_size + 2559) / 2560; | |
93 | signal (2, intrp); | |
94 | for (bl = nblock - 1; bl >= 0; bl--) | |
95 | { | |
96 | lseek (f, bl * 2560, 0); | |
97 | n_byte = read (f, buf, 2560); | |
98 | n_record = n_byte / sizeof buf [0]; | |
99 | for (rec = n_record - 1; rec >= 0; rec--) | |
100 | { | |
101 | ||
102 | if (should_print ()) | |
103 | { | |
104 | q = ctime (&buf[rec].ut_time); | |
105 | printf | |
106 | ( | |
107 | "%-8.8s %-8.8s %10.10s %5.5s ", | |
108 | buf[rec].ut_name, buf[rec].ut_line, q, 11+q | |
109 | ); | |
110 | otime = buf[rec].ut_time; | |
111 | /* | |
112 | * look up the logout time for the tty | |
113 | */ | |
114 | for (i = 0;; i++) | |
115 | { | |
116 | if (!*tty_names [i]) | |
117 | /* not in the table, therefore add it */ | |
118 | { | |
119 | move | |
120 | ( | |
121 | buf[rec].ut_line, | |
122 | tty_names [i] | |
123 | ); | |
124 | ntime = 0; | |
125 | break; | |
126 | } | |
127 | if | |
128 | ( | |
129 | equal | |
130 | ( | |
131 | tty_names [i], | |
132 | buf [rec].ut_line | |
133 | ) | |
134 | ) | |
135 | { | |
136 | ntime = logouts [i]; | |
137 | break; | |
138 | } | |
139 | } | |
140 | if (ntime == 0) | |
141 | { | |
142 | printf (" still logged in\n"); | |
143 | } | |
144 | else | |
145 | { | |
146 | if (ntime < 0) | |
147 | { | |
148 | ntime = -ntime; | |
149 | printf ("- crash"); | |
150 | } | |
151 | else | |
152 | { | |
153 | printf ("- %5.5s", ctime (&ntime) + 11); | |
154 | } | |
155 | /* | |
156 | * calculate how long logged in | |
157 | */ | |
158 | otime = ntime - otime; | |
159 | otime += 231220830 + 10800; | |
160 | if (otime < 231220830 + 86400 + 10800) | |
161 | { | |
162 | printf | |
163 | ( | |
164 | " (%5.5s)\n", | |
165 | ctime (&otime) + 11 | |
166 | ); | |
167 | } | |
168 | else | |
169 | { | |
170 | printf | |
171 | ( | |
172 | " (%ld+%5.5s)\n", | |
173 | (otime - | |
174 | (231330830-86400-10800))/86400, | |
175 | ctime (&otime) + 11 | |
176 | ); | |
177 | } | |
178 | } | |
179 | fflush (stdout); | |
180 | } | |
181 | if | |
182 | ( | |
183 | equal (buf[rec].ut_line, "~") | |
184 | || | |
185 | equal (buf[rec].ut_line, "tty~") | |
186 | ) | |
187 | { | |
188 | for (i = 0; *tty_names [i]; i++) | |
189 | { | |
190 | logouts [i] = -buf[rec].ut_time; | |
191 | } | |
192 | } | |
193 | else | |
194 | { | |
195 | for (k = 0;; k++) | |
196 | { | |
197 | if (!*tty_names [k]) | |
198 | { | |
199 | move | |
200 | ( | |
201 | buf[rec].ut_line, | |
202 | tty_names [k] | |
203 | ); | |
204 | logouts [k] = buf[rec].ut_time; | |
205 | break; | |
206 | } | |
207 | if (equal (tty_names [k], buf[rec].ut_line)) | |
208 | { | |
209 | logouts [k] = buf[rec].ut_time; | |
210 | break; | |
211 | } | |
212 | } | |
213 | } | |
214 | } | |
215 | } | |
216 | q = ctime (&buf [0].ut_time); | |
217 | printf | |
218 | ( | |
219 | "\nwtmp begins %10.10s %5.5s \n", | |
220 | q, q + 11 | |
221 | ); | |
222 | } | |
223 | ||
224 | equal (a, b) | |
225 | char *a, *b; | |
226 | { | |
227 | char i; | |
228 | ||
229 | for (i = 0; i < 8; i++) | |
230 | { | |
231 | if (!*a) return (!*b); | |
232 | if (*a++ != *b++) return (0); | |
233 | } | |
234 | return (1); | |
235 | } | |
236 | ||
237 | ||
238 | intrp () | |
239 | { | |
240 | char *q; | |
241 | ||
242 | signal (2, 1); /* ignore further interrupts */ | |
243 | q = ctime (&buf[rec].ut_time); | |
244 | printf | |
245 | ( | |
246 | "\ninterrupted %10.10s %5.5s \n", | |
247 | q, q + 11 | |
248 | ); | |
249 | exit (); | |
250 | } | |
251 | ||
252 | char * | |
253 | rmchar (c, s) | |
254 | char c, *s; | |
255 | { | |
256 | for (; *s; s++) | |
257 | { | |
258 | if (*s == c) | |
259 | { | |
260 | *s = 0; | |
261 | return (s); | |
262 | } | |
263 | } | |
264 | return (0); | |
265 | } | |
266 | ||
267 | length (a) | |
268 | char *a; | |
269 | { | |
270 | char *b; | |
271 | ||
272 | for (b = a; *b; b++); | |
273 | return (b - a); | |
274 | } | |
275 | ||
276 | char * | |
277 | move (a, b) | |
278 | char *a, *b; | |
279 | { | |
280 | while (*b++ = *a++); | |
281 | return (b - 1); | |
282 | } | |
283 | ||
284 | should_print () | |
285 | { | |
286 | short i; | |
287 | ||
288 | if (buf [rec].ut_name [0] == no) return no; /* a logout entry */ | |
289 | if (!**Arg) return yes; /* no arguments? Print all login entries */ | |
290 | for (i = 0; i < *Arg [i]; i++) | |
291 | { | |
292 | if | |
293 | ( | |
294 | equal (Arg [i], buf[rec].ut_name) | |
295 | || | |
296 | equal (Arg [i], buf[rec].ut_line) | |
297 | ) | |
298 | return yes; | |
299 | } | |
300 | return no; | |
301 | } |