1*12703Smckusick #ifndef lint 2*12703Smckusick static char sccsid[] = "@(#)quotacheck.c 4.2 (Berkeley, Melbourne) 05/24/83"; 312660Smckusick #endif 412660Smckusick 512660Smckusick /* 612660Smckusick * Fix up / report on disc quotas & usage 712660Smckusick */ 812660Smckusick #include <stdio.h> 912660Smckusick #include <ctype.h> 1012660Smckusick #include <signal.h> 1112660Smckusick #include <pwd.h> 1212660Smckusick #include <sys/param.h> 1312660Smckusick #include <sys/inode.h> 1412660Smckusick #include <sys/fs.h> 1512660Smckusick #define QUOTA 1612660Smckusick #include <sys/quota.h> 1712660Smckusick #include <sys/stat.h> 18*12703Smckusick #include <fstab.h> 1912660Smckusick 2012660Smckusick union { 2112660Smckusick struct fs sblk; 22*12703Smckusick char dummy[MAXBSIZE]; 2312660Smckusick } un; 2412660Smckusick #define sblock un.sblk 25*12703Smckusick 26*12703Smckusick #define ITABSZ 256 2712660Smckusick struct dinode itab[ITABSZ]; 2812660Smckusick struct dinode *dp; 2912660Smckusick long blocks; 3012660Smckusick dev_t dev; 3112660Smckusick 32*12703Smckusick struct fileusage { 33*12703Smckusick struct dqusage fu_usage; 34*12703Smckusick u_short fu_uid; 35*12703Smckusick struct fileusage *fu_next; 36*12703Smckusick }; 37*12703Smckusick #define FUHASH 997 38*12703Smckusick struct fileusage *fuhead[FUHASH]; 39*12703Smckusick struct fileusage *lookup(); 40*12703Smckusick struct fileusage *adduid(); 41*12703Smckusick int highuid; 4212660Smckusick 43*12703Smckusick int fi; 44*12703Smckusick ino_t ino; 45*12703Smckusick long done; 4612660Smckusick struct passwd *getpwent(); 4712660Smckusick struct dinode *ginode(); 48*12703Smckusick char *malloc(), *makerawname(); 4912660Smckusick 50*12703Smckusick int vflag; /* verbose */ 51*12703Smckusick int aflag; /* all file systems */ 52*12703Smckusick 53*12703Smckusick char *qfname = "quotas"; 54*12703Smckusick char quotafile[MAXPATHLEN + 1]; 55*12703Smckusick 5612660Smckusick main(argc, argv) 57*12703Smckusick int argc; 5812660Smckusick char **argv; 5912660Smckusick { 60*12703Smckusick register struct fstab *fs; 61*12703Smckusick int i, errs = 0; 6212660Smckusick 63*12703Smckusick again: 64*12703Smckusick argc--, argv++; 65*12703Smckusick if (argc > 0 && strcmp(*argv, "-v") == 0) { 66*12703Smckusick vflag++; 67*12703Smckusick goto again; 6812660Smckusick } 69*12703Smckusick if (argc > 0 && strcmp(*argv, "-a") == 0) { 70*12703Smckusick aflag++; 71*12703Smckusick goto again; 72*12703Smckusick } 73*12703Smckusick if (argc <= 0 && !aflag) { 74*12703Smckusick fprintf(stderr, "Usage:\n\t%s\n\t%s\n", 75*12703Smckusick "quotacheck [-v] -a", 76*12703Smckusick "quotacheck [-v] filesys ..."); 7712660Smckusick exit(1); 7812660Smckusick } 79*12703Smckusick setfsent(); 80*12703Smckusick while ((fs = getfsent()) != NULL) { 81*12703Smckusick if (aflag && 82*12703Smckusick (fs->fs_type == 0 || strcmp(fs->fs_type, "rq") != 0)) 83*12703Smckusick continue; 84*12703Smckusick if (!aflag && 85*12703Smckusick !(oneof(fs->fs_file, argv, argc) || 86*12703Smckusick oneof(fs->fs_spec, argv, argc))) 87*12703Smckusick continue; 88*12703Smckusick (void) sprintf(quotafile, "%s/%s", fs->fs_file, qfname); 89*12703Smckusick errs += chkquota(fs->fs_spec, quotafile); 9012660Smckusick } 91*12703Smckusick endfsent(); 92*12703Smckusick for (i = 0; i < argc; i++) 93*12703Smckusick if ((done & (1 << i)) == 0) 94*12703Smckusick fprintf(stderr, "%s not found in /etc/fstab\n", 95*12703Smckusick argv[i]); 96*12703Smckusick exit(errs); 97*12703Smckusick } 9812660Smckusick 99*12703Smckusick chkquota(fsdev, qffile) 100*12703Smckusick char *fsdev; 101*12703Smckusick char *qffile; 102*12703Smckusick { 103*12703Smckusick register struct fileusage *fup; 104*12703Smckusick dev_t quotadev; 105*12703Smckusick FILE *qf; 106*12703Smckusick u_short uid; 107*12703Smckusick int cg, i; 108*12703Smckusick char *rawdisk; 109*12703Smckusick struct stat statb; 110*12703Smckusick struct dqblk dqbuf; 11112660Smckusick 112*12703Smckusick rawdisk = makerawname(fsdev); 113*12703Smckusick if (vflag) 114*12703Smckusick fprintf(stdout, "*** Check quotas for %s\n", rawdisk); 115*12703Smckusick fi = open(rawdisk, 0); 116*12703Smckusick if (fi < 0) { 117*12703Smckusick perror(rawdisk); 118*12703Smckusick return (1); 11912660Smckusick } 120*12703Smckusick qf = fopen(qffile, "r+"); 121*12703Smckusick if (qf == NULL) { 122*12703Smckusick perror(qffile); 123*12703Smckusick return (1); 12412660Smckusick } 125*12703Smckusick if (fstat(fileno(qf), &statb) < 0) { 126*12703Smckusick perror(qffile); 127*12703Smckusick return (1); 128*12703Smckusick } 129*12703Smckusick quotadev = statb.st_dev; 130*12703Smckusick if (stat(fsdev, &statb) < 0) { 131*12703Smckusick perror(fsdev); 132*12703Smckusick return (1); 133*12703Smckusick } 134*12703Smckusick if (quotadev != statb.st_rdev) { 135*12703Smckusick fprintf(stderr, "%s dev (0x%x) mismatch %s dev (0x%x)\n", 136*12703Smckusick qffile, quotadev, fsdev, statb.st_rdev); 137*12703Smckusick return (1); 138*12703Smckusick } 139*12703Smckusick quota(Q_SYNC, 0, quotadev, 0); 14012660Smckusick sync(); 14112660Smckusick bread(SBLOCK, (char *)&sblock, SBSIZE); 14212660Smckusick ino = 0; 14312660Smckusick for (cg = 0; cg < sblock.fs_ncg; cg++) { 14412660Smckusick dp = NULL; 14512660Smckusick for (i = 0; i < sblock.fs_ipg; i++) 14612660Smckusick acct(ginode()); 14712660Smckusick } 148*12703Smckusick for (uid = 0; uid <= highuid; uid++) { 149*12703Smckusick fup = lookup(uid); 150*12703Smckusick if (fup == 0) 151*12703Smckusick continue; 152*12703Smckusick fseek(qf, uid * sizeof(struct dqblk), 0); 153*12703Smckusick i = fread(&dqbuf, sizeof(struct dqblk), 1, qf); 154*12703Smckusick if (i == 0) 155*12703Smckusick bzero(&dqbuf, sizeof(struct dqblk)); 156*12703Smckusick if (dqbuf.dqb_curinodes == fup->fu_usage.du_curinodes && 157*12703Smckusick dqbuf.dqb_curblocks == fup->fu_usage.du_curblocks) 158*12703Smckusick continue; 159*12703Smckusick if (vflag) { 160*12703Smckusick fprintf(stdout, "uid %d fixed:", uid); 161*12703Smckusick fprintf(stdout, " inodes (old %d, new %d)", 162*12703Smckusick dqbuf.dqb_curinodes, fup->fu_usage.du_curinodes); 163*12703Smckusick fprintf(stdout, " blocks (old %d, new %d)\n", 164*12703Smckusick dqbuf.dqb_curblocks, fup->fu_usage.du_curblocks); 16512660Smckusick } 166*12703Smckusick dqbuf.dqb_curinodes = fup->fu_usage.du_curinodes; 167*12703Smckusick dqbuf.dqb_curblocks = fup->fu_usage.du_curblocks; 168*12703Smckusick fseek(qf, uid * sizeof(struct dqblk), 0); 169*12703Smckusick fwrite(&dqbuf, sizeof(struct dqblk), 1, qf); 170*12703Smckusick quota(Q_SETDUSE, uid, quotadev, &fup->fu_usage); 17112660Smckusick } 172*12703Smckusick return (0); 17312660Smckusick } 17412660Smckusick 17512660Smckusick acct(ip) 17612660Smckusick register struct dinode *ip; 17712660Smckusick { 17812660Smckusick register n; 179*12703Smckusick register struct fileusage *fup; 18012660Smckusick 18112660Smckusick if (ip == NULL) 18212660Smckusick return; 18312660Smckusick if (ip->di_mode == 0) 18412660Smckusick return; 185*12703Smckusick fup = lookup(ip->di_uid); 186*12703Smckusick if (fup == 0) 187*12703Smckusick fup = adduid(ip->di_uid); 188*12703Smckusick fup->fu_usage.du_curinodes++; 18912660Smckusick if ((ip->di_mode & IFMT) == IFCHR || (ip->di_mode & IFMT) == IFBLK) 19012660Smckusick return; 191*12703Smckusick fup->fu_usage.du_curblocks += ip->di_blocks; 19212660Smckusick } 19312660Smckusick 194*12703Smckusick oneof(target, list, n) 195*12703Smckusick char *target, *list[]; 196*12703Smckusick register int n; 19712660Smckusick { 198*12703Smckusick register int i; 19912660Smckusick 200*12703Smckusick for (i = 0; i < n; i++) 201*12703Smckusick if (strcmp(target, list[i]) == 0) { 202*12703Smckusick done |= 1 << i; 203*12703Smckusick return (1); 204*12703Smckusick } 205*12703Smckusick return (0); 20612660Smckusick } 20712660Smckusick 20812660Smckusick struct dinode * 20912660Smckusick ginode() 21012660Smckusick { 21112660Smckusick register unsigned long iblk; 21212660Smckusick 21312660Smckusick if (dp == NULL || ++dp >= &itab[ITABSZ]) { 21412660Smckusick iblk = itod(&sblock, ino); 21512660Smckusick bread(fsbtodb(&sblock, iblk), (char *)itab, sizeof itab); 21612660Smckusick dp = &itab[ino % INOPB(&sblock)]; 21712660Smckusick } 21812660Smckusick if (ino++ < ROOTINO) 21912660Smckusick return(NULL); 22012660Smckusick return(dp); 22112660Smckusick } 22212660Smckusick 22312660Smckusick bread(bno, buf, cnt) 22412660Smckusick long unsigned bno; 22512660Smckusick char *buf; 22612660Smckusick { 22712660Smckusick 228*12703Smckusick lseek(fi, (long)dbtob(bno), 0); 22912660Smckusick if (read(fi, buf, cnt) != cnt) { 23012660Smckusick printf("read error %u\n", bno); 23112660Smckusick exit(1); 23212660Smckusick } 23312660Smckusick } 23412660Smckusick 235*12703Smckusick struct fileusage * 236*12703Smckusick lookup(uid) 237*12703Smckusick u_short uid; 23812660Smckusick { 239*12703Smckusick register struct fileusage *fup; 24012660Smckusick 241*12703Smckusick for (fup = fuhead[uid % FUHASH]; fup != 0; fup = fup->fu_next) 242*12703Smckusick if (fup->fu_uid == uid) 243*12703Smckusick return (fup); 244*12703Smckusick return ((struct fileusage *)0); 24512660Smckusick } 24612660Smckusick 247*12703Smckusick struct fileusage * 248*12703Smckusick adduid(uid) 249*12703Smckusick u_short uid; 25012660Smckusick { 251*12703Smckusick struct fileusage *fup, **fhp; 25212660Smckusick 253*12703Smckusick fup = lookup(uid); 254*12703Smckusick if (fup != 0) 255*12703Smckusick return (fup); 256*12703Smckusick fup = (struct fileusage *)calloc(1, sizeof(struct fileusage)); 257*12703Smckusick if (fup == 0) { 258*12703Smckusick fprintf(stderr, "out of memory for fileusage structures\n"); 259*12703Smckusick exit(1); 260*12703Smckusick } 261*12703Smckusick fhp = &fuhead[uid % FUHASH]; 262*12703Smckusick fup->fu_next = *fhp; 263*12703Smckusick *fhp = fup; 264*12703Smckusick fup->fu_uid = uid; 265*12703Smckusick if (uid > highuid) 266*12703Smckusick highuid = uid; 267*12703Smckusick return (fup); 26812660Smckusick } 26912660Smckusick 27012660Smckusick char * 271*12703Smckusick makerawname(name) 272*12703Smckusick char *name; 27312660Smckusick { 274*12703Smckusick register char *cp; 275*12703Smckusick char tmp, ch, *rindex(); 276*12703Smckusick static char rawname[MAXPATHLEN]; 27712660Smckusick 278*12703Smckusick strcpy(rawname, name); 279*12703Smckusick cp = rindex(rawname, '/') + 1; 280*12703Smckusick if (cp == (char *)1 || *cp == 'r') 281*12703Smckusick return (name); 282*12703Smckusick for (ch = 'r'; *cp != '\0'; ) { 283*12703Smckusick tmp = *cp; 284*12703Smckusick *cp++ = ch; 285*12703Smckusick ch = tmp; 286*12703Smckusick } 287*12703Smckusick *cp++ = ch; 288*12703Smckusick *cp = '\0'; 289*12703Smckusick return (rawname); 29012660Smckusick } 291