112703Smckusick #ifndef lint 2*12802Smckusick static char sccsid[] = "@(#)quotacheck.c 4.3 (Berkeley, Melbourne) 05/27/83"; 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> 17*12802Smckusick #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 31*12802Smckusick #define LOGINNAMESIZE 8 3212703Smckusick struct fileusage { 33*12802Smckusick struct fileusage *fu_next; 3412703Smckusick struct dqusage fu_usage; 3512703Smckusick u_short fu_uid; 36*12802Smckusick 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]; 56*12802Smckusick struct dqblk zerodqbuf; 5712703Smckusick 5812660Smckusick main(argc, argv) 5912703Smckusick int argc; 6012660Smckusick char **argv; 6112660Smckusick { 6212703Smckusick register struct fstab *fs; 63*12802Smckusick register struct fileusage *fup; 64*12802Smckusick 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 } 83*12802Smckusick if (vflag) { 84*12802Smckusick setpwent(); 85*12802Smckusick while ((pw = getpwent()) != 0) { 86*12802Smckusick fup = lookup(pw->pw_uid); 87*12802Smckusick if (fup == 0) 88*12802Smckusick fup = adduid(pw->pw_uid); 89*12802Smckusick strncpy(fup->fu_name, pw->pw_name, 90*12802Smckusick sizeof(fup->fu_name)); 91*12802Smckusick } 92*12802Smckusick endpwent(); 93*12802Smckusick } 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 fup = lookup(uid); 16512703Smckusick if (fup == 0) 16612703Smckusick continue; 16712703Smckusick fseek(qf, uid * sizeof(struct dqblk), 0); 16812703Smckusick i = fread(&dqbuf, sizeof(struct dqblk), 1, qf); 16912703Smckusick if (i == 0) 170*12802Smckusick dqbuf = zerodqbuf; 17112703Smckusick if (dqbuf.dqb_curinodes == fup->fu_usage.du_curinodes && 172*12802Smckusick dqbuf.dqb_curblocks == fup->fu_usage.du_curblocks) { 173*12802Smckusick fup->fu_usage.du_curinodes = 0; 174*12802Smckusick fup->fu_usage.du_curblocks = 0; 17512703Smckusick continue; 176*12802Smckusick } 17712703Smckusick if (vflag) { 178*12802Smckusick if (fup->fu_name[0] != '\0') 179*12802Smckusick printf("%-10s fixed:", fup->fu_name); 180*12802Smckusick else 181*12802Smckusick printf("#%-9d fixed:", uid); 18212703Smckusick fprintf(stdout, " inodes (old %d, new %d)", 18312703Smckusick dqbuf.dqb_curinodes, fup->fu_usage.du_curinodes); 18412703Smckusick fprintf(stdout, " blocks (old %d, new %d)\n", 18512703Smckusick dqbuf.dqb_curblocks, fup->fu_usage.du_curblocks); 18612660Smckusick } 18712703Smckusick dqbuf.dqb_curinodes = fup->fu_usage.du_curinodes; 18812703Smckusick dqbuf.dqb_curblocks = fup->fu_usage.du_curblocks; 189*12802Smckusick fup->fu_usage.du_curinodes = 0; 190*12802Smckusick fup->fu_usage.du_curblocks = 0; 19112703Smckusick fseek(qf, uid * sizeof(struct dqblk), 0); 19212703Smckusick fwrite(&dqbuf, sizeof(struct dqblk), 1, qf); 19312703Smckusick quota(Q_SETDUSE, uid, quotadev, &fup->fu_usage); 19412660Smckusick } 19512703Smckusick return (0); 19612660Smckusick } 19712660Smckusick 19812660Smckusick acct(ip) 19912660Smckusick register struct dinode *ip; 20012660Smckusick { 20112660Smckusick register n; 20212703Smckusick register struct fileusage *fup; 20312660Smckusick 20412660Smckusick if (ip == NULL) 20512660Smckusick return; 20612660Smckusick if (ip->di_mode == 0) 20712660Smckusick return; 20812703Smckusick fup = lookup(ip->di_uid); 20912703Smckusick if (fup == 0) 21012703Smckusick fup = adduid(ip->di_uid); 21112703Smckusick fup->fu_usage.du_curinodes++; 21212660Smckusick if ((ip->di_mode & IFMT) == IFCHR || (ip->di_mode & IFMT) == IFBLK) 21312660Smckusick return; 21412703Smckusick fup->fu_usage.du_curblocks += ip->di_blocks; 21512660Smckusick } 21612660Smckusick 21712703Smckusick oneof(target, list, n) 21812703Smckusick char *target, *list[]; 21912703Smckusick register int n; 22012660Smckusick { 22112703Smckusick register int i; 22212660Smckusick 22312703Smckusick for (i = 0; i < n; i++) 22412703Smckusick if (strcmp(target, list[i]) == 0) { 22512703Smckusick done |= 1 << i; 22612703Smckusick return (1); 22712703Smckusick } 22812703Smckusick return (0); 22912660Smckusick } 23012660Smckusick 23112660Smckusick struct dinode * 23212660Smckusick ginode() 23312660Smckusick { 23412660Smckusick register unsigned long iblk; 23512660Smckusick 23612660Smckusick if (dp == NULL || ++dp >= &itab[ITABSZ]) { 23712660Smckusick iblk = itod(&sblock, ino); 23812660Smckusick bread(fsbtodb(&sblock, iblk), (char *)itab, sizeof itab); 23912660Smckusick dp = &itab[ino % INOPB(&sblock)]; 24012660Smckusick } 24112660Smckusick if (ino++ < ROOTINO) 24212660Smckusick return(NULL); 24312660Smckusick return(dp); 24412660Smckusick } 24512660Smckusick 24612660Smckusick bread(bno, buf, cnt) 24712660Smckusick long unsigned bno; 24812660Smckusick char *buf; 24912660Smckusick { 25012660Smckusick 25112703Smckusick lseek(fi, (long)dbtob(bno), 0); 25212660Smckusick if (read(fi, buf, cnt) != cnt) { 25312660Smckusick printf("read error %u\n", bno); 25412660Smckusick exit(1); 25512660Smckusick } 25612660Smckusick } 25712660Smckusick 25812703Smckusick struct fileusage * 25912703Smckusick lookup(uid) 26012703Smckusick u_short uid; 26112660Smckusick { 26212703Smckusick register struct fileusage *fup; 26312660Smckusick 26412703Smckusick for (fup = fuhead[uid % FUHASH]; fup != 0; fup = fup->fu_next) 26512703Smckusick if (fup->fu_uid == uid) 26612703Smckusick return (fup); 26712703Smckusick return ((struct fileusage *)0); 26812660Smckusick } 26912660Smckusick 27012703Smckusick struct fileusage * 27112703Smckusick adduid(uid) 27212703Smckusick u_short uid; 27312660Smckusick { 27412703Smckusick struct fileusage *fup, **fhp; 27512660Smckusick 27612703Smckusick fup = lookup(uid); 27712703Smckusick if (fup != 0) 27812703Smckusick return (fup); 27912703Smckusick fup = (struct fileusage *)calloc(1, sizeof(struct fileusage)); 28012703Smckusick if (fup == 0) { 28112703Smckusick fprintf(stderr, "out of memory for fileusage structures\n"); 28212703Smckusick exit(1); 28312703Smckusick } 28412703Smckusick fhp = &fuhead[uid % FUHASH]; 28512703Smckusick fup->fu_next = *fhp; 28612703Smckusick *fhp = fup; 28712703Smckusick fup->fu_uid = uid; 28812703Smckusick if (uid > highuid) 28912703Smckusick highuid = uid; 29012703Smckusick return (fup); 29112660Smckusick } 29212660Smckusick 29312660Smckusick char * 29412703Smckusick makerawname(name) 29512703Smckusick char *name; 29612660Smckusick { 29712703Smckusick register char *cp; 29812703Smckusick char tmp, ch, *rindex(); 29912703Smckusick static char rawname[MAXPATHLEN]; 30012660Smckusick 30112703Smckusick strcpy(rawname, name); 30212703Smckusick cp = rindex(rawname, '/') + 1; 30312703Smckusick if (cp == (char *)1 || *cp == 'r') 30412703Smckusick return (name); 30512703Smckusick for (ch = 'r'; *cp != '\0'; ) { 30612703Smckusick tmp = *cp; 30712703Smckusick *cp++ = ch; 30812703Smckusick ch = tmp; 30912703Smckusick } 31012703Smckusick *cp++ = ch; 31112703Smckusick *cp = '\0'; 31212703Smckusick return (rawname); 31312660Smckusick } 314