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*24661Sserge static char sccsid[] = "@(#)quotacheck.c 5.3 (Berkeley) 09/09/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> 2912703Smckusick #include <fstab.h> 3012802Smckusick #include <pwd.h> 3112660Smckusick 3212660Smckusick union { 3312660Smckusick struct fs sblk; 3412703Smckusick char dummy[MAXBSIZE]; 3512660Smckusick } un; 3612660Smckusick #define sblock un.sblk 3712703Smckusick 3812703Smckusick #define ITABSZ 256 3912660Smckusick struct dinode itab[ITABSZ]; 4012660Smckusick struct dinode *dp; 4112660Smckusick long blocks; 4212660Smckusick dev_t dev; 4312660Smckusick 4412802Smckusick #define LOGINNAMESIZE 8 4512703Smckusick struct fileusage { 4612802Smckusick struct fileusage *fu_next; 4712703Smckusick struct dqusage fu_usage; 4812703Smckusick u_short fu_uid; 4912802Smckusick char fu_name[LOGINNAMESIZE + 1]; 5012703Smckusick }; 5112703Smckusick #define FUHASH 997 5212703Smckusick struct fileusage *fuhead[FUHASH]; 5312703Smckusick struct fileusage *lookup(); 5412703Smckusick struct fileusage *adduid(); 5512703Smckusick int highuid; 5612660Smckusick 5712703Smckusick int fi; 5812703Smckusick ino_t ino; 5912703Smckusick long done; 6012660Smckusick struct passwd *getpwent(); 6112660Smckusick struct dinode *ginode(); 6212703Smckusick char *malloc(), *makerawname(); 6312660Smckusick 6412703Smckusick int vflag; /* verbose */ 6512703Smckusick int aflag; /* all file systems */ 6612703Smckusick 6712703Smckusick char *qfname = "quotas"; 6812703Smckusick char quotafile[MAXPATHLEN + 1]; 6912802Smckusick struct dqblk zerodqbuf; 7012703Smckusick 7112660Smckusick main(argc, argv) 7212703Smckusick int argc; 7312660Smckusick char **argv; 7412660Smckusick { 7512703Smckusick register struct fstab *fs; 7612802Smckusick register struct fileusage *fup; 7712802Smckusick register struct passwd *pw; 7812703Smckusick int i, errs = 0; 7912660Smckusick 8012703Smckusick again: 8112703Smckusick argc--, argv++; 8212703Smckusick if (argc > 0 && strcmp(*argv, "-v") == 0) { 8312703Smckusick vflag++; 8412703Smckusick goto again; 8512660Smckusick } 8612703Smckusick if (argc > 0 && strcmp(*argv, "-a") == 0) { 8712703Smckusick aflag++; 8812703Smckusick goto again; 8912703Smckusick } 9012703Smckusick if (argc <= 0 && !aflag) { 9112703Smckusick fprintf(stderr, "Usage:\n\t%s\n\t%s\n", 9212703Smckusick "quotacheck [-v] -a", 9312703Smckusick "quotacheck [-v] filesys ..."); 9412660Smckusick exit(1); 9512660Smckusick } 96*24661Sserge 97*24661Sserge setpwent(); 98*24661Sserge while ((pw = getpwent()) != 0) { 99*24661Sserge fup = lookup(pw->pw_uid); 100*24661Sserge if (fup == 0) 101*24661Sserge fup = adduid(pw->pw_uid); 102*24661Sserge strncpy(fup->fu_name, pw->pw_name, 103*24661Sserge sizeof(fup->fu_name)); 10412802Smckusick } 105*24661Sserge endpwent(); 106*24661Sserge 10712703Smckusick setfsent(); 10812703Smckusick while ((fs = getfsent()) != NULL) { 10912703Smckusick if (aflag && 11012703Smckusick (fs->fs_type == 0 || strcmp(fs->fs_type, "rq") != 0)) 11112703Smckusick continue; 11212703Smckusick if (!aflag && 11312703Smckusick !(oneof(fs->fs_file, argv, argc) || 11412703Smckusick oneof(fs->fs_spec, argv, argc))) 11512703Smckusick continue; 11612703Smckusick (void) sprintf(quotafile, "%s/%s", fs->fs_file, qfname); 117*24661Sserge errs += chkquota(fs->fs_spec, fs->fs_file, quotafile); 11812660Smckusick } 11912703Smckusick endfsent(); 12012703Smckusick for (i = 0; i < argc; i++) 12112703Smckusick if ((done & (1 << i)) == 0) 12212703Smckusick fprintf(stderr, "%s not found in /etc/fstab\n", 12312703Smckusick argv[i]); 12412703Smckusick exit(errs); 12512703Smckusick } 12612660Smckusick 127*24661Sserge chkquota(fsdev, fsfile, qffile) 12812703Smckusick char *fsdev; 129*24661Sserge char *fsfile; 13012703Smckusick char *qffile; 13112703Smckusick { 13212703Smckusick register struct fileusage *fup; 13312703Smckusick dev_t quotadev; 13412703Smckusick FILE *qf; 13512703Smckusick u_short uid; 13612703Smckusick int cg, i; 13712703Smckusick char *rawdisk; 13812703Smckusick struct stat statb; 13912703Smckusick struct dqblk dqbuf; 14021085Smckusick static int warned = 0; 14121085Smckusick extern int errno; 14212660Smckusick 14312703Smckusick rawdisk = makerawname(fsdev); 14412703Smckusick if (vflag) 145*24661Sserge fprintf(stdout, "*** Check quotas for %s (%s)\n", rawdisk, fsfile); 14612703Smckusick fi = open(rawdisk, 0); 14712703Smckusick if (fi < 0) { 14812703Smckusick perror(rawdisk); 14912703Smckusick return (1); 15012660Smckusick } 15112703Smckusick qf = fopen(qffile, "r+"); 15212703Smckusick if (qf == NULL) { 15312703Smckusick perror(qffile); 154*24661Sserge close(fi); 15512703Smckusick return (1); 15612660Smckusick } 15712703Smckusick if (fstat(fileno(qf), &statb) < 0) { 15812703Smckusick perror(qffile); 159*24661Sserge fclose(qf); 160*24661Sserge close(fi); 16112703Smckusick return (1); 16212703Smckusick } 16312703Smckusick quotadev = statb.st_dev; 16412703Smckusick if (stat(fsdev, &statb) < 0) { 16512703Smckusick perror(fsdev); 166*24661Sserge fclose(qf); 167*24661Sserge close(fi); 16812703Smckusick return (1); 16912703Smckusick } 17012703Smckusick if (quotadev != statb.st_rdev) { 17112703Smckusick fprintf(stderr, "%s dev (0x%x) mismatch %s dev (0x%x)\n", 17212703Smckusick qffile, quotadev, fsdev, statb.st_rdev); 173*24661Sserge fclose(qf); 174*24661Sserge close(fi); 17512703Smckusick return (1); 17612703Smckusick } 17721085Smckusick if (quota(Q_SYNC, 0, quotadev, 0) < 0 && 17821085Smckusick errno == EINVAL && !warned && vflag) { 17921085Smckusick warned++; 18021085Smckusick fprintf(stdout, 18121085Smckusick "*** Warning: Quotas are not compiled into this kernel\n"); 18221085Smckusick } 18312660Smckusick sync(); 18412660Smckusick bread(SBLOCK, (char *)&sblock, SBSIZE); 18512660Smckusick ino = 0; 18612660Smckusick for (cg = 0; cg < sblock.fs_ncg; cg++) { 18712660Smckusick dp = NULL; 18812660Smckusick for (i = 0; i < sblock.fs_ipg; i++) 18912660Smckusick acct(ginode()); 19012660Smckusick } 19112703Smckusick for (uid = 0; uid <= highuid; uid++) { 192*24661Sserge fseek(qf, (long)uid * sizeof(struct dqblk), 0); 19312703Smckusick i = fread(&dqbuf, sizeof(struct dqblk), 1, qf); 19412703Smckusick if (i == 0) 19512802Smckusick dqbuf = zerodqbuf; 19618415Smckusick fup = lookup(uid); 19718415Smckusick if (fup == 0) { 19823519Smckusick if ((dqbuf.dqb_curinodes != 0 || 19923519Smckusick dqbuf.dqb_curblocks != 0) && 20023519Smckusick !feof(qf)) { 20123519Smckusick dqbuf.dqb_curinodes = 0; 20223519Smckusick dqbuf.dqb_curblocks = 0; 203*24661Sserge fseek(qf, (long)uid * sizeof(struct dqblk), 0); 20423519Smckusick fwrite(&dqbuf, sizeof(struct dqblk), 1, qf); 20518415Smckusick } 20618415Smckusick continue; 20718415Smckusick } 20812703Smckusick if (dqbuf.dqb_curinodes == fup->fu_usage.du_curinodes && 20912802Smckusick dqbuf.dqb_curblocks == fup->fu_usage.du_curblocks) { 21012802Smckusick fup->fu_usage.du_curinodes = 0; 21112802Smckusick fup->fu_usage.du_curblocks = 0; 21212703Smckusick continue; 21312802Smckusick } 21412703Smckusick if (vflag) { 21512802Smckusick if (fup->fu_name[0] != '\0') 21612802Smckusick printf("%-10s fixed:", fup->fu_name); 21712802Smckusick else 21812802Smckusick printf("#%-9d fixed:", uid); 21912703Smckusick fprintf(stdout, " inodes (old %d, new %d)", 22012703Smckusick dqbuf.dqb_curinodes, fup->fu_usage.du_curinodes); 22112703Smckusick fprintf(stdout, " blocks (old %d, new %d)\n", 22212703Smckusick dqbuf.dqb_curblocks, fup->fu_usage.du_curblocks); 22312660Smckusick } 22412703Smckusick dqbuf.dqb_curinodes = fup->fu_usage.du_curinodes; 22512703Smckusick dqbuf.dqb_curblocks = fup->fu_usage.du_curblocks; 226*24661Sserge fseek(qf, (long)uid * sizeof(struct dqblk), 0); 22712703Smckusick fwrite(&dqbuf, sizeof(struct dqblk), 1, qf); 22812703Smckusick quota(Q_SETDUSE, uid, quotadev, &fup->fu_usage); 22913255Smckusick fup->fu_usage.du_curinodes = 0; 23013255Smckusick fup->fu_usage.du_curblocks = 0; 23112660Smckusick } 232*24661Sserge fflush(qf); 23318415Smckusick ftruncate(fileno(qf), (highuid + 1) * sizeof(struct dqblk)); 234*24661Sserge fclose(qf); 235*24661Sserge close(fi); 23612703Smckusick return (0); 23712660Smckusick } 23812660Smckusick 23912660Smckusick acct(ip) 24012660Smckusick register struct dinode *ip; 24112660Smckusick { 24212660Smckusick register n; 24312703Smckusick register struct fileusage *fup; 24412660Smckusick 24512660Smckusick if (ip == NULL) 24612660Smckusick return; 24712660Smckusick if (ip->di_mode == 0) 24812660Smckusick return; 24912703Smckusick fup = lookup(ip->di_uid); 25012703Smckusick if (fup == 0) 25112703Smckusick fup = adduid(ip->di_uid); 25212703Smckusick fup->fu_usage.du_curinodes++; 25312660Smckusick if ((ip->di_mode & IFMT) == IFCHR || (ip->di_mode & IFMT) == IFBLK) 25412660Smckusick return; 25512703Smckusick fup->fu_usage.du_curblocks += ip->di_blocks; 25612660Smckusick } 25712660Smckusick 25812703Smckusick oneof(target, list, n) 25912703Smckusick char *target, *list[]; 26012703Smckusick register int n; 26112660Smckusick { 26212703Smckusick register int i; 26312660Smckusick 26412703Smckusick for (i = 0; i < n; i++) 26512703Smckusick if (strcmp(target, list[i]) == 0) { 26612703Smckusick done |= 1 << i; 26712703Smckusick return (1); 26812703Smckusick } 26912703Smckusick return (0); 27012660Smckusick } 27112660Smckusick 27212660Smckusick struct dinode * 27312660Smckusick ginode() 27412660Smckusick { 27512660Smckusick register unsigned long iblk; 27612660Smckusick 27712660Smckusick if (dp == NULL || ++dp >= &itab[ITABSZ]) { 27812660Smckusick iblk = itod(&sblock, ino); 27912660Smckusick bread(fsbtodb(&sblock, iblk), (char *)itab, sizeof itab); 28012660Smckusick dp = &itab[ino % INOPB(&sblock)]; 28112660Smckusick } 28212660Smckusick if (ino++ < ROOTINO) 28312660Smckusick return(NULL); 28412660Smckusick return(dp); 28512660Smckusick } 28612660Smckusick 28712660Smckusick bread(bno, buf, cnt) 28812660Smckusick long unsigned bno; 28912660Smckusick char *buf; 29012660Smckusick { 29112660Smckusick 29212703Smckusick lseek(fi, (long)dbtob(bno), 0); 29312660Smckusick if (read(fi, buf, cnt) != cnt) { 29412660Smckusick printf("read error %u\n", bno); 29512660Smckusick exit(1); 29612660Smckusick } 29712660Smckusick } 29812660Smckusick 29912703Smckusick struct fileusage * 30012703Smckusick lookup(uid) 30112703Smckusick u_short uid; 30212660Smckusick { 30312703Smckusick register struct fileusage *fup; 30412660Smckusick 30512703Smckusick for (fup = fuhead[uid % FUHASH]; fup != 0; fup = fup->fu_next) 30612703Smckusick if (fup->fu_uid == uid) 30712703Smckusick return (fup); 30812703Smckusick return ((struct fileusage *)0); 30912660Smckusick } 31012660Smckusick 31112703Smckusick struct fileusage * 31212703Smckusick adduid(uid) 31312703Smckusick u_short uid; 31412660Smckusick { 31512703Smckusick struct fileusage *fup, **fhp; 316*24661Sserge extern char *calloc(); 31712660Smckusick 31812703Smckusick fup = lookup(uid); 31912703Smckusick if (fup != 0) 32012703Smckusick return (fup); 32112703Smckusick fup = (struct fileusage *)calloc(1, sizeof(struct fileusage)); 32212703Smckusick if (fup == 0) { 32312703Smckusick fprintf(stderr, "out of memory for fileusage structures\n"); 32412703Smckusick exit(1); 32512703Smckusick } 32612703Smckusick fhp = &fuhead[uid % FUHASH]; 32712703Smckusick fup->fu_next = *fhp; 32812703Smckusick *fhp = fup; 32912703Smckusick fup->fu_uid = uid; 33012703Smckusick if (uid > highuid) 33112703Smckusick highuid = uid; 33212703Smckusick return (fup); 33312660Smckusick } 33412660Smckusick 33512660Smckusick char * 33612703Smckusick makerawname(name) 33712703Smckusick char *name; 33812660Smckusick { 33912703Smckusick register char *cp; 34012703Smckusick char tmp, ch, *rindex(); 34112703Smckusick static char rawname[MAXPATHLEN]; 34212660Smckusick 34312703Smckusick strcpy(rawname, name); 344*24661Sserge cp = rindex(rawname, '/'); 345*24661Sserge if (cp == NULL || cp[1] == 'r') 34612703Smckusick return (name); 347*24661Sserge else 348*24661Sserge cp++; 34912703Smckusick for (ch = 'r'; *cp != '\0'; ) { 35012703Smckusick tmp = *cp; 35112703Smckusick *cp++ = ch; 35212703Smckusick ch = tmp; 35312703Smckusick } 35412703Smckusick *cp++ = ch; 35512703Smckusick *cp = '\0'; 35612703Smckusick return (rawname); 35712660Smckusick } 358