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*30558Smckusick static char sccsid[] = "@(#)quotacheck.c 5.7 (Berkeley) 02/23/87"; 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> 2924758Sserge #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 */ 6524758Sserge int pflag; /* fsck like parallel check */ 6612703Smckusick 6712703Smckusick char *qfname = "quotas"; 6812703Smckusick char quotafile[MAXPATHLEN + 1]; 6912802Smckusick struct dqblk zerodqbuf; 7024758Sserge struct fileusage zerofileusage; 71*30558Smckusick long dev_bsize = 1; 7212703Smckusick 7312660Smckusick main(argc, argv) 7412703Smckusick int argc; 7512660Smckusick char **argv; 7612660Smckusick { 7712703Smckusick register struct fstab *fs; 7812802Smckusick register struct fileusage *fup; 7912802Smckusick register struct passwd *pw; 8012703Smckusick int i, errs = 0; 8112660Smckusick 8212703Smckusick again: 8312703Smckusick argc--, argv++; 8412703Smckusick if (argc > 0 && strcmp(*argv, "-v") == 0) { 8512703Smckusick vflag++; 8612703Smckusick goto again; 8712660Smckusick } 8812703Smckusick if (argc > 0 && strcmp(*argv, "-a") == 0) { 8912703Smckusick aflag++; 9012703Smckusick goto again; 9112703Smckusick } 9224758Sserge if (argc > 0 && strcmp(*argv, "-p") == 0) { 9324758Sserge pflag++; 9424758Sserge goto again; 9524758Sserge } 9612703Smckusick if (argc <= 0 && !aflag) { 9712703Smckusick fprintf(stderr, "Usage:\n\t%s\n\t%s\n", 9824758Sserge "quotacheck [-v] [-p] -a", 9924758Sserge "quotacheck [-v] [-p] filesys ..."); 10012660Smckusick exit(1); 10112660Smckusick } 10224661Sserge 10324661Sserge setpwent(); 10424661Sserge while ((pw = getpwent()) != 0) { 10524661Sserge fup = lookup(pw->pw_uid); 10624758Sserge if (fup == 0) { 10724661Sserge fup = adduid(pw->pw_uid); 10824758Sserge strncpy(fup->fu_name, pw->pw_name, 10924758Sserge sizeof(fup->fu_name)); 11024758Sserge } 11112802Smckusick } 11224661Sserge endpwent(); 11324661Sserge 11424758Sserge if (pflag) 11524758Sserge errs = preen(argc, argv); 11624758Sserge else { 11724758Sserge if (setfsent() == 0) { 11824758Sserge fprintf(stderr, "Can't open "); 11924758Sserge perror(FSTAB); 12024758Sserge exit(8); 12124758Sserge } 12224758Sserge while ((fs = getfsent()) != NULL) { 12324758Sserge if (aflag && 12424758Sserge (fs->fs_type == 0 || 12524758Sserge strcmp(fs->fs_type, FSTAB_RQ) != 0)) 12624758Sserge continue; 12724758Sserge if (!aflag && 12824758Sserge !(oneof(fs->fs_file, argv, argc) || 12924758Sserge oneof(fs->fs_spec, argv, argc))) 13024758Sserge continue; 13124758Sserge (void) sprintf(quotafile, "%s/%s", fs->fs_file, qfname); 13224758Sserge errs += chkquota(fs->fs_spec, fs->fs_file, quotafile); 13324758Sserge } 13424758Sserge endfsent(); 13512660Smckusick } 13624758Sserge 13712703Smckusick for (i = 0; i < argc; i++) 13812703Smckusick if ((done & (1 << i)) == 0) 13924782Sserge fprintf(stderr, "%s not found in %s\n", 14024782Sserge argv[i], FSTAB); 14112703Smckusick exit(errs); 14212703Smckusick } 14312660Smckusick 14424758Sserge preen(argc, argv) 14524758Sserge int argc; 14624758Sserge char **argv; 14724758Sserge { 14824758Sserge register struct fstab *fs; 14924758Sserge register int passno, anygtr; 15024758Sserge register int errs; 15124758Sserge union wait status; 15224758Sserge 15324758Sserge passno = 1; 15424758Sserge errs = 0; 15524758Sserge do { 15624758Sserge anygtr = 0; 15724758Sserge 15824758Sserge if (setfsent() == 0) { 15924758Sserge fprintf(stderr, "Can't open "); 16024758Sserge perror(FSTAB); 16124758Sserge exit(8); 16224758Sserge } 16324758Sserge 16424758Sserge while ((fs = getfsent()) != NULL) { 16524758Sserge if (fs->fs_passno > passno) 16624758Sserge anygtr = 1; 16724758Sserge 16824758Sserge if (aflag && 16924758Sserge (fs->fs_type == 0 || 17024758Sserge strcmp(fs->fs_type, FSTAB_RQ) != 0)) 17124758Sserge continue; 17224758Sserge 17324758Sserge if (!aflag && 17424758Sserge !(oneof(fs->fs_file, argv, argc) || 17524758Sserge oneof(fs->fs_spec, argv, argc))) 17624758Sserge continue; 17724758Sserge 17824758Sserge if (fs->fs_passno != passno) 17924758Sserge continue; 18024758Sserge 18124758Sserge switch (fork()) { 18224758Sserge case -1: 18324758Sserge perror("fork"); 18424758Sserge exit(8); 18524758Sserge break; 18624758Sserge 18724758Sserge case 0: 18824758Sserge sprintf(quotafile, "%s/%s", 18924758Sserge fs->fs_file, qfname); 19024758Sserge exit(chkquota(fs->fs_spec, 19124758Sserge fs->fs_file, quotafile)); 19224758Sserge } 19324758Sserge } 19424758Sserge 19524758Sserge while (wait(&status) != -1) 19624758Sserge errs += status.w_retcode; 19724758Sserge 19824758Sserge passno++; 19924758Sserge } while (anygtr); 20024758Sserge 20124758Sserge return (errs); 20224758Sserge } 20324758Sserge 20424661Sserge chkquota(fsdev, fsfile, qffile) 20512703Smckusick char *fsdev; 20624661Sserge char *fsfile; 20712703Smckusick char *qffile; 20812703Smckusick { 20912703Smckusick register struct fileusage *fup; 21012703Smckusick dev_t quotadev; 21125377Sserge register FILE *qfi, *qfo; 21212703Smckusick u_short uid; 21325377Sserge int cg, i, fdo; 21412703Smckusick char *rawdisk; 21512703Smckusick struct stat statb; 21612703Smckusick struct dqblk dqbuf; 21721085Smckusick static int warned = 0; 21821085Smckusick extern int errno; 21912660Smckusick 22012703Smckusick rawdisk = makerawname(fsdev); 22112703Smckusick if (vflag) 22224758Sserge fprintf(stdout, "*** Checking quotas for %s (%s)\n", rawdisk, fsfile); 22312703Smckusick fi = open(rawdisk, 0); 22412703Smckusick if (fi < 0) { 22512703Smckusick perror(rawdisk); 22612703Smckusick return (1); 22712660Smckusick } 22825377Sserge qfi = fopen(qffile, "r"); 22925377Sserge if (qfi == NULL) { 23012703Smckusick perror(qffile); 23124661Sserge close(fi); 23212703Smckusick return (1); 23312660Smckusick } 23425377Sserge if (fstat(fileno(qfi), &statb) < 0) { 23512703Smckusick perror(qffile); 23625377Sserge fclose(qfi); 23724661Sserge close(fi); 23812703Smckusick return (1); 23912703Smckusick } 24012703Smckusick quotadev = statb.st_dev; 24112703Smckusick if (stat(fsdev, &statb) < 0) { 24212703Smckusick perror(fsdev); 24325377Sserge fclose(qfi); 24424661Sserge close(fi); 24512703Smckusick return (1); 24612703Smckusick } 24712703Smckusick if (quotadev != statb.st_rdev) { 24812703Smckusick fprintf(stderr, "%s dev (0x%x) mismatch %s dev (0x%x)\n", 24912703Smckusick qffile, quotadev, fsdev, statb.st_rdev); 25025377Sserge fclose(qfi); 25124661Sserge close(fi); 25212703Smckusick return (1); 25312703Smckusick } 25425377Sserge /* 25525377Sserge * Must do fdopen(open(qffile, 1), "w") instead of fopen(qffile, "w") 25625377Sserge * because fopen(qffile, "w") would truncate the quota file. 25725377Sserge */ 25825377Sserge fdo = open(qffile, 1); 25925377Sserge if (fdo < 0 || (qfo = fdopen(fdo, "w")) == NULL) { 26025377Sserge perror(qffile); 26125377Sserge if (fdo >= 0) 26225377Sserge close(fdo); 26325377Sserge fclose(qfi); 26425377Sserge close(fi); 26525377Sserge return (1); 26625377Sserge } 26724758Sserge if (quota(Q_SYNC, 0, quotadev, (caddr_t)0) < 0 && 26821085Smckusick errno == EINVAL && !warned && vflag) { 26921085Smckusick warned++; 27021085Smckusick fprintf(stdout, 27121085Smckusick "*** Warning: Quotas are not compiled into this kernel\n"); 27221085Smckusick } 27312660Smckusick sync(); 274*30558Smckusick bread(SBOFF, (char *)&sblock, SBSIZE); 275*30558Smckusick dev_bsize = sblock.fs_fsize / fsbtodb(&sblock, 1); 27612660Smckusick ino = 0; 27712660Smckusick for (cg = 0; cg < sblock.fs_ncg; cg++) { 27812660Smckusick dp = NULL; 27912660Smckusick for (i = 0; i < sblock.fs_ipg; i++) 28012660Smckusick acct(ginode()); 28112660Smckusick } 28212703Smckusick for (uid = 0; uid <= highuid; uid++) { 28325377Sserge i = fread(&dqbuf, sizeof(struct dqblk), 1, qfi); 28412703Smckusick if (i == 0) 28512802Smckusick dqbuf = zerodqbuf; 28618415Smckusick fup = lookup(uid); 28724758Sserge if (fup == 0) 28824758Sserge fup = &zerofileusage; 28912703Smckusick if (dqbuf.dqb_curinodes == fup->fu_usage.du_curinodes && 29012802Smckusick dqbuf.dqb_curblocks == fup->fu_usage.du_curblocks) { 29112802Smckusick fup->fu_usage.du_curinodes = 0; 29212802Smckusick fup->fu_usage.du_curblocks = 0; 29325377Sserge fseek(qfo, (long)sizeof(struct dqblk), 1); 29412703Smckusick continue; 29512802Smckusick } 29612703Smckusick if (vflag) { 29724758Sserge if (pflag) 29824758Sserge printf("%s: ", rawdisk); 29912802Smckusick if (fup->fu_name[0] != '\0') 30024758Sserge printf("%-8s fixed:", fup->fu_name); 30112802Smckusick else 30224758Sserge printf("#%-7d fixed:", uid); 30324758Sserge if (dqbuf.dqb_curinodes != fup->fu_usage.du_curinodes) 30425377Sserge fprintf(stdout, "\tinodes %d -> %d", 30524758Sserge dqbuf.dqb_curinodes, fup->fu_usage.du_curinodes); 30624758Sserge if (dqbuf.dqb_curblocks != fup->fu_usage.du_curblocks) 30725377Sserge fprintf(stdout, "\tblocks %d -> %d", 30824758Sserge dqbuf.dqb_curblocks, fup->fu_usage.du_curblocks); 30924758Sserge fprintf(stdout, "\n"); 31012660Smckusick } 31112703Smckusick dqbuf.dqb_curinodes = fup->fu_usage.du_curinodes; 31212703Smckusick dqbuf.dqb_curblocks = fup->fu_usage.du_curblocks; 31325377Sserge fwrite(&dqbuf, sizeof(struct dqblk), 1, qfo); 31412703Smckusick quota(Q_SETDUSE, uid, quotadev, &fup->fu_usage); 31513255Smckusick fup->fu_usage.du_curinodes = 0; 31613255Smckusick fup->fu_usage.du_curblocks = 0; 31712660Smckusick } 31825377Sserge fflush(qfo); 31925377Sserge ftruncate(fileno(qfo), (off_t)((highuid + 1) * sizeof(struct dqblk))); 32025377Sserge fclose(qfi); 32125377Sserge fclose(qfo); 32224661Sserge close(fi); 32312703Smckusick return (0); 32412660Smckusick } 32512660Smckusick 32612660Smckusick acct(ip) 32712660Smckusick register struct dinode *ip; 32812660Smckusick { 32912703Smckusick register struct fileusage *fup; 33012660Smckusick 33112660Smckusick if (ip == NULL) 33212660Smckusick return; 33312660Smckusick if (ip->di_mode == 0) 33412660Smckusick return; 33524758Sserge fup = adduid(ip->di_uid); 33612703Smckusick fup->fu_usage.du_curinodes++; 33712660Smckusick if ((ip->di_mode & IFMT) == IFCHR || (ip->di_mode & IFMT) == IFBLK) 33812660Smckusick return; 33912703Smckusick fup->fu_usage.du_curblocks += ip->di_blocks; 34012660Smckusick } 34112660Smckusick 34212703Smckusick oneof(target, list, n) 34312703Smckusick char *target, *list[]; 34412703Smckusick register int n; 34512660Smckusick { 34612703Smckusick register int i; 34712660Smckusick 34812703Smckusick for (i = 0; i < n; i++) 34912703Smckusick if (strcmp(target, list[i]) == 0) { 35012703Smckusick done |= 1 << i; 35112703Smckusick return (1); 35212703Smckusick } 35312703Smckusick return (0); 35412660Smckusick } 35512660Smckusick 35612660Smckusick struct dinode * 35712660Smckusick ginode() 35812660Smckusick { 35912660Smckusick register unsigned long iblk; 36012660Smckusick 36112660Smckusick if (dp == NULL || ++dp >= &itab[ITABSZ]) { 36212660Smckusick iblk = itod(&sblock, ino); 36312660Smckusick bread(fsbtodb(&sblock, iblk), (char *)itab, sizeof itab); 36412660Smckusick dp = &itab[ino % INOPB(&sblock)]; 36512660Smckusick } 36612660Smckusick if (ino++ < ROOTINO) 36712660Smckusick return(NULL); 36812660Smckusick return(dp); 36912660Smckusick } 37012660Smckusick 37112660Smckusick bread(bno, buf, cnt) 37212660Smckusick long unsigned bno; 37312660Smckusick char *buf; 37412660Smckusick { 37512660Smckusick 376*30558Smckusick if (lseek(fi, bno * dev_bsize, 0) < 0) { 37725377Sserge perror("lseek"); 37825377Sserge exit(1); 37925377Sserge } 38025377Sserge 38112660Smckusick if (read(fi, buf, cnt) != cnt) { 38224758Sserge perror("read"); 38312660Smckusick exit(1); 38412660Smckusick } 38512660Smckusick } 38612660Smckusick 38712703Smckusick struct fileusage * 38812703Smckusick lookup(uid) 38912703Smckusick u_short uid; 39012660Smckusick { 39112703Smckusick register struct fileusage *fup; 39212660Smckusick 39312703Smckusick for (fup = fuhead[uid % FUHASH]; fup != 0; fup = fup->fu_next) 39412703Smckusick if (fup->fu_uid == uid) 39512703Smckusick return (fup); 39612703Smckusick return ((struct fileusage *)0); 39712660Smckusick } 39812660Smckusick 39912703Smckusick struct fileusage * 40012703Smckusick adduid(uid) 40112703Smckusick u_short uid; 40212660Smckusick { 40312703Smckusick struct fileusage *fup, **fhp; 40424661Sserge extern char *calloc(); 40512660Smckusick 40612703Smckusick fup = lookup(uid); 40712703Smckusick if (fup != 0) 40812703Smckusick return (fup); 40912703Smckusick fup = (struct fileusage *)calloc(1, sizeof(struct fileusage)); 41012703Smckusick if (fup == 0) { 41112703Smckusick fprintf(stderr, "out of memory for fileusage structures\n"); 41212703Smckusick exit(1); 41312703Smckusick } 41412703Smckusick fhp = &fuhead[uid % FUHASH]; 41512703Smckusick fup->fu_next = *fhp; 41612703Smckusick *fhp = fup; 41712703Smckusick fup->fu_uid = uid; 41812703Smckusick if (uid > highuid) 41912703Smckusick highuid = uid; 42012703Smckusick return (fup); 42112660Smckusick } 42212660Smckusick 42312660Smckusick char * 42412703Smckusick makerawname(name) 42512703Smckusick char *name; 42612660Smckusick { 42712703Smckusick register char *cp; 42812703Smckusick char tmp, ch, *rindex(); 42912703Smckusick static char rawname[MAXPATHLEN]; 43012660Smckusick 43112703Smckusick strcpy(rawname, name); 43224661Sserge cp = rindex(rawname, '/'); 43324782Sserge if (cp == NULL) 43412703Smckusick return (name); 43524661Sserge else 43624661Sserge cp++; 43712703Smckusick for (ch = 'r'; *cp != '\0'; ) { 43812703Smckusick tmp = *cp; 43912703Smckusick *cp++ = ch; 44012703Smckusick ch = tmp; 44112703Smckusick } 44212703Smckusick *cp++ = ch; 44312703Smckusick *cp = '\0'; 44412703Smckusick return (rawname); 44512660Smckusick } 446