121517Smckusick /* 221517Smckusick * Copyright (c) 1980 Regents of the University of California. 3*34364Sbostic * All rights reserved. 4*34364Sbostic * 5*34364Sbostic * Redistribution and use in source and binary forms are permitted 6*34364Sbostic * provided that this notice is preserved and that due credit is given 7*34364Sbostic * to the University of California at Berkeley. The name of the University 8*34364Sbostic * may not be used to endorse or promote products derived from this 9*34364Sbostic * software without specific prior written permission. This software 10*34364Sbostic * is provided ``as is'' without express or implied warranty. 1121517Smckusick */ 1221517Smckusick 1312703Smckusick #ifndef lint 1421517Smckusick char copyright[] = 1521517Smckusick "@(#) Copyright (c) 1980 Regents of the University of California.\n\ 1621517Smckusick All rights reserved.\n"; 17*34364Sbostic #endif /* not lint */ 1812660Smckusick 1921517Smckusick #ifndef lint 20*34364Sbostic static char sccsid[] = "@(#)quotacheck.c 5.9 (Berkeley) 05/20/88"; 21*34364Sbostic #endif /* not lint */ 2221517Smckusick 2312660Smckusick /* 2412660Smckusick * Fix up / report on disc quotas & usage 2512660Smckusick */ 2612660Smckusick #include <stdio.h> 2712660Smckusick #include <ctype.h> 2812660Smckusick #include <signal.h> 2921085Smckusick #include <errno.h> 3012660Smckusick #include <sys/param.h> 3112660Smckusick #include <sys/inode.h> 3212660Smckusick #include <sys/fs.h> 3312660Smckusick #include <sys/quota.h> 3412660Smckusick #include <sys/stat.h> 3524758Sserge #include <sys/wait.h> 3612703Smckusick #include <fstab.h> 3712802Smckusick #include <pwd.h> 3812660Smckusick 3912660Smckusick union { 4012660Smckusick struct fs sblk; 4112703Smckusick char dummy[MAXBSIZE]; 4212660Smckusick } un; 4312660Smckusick #define sblock un.sblk 4412703Smckusick 4512703Smckusick #define ITABSZ 256 4612660Smckusick struct dinode itab[ITABSZ]; 4712660Smckusick struct dinode *dp; 4812660Smckusick 4912802Smckusick #define LOGINNAMESIZE 8 5012703Smckusick struct fileusage { 5112802Smckusick struct fileusage *fu_next; 5212703Smckusick struct dqusage fu_usage; 5312703Smckusick u_short fu_uid; 5412802Smckusick char fu_name[LOGINNAMESIZE + 1]; 5512703Smckusick }; 5612703Smckusick #define FUHASH 997 5712703Smckusick struct fileusage *fuhead[FUHASH]; 5812703Smckusick struct fileusage *lookup(); 5912703Smckusick struct fileusage *adduid(); 6012703Smckusick int highuid; 6112660Smckusick 6212703Smckusick int fi; 6312703Smckusick ino_t ino; 6412703Smckusick long done; 6512660Smckusick struct passwd *getpwent(); 6612660Smckusick struct dinode *ginode(); 6712703Smckusick char *malloc(), *makerawname(); 6812660Smckusick 6912703Smckusick int vflag; /* verbose */ 7012703Smckusick int aflag; /* all file systems */ 7124758Sserge int pflag; /* fsck like parallel check */ 7212703Smckusick 7312703Smckusick char *qfname = "quotas"; 7412703Smckusick char quotafile[MAXPATHLEN + 1]; 7512802Smckusick struct dqblk zerodqbuf; 7624758Sserge struct fileusage zerofileusage; 7730558Smckusick long dev_bsize = 1; 7812703Smckusick 7912660Smckusick main(argc, argv) 8012703Smckusick int argc; 8112660Smckusick char **argv; 8212660Smckusick { 8312703Smckusick register struct fstab *fs; 8412802Smckusick register struct fileusage *fup; 8512802Smckusick register struct passwd *pw; 8612703Smckusick int i, errs = 0; 8712660Smckusick 8812703Smckusick again: 8912703Smckusick argc--, argv++; 9012703Smckusick if (argc > 0 && strcmp(*argv, "-v") == 0) { 9112703Smckusick vflag++; 9212703Smckusick goto again; 9312660Smckusick } 9412703Smckusick if (argc > 0 && strcmp(*argv, "-a") == 0) { 9512703Smckusick aflag++; 9612703Smckusick goto again; 9712703Smckusick } 9824758Sserge if (argc > 0 && strcmp(*argv, "-p") == 0) { 9924758Sserge pflag++; 10024758Sserge goto again; 10124758Sserge } 10212703Smckusick if (argc <= 0 && !aflag) { 10312703Smckusick fprintf(stderr, "Usage:\n\t%s\n\t%s\n", 10424758Sserge "quotacheck [-v] [-p] -a", 10524758Sserge "quotacheck [-v] [-p] filesys ..."); 10612660Smckusick exit(1); 10712660Smckusick } 10824661Sserge 10924661Sserge setpwent(); 11024661Sserge while ((pw = getpwent()) != 0) { 11124661Sserge fup = lookup(pw->pw_uid); 11224758Sserge if (fup == 0) { 11324661Sserge fup = adduid(pw->pw_uid); 11424758Sserge strncpy(fup->fu_name, pw->pw_name, 11524758Sserge sizeof(fup->fu_name)); 11624758Sserge } 11712802Smckusick } 11824661Sserge endpwent(); 11924661Sserge 12024758Sserge if (pflag) 12124758Sserge errs = preen(argc, argv); 12224758Sserge else { 12324758Sserge if (setfsent() == 0) { 12424758Sserge fprintf(stderr, "Can't open "); 12524758Sserge perror(FSTAB); 12624758Sserge exit(8); 12724758Sserge } 12824758Sserge while ((fs = getfsent()) != NULL) { 12924758Sserge if (aflag && 13024758Sserge (fs->fs_type == 0 || 13124758Sserge strcmp(fs->fs_type, FSTAB_RQ) != 0)) 13224758Sserge continue; 13324758Sserge if (!aflag && 13424758Sserge !(oneof(fs->fs_file, argv, argc) || 13524758Sserge oneof(fs->fs_spec, argv, argc))) 13624758Sserge continue; 13724758Sserge (void) sprintf(quotafile, "%s/%s", fs->fs_file, qfname); 13824758Sserge errs += chkquota(fs->fs_spec, fs->fs_file, quotafile); 13924758Sserge } 14024758Sserge endfsent(); 14112660Smckusick } 14224758Sserge 14312703Smckusick for (i = 0; i < argc; i++) 14412703Smckusick if ((done & (1 << i)) == 0) 14524782Sserge fprintf(stderr, "%s not found in %s\n", 14624782Sserge argv[i], FSTAB); 14712703Smckusick exit(errs); 14812703Smckusick } 14912660Smckusick 15024758Sserge preen(argc, argv) 15124758Sserge int argc; 15224758Sserge char **argv; 15324758Sserge { 15424758Sserge register struct fstab *fs; 15524758Sserge register int passno, anygtr; 15624758Sserge register int errs; 15724758Sserge union wait status; 15824758Sserge 15924758Sserge passno = 1; 16024758Sserge errs = 0; 16124758Sserge do { 16224758Sserge anygtr = 0; 16324758Sserge 16424758Sserge if (setfsent() == 0) { 16524758Sserge fprintf(stderr, "Can't open "); 16624758Sserge perror(FSTAB); 16724758Sserge exit(8); 16824758Sserge } 16924758Sserge 17024758Sserge while ((fs = getfsent()) != NULL) { 17124758Sserge if (fs->fs_passno > passno) 17224758Sserge anygtr = 1; 17324758Sserge 17424758Sserge if (aflag && 17524758Sserge (fs->fs_type == 0 || 17624758Sserge strcmp(fs->fs_type, FSTAB_RQ) != 0)) 17724758Sserge continue; 17824758Sserge 17924758Sserge if (!aflag && 18024758Sserge !(oneof(fs->fs_file, argv, argc) || 18124758Sserge oneof(fs->fs_spec, argv, argc))) 18224758Sserge continue; 18324758Sserge 18424758Sserge if (fs->fs_passno != passno) 18524758Sserge continue; 18624758Sserge 18724758Sserge switch (fork()) { 18824758Sserge case -1: 18924758Sserge perror("fork"); 19024758Sserge exit(8); 19124758Sserge break; 19224758Sserge 19324758Sserge case 0: 19432445Sbostic (void) sprintf(quotafile, "%s/%s", 19524758Sserge fs->fs_file, qfname); 19624758Sserge exit(chkquota(fs->fs_spec, 19724758Sserge fs->fs_file, quotafile)); 19824758Sserge } 19924758Sserge } 20024758Sserge 20124758Sserge while (wait(&status) != -1) 20224758Sserge errs += status.w_retcode; 20324758Sserge 20424758Sserge passno++; 20524758Sserge } while (anygtr); 20624758Sserge 20724758Sserge return (errs); 20824758Sserge } 20924758Sserge 21024661Sserge chkquota(fsdev, fsfile, qffile) 21112703Smckusick char *fsdev; 21224661Sserge char *fsfile; 21312703Smckusick char *qffile; 21412703Smckusick { 21512703Smckusick register struct fileusage *fup; 21612703Smckusick dev_t quotadev; 21725377Sserge register FILE *qfi, *qfo; 21812703Smckusick u_short uid; 21925377Sserge int cg, i, fdo; 22012703Smckusick char *rawdisk; 22112703Smckusick struct stat statb; 22212703Smckusick struct dqblk dqbuf; 22321085Smckusick static int warned = 0; 22421085Smckusick extern int errno; 22512660Smckusick 22612703Smckusick rawdisk = makerawname(fsdev); 22712703Smckusick if (vflag) 22824758Sserge fprintf(stdout, "*** Checking quotas for %s (%s)\n", rawdisk, fsfile); 22912703Smckusick fi = open(rawdisk, 0); 23012703Smckusick if (fi < 0) { 23112703Smckusick perror(rawdisk); 23212703Smckusick return (1); 23312660Smckusick } 23425377Sserge qfi = fopen(qffile, "r"); 23525377Sserge if (qfi == NULL) { 23612703Smckusick perror(qffile); 23724661Sserge close(fi); 23812703Smckusick return (1); 23912660Smckusick } 24025377Sserge if (fstat(fileno(qfi), &statb) < 0) { 24112703Smckusick perror(qffile); 24225377Sserge fclose(qfi); 24324661Sserge close(fi); 24412703Smckusick return (1); 24512703Smckusick } 24612703Smckusick quotadev = statb.st_dev; 24712703Smckusick if (stat(fsdev, &statb) < 0) { 24812703Smckusick perror(fsdev); 24925377Sserge fclose(qfi); 25024661Sserge close(fi); 25112703Smckusick return (1); 25212703Smckusick } 25312703Smckusick if (quotadev != statb.st_rdev) { 25412703Smckusick fprintf(stderr, "%s dev (0x%x) mismatch %s dev (0x%x)\n", 25512703Smckusick qffile, quotadev, fsdev, statb.st_rdev); 25625377Sserge fclose(qfi); 25724661Sserge close(fi); 25812703Smckusick return (1); 25912703Smckusick } 26025377Sserge /* 26125377Sserge * Must do fdopen(open(qffile, 1), "w") instead of fopen(qffile, "w") 26225377Sserge * because fopen(qffile, "w") would truncate the quota file. 26325377Sserge */ 26425377Sserge fdo = open(qffile, 1); 26525377Sserge if (fdo < 0 || (qfo = fdopen(fdo, "w")) == NULL) { 26625377Sserge perror(qffile); 26725377Sserge if (fdo >= 0) 26825377Sserge close(fdo); 26925377Sserge fclose(qfi); 27025377Sserge close(fi); 27125377Sserge return (1); 27225377Sserge } 27324758Sserge if (quota(Q_SYNC, 0, quotadev, (caddr_t)0) < 0 && 27421085Smckusick errno == EINVAL && !warned && vflag) { 27521085Smckusick warned++; 27621085Smckusick fprintf(stdout, 27721085Smckusick "*** Warning: Quotas are not compiled into this kernel\n"); 27821085Smckusick } 27912660Smckusick sync(); 28030558Smckusick bread(SBOFF, (char *)&sblock, SBSIZE); 28130558Smckusick dev_bsize = sblock.fs_fsize / fsbtodb(&sblock, 1); 28212660Smckusick ino = 0; 28312660Smckusick for (cg = 0; cg < sblock.fs_ncg; cg++) { 28412660Smckusick dp = NULL; 28512660Smckusick for (i = 0; i < sblock.fs_ipg; i++) 28612660Smckusick acct(ginode()); 28712660Smckusick } 28812703Smckusick for (uid = 0; uid <= highuid; uid++) { 28925377Sserge i = fread(&dqbuf, sizeof(struct dqblk), 1, qfi); 29012703Smckusick if (i == 0) 29112802Smckusick dqbuf = zerodqbuf; 29218415Smckusick fup = lookup(uid); 29324758Sserge if (fup == 0) 29424758Sserge fup = &zerofileusage; 29512703Smckusick if (dqbuf.dqb_curinodes == fup->fu_usage.du_curinodes && 29612802Smckusick dqbuf.dqb_curblocks == fup->fu_usage.du_curblocks) { 29712802Smckusick fup->fu_usage.du_curinodes = 0; 29812802Smckusick fup->fu_usage.du_curblocks = 0; 29925377Sserge fseek(qfo, (long)sizeof(struct dqblk), 1); 30012703Smckusick continue; 30112802Smckusick } 30212703Smckusick if (vflag) { 30324758Sserge if (pflag) 30424758Sserge printf("%s: ", rawdisk); 30512802Smckusick if (fup->fu_name[0] != '\0') 30624758Sserge printf("%-8s fixed:", fup->fu_name); 30712802Smckusick else 30824758Sserge printf("#%-7d fixed:", uid); 30924758Sserge if (dqbuf.dqb_curinodes != fup->fu_usage.du_curinodes) 31025377Sserge fprintf(stdout, "\tinodes %d -> %d", 31124758Sserge dqbuf.dqb_curinodes, fup->fu_usage.du_curinodes); 31224758Sserge if (dqbuf.dqb_curblocks != fup->fu_usage.du_curblocks) 31325377Sserge fprintf(stdout, "\tblocks %d -> %d", 31424758Sserge dqbuf.dqb_curblocks, fup->fu_usage.du_curblocks); 31524758Sserge fprintf(stdout, "\n"); 31612660Smckusick } 31712703Smckusick dqbuf.dqb_curinodes = fup->fu_usage.du_curinodes; 31812703Smckusick dqbuf.dqb_curblocks = fup->fu_usage.du_curblocks; 31925377Sserge fwrite(&dqbuf, sizeof(struct dqblk), 1, qfo); 32012703Smckusick quota(Q_SETDUSE, uid, quotadev, &fup->fu_usage); 32113255Smckusick fup->fu_usage.du_curinodes = 0; 32213255Smckusick fup->fu_usage.du_curblocks = 0; 32312660Smckusick } 32425377Sserge fflush(qfo); 32525377Sserge ftruncate(fileno(qfo), (off_t)((highuid + 1) * sizeof(struct dqblk))); 32625377Sserge fclose(qfi); 32725377Sserge fclose(qfo); 32824661Sserge close(fi); 32912703Smckusick return (0); 33012660Smckusick } 33112660Smckusick 33212660Smckusick acct(ip) 33312660Smckusick register struct dinode *ip; 33412660Smckusick { 33512703Smckusick register struct fileusage *fup; 33612660Smckusick 33712660Smckusick if (ip == NULL) 33812660Smckusick return; 33912660Smckusick if (ip->di_mode == 0) 34012660Smckusick return; 34124758Sserge fup = adduid(ip->di_uid); 34212703Smckusick fup->fu_usage.du_curinodes++; 34312660Smckusick if ((ip->di_mode & IFMT) == IFCHR || (ip->di_mode & IFMT) == IFBLK) 34412660Smckusick return; 34512703Smckusick fup->fu_usage.du_curblocks += ip->di_blocks; 34612660Smckusick } 34712660Smckusick 34812703Smckusick oneof(target, list, n) 34912703Smckusick char *target, *list[]; 35012703Smckusick register int n; 35112660Smckusick { 35212703Smckusick register int i; 35312660Smckusick 35412703Smckusick for (i = 0; i < n; i++) 35512703Smckusick if (strcmp(target, list[i]) == 0) { 35612703Smckusick done |= 1 << i; 35712703Smckusick return (1); 35812703Smckusick } 35912703Smckusick return (0); 36012660Smckusick } 36112660Smckusick 36212660Smckusick struct dinode * 36312660Smckusick ginode() 36412660Smckusick { 36512660Smckusick register unsigned long iblk; 36612660Smckusick 36712660Smckusick if (dp == NULL || ++dp >= &itab[ITABSZ]) { 36812660Smckusick iblk = itod(&sblock, ino); 36912660Smckusick bread(fsbtodb(&sblock, iblk), (char *)itab, sizeof itab); 37012660Smckusick dp = &itab[ino % INOPB(&sblock)]; 37112660Smckusick } 37212660Smckusick if (ino++ < ROOTINO) 37312660Smckusick return(NULL); 37412660Smckusick return(dp); 37512660Smckusick } 37612660Smckusick 37712660Smckusick bread(bno, buf, cnt) 37812660Smckusick long unsigned bno; 37912660Smckusick char *buf; 38012660Smckusick { 38112660Smckusick 38230558Smckusick if (lseek(fi, bno * dev_bsize, 0) < 0) { 38325377Sserge perror("lseek"); 38425377Sserge exit(1); 38525377Sserge } 38625377Sserge 38712660Smckusick if (read(fi, buf, cnt) != cnt) { 38824758Sserge perror("read"); 38912660Smckusick exit(1); 39012660Smckusick } 39112660Smckusick } 39212660Smckusick 39312703Smckusick struct fileusage * 39412703Smckusick lookup(uid) 39512703Smckusick u_short uid; 39612660Smckusick { 39712703Smckusick register struct fileusage *fup; 39812660Smckusick 39912703Smckusick for (fup = fuhead[uid % FUHASH]; fup != 0; fup = fup->fu_next) 40012703Smckusick if (fup->fu_uid == uid) 40112703Smckusick return (fup); 40212703Smckusick return ((struct fileusage *)0); 40312660Smckusick } 40412660Smckusick 40512703Smckusick struct fileusage * 40612703Smckusick adduid(uid) 40712703Smckusick u_short uid; 40812660Smckusick { 40912703Smckusick struct fileusage *fup, **fhp; 41024661Sserge extern char *calloc(); 41112660Smckusick 41212703Smckusick fup = lookup(uid); 41312703Smckusick if (fup != 0) 41412703Smckusick return (fup); 41512703Smckusick fup = (struct fileusage *)calloc(1, sizeof(struct fileusage)); 41612703Smckusick if (fup == 0) { 41712703Smckusick fprintf(stderr, "out of memory for fileusage structures\n"); 41812703Smckusick exit(1); 41912703Smckusick } 42012703Smckusick fhp = &fuhead[uid % FUHASH]; 42112703Smckusick fup->fu_next = *fhp; 42212703Smckusick *fhp = fup; 42312703Smckusick fup->fu_uid = uid; 42412703Smckusick if (uid > highuid) 42512703Smckusick highuid = uid; 42612703Smckusick return (fup); 42712660Smckusick } 42812660Smckusick 42912660Smckusick char * 43012703Smckusick makerawname(name) 43112703Smckusick char *name; 43212660Smckusick { 43312703Smckusick register char *cp; 43412703Smckusick char tmp, ch, *rindex(); 43512703Smckusick static char rawname[MAXPATHLEN]; 43612660Smckusick 43712703Smckusick strcpy(rawname, name); 43824661Sserge cp = rindex(rawname, '/'); 43924782Sserge if (cp == NULL) 44012703Smckusick return (name); 44124661Sserge else 44224661Sserge cp++; 44312703Smckusick for (ch = 'r'; *cp != '\0'; ) { 44412703Smckusick tmp = *cp; 44512703Smckusick *cp++ = ch; 44612703Smckusick ch = tmp; 44712703Smckusick } 44812703Smckusick *cp++ = ch; 44912703Smckusick *cp = '\0'; 45012703Smckusick return (rawname); 45112660Smckusick } 452