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*24782Sserge static char sccsid[] = "@(#)quotacheck.c 5.5 (Berkeley) 09/16/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) 138*24782Sserge fprintf(stderr, "%s not found in %s\n", 139*24782Sserge 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; 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) 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 } 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 } 25324758Sserge 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); 27324758Sserge if (fup == 0) 27424758Sserge 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) { 28224758Sserge if (pflag) 28324758Sserge printf("%s: ", rawdisk); 28412802Smckusick if (fup->fu_name[0] != '\0') 28524758Sserge printf("%-8s fixed:", fup->fu_name); 28612802Smckusick else 28724758Sserge printf("#%-7d fixed:", uid); 28824758Sserge if (dqbuf.dqb_curinodes != fup->fu_usage.du_curinodes) 28924758Sserge fprintf(stdout, " inodes %d -> %d", 29024758Sserge dqbuf.dqb_curinodes, fup->fu_usage.du_curinodes); 29124758Sserge if (dqbuf.dqb_curblocks != fup->fu_usage.du_curblocks) 29224758Sserge fprintf(stdout, " blocks %d -> %d", 29324758Sserge dqbuf.dqb_curblocks, fup->fu_usage.du_curblocks); 29424758Sserge 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; 32024758Sserge 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) { 36324758Sserge 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, '/'); 414*24782Sserge if (cp == NULL) 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