121517Smckusick /* 221517Smckusick * Copyright (c) 1980 Regents of the University of California. 334364Sbostic * All rights reserved. 434364Sbostic * 534364Sbostic * Redistribution and use in source and binary forms are permitted 6*34778Sbostic * provided that the above copyright notice and this paragraph are 7*34778Sbostic * duplicated in all such forms and that any documentation, 8*34778Sbostic * advertising materials, and other materials related to such 9*34778Sbostic * distribution and use acknowledge that the software was developed 10*34778Sbostic * by the University of California, Berkeley. The name of the 11*34778Sbostic * University may not be used to endorse or promote products derived 12*34778Sbostic * from this software without specific prior written permission. 13*34778Sbostic * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 14*34778Sbostic * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 15*34778Sbostic * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 1621517Smckusick */ 1721517Smckusick 1812703Smckusick #ifndef lint 1921517Smckusick char copyright[] = 2021517Smckusick "@(#) Copyright (c) 1980 Regents of the University of California.\n\ 2121517Smckusick All rights reserved.\n"; 2234364Sbostic #endif /* not lint */ 2312660Smckusick 2421517Smckusick #ifndef lint 25*34778Sbostic static char sccsid[] = "@(#)quotacheck.c 5.10 (Berkeley) 06/18/88"; 2634364Sbostic #endif /* not lint */ 2721517Smckusick 2812660Smckusick /* 2912660Smckusick * Fix up / report on disc quotas & usage 3012660Smckusick */ 3112660Smckusick #include <stdio.h> 3212660Smckusick #include <ctype.h> 3312660Smckusick #include <signal.h> 3421085Smckusick #include <errno.h> 3512660Smckusick #include <sys/param.h> 3612660Smckusick #include <sys/inode.h> 3712660Smckusick #include <sys/fs.h> 3812660Smckusick #include <sys/quota.h> 3912660Smckusick #include <sys/stat.h> 4024758Sserge #include <sys/wait.h> 4112703Smckusick #include <fstab.h> 4212802Smckusick #include <pwd.h> 4312660Smckusick 4412660Smckusick union { 4512660Smckusick struct fs sblk; 4612703Smckusick char dummy[MAXBSIZE]; 4712660Smckusick } un; 4812660Smckusick #define sblock un.sblk 4912703Smckusick 5012703Smckusick #define ITABSZ 256 5112660Smckusick struct dinode itab[ITABSZ]; 5212660Smckusick struct dinode *dp; 5312660Smckusick 5412802Smckusick #define LOGINNAMESIZE 8 5512703Smckusick struct fileusage { 5612802Smckusick struct fileusage *fu_next; 5712703Smckusick struct dqusage fu_usage; 5812703Smckusick u_short fu_uid; 5912802Smckusick char fu_name[LOGINNAMESIZE + 1]; 6012703Smckusick }; 6112703Smckusick #define FUHASH 997 6212703Smckusick struct fileusage *fuhead[FUHASH]; 6312703Smckusick struct fileusage *lookup(); 6412703Smckusick struct fileusage *adduid(); 6512703Smckusick int highuid; 6612660Smckusick 6712703Smckusick int fi; 6812703Smckusick ino_t ino; 6912703Smckusick long done; 7012660Smckusick struct passwd *getpwent(); 7112660Smckusick struct dinode *ginode(); 7212703Smckusick char *malloc(), *makerawname(); 7312660Smckusick 7412703Smckusick int vflag; /* verbose */ 7512703Smckusick int aflag; /* all file systems */ 7624758Sserge int pflag; /* fsck like parallel check */ 7712703Smckusick 7812703Smckusick char *qfname = "quotas"; 7912703Smckusick char quotafile[MAXPATHLEN + 1]; 8012802Smckusick struct dqblk zerodqbuf; 8124758Sserge struct fileusage zerofileusage; 8230558Smckusick long dev_bsize = 1; 8312703Smckusick 8412660Smckusick main(argc, argv) 8512703Smckusick int argc; 8612660Smckusick char **argv; 8712660Smckusick { 8812703Smckusick register struct fstab *fs; 8912802Smckusick register struct fileusage *fup; 9012802Smckusick register struct passwd *pw; 9112703Smckusick int i, errs = 0; 9212660Smckusick 9312703Smckusick again: 9412703Smckusick argc--, argv++; 9512703Smckusick if (argc > 0 && strcmp(*argv, "-v") == 0) { 9612703Smckusick vflag++; 9712703Smckusick goto again; 9812660Smckusick } 9912703Smckusick if (argc > 0 && strcmp(*argv, "-a") == 0) { 10012703Smckusick aflag++; 10112703Smckusick goto again; 10212703Smckusick } 10324758Sserge if (argc > 0 && strcmp(*argv, "-p") == 0) { 10424758Sserge pflag++; 10524758Sserge goto again; 10624758Sserge } 10712703Smckusick if (argc <= 0 && !aflag) { 10812703Smckusick fprintf(stderr, "Usage:\n\t%s\n\t%s\n", 10924758Sserge "quotacheck [-v] [-p] -a", 11024758Sserge "quotacheck [-v] [-p] filesys ..."); 11112660Smckusick exit(1); 11212660Smckusick } 11324661Sserge 11424661Sserge setpwent(); 11524661Sserge while ((pw = getpwent()) != 0) { 11624661Sserge fup = lookup(pw->pw_uid); 11724758Sserge if (fup == 0) { 11824661Sserge fup = adduid(pw->pw_uid); 11924758Sserge strncpy(fup->fu_name, pw->pw_name, 12024758Sserge sizeof(fup->fu_name)); 12124758Sserge } 12212802Smckusick } 12324661Sserge endpwent(); 12424661Sserge 12524758Sserge if (pflag) 12624758Sserge errs = preen(argc, argv); 12724758Sserge else { 12824758Sserge if (setfsent() == 0) { 12924758Sserge fprintf(stderr, "Can't open "); 13024758Sserge perror(FSTAB); 13124758Sserge exit(8); 13224758Sserge } 13324758Sserge while ((fs = getfsent()) != NULL) { 13424758Sserge if (aflag && 13524758Sserge (fs->fs_type == 0 || 13624758Sserge strcmp(fs->fs_type, FSTAB_RQ) != 0)) 13724758Sserge continue; 13824758Sserge if (!aflag && 13924758Sserge !(oneof(fs->fs_file, argv, argc) || 14024758Sserge oneof(fs->fs_spec, argv, argc))) 14124758Sserge continue; 14224758Sserge (void) sprintf(quotafile, "%s/%s", fs->fs_file, qfname); 14324758Sserge errs += chkquota(fs->fs_spec, fs->fs_file, quotafile); 14424758Sserge } 14524758Sserge endfsent(); 14612660Smckusick } 14724758Sserge 14812703Smckusick for (i = 0; i < argc; i++) 14912703Smckusick if ((done & (1 << i)) == 0) 15024782Sserge fprintf(stderr, "%s not found in %s\n", 15124782Sserge argv[i], FSTAB); 15212703Smckusick exit(errs); 15312703Smckusick } 15412660Smckusick 15524758Sserge preen(argc, argv) 15624758Sserge int argc; 15724758Sserge char **argv; 15824758Sserge { 15924758Sserge register struct fstab *fs; 16024758Sserge register int passno, anygtr; 16124758Sserge register int errs; 16224758Sserge union wait status; 16324758Sserge 16424758Sserge passno = 1; 16524758Sserge errs = 0; 16624758Sserge do { 16724758Sserge anygtr = 0; 16824758Sserge 16924758Sserge if (setfsent() == 0) { 17024758Sserge fprintf(stderr, "Can't open "); 17124758Sserge perror(FSTAB); 17224758Sserge exit(8); 17324758Sserge } 17424758Sserge 17524758Sserge while ((fs = getfsent()) != NULL) { 17624758Sserge if (fs->fs_passno > passno) 17724758Sserge anygtr = 1; 17824758Sserge 17924758Sserge if (aflag && 18024758Sserge (fs->fs_type == 0 || 18124758Sserge strcmp(fs->fs_type, FSTAB_RQ) != 0)) 18224758Sserge continue; 18324758Sserge 18424758Sserge if (!aflag && 18524758Sserge !(oneof(fs->fs_file, argv, argc) || 18624758Sserge oneof(fs->fs_spec, argv, argc))) 18724758Sserge continue; 18824758Sserge 18924758Sserge if (fs->fs_passno != passno) 19024758Sserge continue; 19124758Sserge 19224758Sserge switch (fork()) { 19324758Sserge case -1: 19424758Sserge perror("fork"); 19524758Sserge exit(8); 19624758Sserge break; 19724758Sserge 19824758Sserge case 0: 19932445Sbostic (void) sprintf(quotafile, "%s/%s", 20024758Sserge fs->fs_file, qfname); 20124758Sserge exit(chkquota(fs->fs_spec, 20224758Sserge fs->fs_file, quotafile)); 20324758Sserge } 20424758Sserge } 20524758Sserge 20624758Sserge while (wait(&status) != -1) 20724758Sserge errs += status.w_retcode; 20824758Sserge 20924758Sserge passno++; 21024758Sserge } while (anygtr); 21124758Sserge 21224758Sserge return (errs); 21324758Sserge } 21424758Sserge 21524661Sserge chkquota(fsdev, fsfile, qffile) 21612703Smckusick char *fsdev; 21724661Sserge char *fsfile; 21812703Smckusick char *qffile; 21912703Smckusick { 22012703Smckusick register struct fileusage *fup; 22112703Smckusick dev_t quotadev; 22225377Sserge register FILE *qfi, *qfo; 22312703Smckusick u_short uid; 22425377Sserge int cg, i, fdo; 22512703Smckusick char *rawdisk; 22612703Smckusick struct stat statb; 22712703Smckusick struct dqblk dqbuf; 22821085Smckusick static int warned = 0; 22921085Smckusick extern int errno; 23012660Smckusick 23112703Smckusick rawdisk = makerawname(fsdev); 23212703Smckusick if (vflag) 23324758Sserge fprintf(stdout, "*** Checking quotas for %s (%s)\n", rawdisk, fsfile); 23412703Smckusick fi = open(rawdisk, 0); 23512703Smckusick if (fi < 0) { 23612703Smckusick perror(rawdisk); 23712703Smckusick return (1); 23812660Smckusick } 23925377Sserge qfi = fopen(qffile, "r"); 24025377Sserge if (qfi == NULL) { 24112703Smckusick perror(qffile); 24224661Sserge close(fi); 24312703Smckusick return (1); 24412660Smckusick } 24525377Sserge if (fstat(fileno(qfi), &statb) < 0) { 24612703Smckusick perror(qffile); 24725377Sserge fclose(qfi); 24824661Sserge close(fi); 24912703Smckusick return (1); 25012703Smckusick } 25112703Smckusick quotadev = statb.st_dev; 25212703Smckusick if (stat(fsdev, &statb) < 0) { 25312703Smckusick perror(fsdev); 25425377Sserge fclose(qfi); 25524661Sserge close(fi); 25612703Smckusick return (1); 25712703Smckusick } 25812703Smckusick if (quotadev != statb.st_rdev) { 25912703Smckusick fprintf(stderr, "%s dev (0x%x) mismatch %s dev (0x%x)\n", 26012703Smckusick qffile, quotadev, fsdev, statb.st_rdev); 26125377Sserge fclose(qfi); 26224661Sserge close(fi); 26312703Smckusick return (1); 26412703Smckusick } 26525377Sserge /* 26625377Sserge * Must do fdopen(open(qffile, 1), "w") instead of fopen(qffile, "w") 26725377Sserge * because fopen(qffile, "w") would truncate the quota file. 26825377Sserge */ 26925377Sserge fdo = open(qffile, 1); 27025377Sserge if (fdo < 0 || (qfo = fdopen(fdo, "w")) == NULL) { 27125377Sserge perror(qffile); 27225377Sserge if (fdo >= 0) 27325377Sserge close(fdo); 27425377Sserge fclose(qfi); 27525377Sserge close(fi); 27625377Sserge return (1); 27725377Sserge } 27824758Sserge if (quota(Q_SYNC, 0, quotadev, (caddr_t)0) < 0 && 27921085Smckusick errno == EINVAL && !warned && vflag) { 28021085Smckusick warned++; 28121085Smckusick fprintf(stdout, 28221085Smckusick "*** Warning: Quotas are not compiled into this kernel\n"); 28321085Smckusick } 28412660Smckusick sync(); 28530558Smckusick bread(SBOFF, (char *)&sblock, SBSIZE); 28630558Smckusick dev_bsize = sblock.fs_fsize / fsbtodb(&sblock, 1); 28712660Smckusick ino = 0; 28812660Smckusick for (cg = 0; cg < sblock.fs_ncg; cg++) { 28912660Smckusick dp = NULL; 29012660Smckusick for (i = 0; i < sblock.fs_ipg; i++) 29112660Smckusick acct(ginode()); 29212660Smckusick } 29312703Smckusick for (uid = 0; uid <= highuid; uid++) { 29425377Sserge i = fread(&dqbuf, sizeof(struct dqblk), 1, qfi); 29512703Smckusick if (i == 0) 29612802Smckusick dqbuf = zerodqbuf; 29718415Smckusick fup = lookup(uid); 29824758Sserge if (fup == 0) 29924758Sserge fup = &zerofileusage; 30012703Smckusick if (dqbuf.dqb_curinodes == fup->fu_usage.du_curinodes && 30112802Smckusick dqbuf.dqb_curblocks == fup->fu_usage.du_curblocks) { 30212802Smckusick fup->fu_usage.du_curinodes = 0; 30312802Smckusick fup->fu_usage.du_curblocks = 0; 30425377Sserge fseek(qfo, (long)sizeof(struct dqblk), 1); 30512703Smckusick continue; 30612802Smckusick } 30712703Smckusick if (vflag) { 30824758Sserge if (pflag) 30924758Sserge printf("%s: ", rawdisk); 31012802Smckusick if (fup->fu_name[0] != '\0') 31124758Sserge printf("%-8s fixed:", fup->fu_name); 31212802Smckusick else 31324758Sserge printf("#%-7d fixed:", uid); 31424758Sserge if (dqbuf.dqb_curinodes != fup->fu_usage.du_curinodes) 31525377Sserge fprintf(stdout, "\tinodes %d -> %d", 31624758Sserge dqbuf.dqb_curinodes, fup->fu_usage.du_curinodes); 31724758Sserge if (dqbuf.dqb_curblocks != fup->fu_usage.du_curblocks) 31825377Sserge fprintf(stdout, "\tblocks %d -> %d", 31924758Sserge dqbuf.dqb_curblocks, fup->fu_usage.du_curblocks); 32024758Sserge fprintf(stdout, "\n"); 32112660Smckusick } 32212703Smckusick dqbuf.dqb_curinodes = fup->fu_usage.du_curinodes; 32312703Smckusick dqbuf.dqb_curblocks = fup->fu_usage.du_curblocks; 32425377Sserge fwrite(&dqbuf, sizeof(struct dqblk), 1, qfo); 32512703Smckusick quota(Q_SETDUSE, uid, quotadev, &fup->fu_usage); 32613255Smckusick fup->fu_usage.du_curinodes = 0; 32713255Smckusick fup->fu_usage.du_curblocks = 0; 32812660Smckusick } 32925377Sserge fflush(qfo); 33025377Sserge ftruncate(fileno(qfo), (off_t)((highuid + 1) * sizeof(struct dqblk))); 33125377Sserge fclose(qfi); 33225377Sserge fclose(qfo); 33324661Sserge close(fi); 33412703Smckusick return (0); 33512660Smckusick } 33612660Smckusick 33712660Smckusick acct(ip) 33812660Smckusick register struct dinode *ip; 33912660Smckusick { 34012703Smckusick register struct fileusage *fup; 34112660Smckusick 34212660Smckusick if (ip == NULL) 34312660Smckusick return; 34412660Smckusick if (ip->di_mode == 0) 34512660Smckusick return; 34624758Sserge fup = adduid(ip->di_uid); 34712703Smckusick fup->fu_usage.du_curinodes++; 34812660Smckusick if ((ip->di_mode & IFMT) == IFCHR || (ip->di_mode & IFMT) == IFBLK) 34912660Smckusick return; 35012703Smckusick fup->fu_usage.du_curblocks += ip->di_blocks; 35112660Smckusick } 35212660Smckusick 35312703Smckusick oneof(target, list, n) 35412703Smckusick char *target, *list[]; 35512703Smckusick register int n; 35612660Smckusick { 35712703Smckusick register int i; 35812660Smckusick 35912703Smckusick for (i = 0; i < n; i++) 36012703Smckusick if (strcmp(target, list[i]) == 0) { 36112703Smckusick done |= 1 << i; 36212703Smckusick return (1); 36312703Smckusick } 36412703Smckusick return (0); 36512660Smckusick } 36612660Smckusick 36712660Smckusick struct dinode * 36812660Smckusick ginode() 36912660Smckusick { 37012660Smckusick register unsigned long iblk; 37112660Smckusick 37212660Smckusick if (dp == NULL || ++dp >= &itab[ITABSZ]) { 37312660Smckusick iblk = itod(&sblock, ino); 37412660Smckusick bread(fsbtodb(&sblock, iblk), (char *)itab, sizeof itab); 37512660Smckusick dp = &itab[ino % INOPB(&sblock)]; 37612660Smckusick } 37712660Smckusick if (ino++ < ROOTINO) 37812660Smckusick return(NULL); 37912660Smckusick return(dp); 38012660Smckusick } 38112660Smckusick 38212660Smckusick bread(bno, buf, cnt) 38312660Smckusick long unsigned bno; 38412660Smckusick char *buf; 38512660Smckusick { 38612660Smckusick 38730558Smckusick if (lseek(fi, bno * dev_bsize, 0) < 0) { 38825377Sserge perror("lseek"); 38925377Sserge exit(1); 39025377Sserge } 39125377Sserge 39212660Smckusick if (read(fi, buf, cnt) != cnt) { 39324758Sserge perror("read"); 39412660Smckusick exit(1); 39512660Smckusick } 39612660Smckusick } 39712660Smckusick 39812703Smckusick struct fileusage * 39912703Smckusick lookup(uid) 40012703Smckusick u_short uid; 40112660Smckusick { 40212703Smckusick register struct fileusage *fup; 40312660Smckusick 40412703Smckusick for (fup = fuhead[uid % FUHASH]; fup != 0; fup = fup->fu_next) 40512703Smckusick if (fup->fu_uid == uid) 40612703Smckusick return (fup); 40712703Smckusick return ((struct fileusage *)0); 40812660Smckusick } 40912660Smckusick 41012703Smckusick struct fileusage * 41112703Smckusick adduid(uid) 41212703Smckusick u_short uid; 41312660Smckusick { 41412703Smckusick struct fileusage *fup, **fhp; 41524661Sserge extern char *calloc(); 41612660Smckusick 41712703Smckusick fup = lookup(uid); 41812703Smckusick if (fup != 0) 41912703Smckusick return (fup); 42012703Smckusick fup = (struct fileusage *)calloc(1, sizeof(struct fileusage)); 42112703Smckusick if (fup == 0) { 42212703Smckusick fprintf(stderr, "out of memory for fileusage structures\n"); 42312703Smckusick exit(1); 42412703Smckusick } 42512703Smckusick fhp = &fuhead[uid % FUHASH]; 42612703Smckusick fup->fu_next = *fhp; 42712703Smckusick *fhp = fup; 42812703Smckusick fup->fu_uid = uid; 42912703Smckusick if (uid > highuid) 43012703Smckusick highuid = uid; 43112703Smckusick return (fup); 43212660Smckusick } 43312660Smckusick 43412660Smckusick char * 43512703Smckusick makerawname(name) 43612703Smckusick char *name; 43712660Smckusick { 43812703Smckusick register char *cp; 43912703Smckusick char tmp, ch, *rindex(); 44012703Smckusick static char rawname[MAXPATHLEN]; 44112660Smckusick 44212703Smckusick strcpy(rawname, name); 44324661Sserge cp = rindex(rawname, '/'); 44424782Sserge if (cp == NULL) 44512703Smckusick return (name); 44624661Sserge else 44724661Sserge cp++; 44812703Smckusick for (ch = 'r'; *cp != '\0'; ) { 44912703Smckusick tmp = *cp; 45012703Smckusick *cp++ = ch; 45112703Smckusick ch = tmp; 45212703Smckusick } 45312703Smckusick *cp++ = ch; 45412703Smckusick *cp = '\0'; 45512703Smckusick return (rawname); 45612660Smckusick } 457