add Berkeley specific copyright
[unix-history] / usr / src / usr.bin / lastcomm / lastcomm.c
CommitLineData
22e155fc
DF
1/*
2 * Copyright (c) 1980 Regents of the University of California.
3 * All rights reserved. The Berkeley software License Agreement
4 * specifies the terms and conditions for redistribution.
5 */
6
7#ifndef lint
8char copyright[] =
9"@(#) Copyright (c) 1980 Regents of the University of California.\n\
10 All rights reserved.\n";
11#endif not lint
12
7f055d32 13#ifndef lint
a41e3d24 14static char sccsid[] = "@(#)lastcomm.c 5.3 (Berkeley) %G%";
22e155fc 15#endif not lint
c7eeef87
BJ
16
17/*
18 * last command
19 */
7f055d32
SL
20#include <sys/param.h>
21#include <sys/acct.h>
cb88b4d5
SL
22#include <sys/file.h>
23
24#include <stdio.h>
7f055d32 25#include <pwd.h>
40d69e19 26#include <sys/stat.h>
7f055d32
SL
27#include <utmp.h>
28#include <struct.h>
29#include <ctype.h>
30
cb88b4d5 31struct acct buf[DEV_BSIZE / sizeof (struct acct)];
c7eeef87 32
cb88b4d5 33time_t expand();
7f055d32 34char *flagbits();
cb88b4d5
SL
35char *getname();
36char *getdev();
c7eeef87 37
7f055d32
SL
38main(argc, argv)
39 char *argv[];
c7eeef87 40{
cb88b4d5 41 register int bn, cc;
7f055d32 42 register struct acct *acp;
cb88b4d5
SL
43 int fd;
44 struct stat sb;
a41e3d24
KB
45 long lseek();
46 char *strcpy(), *ctime();
c7eeef87 47
cb88b4d5
SL
48 fd = open("/usr/adm/acct", O_RDONLY);
49 if (fd < 0) {
7f055d32
SL
50 perror("/usr/adm/acct");
51 exit(1);
c7eeef87 52 }
cb88b4d5 53 fstat(fd, &sb);
3b26b9c3 54 for (bn = btodb(sb.st_size); bn >= 0; bn--) {
a41e3d24 55 (void)lseek(fd, (off_t)dbtob(bn), L_SET);
cb88b4d5
SL
56 cc = read(fd, buf, DEV_BSIZE);
57 if (cc < 0) {
58 perror("read");
59 break;
60 }
61 acp = buf + (cc / sizeof (buf[0])) - 1;
62 for (; acp >= buf; acp--) {
63 register char *cp;
8dc8d395 64 time_t x;
cb88b4d5 65
a4e47cfd 66 if (acp->ac_comm[0] == '\0')
7f055d32 67 strcpy(acp->ac_comm, "?");
a4e47cfd
RC
68 for (cp = &acp->ac_comm[0];
69 cp < &acp->ac_comm[fldsiz(acct, ac_comm)] && *cp;
70 cp++)
71 if (!isascii(*cp) || iscntrl(*cp))
cb88b4d5 72 *cp = '?';
8dc8d395 73 if (argc > 1 && !ok(argc, argv, acp))
7f055d32 74 continue;
8dc8d395 75 x = expand(acp->ac_utime) + expand(acp->ac_stime);
4bf06df2 76 printf("%-*.*s %s %-*s %-*s %6.2f secs %.16s\n",
a41e3d24
KB
77 fldsiz(acct, ac_comm),
78 fldsiz(acct, ac_comm),
79 acp->ac_comm, flagbits(acp->ac_flag),
80 fldsiz(utmp, ut_name),
81 (cp = getname(acp->ac_uid)) ? cp : "",
cb88b4d5 82 fldsiz(utmp, ut_line), getdev(acp->ac_tty),
891ad5df 83 x / (double)AHZ, ctime(&acp->ac_btime));
c7eeef87
BJ
84 }
85 }
86}
87
88time_t
89expand (t)
7f055d32 90 unsigned t;
c7eeef87
BJ
91{
92 register time_t nt;
93
94 nt = t & 017777;
95 t >>= 13;
7f055d32 96 while (t) {
c7eeef87
BJ
97 t--;
98 nt <<= 3;
99 }
100 return (nt);
101}
102
583da166
RE
103char *
104flagbits(f)
7f055d32 105 register int f;
c7eeef87 106{
583da166
RE
107 register int i = 0;
108 static char flags[20];
109
7f055d32
SL
110#define BIT(flag, ch) flags[i++] = (f & flag) ? ch : ' '
111 BIT(ASU, 'S');
112 BIT(AFORK, 'F');
113 BIT(ACOMPAT, 'C');
114 BIT(ACORE, 'D');
115 BIT(AXSIG, 'X');
583da166 116 flags[i] = '\0';
7f055d32 117 return (flags);
583da166
RE
118}
119
cb88b4d5
SL
120ok(argc, argv, acp)
121 register int argc;
122 register char *argv[];
123 register struct acct *acp;
124{
125 register int j;
a41e3d24 126 register char *cp;
cb88b4d5
SL
127
128 for (j = 1; j < argc; j++)
a41e3d24
KB
129 if ((!(cp = getname(acp->ac_uid)) || strcmp(cp, argv[j])) &&
130 (!(cp = getdev(acp->ac_tty)) || strcmp(cp, argv[j])) &&
a4e47cfd 131 strncmp(acp->ac_comm, argv[j], fldsiz(acct, ac_comm)))
cb88b4d5
SL
132 break;
133 return (j == argc);
134}
135
136/* should be done with nameserver or database */
137
138struct utmp utmp;
139
140#define NUID 2048
141#define NMAX (sizeof (utmp.ut_name))
142
143char names[NUID][NMAX+1];
144char outrangename[NMAX+1];
145int outrangeuid = -1;
146
147char *
148getname(uid)
a41e3d24 149 uid_t uid;
cb88b4d5
SL
150{
151 register struct passwd *pw;
152 static init;
153 struct passwd *getpwent();
154
a41e3d24 155 if (uid < NUID && names[uid][0])
cb88b4d5 156 return (&names[uid][0]);
a41e3d24 157 if (uid == outrangeuid)
cb88b4d5
SL
158 return (outrangename);
159 if (init == 2) {
160 if (uid < NUID)
161 return (0);
162 setpwent();
163 while (pw = getpwent()) {
164 if (pw->pw_uid != uid)
165 continue;
166 outrangeuid = pw->pw_uid;
93b9cc72 167 strncpy(outrangename, pw->pw_name, NMAX);
cb88b4d5
SL
168 endpwent();
169 return (outrangename);
170 }
171 endpwent();
172 return (0);
173 }
174 if (init == 0)
175 setpwent(), init = 1;
176 while (pw = getpwent()) {
177 if (pw->pw_uid < 0 || pw->pw_uid >= NUID) {
178 if (pw->pw_uid == uid) {
179 outrangeuid = pw->pw_uid;
93b9cc72 180 strncpy(outrangename, pw->pw_name, NMAX);
cb88b4d5
SL
181 return (outrangename);
182 }
183 continue;
184 }
185 if (names[pw->pw_uid][0])
186 continue;
187 strncpy(names[pw->pw_uid], pw->pw_name, NMAX);
188 if (pw->pw_uid == uid)
189 return (&names[uid][0]);
190 }
191 init = 2;
192 endpwent();
193 return (0);
194}
195
196#include <sys/dir.h>
197
198#define N_DEVS 43 /* hash value for device names */
199#define NDEVS 500 /* max number of file names in /dev */
200
201struct devhash {
202 dev_t dev_dev;
203 char dev_name [fldsiz(utmp, ut_line) + 1];
204 struct devhash * dev_nxt;
205};
206struct devhash *dev_hash[N_DEVS];
207struct devhash *dev_chain;
208#define HASH(d) (((int) d) % N_DEVS)
209
583da166
RE
210setupdevs()
211{
212 register DIR * fd;
213 register struct devhash * hashtab;
214 register ndevs = NDEVS;
215 struct direct * dp;
a41e3d24 216 char *malloc();
583da166 217
a41e3d24 218 /*NOSTRICT*/
cb88b4d5
SL
219 hashtab = (struct devhash *)malloc(NDEVS * sizeof(struct devhash));
220 if (hashtab == (struct devhash *)0) {
a41e3d24
KB
221 fputs("No mem for dev table\n", stderr);
222 return;
223 }
224 if ((fd = opendir("/dev")) == NULL) {
225 perror("/dev");
583da166
RE
226 return;
227 }
583da166
RE
228 while (dp = readdir(fd)) {
229 if (dp->d_ino == 0)
230 continue;
583da166
RE
231 if (dp->d_name[0] != 't' && strcmp(dp->d_name, "console"))
232 continue;
583da166
RE
233 strncpy(hashtab->dev_name, dp->d_name, fldsiz(utmp, ut_line));
234 hashtab->dev_name[fldsiz(utmp, ut_line)] = 0;
235 hashtab->dev_nxt = dev_chain;
236 dev_chain = hashtab;
237 hashtab++;
238 if (--ndevs <= 0)
239 break;
240 }
241 closedir(fd);
242}
243
244char *
cb88b4d5 245getdev(dev)
7f055d32 246 dev_t dev;
583da166
RE
247{
248 register struct devhash *hp, *nhp;
249 struct stat statb;
7f055d32 250 char name[fldsiz(devhash, dev_name) + 6];
583da166
RE
251 static dev_t lastdev = (dev_t) -1;
252 static char *lastname;
f4e5f824 253 static int init = 0;
a41e3d24 254 char *strcpy(), *strcat();
583da166
RE
255
256 if (dev == NODEV)
7f055d32 257 return ("__");
583da166 258 if (dev == lastdev)
7f055d32 259 return (lastname);
cb88b4d5
SL
260 if (!init) {
261 setupdevs();
262 init++;
263 }
583da166
RE
264 for (hp = dev_hash[HASH(dev)]; hp; hp = hp->dev_nxt)
265 if (hp->dev_dev == dev) {
266 lastdev = dev;
7f055d32 267 return (lastname = hp->dev_name);
583da166 268 }
583da166
RE
269 for (hp = dev_chain; hp; hp = nhp) {
270 nhp = hp->dev_nxt;
271 strcpy(name, "/dev/");
272 strcat(name, hp->dev_name);
273 if (stat(name, &statb) < 0) /* name truncated usually */
274 continue;
275 if ((statb.st_mode & S_IFMT) != S_IFCHR)
276 continue;
277 hp->dev_dev = statb.st_rdev;
278 hp->dev_nxt = dev_hash[HASH(hp->dev_dev)];
279 dev_hash[HASH(hp->dev_dev)] = hp;
280 if (hp->dev_dev == dev) {
281 dev_chain = nhp;
282 lastdev = dev;
7f055d32 283 return (lastname = hp->dev_name);
583da166 284 }
c7eeef87 285 }
583da166 286 dev_chain = (struct devhash *) 0;
7f055d32
SL
287 return ("??");
288}