Commit | Line | Data |
---|---|---|
583da166 | 1 | static char *sccsid = "@(#)lastcomm.c 4.4 (Berkeley) 82/07/17"; |
c7eeef87 BJ |
2 | |
3 | /* | |
4 | * last command | |
5 | */ | |
6 | ||
7 | # include <stdio.h> | |
583da166 | 8 | # include <sys/param.h> |
c7eeef87 | 9 | # include <sys/acct.h> |
583da166 | 10 | # include <sys/dir.h> |
c7eeef87 BJ |
11 | # include <signal.h> |
12 | # include <pwd.h> | |
13 | # include <stat.h> | |
583da166 RE |
14 | # include <utmp.h> |
15 | # include <struct.h> | |
c7eeef87 | 16 | |
583da166 RE |
17 | # define N_USER 4000 /* highest alloc user # */ |
18 | # define N_DEVS 43 /* hash value for device names */ | |
19 | # define NDEVS 500 /* max number of file names in /dev */ | |
c7eeef87 BJ |
20 | |
21 | struct acct acct_buff [BUFSIZ / sizeof (struct acct)]; | |
22 | ||
583da166 | 23 | char user_list [N_USER][fldsiz(utmp, ut_name) + 1]; |
c7eeef87 | 24 | |
583da166 RE |
25 | struct devhash { |
26 | dev_t dev_dev; | |
27 | char dev_name [fldsiz(utmp, ut_line) + 1]; | |
28 | struct devhash * dev_nxt; | |
29 | } | |
30 | * dev_hash [ N_DEVS ], | |
31 | * dev_chain ; | |
32 | # define HASH(d) (((int) d) % N_DEVS) | |
c7eeef87 BJ |
33 | |
34 | time_t expand (); | |
583da166 RE |
35 | char * flagbits(); |
36 | char * tername(); | |
c7eeef87 BJ |
37 | |
38 | struct passwd | |
39 | *passwd, | |
40 | *getpwent (); | |
41 | ||
42 | struct stat stat_buff; | |
43 | ||
583da166 RE |
44 | # define equal(a, b) (strcmp(a, b) == 0) |
45 | ||
c7eeef87 BJ |
46 | main (argc, argv) |
47 | char **argv; | |
48 | { | |
49 | char acct_desc, | |
50 | *p; | |
51 | ||
52 | long i, | |
53 | j, | |
54 | i_block, | |
55 | n_blocks, | |
56 | n_byte, | |
57 | n_entry; | |
58 | ||
59 | float x; | |
60 | ||
61 | /* | |
62 | * set up user names | |
63 | */ | |
64 | while (passwd = getpwent ()) | |
65 | { | |
41b37529 | 66 | if (user_list[passwd->pw_uid][0]==0) |
a2d7fa08 | 67 | move (passwd->pw_name, user_list [passwd->pw_uid]); |
c7eeef87 BJ |
68 | } |
69 | ||
583da166 RE |
70 | /* |
71 | * find dev numbers corresponding to names in /dev | |
72 | */ | |
73 | setupdevs(); | |
74 | ||
c7eeef87 BJ |
75 | acct_desc = open ("/usr/adm/acct", 0); |
76 | if (acct_desc < 0) | |
77 | { | |
78 | perror ("/usr/adm/acct"); | |
79 | return; | |
80 | } | |
81 | fstat (acct_desc, &stat_buff); | |
82 | n_blocks = (stat_buff.st_size + BUFSIZ - 1) / BUFSIZ; | |
83 | ||
84 | /* | |
85 | * read one block's worth | |
86 | */ | |
87 | for (i_block = n_blocks - 1; i_block >= 0; i_block--) | |
88 | { | |
89 | lseek (acct_desc, i_block * BUFSIZ, 0); | |
90 | n_byte = read (acct_desc, acct_buff, BUFSIZ); | |
91 | n_entry = n_byte / sizeof acct_buff [0]; | |
92 | for (i = n_entry - 1; i >= 0; i--) | |
93 | { | |
583da166 RE |
94 | if (!*user_list [acct_buff [i].ac_uid]) |
95 | continue; | |
c7eeef87 BJ |
96 | /* |
97 | * get the times | |
98 | */ | |
99 | x = expand (acct_buff [i].ac_utime) | |
100 | + | |
101 | expand (acct_buff [i].ac_stime); | |
102 | /* | |
103 | * null terminate the command name | |
104 | */ | |
105 | acct_buff [i].ac_comm [10] = 0; | |
106 | /* | |
107 | * replace missing command names with question marks | |
108 | */ | |
109 | if (!*acct_buff [i].ac_comm) | |
110 | { | |
111 | move ("?", acct_buff [i].ac_comm); | |
112 | } | |
113 | /* | |
114 | * replace control characters with question marks | |
115 | */ | |
116 | for (p = acct_buff [i].ac_comm; *p; p++) | |
117 | { | |
583da166 RE |
118 | if (*p < '!' || '~' < *p) |
119 | *p = '?'; | |
c7eeef87 BJ |
120 | } |
121 | for (j = 1; j < argc; j++) | |
122 | { | |
123 | if | |
124 | ( | |
125 | equal (acct_buff [i].ac_comm, argv [j]) | |
126 | || | |
127 | equal | |
128 | ( | |
583da166 | 129 | user_list[acct_buff[i].ac_uid], |
c7eeef87 BJ |
130 | argv [j] |
131 | ) | |
583da166 RE |
132 | || |
133 | equal | |
134 | ( | |
135 | tername(acct_buff[i].ac_tty), | |
136 | argv[j] | |
137 | ) | |
c7eeef87 BJ |
138 | ) |
139 | { | |
140 | break; | |
141 | } | |
142 | } | |
143 | if (argc == 1 || j != argc) | |
144 | { | |
145 | printf | |
146 | ( | |
583da166 RE |
147 | "%-*s %s %-*s %-*s %6.2f %.16s\n" |
148 | , fldsiz(acct, ac_comm) | |
149 | , acct_buff [i].ac_comm | |
150 | , flagbits(acct_buff [i].ac_flag) | |
151 | , fldsiz(utmp, ut_name) | |
152 | , user_list [acct_buff [i].ac_uid] | |
153 | , fldsiz(utmp, ut_line) | |
154 | , tername(acct_buff [i].ac_tty) | |
155 | , x / 60.0 | |
156 | , ctime (&acct_buff [i].ac_btime) | |
c7eeef87 BJ |
157 | ); |
158 | } | |
159 | } | |
160 | } | |
161 | } | |
162 | ||
163 | time_t | |
164 | expand (t) | |
165 | unsigned t; | |
166 | { | |
167 | register time_t nt; | |
168 | ||
169 | nt = t & 017777; | |
170 | t >>= 13; | |
171 | while (t) | |
172 | { | |
173 | t--; | |
174 | nt <<= 3; | |
175 | } | |
176 | return (nt); | |
177 | } | |
178 | ||
179 | move (a, b) | |
180 | char *a, *b; | |
181 | { | |
583da166 RE |
182 | while (*b++ = *a++) |
183 | ; | |
c7eeef87 BJ |
184 | } |
185 | ||
583da166 RE |
186 | char * |
187 | flagbits(f) | |
188 | register int f; | |
c7eeef87 | 189 | { |
583da166 RE |
190 | register int i = 0; |
191 | static char flags[20]; | |
192 | ||
193 | # define BIT(flag, ch) flags[i++] = ( f & flag ) ? ch : ' ' | |
194 | ||
195 | BIT( ASU, 'S'); | |
196 | BIT( AFORK, 'F'); | |
197 | BIT( ACOMPAT, 'C'); | |
198 | BIT( ACORE, 'D'); | |
199 | BIT( AXSIG, 'X'); | |
200 | ||
201 | flags[i] = '\0'; | |
202 | ||
203 | return(flags); | |
204 | } | |
205 | ||
206 | setupdevs() | |
207 | { | |
208 | register DIR * fd; | |
209 | register struct devhash * hashtab; | |
210 | register ndevs = NDEVS; | |
211 | struct direct * dp; | |
212 | ||
213 | if ((fd = opendir("/dev")) == NULL) { | |
214 | perror("/dev"); | |
215 | return; | |
216 | } | |
217 | ||
218 | if ((hashtab = (struct devhash *)malloc(NDEVS * sizeof(struct devhash))) | |
219 | == (struct devhash *) 0) { | |
220 | fprintf(stderr, "No mem for dev table\n"); | |
221 | return; | |
222 | } | |
223 | ||
224 | while (dp = readdir(fd)) { | |
225 | if (dp->d_ino == 0) | |
226 | continue; | |
227 | #ifdef MELB | |
228 | if (dp->d_name[0] != 't' && strcmp(dp->d_name, "console")) | |
229 | continue; | |
230 | #endif | |
231 | strncpy(hashtab->dev_name, dp->d_name, fldsiz(utmp, ut_line)); | |
232 | hashtab->dev_name[fldsiz(utmp, ut_line)] = 0; | |
233 | hashtab->dev_nxt = dev_chain; | |
234 | dev_chain = hashtab; | |
235 | hashtab++; | |
236 | if (--ndevs <= 0) | |
237 | break; | |
238 | } | |
239 | closedir(fd); | |
240 | } | |
241 | ||
242 | char * | |
243 | tername(dev) | |
244 | dev_t dev; | |
245 | { | |
246 | register struct devhash *hp, *nhp; | |
247 | struct stat statb; | |
248 | char name [fldsiz(devhash, dev_name) + 6]; | |
249 | static dev_t lastdev = (dev_t) -1; | |
250 | static char *lastname; | |
251 | ||
252 | if (dev == NODEV) | |
253 | return("__"); | |
254 | ||
255 | if (dev == lastdev) | |
256 | return(lastname); | |
257 | ||
258 | for (hp = dev_hash[HASH(dev)]; hp; hp = hp->dev_nxt) | |
259 | if (hp->dev_dev == dev) { | |
260 | lastdev = dev; | |
261 | return(lastname = hp->dev_name); | |
262 | } | |
263 | ||
264 | for (hp = dev_chain; hp; hp = nhp) { | |
265 | nhp = hp->dev_nxt; | |
266 | strcpy(name, "/dev/"); | |
267 | strcat(name, hp->dev_name); | |
268 | if (stat(name, &statb) < 0) /* name truncated usually */ | |
269 | continue; | |
270 | if ((statb.st_mode & S_IFMT) != S_IFCHR) | |
271 | continue; | |
272 | hp->dev_dev = statb.st_rdev; | |
273 | hp->dev_nxt = dev_hash[HASH(hp->dev_dev)]; | |
274 | dev_hash[HASH(hp->dev_dev)] = hp; | |
275 | if (hp->dev_dev == dev) { | |
276 | dev_chain = nhp; | |
277 | lastdev = dev; | |
278 | return(lastname = hp->dev_name); | |
279 | } | |
c7eeef87 | 280 | } |
583da166 RE |
281 | |
282 | dev_chain = (struct devhash *) 0; | |
283 | return("??"); | |
c7eeef87 | 284 | } |