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