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*25377Sserge static char sccsid[] = "@(#)quotacheck.c 5.6 (Berkeley) 11/03/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> 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; 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 } 9124758Sserge if (argc > 0 && strcmp(*argv, "-p") == 0) { 9224758Sserge pflag++; 9324758Sserge goto again; 9424758Sserge } 9512703Smckusick if (argc <= 0 && !aflag) { 9612703Smckusick fprintf(stderr, "Usage:\n\t%s\n\t%s\n", 9724758Sserge "quotacheck [-v] [-p] -a", 9824758Sserge "quotacheck [-v] [-p] filesys ..."); 9912660Smckusick exit(1); 10012660Smckusick } 10124661Sserge 10224661Sserge setpwent(); 10324661Sserge while ((pw = getpwent()) != 0) { 10424661Sserge fup = lookup(pw->pw_uid); 10524758Sserge if (fup == 0) { 10624661Sserge fup = adduid(pw->pw_uid); 10724758Sserge strncpy(fup->fu_name, pw->pw_name, 10824758Sserge sizeof(fup->fu_name)); 10924758Sserge } 11012802Smckusick } 11124661Sserge endpwent(); 11224661Sserge 11324758Sserge if (pflag) 11424758Sserge errs = preen(argc, argv); 11524758Sserge else { 11624758Sserge if (setfsent() == 0) { 11724758Sserge fprintf(stderr, "Can't open "); 11824758Sserge perror(FSTAB); 11924758Sserge exit(8); 12024758Sserge } 12124758Sserge while ((fs = getfsent()) != NULL) { 12224758Sserge if (aflag && 12324758Sserge (fs->fs_type == 0 || 12424758Sserge strcmp(fs->fs_type, FSTAB_RQ) != 0)) 12524758Sserge continue; 12624758Sserge if (!aflag && 12724758Sserge !(oneof(fs->fs_file, argv, argc) || 12824758Sserge oneof(fs->fs_spec, argv, argc))) 12924758Sserge continue; 13024758Sserge (void) sprintf(quotafile, "%s/%s", fs->fs_file, qfname); 13124758Sserge errs += chkquota(fs->fs_spec, fs->fs_file, quotafile); 13224758Sserge } 13324758Sserge endfsent(); 13412660Smckusick } 13524758Sserge 13612703Smckusick for (i = 0; i < argc; i++) 13712703Smckusick if ((done & (1 << i)) == 0) 13824782Sserge fprintf(stderr, "%s not found in %s\n", 13924782Sserge argv[i], FSTAB); 14012703Smckusick exit(errs); 14112703Smckusick } 14212660Smckusick 14324758Sserge preen(argc, argv) 14424758Sserge int argc; 14524758Sserge char **argv; 14624758Sserge { 14724758Sserge register struct fstab *fs; 14824758Sserge register int passno, anygtr; 14924758Sserge register int errs; 15024758Sserge union wait status; 15124758Sserge 15224758Sserge passno = 1; 15324758Sserge errs = 0; 15424758Sserge do { 15524758Sserge anygtr = 0; 15624758Sserge 15724758Sserge if (setfsent() == 0) { 15824758Sserge fprintf(stderr, "Can't open "); 15924758Sserge perror(FSTAB); 16024758Sserge exit(8); 16124758Sserge } 16224758Sserge 16324758Sserge while ((fs = getfsent()) != NULL) { 16424758Sserge if (fs->fs_passno > passno) 16524758Sserge anygtr = 1; 16624758Sserge 16724758Sserge if (aflag && 16824758Sserge (fs->fs_type == 0 || 16924758Sserge strcmp(fs->fs_type, FSTAB_RQ) != 0)) 17024758Sserge continue; 17124758Sserge 17224758Sserge if (!aflag && 17324758Sserge !(oneof(fs->fs_file, argv, argc) || 17424758Sserge oneof(fs->fs_spec, argv, argc))) 17524758Sserge continue; 17624758Sserge 17724758Sserge if (fs->fs_passno != passno) 17824758Sserge continue; 17924758Sserge 18024758Sserge switch (fork()) { 18124758Sserge case -1: 18224758Sserge perror("fork"); 18324758Sserge exit(8); 18424758Sserge break; 18524758Sserge 18624758Sserge case 0: 18724758Sserge sprintf(quotafile, "%s/%s", 18824758Sserge fs->fs_file, qfname); 18924758Sserge exit(chkquota(fs->fs_spec, 19024758Sserge fs->fs_file, quotafile)); 19124758Sserge } 19224758Sserge } 19324758Sserge 19424758Sserge while (wait(&status) != -1) 19524758Sserge errs += status.w_retcode; 19624758Sserge 19724758Sserge passno++; 19824758Sserge } while (anygtr); 19924758Sserge 20024758Sserge return (errs); 20124758Sserge } 20224758Sserge 20324661Sserge chkquota(fsdev, fsfile, qffile) 20412703Smckusick char *fsdev; 20524661Sserge char *fsfile; 20612703Smckusick char *qffile; 20712703Smckusick { 20812703Smckusick register struct fileusage *fup; 20912703Smckusick dev_t quotadev; 210*25377Sserge register FILE *qfi, *qfo; 21112703Smckusick u_short uid; 212*25377Sserge int cg, i, fdo; 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) 22124758Sserge 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 } 227*25377Sserge qfi = fopen(qffile, "r"); 228*25377Sserge if (qfi == NULL) { 22912703Smckusick perror(qffile); 23024661Sserge close(fi); 23112703Smckusick return (1); 23212660Smckusick } 233*25377Sserge if (fstat(fileno(qfi), &statb) < 0) { 23412703Smckusick perror(qffile); 235*25377Sserge fclose(qfi); 23624661Sserge close(fi); 23712703Smckusick return (1); 23812703Smckusick } 23912703Smckusick quotadev = statb.st_dev; 24012703Smckusick if (stat(fsdev, &statb) < 0) { 24112703Smckusick perror(fsdev); 242*25377Sserge fclose(qfi); 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); 249*25377Sserge fclose(qfi); 25024661Sserge close(fi); 25112703Smckusick return (1); 25212703Smckusick } 253*25377Sserge /* 254*25377Sserge * Must do fdopen(open(qffile, 1), "w") instead of fopen(qffile, "w") 255*25377Sserge * because fopen(qffile, "w") would truncate the quota file. 256*25377Sserge */ 257*25377Sserge fdo = open(qffile, 1); 258*25377Sserge if (fdo < 0 || (qfo = fdopen(fdo, "w")) == NULL) { 259*25377Sserge perror(qffile); 260*25377Sserge if (fdo >= 0) 261*25377Sserge close(fdo); 262*25377Sserge fclose(qfi); 263*25377Sserge close(fi); 264*25377Sserge return (1); 265*25377Sserge } 26624758Sserge if (quota(Q_SYNC, 0, quotadev, (caddr_t)0) < 0 && 26721085Smckusick errno == EINVAL && !warned && vflag) { 26821085Smckusick warned++; 26921085Smckusick fprintf(stdout, 27021085Smckusick "*** Warning: Quotas are not compiled into this kernel\n"); 27121085Smckusick } 27212660Smckusick sync(); 27312660Smckusick bread(SBLOCK, (char *)&sblock, SBSIZE); 27412660Smckusick ino = 0; 27512660Smckusick for (cg = 0; cg < sblock.fs_ncg; cg++) { 27612660Smckusick dp = NULL; 27712660Smckusick for (i = 0; i < sblock.fs_ipg; i++) 27812660Smckusick acct(ginode()); 27912660Smckusick } 28012703Smckusick for (uid = 0; uid <= highuid; uid++) { 281*25377Sserge i = fread(&dqbuf, sizeof(struct dqblk), 1, qfi); 28212703Smckusick if (i == 0) 28312802Smckusick dqbuf = zerodqbuf; 28418415Smckusick fup = lookup(uid); 28524758Sserge if (fup == 0) 28624758Sserge fup = &zerofileusage; 28712703Smckusick if (dqbuf.dqb_curinodes == fup->fu_usage.du_curinodes && 28812802Smckusick dqbuf.dqb_curblocks == fup->fu_usage.du_curblocks) { 28912802Smckusick fup->fu_usage.du_curinodes = 0; 29012802Smckusick fup->fu_usage.du_curblocks = 0; 291*25377Sserge fseek(qfo, (long)sizeof(struct dqblk), 1); 29212703Smckusick continue; 29312802Smckusick } 29412703Smckusick if (vflag) { 29524758Sserge if (pflag) 29624758Sserge printf("%s: ", rawdisk); 29712802Smckusick if (fup->fu_name[0] != '\0') 29824758Sserge printf("%-8s fixed:", fup->fu_name); 29912802Smckusick else 30024758Sserge printf("#%-7d fixed:", uid); 30124758Sserge if (dqbuf.dqb_curinodes != fup->fu_usage.du_curinodes) 302*25377Sserge fprintf(stdout, "\tinodes %d -> %d", 30324758Sserge dqbuf.dqb_curinodes, fup->fu_usage.du_curinodes); 30424758Sserge if (dqbuf.dqb_curblocks != fup->fu_usage.du_curblocks) 305*25377Sserge fprintf(stdout, "\tblocks %d -> %d", 30624758Sserge dqbuf.dqb_curblocks, fup->fu_usage.du_curblocks); 30724758Sserge fprintf(stdout, "\n"); 30812660Smckusick } 30912703Smckusick dqbuf.dqb_curinodes = fup->fu_usage.du_curinodes; 31012703Smckusick dqbuf.dqb_curblocks = fup->fu_usage.du_curblocks; 311*25377Sserge fwrite(&dqbuf, sizeof(struct dqblk), 1, qfo); 31212703Smckusick quota(Q_SETDUSE, uid, quotadev, &fup->fu_usage); 31313255Smckusick fup->fu_usage.du_curinodes = 0; 31413255Smckusick fup->fu_usage.du_curblocks = 0; 31512660Smckusick } 316*25377Sserge fflush(qfo); 317*25377Sserge ftruncate(fileno(qfo), (off_t)((highuid + 1) * sizeof(struct dqblk))); 318*25377Sserge fclose(qfi); 319*25377Sserge fclose(qfo); 32024661Sserge close(fi); 32112703Smckusick return (0); 32212660Smckusick } 32312660Smckusick 32412660Smckusick acct(ip) 32512660Smckusick register struct dinode *ip; 32612660Smckusick { 32712703Smckusick register struct fileusage *fup; 32812660Smckusick 32912660Smckusick if (ip == NULL) 33012660Smckusick return; 33112660Smckusick if (ip->di_mode == 0) 33212660Smckusick return; 33324758Sserge fup = adduid(ip->di_uid); 33412703Smckusick fup->fu_usage.du_curinodes++; 33512660Smckusick if ((ip->di_mode & IFMT) == IFCHR || (ip->di_mode & IFMT) == IFBLK) 33612660Smckusick return; 33712703Smckusick fup->fu_usage.du_curblocks += ip->di_blocks; 33812660Smckusick } 33912660Smckusick 34012703Smckusick oneof(target, list, n) 34112703Smckusick char *target, *list[]; 34212703Smckusick register int n; 34312660Smckusick { 34412703Smckusick register int i; 34512660Smckusick 34612703Smckusick for (i = 0; i < n; i++) 34712703Smckusick if (strcmp(target, list[i]) == 0) { 34812703Smckusick done |= 1 << i; 34912703Smckusick return (1); 35012703Smckusick } 35112703Smckusick return (0); 35212660Smckusick } 35312660Smckusick 35412660Smckusick struct dinode * 35512660Smckusick ginode() 35612660Smckusick { 35712660Smckusick register unsigned long iblk; 35812660Smckusick 35912660Smckusick if (dp == NULL || ++dp >= &itab[ITABSZ]) { 36012660Smckusick iblk = itod(&sblock, ino); 36112660Smckusick bread(fsbtodb(&sblock, iblk), (char *)itab, sizeof itab); 36212660Smckusick dp = &itab[ino % INOPB(&sblock)]; 36312660Smckusick } 36412660Smckusick if (ino++ < ROOTINO) 36512660Smckusick return(NULL); 36612660Smckusick return(dp); 36712660Smckusick } 36812660Smckusick 36912660Smckusick bread(bno, buf, cnt) 37012660Smckusick long unsigned bno; 37112660Smckusick char *buf; 37212660Smckusick { 373*25377Sserge extern off_t lseek(); 374*25377Sserge register off_t pos; 37512660Smckusick 376*25377Sserge pos = (off_t)dbtob(bno); 377*25377Sserge if (lseek(fi, pos, 0) != pos) { 378*25377Sserge perror("lseek"); 379*25377Sserge exit(1); 380*25377Sserge } 381*25377Sserge 38212660Smckusick if (read(fi, buf, cnt) != cnt) { 38324758Sserge perror("read"); 38412660Smckusick exit(1); 38512660Smckusick } 38612660Smckusick } 38712660Smckusick 38812703Smckusick struct fileusage * 38912703Smckusick lookup(uid) 39012703Smckusick u_short uid; 39112660Smckusick { 39212703Smckusick register struct fileusage *fup; 39312660Smckusick 39412703Smckusick for (fup = fuhead[uid % FUHASH]; fup != 0; fup = fup->fu_next) 39512703Smckusick if (fup->fu_uid == uid) 39612703Smckusick return (fup); 39712703Smckusick return ((struct fileusage *)0); 39812660Smckusick } 39912660Smckusick 40012703Smckusick struct fileusage * 40112703Smckusick adduid(uid) 40212703Smckusick u_short uid; 40312660Smckusick { 40412703Smckusick struct fileusage *fup, **fhp; 40524661Sserge extern char *calloc(); 40612660Smckusick 40712703Smckusick fup = lookup(uid); 40812703Smckusick if (fup != 0) 40912703Smckusick return (fup); 41012703Smckusick fup = (struct fileusage *)calloc(1, sizeof(struct fileusage)); 41112703Smckusick if (fup == 0) { 41212703Smckusick fprintf(stderr, "out of memory for fileusage structures\n"); 41312703Smckusick exit(1); 41412703Smckusick } 41512703Smckusick fhp = &fuhead[uid % FUHASH]; 41612703Smckusick fup->fu_next = *fhp; 41712703Smckusick *fhp = fup; 41812703Smckusick fup->fu_uid = uid; 41912703Smckusick if (uid > highuid) 42012703Smckusick highuid = uid; 42112703Smckusick return (fup); 42212660Smckusick } 42312660Smckusick 42412660Smckusick char * 42512703Smckusick makerawname(name) 42612703Smckusick char *name; 42712660Smckusick { 42812703Smckusick register char *cp; 42912703Smckusick char tmp, ch, *rindex(); 43012703Smckusick static char rawname[MAXPATHLEN]; 43112660Smckusick 43212703Smckusick strcpy(rawname, name); 43324661Sserge cp = rindex(rawname, '/'); 43424782Sserge if (cp == NULL) 43512703Smckusick return (name); 43624661Sserge else 43724661Sserge cp++; 43812703Smckusick for (ch = 'r'; *cp != '\0'; ) { 43912703Smckusick tmp = *cp; 44012703Smckusick *cp++ = ch; 44112703Smckusick ch = tmp; 44212703Smckusick } 44312703Smckusick *cp++ = ch; 44412703Smckusick *cp = '\0'; 44512703Smckusick return (rawname); 44612660Smckusick } 447