1*21517Smckusick /* 2*21517Smckusick * Copyright (c) 1980 Regents of the University of California. 3*21517Smckusick * All rights reserved. The Berkeley software License Agreement 4*21517Smckusick * specifies the terms and conditions for redistribution. 5*21517Smckusick */ 6*21517Smckusick 712703Smckusick #ifndef lint 8*21517Smckusick char copyright[] = 9*21517Smckusick "@(#) Copyright (c) 1980 Regents of the University of California.\n\ 10*21517Smckusick All rights reserved.\n"; 11*21517Smckusick #endif not lint 1212660Smckusick 13*21517Smckusick #ifndef lint 14*21517Smckusick static char sccsid[] = "@(#)quotacheck.c 5.1 (Berkeley) 05/30/85"; 15*21517Smckusick #endif not lint 16*21517Smckusick 1712660Smckusick /* 1812660Smckusick * Fix up / report on disc quotas & usage 1912660Smckusick */ 2012660Smckusick #include <stdio.h> 2112660Smckusick #include <ctype.h> 2212660Smckusick #include <signal.h> 2321085Smckusick #include <errno.h> 2412660Smckusick #include <sys/param.h> 2512660Smckusick #include <sys/inode.h> 2612660Smckusick #include <sys/fs.h> 2712660Smckusick #include <sys/quota.h> 2812660Smckusick #include <sys/stat.h> 2912703Smckusick #include <fstab.h> 3012802Smckusick #include <pwd.h> 3112660Smckusick 3212660Smckusick union { 3312660Smckusick struct fs sblk; 3412703Smckusick char dummy[MAXBSIZE]; 3512660Smckusick } un; 3612660Smckusick #define sblock un.sblk 3712703Smckusick 3812703Smckusick #define ITABSZ 256 3912660Smckusick struct dinode itab[ITABSZ]; 4012660Smckusick struct dinode *dp; 4112660Smckusick long blocks; 4212660Smckusick dev_t dev; 4312660Smckusick 4412802Smckusick #define LOGINNAMESIZE 8 4512703Smckusick struct fileusage { 4612802Smckusick struct fileusage *fu_next; 4712703Smckusick struct dqusage fu_usage; 4812703Smckusick u_short fu_uid; 4912802Smckusick char fu_name[LOGINNAMESIZE + 1]; 5012703Smckusick }; 5112703Smckusick #define FUHASH 997 5212703Smckusick struct fileusage *fuhead[FUHASH]; 5312703Smckusick struct fileusage *lookup(); 5412703Smckusick struct fileusage *adduid(); 5512703Smckusick int highuid; 5612660Smckusick 5712703Smckusick int fi; 5812703Smckusick ino_t ino; 5912703Smckusick long done; 6012660Smckusick struct passwd *getpwent(); 6112660Smckusick struct dinode *ginode(); 6212703Smckusick char *malloc(), *makerawname(); 6312660Smckusick 6412703Smckusick int vflag; /* verbose */ 6512703Smckusick int aflag; /* all file systems */ 6612703Smckusick 6712703Smckusick char *qfname = "quotas"; 6812703Smckusick char quotafile[MAXPATHLEN + 1]; 6912802Smckusick struct dqblk zerodqbuf; 7012703Smckusick 7112660Smckusick main(argc, argv) 7212703Smckusick int argc; 7312660Smckusick char **argv; 7412660Smckusick { 7512703Smckusick register struct fstab *fs; 7612802Smckusick register struct fileusage *fup; 7712802Smckusick register struct passwd *pw; 7812703Smckusick int i, errs = 0; 7912660Smckusick 8012703Smckusick again: 8112703Smckusick argc--, argv++; 8212703Smckusick if (argc > 0 && strcmp(*argv, "-v") == 0) { 8312703Smckusick vflag++; 8412703Smckusick goto again; 8512660Smckusick } 8612703Smckusick if (argc > 0 && strcmp(*argv, "-a") == 0) { 8712703Smckusick aflag++; 8812703Smckusick goto again; 8912703Smckusick } 9012703Smckusick if (argc <= 0 && !aflag) { 9112703Smckusick fprintf(stderr, "Usage:\n\t%s\n\t%s\n", 9212703Smckusick "quotacheck [-v] -a", 9312703Smckusick "quotacheck [-v] filesys ..."); 9412660Smckusick exit(1); 9512660Smckusick } 9612802Smckusick if (vflag) { 9712802Smckusick setpwent(); 9812802Smckusick while ((pw = getpwent()) != 0) { 9912802Smckusick fup = lookup(pw->pw_uid); 10012802Smckusick if (fup == 0) 10112802Smckusick fup = adduid(pw->pw_uid); 10212802Smckusick strncpy(fup->fu_name, pw->pw_name, 10312802Smckusick sizeof(fup->fu_name)); 10412802Smckusick } 10512802Smckusick endpwent(); 10612802Smckusick } 10712703Smckusick setfsent(); 10812703Smckusick while ((fs = getfsent()) != NULL) { 10912703Smckusick if (aflag && 11012703Smckusick (fs->fs_type == 0 || strcmp(fs->fs_type, "rq") != 0)) 11112703Smckusick continue; 11212703Smckusick if (!aflag && 11312703Smckusick !(oneof(fs->fs_file, argv, argc) || 11412703Smckusick oneof(fs->fs_spec, argv, argc))) 11512703Smckusick continue; 11612703Smckusick (void) sprintf(quotafile, "%s/%s", fs->fs_file, qfname); 11712703Smckusick errs += chkquota(fs->fs_spec, quotafile); 11812660Smckusick } 11912703Smckusick endfsent(); 12012703Smckusick for (i = 0; i < argc; i++) 12112703Smckusick if ((done & (1 << i)) == 0) 12212703Smckusick fprintf(stderr, "%s not found in /etc/fstab\n", 12312703Smckusick argv[i]); 12412703Smckusick exit(errs); 12512703Smckusick } 12612660Smckusick 12712703Smckusick chkquota(fsdev, qffile) 12812703Smckusick char *fsdev; 12912703Smckusick char *qffile; 13012703Smckusick { 13112703Smckusick register struct fileusage *fup; 13212703Smckusick dev_t quotadev; 13312703Smckusick FILE *qf; 13412703Smckusick u_short uid; 13512703Smckusick int cg, i; 13612703Smckusick char *rawdisk; 13712703Smckusick struct stat statb; 13812703Smckusick struct dqblk dqbuf; 13921085Smckusick static int warned = 0; 14021085Smckusick extern int errno; 14112660Smckusick 14212703Smckusick rawdisk = makerawname(fsdev); 14312703Smckusick if (vflag) 14412703Smckusick fprintf(stdout, "*** Check quotas for %s\n", rawdisk); 14512703Smckusick fi = open(rawdisk, 0); 14612703Smckusick if (fi < 0) { 14712703Smckusick perror(rawdisk); 14812703Smckusick return (1); 14912660Smckusick } 15012703Smckusick qf = fopen(qffile, "r+"); 15112703Smckusick if (qf == NULL) { 15212703Smckusick perror(qffile); 15312703Smckusick return (1); 15412660Smckusick } 15512703Smckusick if (fstat(fileno(qf), &statb) < 0) { 15612703Smckusick perror(qffile); 15712703Smckusick return (1); 15812703Smckusick } 15912703Smckusick quotadev = statb.st_dev; 16012703Smckusick if (stat(fsdev, &statb) < 0) { 16112703Smckusick perror(fsdev); 16212703Smckusick return (1); 16312703Smckusick } 16412703Smckusick if (quotadev != statb.st_rdev) { 16512703Smckusick fprintf(stderr, "%s dev (0x%x) mismatch %s dev (0x%x)\n", 16612703Smckusick qffile, quotadev, fsdev, statb.st_rdev); 16712703Smckusick return (1); 16812703Smckusick } 16921085Smckusick if (quota(Q_SYNC, 0, quotadev, 0) < 0 && 17021085Smckusick errno == EINVAL && !warned && vflag) { 17121085Smckusick warned++; 17221085Smckusick fprintf(stdout, 17321085Smckusick "*** Warning: Quotas are not compiled into this kernel\n"); 17421085Smckusick } 17512660Smckusick sync(); 17612660Smckusick bread(SBLOCK, (char *)&sblock, SBSIZE); 17712660Smckusick ino = 0; 17812660Smckusick for (cg = 0; cg < sblock.fs_ncg; cg++) { 17912660Smckusick dp = NULL; 18012660Smckusick for (i = 0; i < sblock.fs_ipg; i++) 18112660Smckusick acct(ginode()); 18212660Smckusick } 18312703Smckusick for (uid = 0; uid <= highuid; uid++) { 18412703Smckusick i = fread(&dqbuf, sizeof(struct dqblk), 1, qf); 18512703Smckusick if (i == 0) 18612802Smckusick dqbuf = zerodqbuf; 18718415Smckusick fup = lookup(uid); 18818415Smckusick if (fup == 0) { 18918415Smckusick if (!feof(qf)) { 19018415Smckusick fseek(qf, uid * sizeof(struct dqblk), 0); 19118415Smckusick fwrite(&zerodqbuf, sizeof(struct dqblk), 1, qf); 19218415Smckusick } 19318415Smckusick continue; 19418415Smckusick } 19512703Smckusick if (dqbuf.dqb_curinodes == fup->fu_usage.du_curinodes && 19612802Smckusick dqbuf.dqb_curblocks == fup->fu_usage.du_curblocks) { 19712802Smckusick fup->fu_usage.du_curinodes = 0; 19812802Smckusick fup->fu_usage.du_curblocks = 0; 19912703Smckusick continue; 20012802Smckusick } 20112703Smckusick if (vflag) { 20212802Smckusick if (fup->fu_name[0] != '\0') 20312802Smckusick printf("%-10s fixed:", fup->fu_name); 20412802Smckusick else 20512802Smckusick printf("#%-9d fixed:", uid); 20612703Smckusick fprintf(stdout, " inodes (old %d, new %d)", 20712703Smckusick dqbuf.dqb_curinodes, fup->fu_usage.du_curinodes); 20812703Smckusick fprintf(stdout, " blocks (old %d, new %d)\n", 20912703Smckusick dqbuf.dqb_curblocks, fup->fu_usage.du_curblocks); 21012660Smckusick } 21112703Smckusick dqbuf.dqb_curinodes = fup->fu_usage.du_curinodes; 21212703Smckusick dqbuf.dqb_curblocks = fup->fu_usage.du_curblocks; 21312703Smckusick fseek(qf, uid * sizeof(struct dqblk), 0); 21412703Smckusick fwrite(&dqbuf, sizeof(struct dqblk), 1, qf); 21512703Smckusick quota(Q_SETDUSE, uid, quotadev, &fup->fu_usage); 21613255Smckusick fup->fu_usage.du_curinodes = 0; 21713255Smckusick fup->fu_usage.du_curblocks = 0; 21812660Smckusick } 21918415Smckusick ftruncate(fileno(qf), (highuid + 1) * sizeof(struct dqblk)); 22012703Smckusick return (0); 22112660Smckusick } 22212660Smckusick 22312660Smckusick acct(ip) 22412660Smckusick register struct dinode *ip; 22512660Smckusick { 22612660Smckusick register n; 22712703Smckusick register struct fileusage *fup; 22812660Smckusick 22912660Smckusick if (ip == NULL) 23012660Smckusick return; 23112660Smckusick if (ip->di_mode == 0) 23212660Smckusick return; 23312703Smckusick fup = lookup(ip->di_uid); 23412703Smckusick if (fup == 0) 23512703Smckusick fup = adduid(ip->di_uid); 23612703Smckusick fup->fu_usage.du_curinodes++; 23712660Smckusick if ((ip->di_mode & IFMT) == IFCHR || (ip->di_mode & IFMT) == IFBLK) 23812660Smckusick return; 23912703Smckusick fup->fu_usage.du_curblocks += ip->di_blocks; 24012660Smckusick } 24112660Smckusick 24212703Smckusick oneof(target, list, n) 24312703Smckusick char *target, *list[]; 24412703Smckusick register int n; 24512660Smckusick { 24612703Smckusick register int i; 24712660Smckusick 24812703Smckusick for (i = 0; i < n; i++) 24912703Smckusick if (strcmp(target, list[i]) == 0) { 25012703Smckusick done |= 1 << i; 25112703Smckusick return (1); 25212703Smckusick } 25312703Smckusick return (0); 25412660Smckusick } 25512660Smckusick 25612660Smckusick struct dinode * 25712660Smckusick ginode() 25812660Smckusick { 25912660Smckusick register unsigned long iblk; 26012660Smckusick 26112660Smckusick if (dp == NULL || ++dp >= &itab[ITABSZ]) { 26212660Smckusick iblk = itod(&sblock, ino); 26312660Smckusick bread(fsbtodb(&sblock, iblk), (char *)itab, sizeof itab); 26412660Smckusick dp = &itab[ino % INOPB(&sblock)]; 26512660Smckusick } 26612660Smckusick if (ino++ < ROOTINO) 26712660Smckusick return(NULL); 26812660Smckusick return(dp); 26912660Smckusick } 27012660Smckusick 27112660Smckusick bread(bno, buf, cnt) 27212660Smckusick long unsigned bno; 27312660Smckusick char *buf; 27412660Smckusick { 27512660Smckusick 27612703Smckusick lseek(fi, (long)dbtob(bno), 0); 27712660Smckusick if (read(fi, buf, cnt) != cnt) { 27812660Smckusick printf("read error %u\n", bno); 27912660Smckusick exit(1); 28012660Smckusick } 28112660Smckusick } 28212660Smckusick 28312703Smckusick struct fileusage * 28412703Smckusick lookup(uid) 28512703Smckusick u_short uid; 28612660Smckusick { 28712703Smckusick register struct fileusage *fup; 28812660Smckusick 28912703Smckusick for (fup = fuhead[uid % FUHASH]; fup != 0; fup = fup->fu_next) 29012703Smckusick if (fup->fu_uid == uid) 29112703Smckusick return (fup); 29212703Smckusick return ((struct fileusage *)0); 29312660Smckusick } 29412660Smckusick 29512703Smckusick struct fileusage * 29612703Smckusick adduid(uid) 29712703Smckusick u_short uid; 29812660Smckusick { 29912703Smckusick struct fileusage *fup, **fhp; 30012660Smckusick 30112703Smckusick fup = lookup(uid); 30212703Smckusick if (fup != 0) 30312703Smckusick return (fup); 30412703Smckusick fup = (struct fileusage *)calloc(1, sizeof(struct fileusage)); 30512703Smckusick if (fup == 0) { 30612703Smckusick fprintf(stderr, "out of memory for fileusage structures\n"); 30712703Smckusick exit(1); 30812703Smckusick } 30912703Smckusick fhp = &fuhead[uid % FUHASH]; 31012703Smckusick fup->fu_next = *fhp; 31112703Smckusick *fhp = fup; 31212703Smckusick fup->fu_uid = uid; 31312703Smckusick if (uid > highuid) 31412703Smckusick highuid = uid; 31512703Smckusick return (fup); 31612660Smckusick } 31712660Smckusick 31812660Smckusick char * 31912703Smckusick makerawname(name) 32012703Smckusick char *name; 32112660Smckusick { 32212703Smckusick register char *cp; 32312703Smckusick char tmp, ch, *rindex(); 32412703Smckusick static char rawname[MAXPATHLEN]; 32512660Smckusick 32612703Smckusick strcpy(rawname, name); 32712703Smckusick cp = rindex(rawname, '/') + 1; 32812703Smckusick if (cp == (char *)1 || *cp == 'r') 32912703Smckusick return (name); 33012703Smckusick for (ch = 'r'; *cp != '\0'; ) { 33112703Smckusick tmp = *cp; 33212703Smckusick *cp++ = ch; 33312703Smckusick ch = tmp; 33412703Smckusick } 33512703Smckusick *cp++ = ch; 33612703Smckusick *cp = '\0'; 33712703Smckusick return (rawname); 33812660Smckusick } 339