rewrite
[unix-history] / usr / src / usr.bin / lastcomm / lastcomm.c
CommitLineData
7f055d32
SL
1#ifndef lint
2static char *sccsid = "@(#)lastcomm.c 4.5 (Berkeley) 83/04/04";
3#endif
c7eeef87
BJ
4
5/*
6 * last command
7 */
7f055d32
SL
8#include <stdio.h>
9#include <sys/param.h>
10#include <sys/acct.h>
11#include <sys/dir.h>
12#include <signal.h>
13#include <pwd.h>
14#include <stat.h>
15#include <utmp.h>
16#include <struct.h>
17#include <ctype.h>
18
19#define N_USER 4000 /* highest alloc user # */
20#define N_DEVS 43 /* hash value for device names */
21#define NDEVS 500 /* max number of file names in /dev */
22
23struct acct acct_buff[BUFSIZ / sizeof (struct acct)];
24char user_list[N_USER][fldsiz(utmp, ut_name) + 1];
c7eeef87 25
583da166
RE
26struct devhash {
27 dev_t dev_dev;
28 char dev_name [fldsiz(utmp, ut_line) + 1];
29 struct devhash * dev_nxt;
7f055d32
SL
30};
31struct devhash *dev_hash[N_DEVS];
32struct devhash *dev_chain ;
33#define HASH(d) (((int) d) % N_DEVS)
c7eeef87
BJ
34
35time_t expand ();
7f055d32
SL
36char *flagbits();
37char *ttyname();
c7eeef87 38
7f055d32 39struct passwd *passwd, *getpwent ();
c7eeef87
BJ
40struct stat stat_buff;
41
7f055d32
SL
42main(argc, argv)
43 char *argv[];
c7eeef87 44{
7f055d32
SL
45 char acct_desc, *p;
46 long i, j, i_block, n_blocks, n_byte, n_entry, x;
47 register struct acct *acp;
c7eeef87 48
7f055d32
SL
49 /*
50 * Set up user names
51 */
52 while (passwd = getpwent())
53 if (user_list[passwd->pw_uid][0] == 0)
54 strcpy(user_list[passwd->pw_uid], passwd->pw_name);
55 /*
56 * Find dev numbers corresponding to names in /dev
57 */
583da166 58 setupdevs();
7f055d32
SL
59 acct_desc = open("/usr/adm/acct", 0);
60 if (acct_desc < 0) {
61 perror("/usr/adm/acct");
62 exit(1);
c7eeef87 63 }
7f055d32 64 fstat(acct_desc, &stat_buff);
c7eeef87
BJ
65 n_blocks = (stat_buff.st_size + BUFSIZ - 1) / BUFSIZ;
66
67 /*
7f055d32 68 * Read one block's worth
c7eeef87 69 */
7f055d32
SL
70 for (i_block = n_blocks - 1; i_block >= 0; i_block--) {
71 lseek(acct_desc, i_block * BUFSIZ, 0);
72 n_byte = read(acct_desc, acct_buff, BUFSIZ);
73 n_entry = n_byte / sizeof acct_buff[0];
74 for (acp = acct_buff + n_entry - 1; acp >= acct_buff; acp--) {
75 if (*user_list[acp->ac_uid] == '\0')
583da166 76 continue;
7f055d32
SL
77 x = expand(acp->ac_utime) + expand(acp->ac_stime);
78 acp->ac_comm[10] = '\0';
79 if (*acp->ac_comm == '\0')
80 strcpy(acp->ac_comm, "?");
81 for (p = acp->ac_comm; *p; p++)
82 if (iscntrl(*p))
583da166 83 *p = '?';
7f055d32
SL
84 if (!ok(argc, argv, acp) && argc != 1)
85 continue;
86 printf("%-*s %s %-*s %-*s %4d sec%s %.16s\n",
87 fldsiz(acct, ac_comm), acp->ac_comm,
88 flagbits(acp->ac_flag),
89 fldsiz(utmp, ut_name), user_list[acp->ac_uid],
90 fldsiz(utmp, ut_line), ttyname(acp->ac_tty),
91 x, x > 1 || x == 0 ? "s" : " ",
92 ctime(&acp->ac_btime));
c7eeef87
BJ
93 }
94 }
95}
96
97time_t
98expand (t)
7f055d32 99 unsigned t;
c7eeef87
BJ
100{
101 register time_t nt;
102
103 nt = t & 017777;
104 t >>= 13;
7f055d32 105 while (t) {
c7eeef87
BJ
106 t--;
107 nt <<= 3;
108 }
109 return (nt);
110}
111
583da166
RE
112char *
113flagbits(f)
7f055d32 114 register int f;
c7eeef87 115{
583da166
RE
116 register int i = 0;
117 static char flags[20];
118
7f055d32
SL
119#define BIT(flag, ch) flags[i++] = (f & flag) ? ch : ' '
120 BIT(ASU, 'S');
121 BIT(AFORK, 'F');
122 BIT(ACOMPAT, 'C');
123 BIT(ACORE, 'D');
124 BIT(AXSIG, 'X');
583da166 125 flags[i] = '\0';
7f055d32 126 return (flags);
583da166
RE
127}
128
129setupdevs()
130{
131 register DIR * fd;
132 register struct devhash * hashtab;
133 register ndevs = NDEVS;
134 struct direct * dp;
135
136 if ((fd = opendir("/dev")) == NULL) {
137 perror("/dev");
138 return;
139 }
583da166
RE
140 if ((hashtab = (struct devhash *)malloc(NDEVS * sizeof(struct devhash)))
141 == (struct devhash *) 0) {
142 fprintf(stderr, "No mem for dev table\n");
143 return;
144 }
583da166
RE
145 while (dp = readdir(fd)) {
146 if (dp->d_ino == 0)
147 continue;
148#ifdef MELB
149 if (dp->d_name[0] != 't' && strcmp(dp->d_name, "console"))
150 continue;
151#endif
152 strncpy(hashtab->dev_name, dp->d_name, fldsiz(utmp, ut_line));
153 hashtab->dev_name[fldsiz(utmp, ut_line)] = 0;
154 hashtab->dev_nxt = dev_chain;
155 dev_chain = hashtab;
156 hashtab++;
157 if (--ndevs <= 0)
158 break;
159 }
160 closedir(fd);
161}
162
163char *
7f055d32
SL
164ttyname(dev)
165 dev_t dev;
583da166
RE
166{
167 register struct devhash *hp, *nhp;
168 struct stat statb;
7f055d32 169 char name[fldsiz(devhash, dev_name) + 6];
583da166
RE
170 static dev_t lastdev = (dev_t) -1;
171 static char *lastname;
172
173 if (dev == NODEV)
7f055d32 174 return ("__");
583da166 175 if (dev == lastdev)
7f055d32 176 return (lastname);
583da166
RE
177 for (hp = dev_hash[HASH(dev)]; hp; hp = hp->dev_nxt)
178 if (hp->dev_dev == dev) {
179 lastdev = dev;
7f055d32 180 return (lastname = hp->dev_name);
583da166 181 }
583da166
RE
182 for (hp = dev_chain; hp; hp = nhp) {
183 nhp = hp->dev_nxt;
184 strcpy(name, "/dev/");
185 strcat(name, hp->dev_name);
186 if (stat(name, &statb) < 0) /* name truncated usually */
187 continue;
188 if ((statb.st_mode & S_IFMT) != S_IFCHR)
189 continue;
190 hp->dev_dev = statb.st_rdev;
191 hp->dev_nxt = dev_hash[HASH(hp->dev_dev)];
192 dev_hash[HASH(hp->dev_dev)] = hp;
193 if (hp->dev_dev == dev) {
194 dev_chain = nhp;
195 lastdev = dev;
7f055d32 196 return (lastname = hp->dev_name);
583da166 197 }
c7eeef87 198 }
583da166 199 dev_chain = (struct devhash *) 0;
7f055d32
SL
200 return ("??");
201}
202
203ok(argc, argv, acp)
204 register int argc;
205 register char *argv[];
206 register struct acct *acp;
207{
208 register int j;
209
210 for (j = 1; j < argc; j++)
211 if (strcmp(user_list[acp->ac_uid], argv[j]) &&
212 strcmp(ttyname(acp->ac_tty), argv[j]) &&
213 strcmp(acp->ac_comm, argv[j]))
214 break;
215 return (j == argc);
c7eeef87 216}