1 static char *sccsid = "@(#)sa.c 4.1 (Berkeley) 10/01/80"; 2 #include <stdio.h> 3 #include <sys/types.h> 4 #include <sys/acct.h> 5 #include <signal.h> 6 7 /* interpret command time accounting */ 8 9 #define size 2500 10 #define NC sizeof(acctbuf.ac_comm) 11 struct acct acctbuf; 12 int lflg; 13 int cflg; 14 int Dflg; 15 int dflg; 16 int iflg; 17 int jflg; 18 int Kflg; 19 int kflg; 20 int nflg; 21 int aflg; 22 int rflg; 23 int oflg; 24 int tflg; 25 int vflg; 26 int uflg; 27 int thres = 1; 28 int sflg; 29 int bflg; 30 int mflg; 31 32 struct user { 33 int us_cnt; 34 double us_ctime; 35 double us_io; 36 double us_imem; 37 } user[1000]; 38 39 struct tab { 40 char name[NC]; 41 int count; 42 double realt; 43 double cput; 44 double syst; 45 double imem; 46 double io; 47 } tab[size]; 48 49 double treal; 50 double tcpu; 51 double tsys; 52 double tio; 53 double timem; 54 int junkp = -1; 55 char *sname; 56 double ncom; 57 time_t expand(); 58 char *getname(); 59 60 main(argc, argv) 61 char **argv; 62 { 63 FILE *ff; 64 int i, j, k; 65 int (*cmp)(); 66 extern tcmp(), ncmp(), bcmp(), dcmp(), Dcmp(), kcmp(), Kcmp(); 67 extern double sum(); 68 double ft; 69 70 cmp = tcmp; 71 if (argc>1) 72 if (argv[1][0]=='-') { 73 argv++; 74 argc--; 75 for(i=1; argv[0][i]; i++) 76 switch(argv[0][i]) { 77 78 case 'o': 79 oflg++; 80 break; 81 82 case 'i': 83 iflg++; 84 break; 85 86 case 'b': 87 bflg++; 88 cmp = bcmp; 89 break; 90 91 case 'l': 92 lflg++; 93 break; 94 95 case 'c': 96 cflg++; 97 break; 98 99 case 'd': 100 dflg++; 101 cmp = dcmp; 102 break; 103 104 case 'D': 105 Dflg++; 106 cmp = Dcmp; 107 break; 108 109 case 'j': 110 jflg++; 111 break; 112 113 case 'k': 114 kflg++; 115 cmp = kcmp; 116 break; 117 118 case 'K': 119 Kflg++; 120 cmp = Kcmp; 121 break; 122 123 case 'n': 124 nflg++; 125 cmp = ncmp; 126 break; 127 128 case 'a': 129 aflg++; 130 break; 131 132 case 'r': 133 rflg++; 134 break; 135 136 case 't': 137 tflg++; 138 break; 139 140 case 's': 141 sflg++; 142 aflg++; 143 break; 144 145 case '0': 146 case '1': 147 case '2': 148 case '3': 149 case '4': 150 case '5': 151 case '6': 152 case '7': 153 case '8': 154 case '9': 155 thres = argv[0][i]-'0'; 156 break; 157 158 case 'v': 159 vflg++; 160 break; 161 162 case 'u': 163 uflg++; 164 break; 165 166 case 'm': 167 mflg++; 168 break; 169 } 170 } 171 if (iflg==0) 172 init(); 173 if (argc<2) 174 doacct("/usr/adm/acct"); 175 else while (--argc) 176 doacct(*++argv); 177 if (uflg) { 178 return; 179 } 180 181 /* 182 * cleanup pass 183 * put junk together 184 */ 185 186 if (vflg) 187 strip(); 188 if(!aflg) 189 for (i=0; i<size; i++) 190 if (tab[i].name[0]) { 191 for(j=0; j<NC; j++) 192 if(tab[i].name[j] == '?') 193 goto yes; 194 if(tab[i].count != 1) 195 continue; 196 yes: 197 if(junkp == -1) 198 junkp = enter("***other"); 199 tab[junkp].count += tab[i].count; 200 tab[junkp].realt += tab[i].realt; 201 tab[junkp].cput += tab[i].cput; 202 tab[junkp].syst += tab[i].syst; 203 tab[junkp].imem += tab[i].imem; 204 tab[junkp].io += tab[i].io; 205 tab[i].name[0] = 0; 206 } 207 for(i=k=0; i<size; i++) 208 if(tab[i].name[0]) { 209 tab[k] = tab[i]; 210 k++; 211 } 212 if (sflg) { 213 signal(SIGINT, SIG_IGN); 214 if ((ff = fopen("/usr/adm/usracct", "w")) != NULL) { 215 fwrite((char *)user, sizeof(user), 1, ff); 216 fclose(ff); 217 } 218 if ((ff = fopen("/usr/adm/savacct", "w")) == NULL) { 219 printf("Can't save\n"); 220 exit(0); 221 } 222 fwrite((char *)tab, sizeof(tab[0]), k, ff); 223 fclose(ff); 224 creat("/usr/adm/acct", 0644); 225 signal(SIGINT, SIG_DFL); 226 } 227 /* 228 * sort and print 229 */ 230 231 if (mflg) { 232 printmoney(); 233 exit(0); 234 } 235 qsort(tab, k, sizeof(tab[0]), cmp); 236 column(ncom, treal, tcpu, tsys, timem, tio); 237 printf("\n"); 238 for (i=0; i<k; i++) 239 if (tab[i].name[0]) { 240 ft = tab[i].count; 241 column(ft, tab[i].realt, tab[i].cput, tab[i].syst, tab[i].imem, tab[i].io); 242 printf(" %.14s\n", tab[i].name); 243 } 244 } 245 246 printmoney() 247 { 248 register i; 249 char buf[128]; 250 register char *cp; 251 252 for (i=0; i<sizeof(user)/sizeof(user[0]); i++) { 253 if (user[i].us_cnt && user[i].us_ctime) { 254 cp = getname(i); 255 if (cp == 0) 256 printf("%-8d", i); 257 else 258 printf("%-8s", cp); 259 printf("%7u %9.2fcpu %10.0ftio %12.0fk*sec\n", 260 user[i].us_cnt, user[i].us_ctime/60, 261 user[i].us_io, 262 user[i].us_imem / (60 * 2)); 263 } 264 } 265 } 266 267 column(n, a, b, c, d, e) 268 double n, a, b, c, d, e; 269 { 270 271 printf("%8.0f", n); 272 if(cflg) { 273 if(n == ncom) 274 printf("%9s", ""); else 275 printf("%8.2f%%", 100.*n/ncom); 276 } 277 col(n, a, treal, "re"); 278 if (oflg) 279 col(n, 3600*(b/(b+c)), tcpu+tsys, "u/s"); 280 else if(lflg) { 281 col(n, b, tcpu, "u"); 282 col(n, c, tsys, "s"); 283 } else 284 col(n, b+c, tcpu+tsys, "cp"); 285 if(tflg) 286 printf("%8.1f", a/(b+c), "re/cp"); 287 if(dflg || !Dflg) 288 printf("%10.0favio", e/(n?n:1)); 289 else 290 printf("%10.0ftio", e); 291 if (kflg || !Kflg) 292 printf("%10.0fk", d/(2*((b+c)!=0.0?(b+c):1.0))); 293 else 294 printf("%10.0fk*sec", d/(2*60)); 295 } 296 297 col(n, a, m, cp) 298 double n, a, m; 299 char *cp; 300 { 301 302 if(jflg) 303 printf("%11.2f%s", a/(n*60.), cp); else 304 printf("%11.2f%s", a/3600., cp); 305 if(cflg) { 306 if(a == m) 307 printf("%9s", ""); else 308 printf("%8.2f%%", 100.*a/m); 309 } 310 } 311 312 doacct(f) 313 char *f; 314 { 315 int i; 316 FILE *ff; 317 long x, y, z; 318 struct acct fbuf; 319 register char *cp; 320 register int c; 321 322 if (sflg && sname) { 323 printf("Only 1 file with -s\n"); 324 exit(0); 325 } 326 if (sflg) 327 sname = f; 328 if ((ff = fopen(f, "r"))==NULL) { 329 printf("Can't open %s\n", f); 330 return; 331 } 332 while (fread((char *)&fbuf, sizeof(fbuf), 1, ff) == 1) { 333 if (fbuf.ac_comm[0]==0) { 334 fbuf.ac_comm[0] = '?'; 335 } 336 for (cp = fbuf.ac_comm; cp < &fbuf.ac_comm[NC]; cp++) { 337 c = *cp & 0377; 338 if (c && (c < ' ' || c >= 0200)) { 339 *cp = '?'; 340 } 341 } 342 if (fbuf.ac_flag&AFORK) { 343 for (cp=fbuf.ac_comm; cp < &fbuf.ac_comm[NC]; cp++) 344 if (*cp==0) { 345 *cp = '*'; 346 break; 347 } 348 } 349 x = expand(fbuf.ac_utime) + expand(fbuf.ac_stime); 350 y = fbuf.ac_mem; 351 z = expand(fbuf.ac_io); 352 if (uflg) { 353 printf("%3d%6.1fcp %6dmem %6dio %.14s\n", 354 fbuf.ac_uid, x/60.0, y, z, 355 fbuf.ac_comm); 356 continue; 357 } 358 c = fbuf.ac_uid; 359 user[c].us_cnt++; 360 user[c].us_ctime += x/60.; 361 user[c].us_imem += x * y; 362 user[c].us_io += z; 363 ncom += 1.0; 364 i = enter(fbuf.ac_comm); 365 tab[i].imem += x * y; 366 timem += x * y; 367 tab[i].count++; 368 x = expand(fbuf.ac_etime)*60; 369 tab[i].realt += x; 370 treal += x; 371 x = expand(fbuf.ac_utime); 372 tab[i].cput += x; 373 tcpu += x; 374 x = expand(fbuf.ac_stime); 375 tab[i].syst += x; 376 tsys += x; 377 tab[i].io += z; 378 tio += z; 379 } 380 fclose(ff); 381 } 382 383 ncmp(p1, p2) 384 struct tab *p1, *p2; 385 { 386 387 if(p1->count == p2->count) 388 return(tcmp(p1, p2)); 389 if(rflg) 390 return(p1->count - p2->count); 391 return(p2->count - p1->count); 392 } 393 394 bcmp(p1, p2) 395 struct tab *p1, *p2; 396 { 397 double f1, f2; 398 double sum(); 399 400 f1 = sum(p1)/p1->count; 401 f2 = sum(p2)/p2->count; 402 if(f1 < f2) { 403 if(rflg) 404 return(-1); 405 return(1); 406 } 407 if(f1 > f2) { 408 if(rflg) 409 return(1); 410 return(-1); 411 } 412 return(0); 413 } 414 415 Kcmp(p1, p2) 416 struct tab *p1, *p2; 417 { 418 419 if (p1->imem < p2->imem) { 420 if(rflg) 421 return(-1); 422 return(1); 423 } 424 if (p1->imem > p2->imem) { 425 if(rflg) 426 return(1); 427 return(-1); 428 } 429 return(0); 430 } 431 432 kcmp(p1, p2) 433 struct tab *p1, *p2; 434 { 435 double a1, a2; 436 437 a1 = p1->imem / ((p1->cput+p1->syst)?(p1->cput+p1->syst):1); 438 a2 = p2->imem / ((p2->cput+p2->syst)?(p2->cput+p2->syst):1); 439 if (a1 < a2) { 440 if(rflg) 441 return(-1); 442 return(1); 443 } 444 if (a1 > a2) { 445 if(rflg) 446 return(1); 447 return(-1); 448 } 449 return(0); 450 } 451 452 dcmp(p1, p2) 453 struct tab *p1, *p2; 454 { 455 double a1, a2; 456 457 a1 = p1->io / (p1->count?p1->count:1); 458 a2 = p2->io / (p2->count?p2->count:1); 459 if (a1 < a2) { 460 if(rflg) 461 return(-1); 462 return(1); 463 } 464 if (a1 > a2) { 465 if(rflg) 466 return(1); 467 return(-1); 468 } 469 return(0); 470 } 471 472 Dcmp(p1, p2) 473 struct tab *p1, *p2; 474 { 475 476 if (p1->io < p2->io) { 477 if(rflg) 478 return(-1); 479 return(1); 480 } 481 if (p1->io > p2->io) { 482 if(rflg) 483 return(1); 484 return(-1); 485 } 486 return(0); 487 } 488 489 tcmp(p1, p2) 490 struct tab *p1, *p2; 491 { 492 extern double sum(); 493 double f1, f2; 494 495 f1 = sum(p1); 496 f2 = sum(p2); 497 if(f1 < f2) { 498 if(rflg) 499 return(-1); 500 return(1); 501 } 502 if(f1 > f2) { 503 if(rflg) 504 return(1); 505 return(-1); 506 } 507 return(0); 508 } 509 510 double sum(p) 511 struct tab *p; 512 { 513 514 if(p->name[0] == 0) 515 return(0.0); 516 return( 517 p->cput+ 518 p->syst); 519 } 520 521 init() 522 { 523 struct tab tbuf; 524 int i; 525 FILE *f; 526 527 if ((f = fopen("/usr/adm/savacct", "r")) == NULL) 528 goto gshm; 529 while (fread((char *)&tbuf, sizeof(tbuf), 1, f) == 1) { 530 i = enter(tbuf.name); 531 ncom += tbuf.count; 532 tab[i].count = tbuf.count; 533 treal += tbuf.realt; 534 tab[i].realt = tbuf.realt; 535 tcpu += tbuf.cput; 536 tab[i].cput = tbuf.cput; 537 tsys += tbuf.syst; 538 tab[i].syst = tbuf.syst; 539 tio += tbuf.io; 540 tab[i].io = tbuf.io; 541 timem += tbuf.imem; 542 tab[i].imem = tbuf.imem; 543 } 544 fclose(f); 545 gshm: 546 if ((f = fopen("/usr/adm/usracct", "r")) == NULL) 547 return; 548 fread((char *)user, sizeof(user), 1, f); 549 fclose(f); 550 } 551 552 enter(np) 553 char *np; 554 { 555 int i, j; 556 557 for (i=j=0; i<NC; i++) { 558 if (np[i]==0) 559 j = i; 560 if (j) 561 np[i] = 0; 562 } 563 for (i=j=0; j<NC; j++) { 564 i = i*7 + np[j]; 565 } 566 if (i < 0) 567 i = -i; 568 for (i%=size; tab[i].name[0]; i = (i+1)%size) { 569 for (j=0; j<NC; j++) 570 if (tab[i].name[j]!=np[j]) 571 goto no; 572 goto yes; 573 no:; 574 } 575 for (j=0; j<NC; j++) 576 tab[i].name[j] = np[j]; 577 yes: 578 return(i); 579 } 580 581 strip() 582 { 583 int i, j, c; 584 585 j = enter("**junk**"); 586 for (i = 0; i<size; i++) { 587 if (tab[i].name[0] && tab[i].count<=thres) { 588 printf("%.14s--", tab[i].name); 589 if ((c=getchar())=='y') { 590 tab[i].name[0] = '\0'; 591 tab[j].count += tab[i].count; 592 tab[j].realt += tab[i].realt; 593 tab[j].cput += tab[i].cput; 594 tab[j].syst += tab[i].syst; 595 } 596 while (c && c!='\n') 597 c = getchar(); 598 } 599 } 600 } 601 602 time_t 603 expand(t) 604 unsigned t; 605 { 606 register time_t nt; 607 608 nt = t&017777; 609 t >>= 13; 610 while (t!=0) { 611 t--; 612 nt <<= 3; 613 } 614 return(nt); 615 } 616 617 #include <utmp.h> 618 #include <pwd.h> 619 620 struct utmp utmp; 621 #define NMAX sizeof (utmp.ut_name) 622 #define NUID 2048 623 624 char names[NUID][NMAX+1]; 625 626 char * 627 getname(uid) 628 { 629 register struct passwd *pw; 630 static init; 631 struct passwd *getpwent(); 632 633 if (names[uid][0]) 634 return (&names[uid][0]); 635 if (init == 2) 636 return (0); 637 if (init == 0) 638 setpwent(), init = 1; 639 while (pw = getpwent()) { 640 if (pw->pw_uid >= NUID) 641 continue; 642 if (names[pw->pw_uid][0]) 643 continue; 644 strncpy(names[pw->pw_uid], pw->pw_name, NMAX); 645 if (pw->pw_uid == uid) 646 return (&names[uid][0]); 647 } 648 init = 2; 649 endpwent(); 650 return (0); 651 } 652