123365Smckusick /* 229085Smckusick * Copyright (c) 1982, 1986 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*35809Smarc * @(#)kern_acct.c 7.3 (Berkeley) 10/18/88 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) { 4330166Skarels acctp = NULL; 4412788Ssam irele(ip); 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); 5226277Skarels if (ip == NULL) 5312788Ssam return; 5426277Skarels 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); 107*35809Smarc bcopy(u.u_comm, ap->ac_comm, sizeof(ap->ac_comm)); 10816715Ssam ru = &u.u_ru; 10916715Ssam ap->ac_utime = compress(ru->ru_utime.tv_sec, ru->ru_utime.tv_usec); 11016715Ssam ap->ac_stime = compress(ru->ru_stime.tv_sec, ru->ru_stime.tv_usec); 11116715Ssam t = time; 11216715Ssam timevalsub(&t, &u.u_start); 11316715Ssam ap->ac_etime = compress(t.tv_sec, t.tv_usec); 11416715Ssam ap->ac_btime = u.u_start.tv_sec; 11512788Ssam ap->ac_uid = u.u_ruid; 11612788Ssam ap->ac_gid = u.u_rgid; 11716715Ssam t = ru->ru_stime; 11816715Ssam timevaladd(&t, &ru->ru_utime); 11916719Skarels if (i = t.tv_sec * hz + t.tv_usec / tick) 12016715Ssam ap->ac_mem = (ru->ru_ixrss+ru->ru_idrss+ru->ru_isrss) / i; 12116715Ssam else 12216715Ssam ap->ac_mem = 0; 12316715Ssam ap->ac_mem >>= CLSIZELOG2; 12426277Skarels ap->ac_io = compress(ru->ru_inblock + ru->ru_oublock, (long)0); 12512788Ssam if (u.u_ttyp) 12612788Ssam ap->ac_tty = u.u_ttyd; 12712788Ssam else 12812788Ssam ap->ac_tty = NODEV; 12912788Ssam ap->ac_flag = u.u_acflag; 13012788Ssam siz = ip->i_size; 13112788Ssam u.u_error = 0; /* XXX */ 13212788Ssam u.u_error = 13312788Ssam rdwri(UIO_WRITE, ip, (caddr_t)ap, sizeof (acctbuf), siz, 13412788Ssam 1, (int *)0); 13512788Ssam if (u.u_error) 13612788Ssam itrunc(ip, (u_long)siz); 13712788Ssam iunlock(ip); 13812788Ssam } 13912788Ssam 14012788Ssam /* 14112788Ssam * Produce a pseudo-floating point representation 14212788Ssam * with 3 bits base-8 exponent, 13 bits fraction. 14312788Ssam */ 14416715Ssam compress(t, ut) 14512788Ssam register long t; 14616715Ssam long ut; 14712788Ssam { 14812788Ssam register exp = 0, round = 0; 14912788Ssam 15017501Skarels t = t * AHZ; /* compiler will convert only this format to a shift */ 15116715Ssam if (ut) 15217501Skarels t += ut / (1000000 / AHZ); 15312788Ssam while (t >= 8192) { 15412788Ssam exp++; 15512788Ssam round = t&04; 15612788Ssam t >>= 3; 15712788Ssam } 15812788Ssam if (round) { 15912788Ssam t++; 16012788Ssam if (t >= 8192) { 16112788Ssam t >>= 3; 16212788Ssam exp++; 16312788Ssam } 16412788Ssam } 16512788Ssam return ((exp<<13) + t); 16612788Ssam } 167