1 static char *sccsid = "@(#)lastcomm.c 4.4 (Berkeley) 82/07/17"; 2 3 /* 4 * last command 5 */ 6 7 # include <stdio.h> 8 # include <sys/param.h> 9 # include <sys/acct.h> 10 # include <sys/dir.h> 11 # include <signal.h> 12 # include <pwd.h> 13 # include <stat.h> 14 # include <utmp.h> 15 # include <struct.h> 16 17 # define N_USER 4000 /* highest alloc user # */ 18 # define N_DEVS 43 /* hash value for device names */ 19 # define NDEVS 500 /* max number of file names in /dev */ 20 21 struct acct acct_buff [BUFSIZ / sizeof (struct acct)]; 22 23 char user_list [N_USER][fldsiz(utmp, ut_name) + 1]; 24 25 struct devhash { 26 dev_t dev_dev; 27 char dev_name [fldsiz(utmp, ut_line) + 1]; 28 struct devhash * dev_nxt; 29 } 30 * dev_hash [ N_DEVS ], 31 * dev_chain ; 32 # define HASH(d) (((int) d) % N_DEVS) 33 34 time_t expand (); 35 char * flagbits(); 36 char * tername(); 37 38 struct passwd 39 *passwd, 40 *getpwent (); 41 42 struct stat stat_buff; 43 44 # define equal(a, b) (strcmp(a, b) == 0) 45 46 main (argc, argv) 47 char **argv; 48 { 49 char acct_desc, 50 *p; 51 52 long i, 53 j, 54 i_block, 55 n_blocks, 56 n_byte, 57 n_entry; 58 59 float x; 60 61 /* 62 * set up user names 63 */ 64 while (passwd = getpwent ()) 65 { 66 if (user_list[passwd->pw_uid][0]==0) 67 move (passwd->pw_name, user_list [passwd->pw_uid]); 68 } 69 70 /* 71 * find dev numbers corresponding to names in /dev 72 */ 73 setupdevs(); 74 75 acct_desc = open ("/usr/adm/acct", 0); 76 if (acct_desc < 0) 77 { 78 perror ("/usr/adm/acct"); 79 return; 80 } 81 fstat (acct_desc, &stat_buff); 82 n_blocks = (stat_buff.st_size + BUFSIZ - 1) / BUFSIZ; 83 84 /* 85 * read one block's worth 86 */ 87 for (i_block = n_blocks - 1; i_block >= 0; i_block--) 88 { 89 lseek (acct_desc, i_block * BUFSIZ, 0); 90 n_byte = read (acct_desc, acct_buff, BUFSIZ); 91 n_entry = n_byte / sizeof acct_buff [0]; 92 for (i = n_entry - 1; i >= 0; i--) 93 { 94 if (!*user_list [acct_buff [i].ac_uid]) 95 continue; 96 /* 97 * get the times 98 */ 99 x = expand (acct_buff [i].ac_utime) 100 + 101 expand (acct_buff [i].ac_stime); 102 /* 103 * null terminate the command name 104 */ 105 acct_buff [i].ac_comm [10] = 0; 106 /* 107 * replace missing command names with question marks 108 */ 109 if (!*acct_buff [i].ac_comm) 110 { 111 move ("?", acct_buff [i].ac_comm); 112 } 113 /* 114 * replace control characters with question marks 115 */ 116 for (p = acct_buff [i].ac_comm; *p; p++) 117 { 118 if (*p < '!' || '~' < *p) 119 *p = '?'; 120 } 121 for (j = 1; j < argc; j++) 122 { 123 if 124 ( 125 equal (acct_buff [i].ac_comm, argv [j]) 126 || 127 equal 128 ( 129 user_list[acct_buff[i].ac_uid], 130 argv [j] 131 ) 132 || 133 equal 134 ( 135 tername(acct_buff[i].ac_tty), 136 argv[j] 137 ) 138 ) 139 { 140 break; 141 } 142 } 143 if (argc == 1 || j != argc) 144 { 145 printf 146 ( 147 "%-*s %s %-*s %-*s %6.2f %.16s\n" 148 , fldsiz(acct, ac_comm) 149 , acct_buff [i].ac_comm 150 , flagbits(acct_buff [i].ac_flag) 151 , fldsiz(utmp, ut_name) 152 , user_list [acct_buff [i].ac_uid] 153 , fldsiz(utmp, ut_line) 154 , tername(acct_buff [i].ac_tty) 155 , x / 60.0 156 , ctime (&acct_buff [i].ac_btime) 157 ); 158 } 159 } 160 } 161 } 162 163 time_t 164 expand (t) 165 unsigned t; 166 { 167 register time_t nt; 168 169 nt = t & 017777; 170 t >>= 13; 171 while (t) 172 { 173 t--; 174 nt <<= 3; 175 } 176 return (nt); 177 } 178 179 move (a, b) 180 char *a, *b; 181 { 182 while (*b++ = *a++) 183 ; 184 } 185 186 char * 187 flagbits(f) 188 register int f; 189 { 190 register int i = 0; 191 static char flags[20]; 192 193 # define BIT(flag, ch) flags[i++] = ( f & flag ) ? ch : ' ' 194 195 BIT( ASU, 'S'); 196 BIT( AFORK, 'F'); 197 BIT( ACOMPAT, 'C'); 198 BIT( ACORE, 'D'); 199 BIT( AXSIG, 'X'); 200 201 flags[i] = '\0'; 202 203 return(flags); 204 } 205 206 setupdevs() 207 { 208 register DIR * fd; 209 register struct devhash * hashtab; 210 register ndevs = NDEVS; 211 struct direct * dp; 212 213 if ((fd = opendir("/dev")) == NULL) { 214 perror("/dev"); 215 return; 216 } 217 218 if ((hashtab = (struct devhash *)malloc(NDEVS * sizeof(struct devhash))) 219 == (struct devhash *) 0) { 220 fprintf(stderr, "No mem for dev table\n"); 221 return; 222 } 223 224 while (dp = readdir(fd)) { 225 if (dp->d_ino == 0) 226 continue; 227 #ifdef MELB 228 if (dp->d_name[0] != 't' && strcmp(dp->d_name, "console")) 229 continue; 230 #endif 231 strncpy(hashtab->dev_name, dp->d_name, fldsiz(utmp, ut_line)); 232 hashtab->dev_name[fldsiz(utmp, ut_line)] = 0; 233 hashtab->dev_nxt = dev_chain; 234 dev_chain = hashtab; 235 hashtab++; 236 if (--ndevs <= 0) 237 break; 238 } 239 closedir(fd); 240 } 241 242 char * 243 tername(dev) 244 dev_t dev; 245 { 246 register struct devhash *hp, *nhp; 247 struct stat statb; 248 char name [fldsiz(devhash, dev_name) + 6]; 249 static dev_t lastdev = (dev_t) -1; 250 static char *lastname; 251 252 if (dev == NODEV) 253 return("__"); 254 255 if (dev == lastdev) 256 return(lastname); 257 258 for (hp = dev_hash[HASH(dev)]; hp; hp = hp->dev_nxt) 259 if (hp->dev_dev == dev) { 260 lastdev = dev; 261 return(lastname = hp->dev_name); 262 } 263 264 for (hp = dev_chain; hp; hp = nhp) { 265 nhp = hp->dev_nxt; 266 strcpy(name, "/dev/"); 267 strcat(name, hp->dev_name); 268 if (stat(name, &statb) < 0) /* name truncated usually */ 269 continue; 270 if ((statb.st_mode & S_IFMT) != S_IFCHR) 271 continue; 272 hp->dev_dev = statb.st_rdev; 273 hp->dev_nxt = dev_hash[HASH(hp->dev_dev)]; 274 dev_hash[HASH(hp->dev_dev)] = hp; 275 if (hp->dev_dev == dev) { 276 dev_chain = nhp; 277 lastdev = dev; 278 return(lastname = hp->dev_name); 279 } 280 } 281 282 dev_chain = (struct devhash *) 0; 283 return("??"); 284 } 285