112703Smckusick #ifndef lint 2*21085Smckusick static char sccsid[] = "@(#)quotacheck.c 4.6 (Berkeley, Melbourne) 05/24/85"; 312660Smckusick #endif 412660Smckusick 512660Smckusick /* 612660Smckusick * Fix up / report on disc quotas & usage 712660Smckusick */ 812660Smckusick #include <stdio.h> 912660Smckusick #include <ctype.h> 1012660Smckusick #include <signal.h> 11*21085Smckusick #include <errno.h> 1212660Smckusick #include <sys/param.h> 1312660Smckusick #include <sys/inode.h> 1412660Smckusick #include <sys/fs.h> 1512660Smckusick #include <sys/quota.h> 1612660Smckusick #include <sys/stat.h> 1712703Smckusick #include <fstab.h> 1812802Smckusick #include <pwd.h> 1912660Smckusick 2012660Smckusick union { 2112660Smckusick struct fs sblk; 2212703Smckusick char dummy[MAXBSIZE]; 2312660Smckusick } un; 2412660Smckusick #define sblock un.sblk 2512703Smckusick 2612703Smckusick #define ITABSZ 256 2712660Smckusick struct dinode itab[ITABSZ]; 2812660Smckusick struct dinode *dp; 2912660Smckusick long blocks; 3012660Smckusick dev_t dev; 3112660Smckusick 3212802Smckusick #define LOGINNAMESIZE 8 3312703Smckusick struct fileusage { 3412802Smckusick struct fileusage *fu_next; 3512703Smckusick struct dqusage fu_usage; 3612703Smckusick u_short fu_uid; 3712802Smckusick char fu_name[LOGINNAMESIZE + 1]; 3812703Smckusick }; 3912703Smckusick #define FUHASH 997 4012703Smckusick struct fileusage *fuhead[FUHASH]; 4112703Smckusick struct fileusage *lookup(); 4212703Smckusick struct fileusage *adduid(); 4312703Smckusick int highuid; 4412660Smckusick 4512703Smckusick int fi; 4612703Smckusick ino_t ino; 4712703Smckusick long done; 4812660Smckusick struct passwd *getpwent(); 4912660Smckusick struct dinode *ginode(); 5012703Smckusick char *malloc(), *makerawname(); 5112660Smckusick 5212703Smckusick int vflag; /* verbose */ 5312703Smckusick int aflag; /* all file systems */ 5412703Smckusick 5512703Smckusick char *qfname = "quotas"; 5612703Smckusick char quotafile[MAXPATHLEN + 1]; 5712802Smckusick struct dqblk zerodqbuf; 5812703Smckusick 5912660Smckusick main(argc, argv) 6012703Smckusick int argc; 6112660Smckusick char **argv; 6212660Smckusick { 6312703Smckusick register struct fstab *fs; 6412802Smckusick register struct fileusage *fup; 6512802Smckusick register struct passwd *pw; 6612703Smckusick int i, errs = 0; 6712660Smckusick 6812703Smckusick again: 6912703Smckusick argc--, argv++; 7012703Smckusick if (argc > 0 && strcmp(*argv, "-v") == 0) { 7112703Smckusick vflag++; 7212703Smckusick goto again; 7312660Smckusick } 7412703Smckusick if (argc > 0 && strcmp(*argv, "-a") == 0) { 7512703Smckusick aflag++; 7612703Smckusick goto again; 7712703Smckusick } 7812703Smckusick if (argc <= 0 && !aflag) { 7912703Smckusick fprintf(stderr, "Usage:\n\t%s\n\t%s\n", 8012703Smckusick "quotacheck [-v] -a", 8112703Smckusick "quotacheck [-v] filesys ..."); 8212660Smckusick exit(1); 8312660Smckusick } 8412802Smckusick if (vflag) { 8512802Smckusick setpwent(); 8612802Smckusick while ((pw = getpwent()) != 0) { 8712802Smckusick fup = lookup(pw->pw_uid); 8812802Smckusick if (fup == 0) 8912802Smckusick fup = adduid(pw->pw_uid); 9012802Smckusick strncpy(fup->fu_name, pw->pw_name, 9112802Smckusick sizeof(fup->fu_name)); 9212802Smckusick } 9312802Smckusick endpwent(); 9412802Smckusick } 9512703Smckusick setfsent(); 9612703Smckusick while ((fs = getfsent()) != NULL) { 9712703Smckusick if (aflag && 9812703Smckusick (fs->fs_type == 0 || strcmp(fs->fs_type, "rq") != 0)) 9912703Smckusick continue; 10012703Smckusick if (!aflag && 10112703Smckusick !(oneof(fs->fs_file, argv, argc) || 10212703Smckusick oneof(fs->fs_spec, argv, argc))) 10312703Smckusick continue; 10412703Smckusick (void) sprintf(quotafile, "%s/%s", fs->fs_file, qfname); 10512703Smckusick errs += chkquota(fs->fs_spec, quotafile); 10612660Smckusick } 10712703Smckusick endfsent(); 10812703Smckusick for (i = 0; i < argc; i++) 10912703Smckusick if ((done & (1 << i)) == 0) 11012703Smckusick fprintf(stderr, "%s not found in /etc/fstab\n", 11112703Smckusick argv[i]); 11212703Smckusick exit(errs); 11312703Smckusick } 11412660Smckusick 11512703Smckusick chkquota(fsdev, qffile) 11612703Smckusick char *fsdev; 11712703Smckusick char *qffile; 11812703Smckusick { 11912703Smckusick register struct fileusage *fup; 12012703Smckusick dev_t quotadev; 12112703Smckusick FILE *qf; 12212703Smckusick u_short uid; 12312703Smckusick int cg, i; 12412703Smckusick char *rawdisk; 12512703Smckusick struct stat statb; 12612703Smckusick struct dqblk dqbuf; 127*21085Smckusick static int warned = 0; 128*21085Smckusick extern int errno; 12912660Smckusick 13012703Smckusick rawdisk = makerawname(fsdev); 13112703Smckusick if (vflag) 13212703Smckusick fprintf(stdout, "*** Check quotas for %s\n", rawdisk); 13312703Smckusick fi = open(rawdisk, 0); 13412703Smckusick if (fi < 0) { 13512703Smckusick perror(rawdisk); 13612703Smckusick return (1); 13712660Smckusick } 13812703Smckusick qf = fopen(qffile, "r+"); 13912703Smckusick if (qf == NULL) { 14012703Smckusick perror(qffile); 14112703Smckusick return (1); 14212660Smckusick } 14312703Smckusick if (fstat(fileno(qf), &statb) < 0) { 14412703Smckusick perror(qffile); 14512703Smckusick return (1); 14612703Smckusick } 14712703Smckusick quotadev = statb.st_dev; 14812703Smckusick if (stat(fsdev, &statb) < 0) { 14912703Smckusick perror(fsdev); 15012703Smckusick return (1); 15112703Smckusick } 15212703Smckusick if (quotadev != statb.st_rdev) { 15312703Smckusick fprintf(stderr, "%s dev (0x%x) mismatch %s dev (0x%x)\n", 15412703Smckusick qffile, quotadev, fsdev, statb.st_rdev); 15512703Smckusick return (1); 15612703Smckusick } 157*21085Smckusick if (quota(Q_SYNC, 0, quotadev, 0) < 0 && 158*21085Smckusick errno == EINVAL && !warned && vflag) { 159*21085Smckusick warned++; 160*21085Smckusick fprintf(stdout, 161*21085Smckusick "*** Warning: Quotas are not compiled into this kernel\n"); 162*21085Smckusick } 16312660Smckusick sync(); 16412660Smckusick bread(SBLOCK, (char *)&sblock, SBSIZE); 16512660Smckusick ino = 0; 16612660Smckusick for (cg = 0; cg < sblock.fs_ncg; cg++) { 16712660Smckusick dp = NULL; 16812660Smckusick for (i = 0; i < sblock.fs_ipg; i++) 16912660Smckusick acct(ginode()); 17012660Smckusick } 17112703Smckusick for (uid = 0; uid <= highuid; uid++) { 17212703Smckusick i = fread(&dqbuf, sizeof(struct dqblk), 1, qf); 17312703Smckusick if (i == 0) 17412802Smckusick dqbuf = zerodqbuf; 17518415Smckusick fup = lookup(uid); 17618415Smckusick if (fup == 0) { 17718415Smckusick if (!feof(qf)) { 17818415Smckusick fseek(qf, uid * sizeof(struct dqblk), 0); 17918415Smckusick fwrite(&zerodqbuf, sizeof(struct dqblk), 1, qf); 18018415Smckusick } 18118415Smckusick continue; 18218415Smckusick } 18312703Smckusick if (dqbuf.dqb_curinodes == fup->fu_usage.du_curinodes && 18412802Smckusick dqbuf.dqb_curblocks == fup->fu_usage.du_curblocks) { 18512802Smckusick fup->fu_usage.du_curinodes = 0; 18612802Smckusick fup->fu_usage.du_curblocks = 0; 18712703Smckusick continue; 18812802Smckusick } 18912703Smckusick if (vflag) { 19012802Smckusick if (fup->fu_name[0] != '\0') 19112802Smckusick printf("%-10s fixed:", fup->fu_name); 19212802Smckusick else 19312802Smckusick printf("#%-9d fixed:", uid); 19412703Smckusick fprintf(stdout, " inodes (old %d, new %d)", 19512703Smckusick dqbuf.dqb_curinodes, fup->fu_usage.du_curinodes); 19612703Smckusick fprintf(stdout, " blocks (old %d, new %d)\n", 19712703Smckusick dqbuf.dqb_curblocks, fup->fu_usage.du_curblocks); 19812660Smckusick } 19912703Smckusick dqbuf.dqb_curinodes = fup->fu_usage.du_curinodes; 20012703Smckusick dqbuf.dqb_curblocks = fup->fu_usage.du_curblocks; 20112703Smckusick fseek(qf, uid * sizeof(struct dqblk), 0); 20212703Smckusick fwrite(&dqbuf, sizeof(struct dqblk), 1, qf); 20312703Smckusick quota(Q_SETDUSE, uid, quotadev, &fup->fu_usage); 20413255Smckusick fup->fu_usage.du_curinodes = 0; 20513255Smckusick fup->fu_usage.du_curblocks = 0; 20612660Smckusick } 20718415Smckusick ftruncate(fileno(qf), (highuid + 1) * sizeof(struct dqblk)); 20812703Smckusick return (0); 20912660Smckusick } 21012660Smckusick 21112660Smckusick acct(ip) 21212660Smckusick register struct dinode *ip; 21312660Smckusick { 21412660Smckusick register n; 21512703Smckusick register struct fileusage *fup; 21612660Smckusick 21712660Smckusick if (ip == NULL) 21812660Smckusick return; 21912660Smckusick if (ip->di_mode == 0) 22012660Smckusick return; 22112703Smckusick fup = lookup(ip->di_uid); 22212703Smckusick if (fup == 0) 22312703Smckusick fup = adduid(ip->di_uid); 22412703Smckusick fup->fu_usage.du_curinodes++; 22512660Smckusick if ((ip->di_mode & IFMT) == IFCHR || (ip->di_mode & IFMT) == IFBLK) 22612660Smckusick return; 22712703Smckusick fup->fu_usage.du_curblocks += ip->di_blocks; 22812660Smckusick } 22912660Smckusick 23012703Smckusick oneof(target, list, n) 23112703Smckusick char *target, *list[]; 23212703Smckusick register int n; 23312660Smckusick { 23412703Smckusick register int i; 23512660Smckusick 23612703Smckusick for (i = 0; i < n; i++) 23712703Smckusick if (strcmp(target, list[i]) == 0) { 23812703Smckusick done |= 1 << i; 23912703Smckusick return (1); 24012703Smckusick } 24112703Smckusick return (0); 24212660Smckusick } 24312660Smckusick 24412660Smckusick struct dinode * 24512660Smckusick ginode() 24612660Smckusick { 24712660Smckusick register unsigned long iblk; 24812660Smckusick 24912660Smckusick if (dp == NULL || ++dp >= &itab[ITABSZ]) { 25012660Smckusick iblk = itod(&sblock, ino); 25112660Smckusick bread(fsbtodb(&sblock, iblk), (char *)itab, sizeof itab); 25212660Smckusick dp = &itab[ino % INOPB(&sblock)]; 25312660Smckusick } 25412660Smckusick if (ino++ < ROOTINO) 25512660Smckusick return(NULL); 25612660Smckusick return(dp); 25712660Smckusick } 25812660Smckusick 25912660Smckusick bread(bno, buf, cnt) 26012660Smckusick long unsigned bno; 26112660Smckusick char *buf; 26212660Smckusick { 26312660Smckusick 26412703Smckusick lseek(fi, (long)dbtob(bno), 0); 26512660Smckusick if (read(fi, buf, cnt) != cnt) { 26612660Smckusick printf("read error %u\n", bno); 26712660Smckusick exit(1); 26812660Smckusick } 26912660Smckusick } 27012660Smckusick 27112703Smckusick struct fileusage * 27212703Smckusick lookup(uid) 27312703Smckusick u_short uid; 27412660Smckusick { 27512703Smckusick register struct fileusage *fup; 27612660Smckusick 27712703Smckusick for (fup = fuhead[uid % FUHASH]; fup != 0; fup = fup->fu_next) 27812703Smckusick if (fup->fu_uid == uid) 27912703Smckusick return (fup); 28012703Smckusick return ((struct fileusage *)0); 28112660Smckusick } 28212660Smckusick 28312703Smckusick struct fileusage * 28412703Smckusick adduid(uid) 28512703Smckusick u_short uid; 28612660Smckusick { 28712703Smckusick struct fileusage *fup, **fhp; 28812660Smckusick 28912703Smckusick fup = lookup(uid); 29012703Smckusick if (fup != 0) 29112703Smckusick return (fup); 29212703Smckusick fup = (struct fileusage *)calloc(1, sizeof(struct fileusage)); 29312703Smckusick if (fup == 0) { 29412703Smckusick fprintf(stderr, "out of memory for fileusage structures\n"); 29512703Smckusick exit(1); 29612703Smckusick } 29712703Smckusick fhp = &fuhead[uid % FUHASH]; 29812703Smckusick fup->fu_next = *fhp; 29912703Smckusick *fhp = fup; 30012703Smckusick fup->fu_uid = uid; 30112703Smckusick if (uid > highuid) 30212703Smckusick highuid = uid; 30312703Smckusick return (fup); 30412660Smckusick } 30512660Smckusick 30612660Smckusick char * 30712703Smckusick makerawname(name) 30812703Smckusick char *name; 30912660Smckusick { 31012703Smckusick register char *cp; 31112703Smckusick char tmp, ch, *rindex(); 31212703Smckusick static char rawname[MAXPATHLEN]; 31312660Smckusick 31412703Smckusick strcpy(rawname, name); 31512703Smckusick cp = rindex(rawname, '/') + 1; 31612703Smckusick if (cp == (char *)1 || *cp == 'r') 31712703Smckusick return (name); 31812703Smckusick for (ch = 'r'; *cp != '\0'; ) { 31912703Smckusick tmp = *cp; 32012703Smckusick *cp++ = ch; 32112703Smckusick ch = tmp; 32212703Smckusick } 32312703Smckusick *cp++ = ch; 32412703Smckusick *cp = '\0'; 32512703Smckusick return (rawname); 32612660Smckusick } 327