121517Smckusick /* 221517Smckusick * Copyright (c) 1980 Regents of the University of California. 321517Smckusick * All rights reserved. The Berkeley software License Agreement 421517Smckusick * specifies the terms and conditions for redistribution. 521517Smckusick */ 621517Smckusick 712703Smckusick #ifndef lint 821517Smckusick char copyright[] = 921517Smckusick "@(#) Copyright (c) 1980 Regents of the University of California.\n\ 1021517Smckusick All rights reserved.\n"; 1121517Smckusick #endif not lint 1212660Smckusick 1321517Smckusick #ifndef lint 14*24758Sserge static char sccsid[] = "@(#)quotacheck.c 5.4 (Berkeley) 09/15/85"; 1521517Smckusick #endif not lint 1621517Smckusick 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> 29*24758Sserge #include <sys/wait.h> 3012703Smckusick #include <fstab.h> 3112802Smckusick #include <pwd.h> 3212660Smckusick 3312660Smckusick union { 3412660Smckusick struct fs sblk; 3512703Smckusick char dummy[MAXBSIZE]; 3612660Smckusick } un; 3712660Smckusick #define sblock un.sblk 3812703Smckusick 3912703Smckusick #define ITABSZ 256 4012660Smckusick struct dinode itab[ITABSZ]; 4112660Smckusick struct dinode *dp; 4212660Smckusick 4312802Smckusick #define LOGINNAMESIZE 8 4412703Smckusick struct fileusage { 4512802Smckusick struct fileusage *fu_next; 4612703Smckusick struct dqusage fu_usage; 4712703Smckusick u_short fu_uid; 4812802Smckusick char fu_name[LOGINNAMESIZE + 1]; 4912703Smckusick }; 5012703Smckusick #define FUHASH 997 5112703Smckusick struct fileusage *fuhead[FUHASH]; 5212703Smckusick struct fileusage *lookup(); 5312703Smckusick struct fileusage *adduid(); 5412703Smckusick int highuid; 5512660Smckusick 5612703Smckusick int fi; 5712703Smckusick ino_t ino; 5812703Smckusick long done; 5912660Smckusick struct passwd *getpwent(); 6012660Smckusick struct dinode *ginode(); 6112703Smckusick char *malloc(), *makerawname(); 6212660Smckusick 6312703Smckusick int vflag; /* verbose */ 6412703Smckusick int aflag; /* all file systems */ 65*24758Sserge int pflag; /* fsck like parallel check */ 6612703Smckusick 6712703Smckusick char *qfname = "quotas"; 6812703Smckusick char quotafile[MAXPATHLEN + 1]; 6912802Smckusick struct dqblk zerodqbuf; 70*24758Sserge struct fileusage zerofileusage; 7112703Smckusick 7212660Smckusick main(argc, argv) 7312703Smckusick int argc; 7412660Smckusick char **argv; 7512660Smckusick { 7612703Smckusick register struct fstab *fs; 7712802Smckusick register struct fileusage *fup; 7812802Smckusick register struct passwd *pw; 7912703Smckusick int i, errs = 0; 8012660Smckusick 8112703Smckusick again: 8212703Smckusick argc--, argv++; 8312703Smckusick if (argc > 0 && strcmp(*argv, "-v") == 0) { 8412703Smckusick vflag++; 8512703Smckusick goto again; 8612660Smckusick } 8712703Smckusick if (argc > 0 && strcmp(*argv, "-a") == 0) { 8812703Smckusick aflag++; 8912703Smckusick goto again; 9012703Smckusick } 91*24758Sserge if (argc > 0 && strcmp(*argv, "-p") == 0) { 92*24758Sserge pflag++; 93*24758Sserge goto again; 94*24758Sserge } 9512703Smckusick if (argc <= 0 && !aflag) { 9612703Smckusick fprintf(stderr, "Usage:\n\t%s\n\t%s\n", 97*24758Sserge "quotacheck [-v] [-p] -a", 98*24758Sserge "quotacheck [-v] [-p] filesys ..."); 9912660Smckusick exit(1); 10012660Smckusick } 10124661Sserge 10224661Sserge setpwent(); 10324661Sserge while ((pw = getpwent()) != 0) { 10424661Sserge fup = lookup(pw->pw_uid); 105*24758Sserge if (fup == 0) { 10624661Sserge fup = adduid(pw->pw_uid); 107*24758Sserge strncpy(fup->fu_name, pw->pw_name, 108*24758Sserge sizeof(fup->fu_name)); 109*24758Sserge } 11012802Smckusick } 11124661Sserge endpwent(); 11224661Sserge 113*24758Sserge if (pflag) 114*24758Sserge errs = preen(argc, argv); 115*24758Sserge else { 116*24758Sserge if (setfsent() == 0) { 117*24758Sserge fprintf(stderr, "Can't open "); 118*24758Sserge perror(FSTAB); 119*24758Sserge exit(8); 120*24758Sserge } 121*24758Sserge while ((fs = getfsent()) != NULL) { 122*24758Sserge if (aflag && 123*24758Sserge (fs->fs_type == 0 || 124*24758Sserge strcmp(fs->fs_type, FSTAB_RQ) != 0)) 125*24758Sserge continue; 126*24758Sserge if (!aflag && 127*24758Sserge !(oneof(fs->fs_file, argv, argc) || 128*24758Sserge oneof(fs->fs_spec, argv, argc))) 129*24758Sserge continue; 130*24758Sserge (void) sprintf(quotafile, "%s/%s", fs->fs_file, qfname); 131*24758Sserge errs += chkquota(fs->fs_spec, fs->fs_file, quotafile); 132*24758Sserge } 133*24758Sserge endfsent(); 13412660Smckusick } 135*24758Sserge 13612703Smckusick for (i = 0; i < argc; i++) 13712703Smckusick if ((done & (1 << i)) == 0) 13812703Smckusick fprintf(stderr, "%s not found in /etc/fstab\n", 13912703Smckusick argv[i]); 14012703Smckusick exit(errs); 14112703Smckusick } 14212660Smckusick 143*24758Sserge preen(argc, argv) 144*24758Sserge int argc; 145*24758Sserge char **argv; 146*24758Sserge { 147*24758Sserge register struct fstab *fs; 148*24758Sserge register int passno, anygtr; 149*24758Sserge register int errs; 150*24758Sserge union wait status; 151*24758Sserge 152*24758Sserge passno = 1; 153*24758Sserge errs = 0; 154*24758Sserge do { 155*24758Sserge anygtr = 0; 156*24758Sserge 157*24758Sserge if (setfsent() == 0) { 158*24758Sserge fprintf(stderr, "Can't open "); 159*24758Sserge perror(FSTAB); 160*24758Sserge exit(8); 161*24758Sserge } 162*24758Sserge 163*24758Sserge while ((fs = getfsent()) != NULL) { 164*24758Sserge if (fs->fs_passno > passno) 165*24758Sserge anygtr = 1; 166*24758Sserge 167*24758Sserge if (aflag && 168*24758Sserge (fs->fs_type == 0 || 169*24758Sserge strcmp(fs->fs_type, FSTAB_RQ) != 0)) 170*24758Sserge continue; 171*24758Sserge 172*24758Sserge if (!aflag && 173*24758Sserge !(oneof(fs->fs_file, argv, argc) || 174*24758Sserge oneof(fs->fs_spec, argv, argc))) 175*24758Sserge continue; 176*24758Sserge 177*24758Sserge if (fs->fs_passno != passno) 178*24758Sserge continue; 179*24758Sserge 180*24758Sserge switch (fork()) { 181*24758Sserge case -1: 182*24758Sserge perror("fork"); 183*24758Sserge exit(8); 184*24758Sserge break; 185*24758Sserge 186*24758Sserge case 0: 187*24758Sserge sprintf(quotafile, "%s/%s", 188*24758Sserge fs->fs_file, qfname); 189*24758Sserge exit(chkquota(fs->fs_spec, 190*24758Sserge fs->fs_file, quotafile)); 191*24758Sserge } 192*24758Sserge } 193*24758Sserge 194*24758Sserge while (wait(&status) != -1) 195*24758Sserge errs += status.w_retcode; 196*24758Sserge 197*24758Sserge passno++; 198*24758Sserge } while (anygtr); 199*24758Sserge 200*24758Sserge return (errs); 201*24758Sserge } 202*24758Sserge 20324661Sserge chkquota(fsdev, fsfile, qffile) 20412703Smckusick char *fsdev; 20524661Sserge char *fsfile; 20612703Smckusick char *qffile; 20712703Smckusick { 20812703Smckusick register struct fileusage *fup; 20912703Smckusick dev_t quotadev; 21012703Smckusick FILE *qf; 21112703Smckusick u_short uid; 21212703Smckusick int cg, i; 21312703Smckusick char *rawdisk; 21412703Smckusick struct stat statb; 21512703Smckusick struct dqblk dqbuf; 21621085Smckusick static int warned = 0; 21721085Smckusick extern int errno; 21812660Smckusick 21912703Smckusick rawdisk = makerawname(fsdev); 22012703Smckusick if (vflag) 221*24758Sserge fprintf(stdout, "*** Checking quotas for %s (%s)\n", rawdisk, fsfile); 22212703Smckusick fi = open(rawdisk, 0); 22312703Smckusick if (fi < 0) { 22412703Smckusick perror(rawdisk); 22512703Smckusick return (1); 22612660Smckusick } 22712703Smckusick qf = fopen(qffile, "r+"); 22812703Smckusick if (qf == NULL) { 22912703Smckusick perror(qffile); 23024661Sserge close(fi); 23112703Smckusick return (1); 23212660Smckusick } 23312703Smckusick if (fstat(fileno(qf), &statb) < 0) { 23412703Smckusick perror(qffile); 23524661Sserge fclose(qf); 23624661Sserge close(fi); 23712703Smckusick return (1); 23812703Smckusick } 23912703Smckusick quotadev = statb.st_dev; 24012703Smckusick if (stat(fsdev, &statb) < 0) { 24112703Smckusick perror(fsdev); 24224661Sserge fclose(qf); 24324661Sserge close(fi); 24412703Smckusick return (1); 24512703Smckusick } 24612703Smckusick if (quotadev != statb.st_rdev) { 24712703Smckusick fprintf(stderr, "%s dev (0x%x) mismatch %s dev (0x%x)\n", 24812703Smckusick qffile, quotadev, fsdev, statb.st_rdev); 24924661Sserge fclose(qf); 25024661Sserge close(fi); 25112703Smckusick return (1); 25212703Smckusick } 253*24758Sserge if (quota(Q_SYNC, 0, quotadev, (caddr_t)0) < 0 && 25421085Smckusick errno == EINVAL && !warned && vflag) { 25521085Smckusick warned++; 25621085Smckusick fprintf(stdout, 25721085Smckusick "*** Warning: Quotas are not compiled into this kernel\n"); 25821085Smckusick } 25912660Smckusick sync(); 26012660Smckusick bread(SBLOCK, (char *)&sblock, SBSIZE); 26112660Smckusick ino = 0; 26212660Smckusick for (cg = 0; cg < sblock.fs_ncg; cg++) { 26312660Smckusick dp = NULL; 26412660Smckusick for (i = 0; i < sblock.fs_ipg; i++) 26512660Smckusick acct(ginode()); 26612660Smckusick } 26712703Smckusick for (uid = 0; uid <= highuid; uid++) { 26824661Sserge fseek(qf, (long)uid * sizeof(struct dqblk), 0); 26912703Smckusick i = fread(&dqbuf, sizeof(struct dqblk), 1, qf); 27012703Smckusick if (i == 0) 27112802Smckusick dqbuf = zerodqbuf; 27218415Smckusick fup = lookup(uid); 273*24758Sserge if (fup == 0) 274*24758Sserge fup = &zerofileusage; 27512703Smckusick if (dqbuf.dqb_curinodes == fup->fu_usage.du_curinodes && 27612802Smckusick dqbuf.dqb_curblocks == fup->fu_usage.du_curblocks) { 27712802Smckusick fup->fu_usage.du_curinodes = 0; 27812802Smckusick fup->fu_usage.du_curblocks = 0; 27912703Smckusick continue; 28012802Smckusick } 28112703Smckusick if (vflag) { 282*24758Sserge if (pflag) 283*24758Sserge printf("%s: ", rawdisk); 28412802Smckusick if (fup->fu_name[0] != '\0') 285*24758Sserge printf("%-8s fixed:", fup->fu_name); 28612802Smckusick else 287*24758Sserge printf("#%-7d fixed:", uid); 288*24758Sserge if (dqbuf.dqb_curinodes != fup->fu_usage.du_curinodes) 289*24758Sserge fprintf(stdout, " inodes %d -> %d", 290*24758Sserge dqbuf.dqb_curinodes, fup->fu_usage.du_curinodes); 291*24758Sserge if (dqbuf.dqb_curblocks != fup->fu_usage.du_curblocks) 292*24758Sserge fprintf(stdout, " blocks %d -> %d", 293*24758Sserge dqbuf.dqb_curblocks, fup->fu_usage.du_curblocks); 294*24758Sserge fprintf(stdout, "\n"); 29512660Smckusick } 29612703Smckusick dqbuf.dqb_curinodes = fup->fu_usage.du_curinodes; 29712703Smckusick dqbuf.dqb_curblocks = fup->fu_usage.du_curblocks; 29824661Sserge fseek(qf, (long)uid * sizeof(struct dqblk), 0); 29912703Smckusick fwrite(&dqbuf, sizeof(struct dqblk), 1, qf); 30012703Smckusick quota(Q_SETDUSE, uid, quotadev, &fup->fu_usage); 30113255Smckusick fup->fu_usage.du_curinodes = 0; 30213255Smckusick fup->fu_usage.du_curblocks = 0; 30312660Smckusick } 30424661Sserge fflush(qf); 30518415Smckusick ftruncate(fileno(qf), (highuid + 1) * sizeof(struct dqblk)); 30624661Sserge fclose(qf); 30724661Sserge close(fi); 30812703Smckusick return (0); 30912660Smckusick } 31012660Smckusick 31112660Smckusick acct(ip) 31212660Smckusick register struct dinode *ip; 31312660Smckusick { 31412703Smckusick register struct fileusage *fup; 31512660Smckusick 31612660Smckusick if (ip == NULL) 31712660Smckusick return; 31812660Smckusick if (ip->di_mode == 0) 31912660Smckusick return; 320*24758Sserge fup = adduid(ip->di_uid); 32112703Smckusick fup->fu_usage.du_curinodes++; 32212660Smckusick if ((ip->di_mode & IFMT) == IFCHR || (ip->di_mode & IFMT) == IFBLK) 32312660Smckusick return; 32412703Smckusick fup->fu_usage.du_curblocks += ip->di_blocks; 32512660Smckusick } 32612660Smckusick 32712703Smckusick oneof(target, list, n) 32812703Smckusick char *target, *list[]; 32912703Smckusick register int n; 33012660Smckusick { 33112703Smckusick register int i; 33212660Smckusick 33312703Smckusick for (i = 0; i < n; i++) 33412703Smckusick if (strcmp(target, list[i]) == 0) { 33512703Smckusick done |= 1 << i; 33612703Smckusick return (1); 33712703Smckusick } 33812703Smckusick return (0); 33912660Smckusick } 34012660Smckusick 34112660Smckusick struct dinode * 34212660Smckusick ginode() 34312660Smckusick { 34412660Smckusick register unsigned long iblk; 34512660Smckusick 34612660Smckusick if (dp == NULL || ++dp >= &itab[ITABSZ]) { 34712660Smckusick iblk = itod(&sblock, ino); 34812660Smckusick bread(fsbtodb(&sblock, iblk), (char *)itab, sizeof itab); 34912660Smckusick dp = &itab[ino % INOPB(&sblock)]; 35012660Smckusick } 35112660Smckusick if (ino++ < ROOTINO) 35212660Smckusick return(NULL); 35312660Smckusick return(dp); 35412660Smckusick } 35512660Smckusick 35612660Smckusick bread(bno, buf, cnt) 35712660Smckusick long unsigned bno; 35812660Smckusick char *buf; 35912660Smckusick { 36012660Smckusick 36112703Smckusick lseek(fi, (long)dbtob(bno), 0); 36212660Smckusick if (read(fi, buf, cnt) != cnt) { 363*24758Sserge perror("read"); 36412660Smckusick exit(1); 36512660Smckusick } 36612660Smckusick } 36712660Smckusick 36812703Smckusick struct fileusage * 36912703Smckusick lookup(uid) 37012703Smckusick u_short uid; 37112660Smckusick { 37212703Smckusick register struct fileusage *fup; 37312660Smckusick 37412703Smckusick for (fup = fuhead[uid % FUHASH]; fup != 0; fup = fup->fu_next) 37512703Smckusick if (fup->fu_uid == uid) 37612703Smckusick return (fup); 37712703Smckusick return ((struct fileusage *)0); 37812660Smckusick } 37912660Smckusick 38012703Smckusick struct fileusage * 38112703Smckusick adduid(uid) 38212703Smckusick u_short uid; 38312660Smckusick { 38412703Smckusick struct fileusage *fup, **fhp; 38524661Sserge extern char *calloc(); 38612660Smckusick 38712703Smckusick fup = lookup(uid); 38812703Smckusick if (fup != 0) 38912703Smckusick return (fup); 39012703Smckusick fup = (struct fileusage *)calloc(1, sizeof(struct fileusage)); 39112703Smckusick if (fup == 0) { 39212703Smckusick fprintf(stderr, "out of memory for fileusage structures\n"); 39312703Smckusick exit(1); 39412703Smckusick } 39512703Smckusick fhp = &fuhead[uid % FUHASH]; 39612703Smckusick fup->fu_next = *fhp; 39712703Smckusick *fhp = fup; 39812703Smckusick fup->fu_uid = uid; 39912703Smckusick if (uid > highuid) 40012703Smckusick highuid = uid; 40112703Smckusick return (fup); 40212660Smckusick } 40312660Smckusick 40412660Smckusick char * 40512703Smckusick makerawname(name) 40612703Smckusick char *name; 40712660Smckusick { 40812703Smckusick register char *cp; 40912703Smckusick char tmp, ch, *rindex(); 41012703Smckusick static char rawname[MAXPATHLEN]; 41112660Smckusick 41212703Smckusick strcpy(rawname, name); 41324661Sserge cp = rindex(rawname, '/'); 41424661Sserge if (cp == NULL || cp[1] == 'r') 41512703Smckusick return (name); 41624661Sserge else 41724661Sserge cp++; 41812703Smckusick for (ch = 'r'; *cp != '\0'; ) { 41912703Smckusick tmp = *cp; 42012703Smckusick *cp++ = ch; 42112703Smckusick ch = tmp; 42212703Smckusick } 42312703Smckusick *cp++ = ch; 42412703Smckusick *cp = '\0'; 42512703Smckusick return (rawname); 42612660Smckusick } 427