date and time created 83/09/07 13:20:12 by ralph
[unix-history] / usr / src / usr.bin / lastcomm / lastcomm.c
CommitLineData
7f055d32 1#ifndef lint
93b9cc72 2static char *sccsid = "@(#)lastcomm.c 4.8 (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
SL
39 fstat(fd, &sb);
40 for (bn = btodb(sb.st_size) - 1; bn >= 0; bn--) {
41 lseek(fd, bn * DEV_BSIZE, L_SET);
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;
50 time_t x =
51 expand(acp->ac_utime) + expand(acp->ac_stime);
52
7f055d32
SL
53 acp->ac_comm[10] = '\0';
54 if (*acp->ac_comm == '\0')
55 strcpy(acp->ac_comm, "?");
cb88b4d5
SL
56 for (cp = acp->ac_comm; *cp; cp++)
57 if (iscntrl(*cp))
58 *cp = '?';
7f055d32
SL
59 if (!ok(argc, argv, acp) && argc != 1)
60 continue;
61 printf("%-*s %s %-*s %-*s %4d sec%s %.16s\n",
62 fldsiz(acct, ac_comm), acp->ac_comm,
63 flagbits(acp->ac_flag),
cb88b4d5
SL
64 fldsiz(utmp, ut_name), getname(acp->ac_uid),
65 fldsiz(utmp, ut_line), getdev(acp->ac_tty),
7f055d32
SL
66 x, x > 1 || x == 0 ? "s" : " ",
67 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]) &&
114 strcmp(acp->ac_comm, argv[j]))
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
RE
205 fprintf(stderr, "No mem for dev table\n");
206 return;
207 }
583da166
RE
208 while (dp = readdir(fd)) {
209 if (dp->d_ino == 0)
210 continue;
583da166
RE
211 if (dp->d_name[0] != 't' && strcmp(dp->d_name, "console"))
212 continue;
583da166
RE
213 strncpy(hashtab->dev_name, dp->d_name, fldsiz(utmp, ut_line));
214 hashtab->dev_name[fldsiz(utmp, ut_line)] = 0;
215 hashtab->dev_nxt = dev_chain;
216 dev_chain = hashtab;
217 hashtab++;
218 if (--ndevs <= 0)
219 break;
220 }
221 closedir(fd);
222}
223
224char *
cb88b4d5 225getdev(dev)
7f055d32 226 dev_t dev;
583da166
RE
227{
228 register struct devhash *hp, *nhp;
229 struct stat statb;
7f055d32 230 char name[fldsiz(devhash, dev_name) + 6];
583da166
RE
231 static dev_t lastdev = (dev_t) -1;
232 static char *lastname;
cb88b4d5 233 int init = 0;
583da166
RE
234
235 if (dev == NODEV)
7f055d32 236 return ("__");
583da166 237 if (dev == lastdev)
7f055d32 238 return (lastname);
cb88b4d5
SL
239 if (!init) {
240 setupdevs();
241 init++;
242 }
583da166
RE
243 for (hp = dev_hash[HASH(dev)]; hp; hp = hp->dev_nxt)
244 if (hp->dev_dev == dev) {
245 lastdev = dev;
7f055d32 246 return (lastname = hp->dev_name);
583da166 247 }
583da166
RE
248 for (hp = dev_chain; hp; hp = nhp) {
249 nhp = hp->dev_nxt;
250 strcpy(name, "/dev/");
251 strcat(name, hp->dev_name);
252 if (stat(name, &statb) < 0) /* name truncated usually */
253 continue;
254 if ((statb.st_mode & S_IFMT) != S_IFCHR)
255 continue;
256 hp->dev_dev = statb.st_rdev;
257 hp->dev_nxt = dev_hash[HASH(hp->dev_dev)];
258 dev_hash[HASH(hp->dev_dev)] = hp;
259 if (hp->dev_dev == dev) {
260 dev_chain = nhp;
261 lastdev = dev;
7f055d32 262 return (lastname = hp->dev_name);
583da166 263 }
c7eeef87 264 }
583da166 265 dev_chain = (struct devhash *) 0;
7f055d32
SL
266 return ("??");
267}