112703Smckusick #ifndef lint 2*18415Smckusick static char sccsid[] = "@(#)quotacheck.c 4.5 (Berkeley, Melbourne) 03/19/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> 1112660Smckusick #include <sys/param.h> 1212660Smckusick #include <sys/inode.h> 1312660Smckusick #include <sys/fs.h> 1412660Smckusick #include <sys/quota.h> 1512660Smckusick #include <sys/stat.h> 1612703Smckusick #include <fstab.h> 1712802Smckusick #include <pwd.h> 1812660Smckusick 1912660Smckusick union { 2012660Smckusick struct fs sblk; 2112703Smckusick char dummy[MAXBSIZE]; 2212660Smckusick } un; 2312660Smckusick #define sblock un.sblk 2412703Smckusick 2512703Smckusick #define ITABSZ 256 2612660Smckusick struct dinode itab[ITABSZ]; 2712660Smckusick struct dinode *dp; 2812660Smckusick long blocks; 2912660Smckusick dev_t dev; 3012660Smckusick 3112802Smckusick #define LOGINNAMESIZE 8 3212703Smckusick struct fileusage { 3312802Smckusick struct fileusage *fu_next; 3412703Smckusick struct dqusage fu_usage; 3512703Smckusick u_short fu_uid; 3612802Smckusick char fu_name[LOGINNAMESIZE + 1]; 3712703Smckusick }; 3812703Smckusick #define FUHASH 997 3912703Smckusick struct fileusage *fuhead[FUHASH]; 4012703Smckusick struct fileusage *lookup(); 4112703Smckusick struct fileusage *adduid(); 4212703Smckusick int highuid; 4312660Smckusick 4412703Smckusick int fi; 4512703Smckusick ino_t ino; 4612703Smckusick long done; 4712660Smckusick struct passwd *getpwent(); 4812660Smckusick struct dinode *ginode(); 4912703Smckusick char *malloc(), *makerawname(); 5012660Smckusick 5112703Smckusick int vflag; /* verbose */ 5212703Smckusick int aflag; /* all file systems */ 5312703Smckusick 5412703Smckusick char *qfname = "quotas"; 5512703Smckusick char quotafile[MAXPATHLEN + 1]; 5612802Smckusick struct dqblk zerodqbuf; 5712703Smckusick 5812660Smckusick main(argc, argv) 5912703Smckusick int argc; 6012660Smckusick char **argv; 6112660Smckusick { 6212703Smckusick register struct fstab *fs; 6312802Smckusick register struct fileusage *fup; 6412802Smckusick register struct passwd *pw; 6512703Smckusick int i, errs = 0; 6612660Smckusick 6712703Smckusick again: 6812703Smckusick argc--, argv++; 6912703Smckusick if (argc > 0 && strcmp(*argv, "-v") == 0) { 7012703Smckusick vflag++; 7112703Smckusick goto again; 7212660Smckusick } 7312703Smckusick if (argc > 0 && strcmp(*argv, "-a") == 0) { 7412703Smckusick aflag++; 7512703Smckusick goto again; 7612703Smckusick } 7712703Smckusick if (argc <= 0 && !aflag) { 7812703Smckusick fprintf(stderr, "Usage:\n\t%s\n\t%s\n", 7912703Smckusick "quotacheck [-v] -a", 8012703Smckusick "quotacheck [-v] filesys ..."); 8112660Smckusick exit(1); 8212660Smckusick } 8312802Smckusick if (vflag) { 8412802Smckusick setpwent(); 8512802Smckusick while ((pw = getpwent()) != 0) { 8612802Smckusick fup = lookup(pw->pw_uid); 8712802Smckusick if (fup == 0) 8812802Smckusick fup = adduid(pw->pw_uid); 8912802Smckusick strncpy(fup->fu_name, pw->pw_name, 9012802Smckusick sizeof(fup->fu_name)); 9112802Smckusick } 9212802Smckusick endpwent(); 9312802Smckusick } 9412703Smckusick setfsent(); 9512703Smckusick while ((fs = getfsent()) != NULL) { 9612703Smckusick if (aflag && 9712703Smckusick (fs->fs_type == 0 || strcmp(fs->fs_type, "rq") != 0)) 9812703Smckusick continue; 9912703Smckusick if (!aflag && 10012703Smckusick !(oneof(fs->fs_file, argv, argc) || 10112703Smckusick oneof(fs->fs_spec, argv, argc))) 10212703Smckusick continue; 10312703Smckusick (void) sprintf(quotafile, "%s/%s", fs->fs_file, qfname); 10412703Smckusick errs += chkquota(fs->fs_spec, quotafile); 10512660Smckusick } 10612703Smckusick endfsent(); 10712703Smckusick for (i = 0; i < argc; i++) 10812703Smckusick if ((done & (1 << i)) == 0) 10912703Smckusick fprintf(stderr, "%s not found in /etc/fstab\n", 11012703Smckusick argv[i]); 11112703Smckusick exit(errs); 11212703Smckusick } 11312660Smckusick 11412703Smckusick chkquota(fsdev, qffile) 11512703Smckusick char *fsdev; 11612703Smckusick char *qffile; 11712703Smckusick { 11812703Smckusick register struct fileusage *fup; 11912703Smckusick dev_t quotadev; 12012703Smckusick FILE *qf; 12112703Smckusick u_short uid; 12212703Smckusick int cg, i; 12312703Smckusick char *rawdisk; 12412703Smckusick struct stat statb; 12512703Smckusick struct dqblk dqbuf; 12612660Smckusick 12712703Smckusick rawdisk = makerawname(fsdev); 12812703Smckusick if (vflag) 12912703Smckusick fprintf(stdout, "*** Check quotas for %s\n", rawdisk); 13012703Smckusick fi = open(rawdisk, 0); 13112703Smckusick if (fi < 0) { 13212703Smckusick perror(rawdisk); 13312703Smckusick return (1); 13412660Smckusick } 13512703Smckusick qf = fopen(qffile, "r+"); 13612703Smckusick if (qf == NULL) { 13712703Smckusick perror(qffile); 13812703Smckusick return (1); 13912660Smckusick } 14012703Smckusick if (fstat(fileno(qf), &statb) < 0) { 14112703Smckusick perror(qffile); 14212703Smckusick return (1); 14312703Smckusick } 14412703Smckusick quotadev = statb.st_dev; 14512703Smckusick if (stat(fsdev, &statb) < 0) { 14612703Smckusick perror(fsdev); 14712703Smckusick return (1); 14812703Smckusick } 14912703Smckusick if (quotadev != statb.st_rdev) { 15012703Smckusick fprintf(stderr, "%s dev (0x%x) mismatch %s dev (0x%x)\n", 15112703Smckusick qffile, quotadev, fsdev, statb.st_rdev); 15212703Smckusick return (1); 15312703Smckusick } 15412703Smckusick quota(Q_SYNC, 0, quotadev, 0); 15512660Smckusick sync(); 15612660Smckusick bread(SBLOCK, (char *)&sblock, SBSIZE); 15712660Smckusick ino = 0; 15812660Smckusick for (cg = 0; cg < sblock.fs_ncg; cg++) { 15912660Smckusick dp = NULL; 16012660Smckusick for (i = 0; i < sblock.fs_ipg; i++) 16112660Smckusick acct(ginode()); 16212660Smckusick } 16312703Smckusick for (uid = 0; uid <= highuid; uid++) { 16412703Smckusick i = fread(&dqbuf, sizeof(struct dqblk), 1, qf); 16512703Smckusick if (i == 0) 16612802Smckusick dqbuf = zerodqbuf; 167*18415Smckusick fup = lookup(uid); 168*18415Smckusick if (fup == 0) { 169*18415Smckusick if (!feof(qf)) { 170*18415Smckusick fseek(qf, uid * sizeof(struct dqblk), 0); 171*18415Smckusick fwrite(&zerodqbuf, sizeof(struct dqblk), 1, qf); 172*18415Smckusick } 173*18415Smckusick continue; 174*18415Smckusick } 17512703Smckusick if (dqbuf.dqb_curinodes == fup->fu_usage.du_curinodes && 17612802Smckusick dqbuf.dqb_curblocks == fup->fu_usage.du_curblocks) { 17712802Smckusick fup->fu_usage.du_curinodes = 0; 17812802Smckusick fup->fu_usage.du_curblocks = 0; 17912703Smckusick continue; 18012802Smckusick } 18112703Smckusick if (vflag) { 18212802Smckusick if (fup->fu_name[0] != '\0') 18312802Smckusick printf("%-10s fixed:", fup->fu_name); 18412802Smckusick else 18512802Smckusick printf("#%-9d fixed:", uid); 18612703Smckusick fprintf(stdout, " inodes (old %d, new %d)", 18712703Smckusick dqbuf.dqb_curinodes, fup->fu_usage.du_curinodes); 18812703Smckusick fprintf(stdout, " blocks (old %d, new %d)\n", 18912703Smckusick dqbuf.dqb_curblocks, fup->fu_usage.du_curblocks); 19012660Smckusick } 19112703Smckusick dqbuf.dqb_curinodes = fup->fu_usage.du_curinodes; 19212703Smckusick dqbuf.dqb_curblocks = fup->fu_usage.du_curblocks; 19312703Smckusick fseek(qf, uid * sizeof(struct dqblk), 0); 19412703Smckusick fwrite(&dqbuf, sizeof(struct dqblk), 1, qf); 19512703Smckusick quota(Q_SETDUSE, uid, quotadev, &fup->fu_usage); 19613255Smckusick fup->fu_usage.du_curinodes = 0; 19713255Smckusick fup->fu_usage.du_curblocks = 0; 19812660Smckusick } 199*18415Smckusick ftruncate(fileno(qf), (highuid + 1) * sizeof(struct dqblk)); 20012703Smckusick return (0); 20112660Smckusick } 20212660Smckusick 20312660Smckusick acct(ip) 20412660Smckusick register struct dinode *ip; 20512660Smckusick { 20612660Smckusick register n; 20712703Smckusick register struct fileusage *fup; 20812660Smckusick 20912660Smckusick if (ip == NULL) 21012660Smckusick return; 21112660Smckusick if (ip->di_mode == 0) 21212660Smckusick return; 21312703Smckusick fup = lookup(ip->di_uid); 21412703Smckusick if (fup == 0) 21512703Smckusick fup = adduid(ip->di_uid); 21612703Smckusick fup->fu_usage.du_curinodes++; 21712660Smckusick if ((ip->di_mode & IFMT) == IFCHR || (ip->di_mode & IFMT) == IFBLK) 21812660Smckusick return; 21912703Smckusick fup->fu_usage.du_curblocks += ip->di_blocks; 22012660Smckusick } 22112660Smckusick 22212703Smckusick oneof(target, list, n) 22312703Smckusick char *target, *list[]; 22412703Smckusick register int n; 22512660Smckusick { 22612703Smckusick register int i; 22712660Smckusick 22812703Smckusick for (i = 0; i < n; i++) 22912703Smckusick if (strcmp(target, list[i]) == 0) { 23012703Smckusick done |= 1 << i; 23112703Smckusick return (1); 23212703Smckusick } 23312703Smckusick return (0); 23412660Smckusick } 23512660Smckusick 23612660Smckusick struct dinode * 23712660Smckusick ginode() 23812660Smckusick { 23912660Smckusick register unsigned long iblk; 24012660Smckusick 24112660Smckusick if (dp == NULL || ++dp >= &itab[ITABSZ]) { 24212660Smckusick iblk = itod(&sblock, ino); 24312660Smckusick bread(fsbtodb(&sblock, iblk), (char *)itab, sizeof itab); 24412660Smckusick dp = &itab[ino % INOPB(&sblock)]; 24512660Smckusick } 24612660Smckusick if (ino++ < ROOTINO) 24712660Smckusick return(NULL); 24812660Smckusick return(dp); 24912660Smckusick } 25012660Smckusick 25112660Smckusick bread(bno, buf, cnt) 25212660Smckusick long unsigned bno; 25312660Smckusick char *buf; 25412660Smckusick { 25512660Smckusick 25612703Smckusick lseek(fi, (long)dbtob(bno), 0); 25712660Smckusick if (read(fi, buf, cnt) != cnt) { 25812660Smckusick printf("read error %u\n", bno); 25912660Smckusick exit(1); 26012660Smckusick } 26112660Smckusick } 26212660Smckusick 26312703Smckusick struct fileusage * 26412703Smckusick lookup(uid) 26512703Smckusick u_short uid; 26612660Smckusick { 26712703Smckusick register struct fileusage *fup; 26812660Smckusick 26912703Smckusick for (fup = fuhead[uid % FUHASH]; fup != 0; fup = fup->fu_next) 27012703Smckusick if (fup->fu_uid == uid) 27112703Smckusick return (fup); 27212703Smckusick return ((struct fileusage *)0); 27312660Smckusick } 27412660Smckusick 27512703Smckusick struct fileusage * 27612703Smckusick adduid(uid) 27712703Smckusick u_short uid; 27812660Smckusick { 27912703Smckusick struct fileusage *fup, **fhp; 28012660Smckusick 28112703Smckusick fup = lookup(uid); 28212703Smckusick if (fup != 0) 28312703Smckusick return (fup); 28412703Smckusick fup = (struct fileusage *)calloc(1, sizeof(struct fileusage)); 28512703Smckusick if (fup == 0) { 28612703Smckusick fprintf(stderr, "out of memory for fileusage structures\n"); 28712703Smckusick exit(1); 28812703Smckusick } 28912703Smckusick fhp = &fuhead[uid % FUHASH]; 29012703Smckusick fup->fu_next = *fhp; 29112703Smckusick *fhp = fup; 29212703Smckusick fup->fu_uid = uid; 29312703Smckusick if (uid > highuid) 29412703Smckusick highuid = uid; 29512703Smckusick return (fup); 29612660Smckusick } 29712660Smckusick 29812660Smckusick char * 29912703Smckusick makerawname(name) 30012703Smckusick char *name; 30112660Smckusick { 30212703Smckusick register char *cp; 30312703Smckusick char tmp, ch, *rindex(); 30412703Smckusick static char rawname[MAXPATHLEN]; 30512660Smckusick 30612703Smckusick strcpy(rawname, name); 30712703Smckusick cp = rindex(rawname, '/') + 1; 30812703Smckusick if (cp == (char *)1 || *cp == 'r') 30912703Smckusick return (name); 31012703Smckusick for (ch = 'r'; *cp != '\0'; ) { 31112703Smckusick tmp = *cp; 31212703Smckusick *cp++ = ch; 31312703Smckusick ch = tmp; 31412703Smckusick } 31512703Smckusick *cp++ = ch; 31612703Smckusick *cp = '\0'; 31712703Smckusick return (rawname); 31812660Smckusick } 319