123365Smckusick /* 223365Smckusick * Copyright (c) 1982 Regents of the University of California. 323365Smckusick * All rights reserved. The Berkeley software License Agreement 423365Smckusick * specifies the terms and conditions for redistribution. 523365Smckusick * 6*26277Skarels * @(#)kern_acct.c 6.9 (Berkeley) 02/20/86 723365Smckusick */ 812788Ssam 917088Sbloom #include "param.h" 1017088Sbloom #include "systm.h" 1117088Sbloom #include "dir.h" 1217088Sbloom #include "user.h" 1317088Sbloom #include "inode.h" 1417088Sbloom #include "fs.h" 1517088Sbloom #include "kernel.h" 1617088Sbloom #include "acct.h" 1717088Sbloom #include "uio.h" 1812788Ssam 1912788Ssam /* 2012788Ssam * SHOULD REPLACE THIS WITH A DRIVER THAT CAN BE READ TO SIMPLIFY. 2112788Ssam */ 2212788Ssam struct inode *acctp; 2312788Ssam struct inode *savacctp; 2412788Ssam 2512788Ssam /* 2612788Ssam * Perform process accounting functions. 2712788Ssam */ 2812788Ssam sysacct() 2912788Ssam { 3012788Ssam register struct inode *ip; 3112788Ssam register struct a { 3212788Ssam char *fname; 3312788Ssam } *uap = (struct a *)u.u_ap; 3416695Smckusick register struct nameidata *ndp = &u.u_nd; 3512788Ssam 3612788Ssam if (suser()) { 3712788Ssam if (savacctp) { 3812788Ssam acctp = savacctp; 3912788Ssam savacctp = NULL; 4012788Ssam } 4112788Ssam if (uap->fname==NULL) { 4212788Ssam if (ip = acctp) { 4312788Ssam irele(ip); 4412788Ssam acctp = NULL; 4512788Ssam } 4612788Ssam return; 4712788Ssam } 4816695Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW; 4916695Smckusick ndp->ni_segflg = UIO_USERSPACE; 5016695Smckusick ndp->ni_dirp = uap->fname; 5116695Smckusick ip = namei(ndp); 52*26277Skarels if (ip == NULL) 5312788Ssam return; 54*26277Skarels if ((ip->i_mode&IFMT) != IFREG) { 5512788Ssam u.u_error = EACCES; 5612788Ssam iput(ip); 5712788Ssam return; 5812788Ssam } 5920983Smckusick if (ip->i_fs->fs_ronly) { 6020983Smckusick u.u_error = EROFS; 6120983Smckusick iput(ip); 6220983Smckusick return; 6320983Smckusick } 6412788Ssam if (acctp && (acctp->i_number != ip->i_number || 6512788Ssam acctp->i_dev != ip->i_dev)) 6612788Ssam irele(acctp); 6712788Ssam acctp = ip; 6812788Ssam iunlock(ip); 6912788Ssam } 7012788Ssam } 7112788Ssam 7212788Ssam int acctsuspend = 2; /* stop accounting when < 2% free space left */ 7312788Ssam int acctresume = 4; /* resume when free space risen to > 4% */ 7412788Ssam 7512788Ssam struct acct acctbuf; 7612788Ssam /* 7712788Ssam * On exit, write a record on the accounting file. 7812788Ssam */ 7912788Ssam acct() 8012788Ssam { 8112788Ssam register int i; 8212788Ssam register struct inode *ip; 8312788Ssam register struct fs *fs; 8416715Ssam register struct rusage *ru; 8512788Ssam off_t siz; 8616715Ssam struct timeval t; 8712788Ssam register struct acct *ap = &acctbuf; 8812788Ssam 8912788Ssam if (savacctp) { 9012788Ssam fs = savacctp->i_fs; 9112788Ssam if (freespace(fs, fs->fs_minfree + acctresume) > 0) { 9212788Ssam acctp = savacctp; 9312788Ssam savacctp = NULL; 9412788Ssam printf("Accounting resumed\n"); 9512788Ssam } 9612788Ssam } 9712788Ssam if ((ip = acctp) == NULL) 9812788Ssam return; 9912788Ssam fs = acctp->i_fs; 10012788Ssam if (freespace(fs, fs->fs_minfree + acctsuspend) <= 0) { 10112788Ssam savacctp = acctp; 10212788Ssam acctp = NULL; 10312788Ssam printf("Accounting suspended\n"); 10412788Ssam return; 10512788Ssam } 10612788Ssam ilock(ip); 10712788Ssam for (i = 0; i < sizeof (ap->ac_comm); i++) 10812788Ssam ap->ac_comm[i] = u.u_comm[i]; 10916715Ssam ru = &u.u_ru; 11016715Ssam ap->ac_utime = compress(ru->ru_utime.tv_sec, ru->ru_utime.tv_usec); 11116715Ssam ap->ac_stime = compress(ru->ru_stime.tv_sec, ru->ru_stime.tv_usec); 11216715Ssam t = time; 11316715Ssam timevalsub(&t, &u.u_start); 11416715Ssam ap->ac_etime = compress(t.tv_sec, t.tv_usec); 11516715Ssam ap->ac_btime = u.u_start.tv_sec; 11612788Ssam ap->ac_uid = u.u_ruid; 11712788Ssam ap->ac_gid = u.u_rgid; 11816715Ssam t = ru->ru_stime; 11916715Ssam timevaladd(&t, &ru->ru_utime); 12016719Skarels if (i = t.tv_sec * hz + t.tv_usec / tick) 12116715Ssam ap->ac_mem = (ru->ru_ixrss+ru->ru_idrss+ru->ru_isrss) / i; 12216715Ssam else 12316715Ssam ap->ac_mem = 0; 12416715Ssam ap->ac_mem >>= CLSIZELOG2; 125*26277Skarels ap->ac_io = compress(ru->ru_inblock + ru->ru_oublock, (long)0); 12612788Ssam if (u.u_ttyp) 12712788Ssam ap->ac_tty = u.u_ttyd; 12812788Ssam else 12912788Ssam ap->ac_tty = NODEV; 13012788Ssam ap->ac_flag = u.u_acflag; 13112788Ssam siz = ip->i_size; 13212788Ssam u.u_error = 0; /* XXX */ 13312788Ssam u.u_error = 13412788Ssam rdwri(UIO_WRITE, ip, (caddr_t)ap, sizeof (acctbuf), siz, 13512788Ssam 1, (int *)0); 13612788Ssam if (u.u_error) 13712788Ssam itrunc(ip, (u_long)siz); 13812788Ssam iunlock(ip); 13912788Ssam } 14012788Ssam 14112788Ssam /* 14212788Ssam * Produce a pseudo-floating point representation 14312788Ssam * with 3 bits base-8 exponent, 13 bits fraction. 14412788Ssam */ 14516715Ssam compress(t, ut) 14612788Ssam register long t; 14716715Ssam long ut; 14812788Ssam { 14912788Ssam register exp = 0, round = 0; 15012788Ssam 15117501Skarels t = t * AHZ; /* compiler will convert only this format to a shift */ 15216715Ssam if (ut) 15317501Skarels t += ut / (1000000 / AHZ); 15412788Ssam while (t >= 8192) { 15512788Ssam exp++; 15612788Ssam round = t&04; 15712788Ssam t >>= 3; 15812788Ssam } 15912788Ssam if (round) { 16012788Ssam t++; 16112788Ssam if (t >= 8192) { 16212788Ssam t >>= 3; 16312788Ssam exp++; 16412788Ssam } 16512788Ssam } 16612788Ssam return ((exp<<13) + t); 16712788Ssam } 168