Commit | Line | Data |
---|---|---|
7f055d32 SL |
1 | #ifndef lint |
2 | static 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 | ||
23 | struct acct acct_buff[BUFSIZ / sizeof (struct acct)]; | |
24 | char user_list[N_USER][fldsiz(utmp, ut_name) + 1]; | |
c7eeef87 | 25 | |
583da166 RE |
26 | struct devhash { |
27 | dev_t dev_dev; | |
28 | char dev_name [fldsiz(utmp, ut_line) + 1]; | |
29 | struct devhash * dev_nxt; | |
7f055d32 SL |
30 | }; |
31 | struct devhash *dev_hash[N_DEVS]; | |
32 | struct devhash *dev_chain ; | |
33 | #define HASH(d) (((int) d) % N_DEVS) | |
c7eeef87 BJ |
34 | |
35 | time_t expand (); | |
7f055d32 SL |
36 | char *flagbits(); |
37 | char *ttyname(); | |
c7eeef87 | 38 | |
7f055d32 | 39 | struct passwd *passwd, *getpwent (); |
c7eeef87 BJ |
40 | struct stat stat_buff; |
41 | ||
7f055d32 SL |
42 | main(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 | ||
97 | time_t | |
98 | expand (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 |
112 | char * |
113 | flagbits(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 | ||
129 | setupdevs() | |
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 | ||
163 | char * | |
7f055d32 SL |
164 | ttyname(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 | ||
203 | ok(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 | } |