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