use bzero
[unix-history] / usr / src / usr.bin / lastcomm / lastcomm.c
CommitLineData
7f055d32 1#ifndef lint
891ad5df 2static char *sccsid = "@(#)lastcomm.c 4.12 (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;
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;
891ad5df 61 printf("%-*s %s %-*s %-*s %6.2f secs %.16s\n",
7f055d32
SL
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),
891ad5df 66 x / (double)AHZ, ctime(&acp->ac_btime));
c7eeef87
BJ
67 }
68 }
69}
70
71time_t
72expand (t)
7f055d32 73 unsigned t;
c7eeef87
BJ
74{
75 register time_t nt;
76
77 nt = t & 017777;
78 t >>= 13;
7f055d32 79 while (t) {
c7eeef87
BJ
80 t--;
81 nt <<= 3;
82 }
83 return (nt);
84}
85
583da166
RE
86char *
87flagbits(f)
7f055d32 88 register int f;
c7eeef87 89{
583da166
RE
90 register int i = 0;
91 static char flags[20];
92
7f055d32
SL
93#define BIT(flag, ch) flags[i++] = (f & flag) ? ch : ' '
94 BIT(ASU, 'S');
95 BIT(AFORK, 'F');
96 BIT(ACOMPAT, 'C');
97 BIT(ACORE, 'D');
98 BIT(AXSIG, 'X');
583da166 99 flags[i] = '\0';
7f055d32 100 return (flags);
583da166
RE
101}
102
cb88b4d5
SL
103ok(argc, argv, acp)
104 register int argc;
105 register char *argv[];
106 register struct acct *acp;
107{
108 register int j;
109
110 for (j = 1; j < argc; j++)
111 if (strcmp(getname(acp->ac_uid), argv[j]) &&
112 strcmp(getdev(acp->ac_tty), argv[j]) &&
113 strcmp(acp->ac_comm, argv[j]))
114 break;
115 return (j == argc);
116}
117
118/* should be done with nameserver or database */
119
120struct utmp utmp;
121
122#define NUID 2048
123#define NMAX (sizeof (utmp.ut_name))
124
125char names[NUID][NMAX+1];
126char outrangename[NMAX+1];
127int outrangeuid = -1;
128
129char *
130getname(uid)
131{
132 register struct passwd *pw;
133 static init;
134 struct passwd *getpwent();
135
136 if (uid >= 0 && uid < NUID && names[uid][0])
137 return (&names[uid][0]);
138 if (uid >= 0 && uid == outrangeuid)
139 return (outrangename);
140 if (init == 2) {
141 if (uid < NUID)
142 return (0);
143 setpwent();
144 while (pw = getpwent()) {
145 if (pw->pw_uid != uid)
146 continue;
147 outrangeuid = pw->pw_uid;
93b9cc72 148 strncpy(outrangename, pw->pw_name, NMAX);
cb88b4d5
SL
149 endpwent();
150 return (outrangename);
151 }
152 endpwent();
153 return (0);
154 }
155 if (init == 0)
156 setpwent(), init = 1;
157 while (pw = getpwent()) {
158 if (pw->pw_uid < 0 || pw->pw_uid >= NUID) {
159 if (pw->pw_uid == uid) {
160 outrangeuid = pw->pw_uid;
93b9cc72 161 strncpy(outrangename, pw->pw_name, NMAX);
cb88b4d5
SL
162 return (outrangename);
163 }
164 continue;
165 }
166 if (names[pw->pw_uid][0])
167 continue;
168 strncpy(names[pw->pw_uid], pw->pw_name, NMAX);
169 if (pw->pw_uid == uid)
170 return (&names[uid][0]);
171 }
172 init = 2;
173 endpwent();
174 return (0);
175}
176
177#include <sys/dir.h>
178
179#define N_DEVS 43 /* hash value for device names */
180#define NDEVS 500 /* max number of file names in /dev */
181
182struct devhash {
183 dev_t dev_dev;
184 char dev_name [fldsiz(utmp, ut_line) + 1];
185 struct devhash * dev_nxt;
186};
187struct devhash *dev_hash[N_DEVS];
188struct devhash *dev_chain;
189#define HASH(d) (((int) d) % N_DEVS)
190
583da166
RE
191setupdevs()
192{
193 register DIR * fd;
194 register struct devhash * hashtab;
195 register ndevs = NDEVS;
196 struct direct * dp;
197
198 if ((fd = opendir("/dev")) == NULL) {
199 perror("/dev");
200 return;
201 }
cb88b4d5
SL
202 hashtab = (struct devhash *)malloc(NDEVS * sizeof(struct devhash));
203 if (hashtab == (struct devhash *)0) {
583da166 204 fprintf(stderr, "No mem for dev table\n");
f4e5f824 205 closedir(fd);
583da166
RE
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;
f4e5f824 233 static 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}