|
|
1.1 root 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: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.