1 /* 2 * Copyright (c) 1980 Regents of the University of California. 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms are permitted 6 * provided that the above copyright notice and this paragraph are 7 * duplicated in all such forms and that any documentation, 8 * advertising materials, and other materials related to such 9 * distribution and use acknowledge that the software was developed 10 * by the University of California, Berkeley. The name of the 11 * University may not be used to endorse or promote products derived 12 * from this software without specific prior written permission. 13 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 14 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 15 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 16 */ 17 18 #ifndef lint 19 char copyright[] = 20 "@(#) Copyright (c) 1980 Regents of the University of California.\n\ 21 All rights reserved.\n"; 22 #endif /* not lint */ 23 24 #ifndef lint 25 static char sccsid[] = "@(#)lastcomm.c 5.6 (Berkeley) 06/29/88"; 26 #endif /* not lint */ 27 28 /* 29 * last command 30 */ 31 #include <sys/param.h> 32 #include <sys/acct.h> 33 #include <sys/file.h> 34 #include <sys/stat.h> 35 #include <utmp.h> 36 #include <struct.h> 37 #include <ctype.h> 38 #include <stdio.h> 39 40 struct acct buf[DEV_BSIZE / sizeof (struct acct)]; 41 42 time_t expand(); 43 char *flagbits(); 44 char *getname(); 45 char *getdev(); 46 47 main(argc, argv) 48 int argc; 49 char *argv[]; 50 { 51 extern int optind; 52 extern char *optarg; 53 register struct acct *acp; 54 register int bn, cc; 55 struct stat sb; 56 int ch, fd; 57 char *acctfile, *strcpy(), *ctime(); 58 long lseek(); 59 60 acctfile = NULL; 61 while ((ch = getopt(argc, argv, "f:")) != EOF) 62 switch((char)ch) { 63 case 'f': 64 acctfile = optarg; 65 break; 66 case '?': 67 default: 68 fputs("lastcomm [ -f file ]\n", stderr); 69 exit(1); 70 } 71 argv += optind; 72 if (!acctfile) 73 acctfile = "/usr/adm/acct"; 74 fd = open(acctfile, O_RDONLY); 75 if (fd < 0) { 76 perror(acctfile); 77 exit(1); 78 } 79 (void)fstat(fd, &sb); 80 for (bn = btodb(sb.st_size); bn >= 0; bn--) { 81 (void)lseek(fd, (off_t)dbtob(bn), L_SET); 82 cc = read(fd, buf, DEV_BSIZE); 83 if (cc < 0) { 84 perror("read"); 85 break; 86 } 87 acp = buf + (cc / sizeof (buf[0])) - 1; 88 for (; acp >= buf; acp--) { 89 register char *cp; 90 time_t x; 91 92 if (acp->ac_comm[0] == '\0') 93 (void)strcpy(acp->ac_comm, "?"); 94 for (cp = &acp->ac_comm[0]; 95 cp < &acp->ac_comm[fldsiz(acct, ac_comm)] && *cp; 96 cp++) 97 if (!isascii(*cp) || iscntrl(*cp)) 98 *cp = '?'; 99 if (*argv && !ok(argv, acp)) 100 continue; 101 x = expand(acp->ac_utime) + expand(acp->ac_stime); 102 printf("%-*.*s %s %-*s %-*s %6.2f secs %.16s\n", 103 fldsiz(acct, ac_comm), 104 fldsiz(acct, ac_comm), 105 acp->ac_comm, flagbits(acp->ac_flag), 106 fldsiz(utmp, ut_name), 107 (cp = getname(acp->ac_uid)) ? cp : "", 108 fldsiz(utmp, ut_line), getdev(acp->ac_tty), 109 x / (double)AHZ, ctime(&acp->ac_btime)); 110 } 111 } 112 } 113 114 time_t 115 expand (t) 116 unsigned t; 117 { 118 register time_t nt; 119 120 nt = t & 017777; 121 t >>= 13; 122 while (t) { 123 t--; 124 nt <<= 3; 125 } 126 return (nt); 127 } 128 129 char * 130 flagbits(f) 131 register int f; 132 { 133 static char flags[20]; 134 char *p, *strcpy(); 135 136 #define BIT(flag, ch) if (f & flag) *p++ = ch; 137 p = strcpy(flags, "- "); 138 BIT(ASU, 'S'); 139 BIT(AFORK, 'F'); 140 BIT(ACOMPAT, 'C'); 141 BIT(ACORE, 'D'); 142 BIT(AXSIG, 'X'); 143 return (flags); 144 } 145 146 ok(argv, acp) 147 register char *argv[]; 148 register struct acct *acp; 149 { 150 register char *cp; 151 152 do { 153 if ((cp = getname(acp->ac_uid)) && !strcmp(cp, *argv) || 154 (cp = getdev(acp->ac_tty)) && !strcmp(cp, *argv) || 155 !strncmp(acp->ac_comm, *argv, fldsiz(acct, ac_comm))) 156 return(1); 157 } while (*++argv); 158 return(0); 159 } 160 161 /* should be done with nameserver or database */ 162 163 #include <pwd.h> 164 165 struct utmp utmp; 166 #define NMAX (sizeof (utmp.ut_name)) 167 #define SCPYN(a, b) strncpy(a, b, NMAX) 168 169 #define NCACHE 64 /* power of 2 */ 170 #define CAMASK NCACHE - 1 171 172 char * 173 getname(uid) 174 uid_t uid; 175 { 176 extern int _pw_stayopen; 177 static struct ncache { 178 uid_t uid; 179 char name[NMAX+1]; 180 } c_uid[NCACHE]; 181 register struct passwd *pw; 182 register struct ncache *cp; 183 184 _pw_stayopen = 1; 185 cp = c_uid + (uid & CAMASK); 186 if (cp->uid == uid && *cp->name) 187 return(cp->name); 188 if (!(pw = getpwuid(uid))) 189 return((char *)0); 190 cp->uid = uid; 191 SCPYN(cp->name, pw->pw_name); 192 return(cp->name); 193 } 194 195 #include <sys/dir.h> 196 197 #define N_DEVS 43 /* hash value for device names */ 198 #define NDEVS 500 /* max number of file names in /dev */ 199 200 struct devhash { 201 dev_t dev_dev; 202 char dev_name [fldsiz(utmp, ut_line) + 1]; 203 struct devhash * dev_nxt; 204 }; 205 struct devhash *dev_hash[N_DEVS]; 206 struct devhash *dev_chain; 207 #define HASH(d) (((int) d) % N_DEVS) 208 209 setupdevs() 210 { 211 register DIR * fd; 212 register struct devhash * hashtab; 213 register ndevs = NDEVS; 214 struct direct * dp; 215 char *malloc(); 216 217 /*NOSTRICT*/ 218 hashtab = (struct devhash *)malloc(NDEVS * sizeof(struct devhash)); 219 if (hashtab == (struct devhash *)0) { 220 fputs("No mem for dev table\n", stderr); 221 return; 222 } 223 if ((fd = opendir("/dev")) == NULL) { 224 perror("/dev"); 225 return; 226 } 227 while (dp = readdir(fd)) { 228 if (dp->d_ino == 0) 229 continue; 230 if (dp->d_name[0] != 't' && strcmp(dp->d_name, "console")) 231 continue; 232 strncpy(hashtab->dev_name, dp->d_name, fldsiz(utmp, ut_line)); 233 hashtab->dev_name[fldsiz(utmp, ut_line)] = 0; 234 hashtab->dev_nxt = dev_chain; 235 dev_chain = hashtab; 236 hashtab++; 237 if (--ndevs <= 0) 238 break; 239 } 240 closedir(fd); 241 } 242 243 char * 244 getdev(dev) 245 dev_t dev; 246 { 247 register struct devhash *hp, *nhp; 248 struct stat statb; 249 char name[fldsiz(devhash, dev_name) + 6]; 250 static dev_t lastdev = (dev_t) -1; 251 static char *lastname; 252 static int init = 0; 253 char *strcpy(), *strcat(); 254 255 if (dev == NODEV) 256 return ("__"); 257 if (dev == lastdev) 258 return (lastname); 259 if (!init) { 260 setupdevs(); 261 init++; 262 } 263 for (hp = dev_hash[HASH(dev)]; hp; hp = hp->dev_nxt) 264 if (hp->dev_dev == dev) { 265 lastdev = dev; 266 return (lastname = hp->dev_name); 267 } 268 for (hp = dev_chain; hp; hp = nhp) { 269 nhp = hp->dev_nxt; 270 strcpy(name, "/dev/"); 271 strcat(name, hp->dev_name); 272 if (stat(name, &statb) < 0) /* name truncated usually */ 273 continue; 274 if ((statb.st_mode & S_IFMT) != S_IFCHR) 275 continue; 276 hp->dev_dev = statb.st_rdev; 277 hp->dev_nxt = dev_hash[HASH(hp->dev_dev)]; 278 dev_hash[HASH(hp->dev_dev)] = hp; 279 if (hp->dev_dev == dev) { 280 dev_chain = nhp; 281 lastdev = dev; 282 return (lastname = hp->dev_name); 283 } 284 } 285 dev_chain = (struct devhash *) 0; 286 return ("??"); 287 } 288