quotacheck.c revision 14280
1218887Sdim/* 2218887Sdim * Copyright (c) 1980, 1990, 1993 3218887Sdim * The Regents of the University of California. All rights reserved. 4218887Sdim * 5218887Sdim * This code is derived from software contributed to Berkeley by 6218887Sdim * Robert Elz at The University of Melbourne. 7218887Sdim * 8218887Sdim * Redistribution and use in source and binary forms, with or without 9218887Sdim * modification, are permitted provided that the following conditions 10218887Sdim * are met: 11218887Sdim * 1. Redistributions of source code must retain the above copyright 12218887Sdim * notice, this list of conditions and the following disclaimer. 13218887Sdim * 2. Redistributions in binary form must reproduce the above copyright 14218887Sdim * notice, this list of conditions and the following disclaimer in the 15280031Sdim * documentation and/or other materials provided with the distribution. 16280031Sdim * 3. All advertising materials mentioning features or use of this software 17218887Sdim * must display the following acknowledgement: 18218887Sdim * This product includes software developed by the University of 19218887Sdim * California, Berkeley and its contributors. 20218887Sdim * 4. Neither the name of the University nor the names of its contributors 21226633Sdim * may be used to endorse or promote products derived from this software 22226633Sdim * without specific prior written permission. 23249423Sdim * 24249423Sdim * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 25249423Sdim * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 26276479Sdim * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 27218887Sdim * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 28218887Sdim * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 29218887Sdim * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 30218887Sdim * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 31218887Sdim * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 32218887Sdim * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 33218887Sdim * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 34218887Sdim * SUCH DAMAGE. 35218887Sdim */ 36218887Sdim 37226633Sdim#ifndef lint 38218887Sdimstatic char copyright[] = 39218887Sdim"@(#) Copyright (c) 1980, 1990, 1993\n\ 40234353Sdim The Regents of the University of California. All rights reserved.\n"; 41234353Sdim#endif /* not lint */ 42218887Sdim 43234353Sdim#ifndef lint 44218887Sdimstatic char sccsid[] = "@(#)quotacheck.c 8.3 (Berkeley) 1/29/94"; 45226633Sdim#endif /* not lint */ 46218887Sdim 47226633Sdim/* 48226633Sdim * Fix up / report on disk quotas & usage 49251662Sdim */ 50251662Sdim#include <sys/param.h> 51251662Sdim#include <sys/queue.h> 52251662Sdim#include <sys/stat.h> 53218887Sdim 54218887Sdim#include <ufs/ufs/dinode.h> 55218887Sdim#include <ufs/ufs/quota.h> 56218887Sdim#include <ufs/ffs/fs.h> 57218887Sdim 58218887Sdim#include <fcntl.h> 59218887Sdim#include <fstab.h> 60218887Sdim#include <pwd.h> 61218887Sdim#include <grp.h> 62218887Sdim#include <errno.h> 63218887Sdim#include <unistd.h> 64234353Sdim#include <stdio.h> 65218887Sdim#include <stdlib.h> 66234353Sdim#include <string.h> 67218887Sdim 68243830Sdimchar *qfname = QUOTAFILENAME; 69218887Sdimchar *qfextension[] = INITQFNAMES; 70218887Sdimchar *quotagroup = QUOTAGROUP; 71234353Sdim 72234353Sdimunion { 73234353Sdim struct fs sblk; 74234353Sdim char dummy[MAXBSIZE]; 75234353Sdim} un; 76234353Sdim#define sblock un.sblk 77234353Sdimlong dev_bsize = 1; 78234353Sdimlong maxino; 79234353Sdim 80234353Sdimstruct quotaname { 81234353Sdim long flags; 82234353Sdim char grpqfname[MAXPATHLEN + 1]; 83234353Sdim char usrqfname[MAXPATHLEN + 1]; 84234353Sdim}; 85234353Sdim#define HASUSR 1 86234353Sdim#define HASGRP 2 87234353Sdim 88234353Sdimstruct fileusage { 89234353Sdim struct fileusage *fu_next; 90234353Sdim u_long fu_curinodes; 91234353Sdim u_long fu_curblocks; 92234353Sdim u_long fu_id; 93234353Sdim char fu_name[1]; 94239462Sdim /* actually bigger */ 95239462Sdim}; 96218887Sdim#define FUHASH 1024 /* must be power of two */ 97218887Sdimstruct fileusage *fuhead[MAXQUOTAS][FUHASH]; 98234353Sdim 99249423Sdimint aflag; /* all file systems */ 100234353Sdimint gflag; /* check group quotas */ 101218887Sdimint uflag; /* check user quotas */ 102234353Sdimint vflag; /* verbose */ 103234353Sdimint fi; /* open disk file descriptor */ 104218887Sdimu_long highid[MAXQUOTAS]; /* highest addid()'ed identifier per type */ 105276479Sdim 106218887Sdimstruct fileusage * 107218887Sdim addid __P((u_long, int, char *)); 108218887Sdimchar *blockcheck __P((char *)); 109218887Sdimvoid bread __P((daddr_t, char *, long)); 110218887Sdimint chkquota __P((char *, char *, struct quotaname *)); 111218887Sdimvoid err __P((const char *, ...)); 112218887Sdimvoid freeinodebuf __P((void)); 113218887Sdimstruct dinode * 114218887Sdim getnextinode __P((ino_t)); 115218887Sdimint getquotagid __P((void)); 116218887Sdimint hasquota __P((struct fstab *, int, char **)); 117226633Sdimstruct fileusage * 118218887Sdim lookup __P((u_long, int)); 119226633Sdimvoid *needchk __P((struct fstab *)); 120218887Sdimint oneof __P((char *, char*[], int)); 121218887Sdimvoid resetinodebuf __P((void)); 122218887Sdimint update __P((char *, char *, int)); 123234353Sdimvoid usage __P((void)); 124218887Sdim 125226633Sdimint 126218887Sdimmain(argc, argv) 127218887Sdim int argc; 128226633Sdim char *argv[]; 129218887Sdim{ 130218887Sdim register struct fstab *fs; 131226633Sdim register struct passwd *pw; 132218887Sdim register struct group *gr; 133226633Sdim struct quotaname *auxdata; 134218887Sdim int i, argnum, maxrun, errs; 135218887Sdim long done = 0; 136218887Sdim char ch, *name; 137218887Sdim 138276479Sdim errs = maxrun = 0; 139218887Sdim while ((ch = getopt(argc, argv, "aguvl:")) != EOF) { 140218887Sdim switch(ch) { 141218887Sdim case 'a': 142276479Sdim aflag++; 143218887Sdim break; 144276479Sdim case 'g': 145218887Sdim gflag++; 146218887Sdim break; 147226633Sdim case 'u': 148218887Sdim uflag++; 149218887Sdim break; 150218887Sdim case 'v': 151218887Sdim vflag++; 152234353Sdim break; 153234353Sdim case 'l': 154218887Sdim maxrun = atoi(optarg); 155226633Sdim break; 156218887Sdim default: 157218887Sdim usage(); 158234353Sdim } 159226633Sdim } 160218887Sdim argc -= optind; 161218887Sdim argv += optind; 162234353Sdim if ((argc == 0 && !aflag) || (argc > 0 && aflag)) 163234353Sdim usage(); 164226633Sdim if (!gflag && !uflag) { 165218887Sdim gflag++; 166234353Sdim uflag++; 167218887Sdim } 168218887Sdim if (gflag) { 169226633Sdim setgrent(); 170218887Sdim while ((gr = getgrent()) != NULL) 171226633Sdim (void) addid((u_long)gr->gr_gid, GRPQUOTA, gr->gr_name); 172218887Sdim endgrent(); 173276479Sdim } 174218887Sdim if (uflag) { 175276479Sdim setpwent(); 176218887Sdim while ((pw = getpwent()) != NULL) 177226633Sdim (void) addid((u_long)pw->pw_uid, USRQUOTA, pw->pw_name); 178234353Sdim endpwent(); 179234353Sdim } 180218887Sdim if (aflag) 181218887Sdim exit(checkfstab(1, maxrun, needchk, chkquota)); 182234353Sdim if (setfsent() == 0) 183218887Sdim err("%s: can't open", FSTAB); 184218887Sdim while ((fs = getfsent()) != NULL) { 185218887Sdim if (((argnum = oneof(fs->fs_file, argv, argc)) >= 0 || 186218887Sdim (argnum = oneof(fs->fs_spec, argv, argc)) >= 0) && 187218887Sdim (auxdata = needchk(fs)) && 188276479Sdim (name = blockcheck(fs->fs_spec))) { 189234353Sdim done |= 1 << argnum; 190218887Sdim errs += chkquota(name, fs->fs_file, auxdata); 191218887Sdim } 192218887Sdim } 193226633Sdim endfsent(); 194218887Sdim for (i = 0; i < argc; i++) 195218887Sdim if ((done & (1 << i)) == 0) 196218887Sdim fprintf(stderr, "%s not found in %s\n", 197218887Sdim argv[i], FSTAB); 198226633Sdim exit(errs); 199226633Sdim} 200218887Sdim 201218887Sdimvoid 202226633Sdimusage() 203218887Sdim{ 204218887Sdim (void)fprintf(stderr, "usage:\t%s\n\t%s\n", 205226633Sdim "quotacheck -a [-guv]", 206218887Sdim "quotacheck [-guv] filesys ..."); 207218887Sdim exit(1); 208218887Sdim} 209226633Sdim 210218887Sdimvoid * 211276479Sdimneedchk(fs) 212218887Sdim register struct fstab *fs; 213276479Sdim{ 214218887Sdim register struct quotaname *qnp; 215218887Sdim char *qfnp; 216226633Sdim 217218887Sdim if (strcmp(fs->fs_vfstype, "ufs") || 218218887Sdim strcmp(fs->fs_type, FSTAB_RW)) 219218887Sdim return (NULL); 220218887Sdim if ((qnp = malloc(sizeof(*qnp))) == NULL) 221218887Sdim err("%s", strerror(errno)); 222276479Sdim qnp->flags = 0; 223218887Sdim if (gflag && hasquota(fs, GRPQUOTA, &qfnp)) { 224218887Sdim strcpy(qnp->grpqfname, qfnp); 225218887Sdim qnp->flags |= HASGRP; 226218887Sdim } 227226633Sdim if (uflag && hasquota(fs, USRQUOTA, &qfnp)) { 228218887Sdim strcpy(qnp->usrqfname, qfnp); 229218887Sdim qnp->flags |= HASUSR; 230218887Sdim } 231218887Sdim if (qnp->flags) 232218887Sdim return (qnp); 233218887Sdim free(qnp); 234218887Sdim return (NULL); 235218887Sdim} 236218887Sdim 237218887Sdim/* 238218887Sdim * Scan the specified filesystem to check quota(s) present on it. 239218887Sdim */ 240218887Sdimint 241218887Sdimchkquota(fsname, mntpt, qnp) 242218887Sdim char *fsname, *mntpt; 243218887Sdim register struct quotaname *qnp; 244276479Sdim{ 245218887Sdim register struct fileusage *fup; 246276479Sdim register struct dinode *dp; 247218887Sdim int cg, i, mode, errs = 0; 248218887Sdim ino_t ino; 249218887Sdim 250218887Sdim if ((fi = open(fsname, O_RDONLY, 0)) < 0) { 251218887Sdim perror(fsname); 252218887Sdim return (1); 253276479Sdim } 254218887Sdim if (vflag) { 255218887Sdim (void)printf("*** Checking "); 256218887Sdim if (qnp->flags & HASUSR) 257218887Sdim (void)printf("%s%s", qfextension[USRQUOTA], 258226633Sdim (qnp->flags & HASGRP) ? " and " : ""); 259218887Sdim if (qnp->flags & HASGRP) 260218887Sdim (void)printf("%s", qfextension[GRPQUOTA]); 261218887Sdim (void)printf(" quotas for %s (%s)\n", fsname, mntpt); 262218887Sdim } 263218887Sdim sync(); 264218887Sdim dev_bsize = 1; 265218887Sdim bread(SBOFF, (char *)&sblock, (long)SBSIZE); 266218887Sdim dev_bsize = sblock.fs_fsize / fsbtodb(&sblock, 1); 267218887Sdim maxino = sblock.fs_ncg * sblock.fs_ipg; 268218887Sdim resetinodebuf(); 269226633Sdim for (ino = 0, cg = 0; cg < sblock.fs_ncg; cg++) { 270218887Sdim for (i = 0; i < sblock.fs_ipg; i++, ino++) { 271218887Sdim if (ino < ROOTINO) 272226633Sdim continue; 273218887Sdim if ((dp = getnextinode(ino)) == NULL) 274226633Sdim continue; 275226633Sdim if ((mode = dp->di_mode & IFMT) == 0) 276218887Sdim continue; 277218887Sdim if (qnp->flags & HASGRP) { 278218887Sdim fup = addid((u_long)dp->di_gid, GRPQUOTA, 279226633Sdim (char *)0); 280218887Sdim fup->fu_curinodes++; 281226633Sdim if (mode == IFREG || mode == IFDIR || 282218887Sdim mode == IFLNK) 283276479Sdim fup->fu_curblocks += dp->di_blocks; 284218887Sdim } 285276479Sdim if (qnp->flags & HASUSR) { 286218887Sdim fup = addid((u_long)dp->di_uid, USRQUOTA, 287218887Sdim (char *)0); 288218887Sdim fup->fu_curinodes++; 289218887Sdim if (mode == IFREG || mode == IFDIR || 290218887Sdim mode == IFLNK) 291218887Sdim fup->fu_curblocks += dp->di_blocks; 292218887Sdim } 293218887Sdim } 294218887Sdim } 295218887Sdim freeinodebuf(); 296218887Sdim if (qnp->flags & HASUSR) 297218887Sdim errs += update(mntpt, qnp->usrqfname, USRQUOTA); 298276479Sdim if (qnp->flags & HASGRP) 299218887Sdim errs += update(mntpt, qnp->grpqfname, GRPQUOTA); 300218887Sdim close(fi); 301218887Sdim return (errs); 302218887Sdim} 303226633Sdim 304218887Sdim/* 305218887Sdim * Update a specified quota file. 306218887Sdim */ 307218887Sdimint 308234353Sdimupdate(fsname, quotafile, type) 309234353Sdim char *fsname, *quotafile; 310234353Sdim register int type; 311234353Sdim{ 312234353Sdim register struct fileusage *fup; 313234353Sdim register FILE *qfi, *qfo; 314234353Sdim register u_long id, lastid; 315234353Sdim register off_t offset; 316234353Sdim struct dqblk dqbuf; 317234353Sdim static int warned = 0; 318234353Sdim static struct dqblk zerodqbuf; 319234353Sdim static struct fileusage zerofileusage; 320276479Sdim 321234353Sdim if ((qfo = fopen(quotafile, "r+")) == NULL) { 322234353Sdim if (errno == ENOENT) 323234353Sdim qfo = fopen(quotafile, "w+"); 324276479Sdim if (qfo) { 325234353Sdim (void) fprintf(stderr, 326234353Sdim "quotacheck: creating quota file %s\n", quotafile); 327234353Sdim#define MODE (S_IRUSR|S_IWUSR|S_IRGRP) 328234353Sdim (void) fchown(fileno(qfo), getuid(), getquotagid()); 329234353Sdim (void) fchmod(fileno(qfo), MODE); 330234353Sdim } else { 331234353Sdim (void) fprintf(stderr, 332234353Sdim "quotacheck: %s: %s\n", quotafile, strerror(errno)); 333234353Sdim return (1); 334276479Sdim } 335234353Sdim } 336234353Sdim if ((qfi = fopen(quotafile, "r")) == NULL) { 337234353Sdim (void) fprintf(stderr, 338234353Sdim "quotacheck: %s: %s\n", quotafile, strerror(errno)); 339234353Sdim (void) fclose(qfo); 340234353Sdim return (1); 341234353Sdim } 342234353Sdim if (quotactl(fsname, QCMD(Q_SYNC, type), (u_long)0, (caddr_t)0) < 0 && 343234353Sdim errno == EOPNOTSUPP && !warned && vflag) { 344251662Sdim warned++; 345251662Sdim (void)printf("*** Warning: %s\n", 346218887Sdim "Quotas are not compiled into this kernel"); 347218887Sdim } 348218887Sdim for (lastid = highid[type], id = 0, offset = 0; id <= lastid; 349251662Sdim id++, offset += sizeof(struct dqblk)) { 350251662Sdim if (fread((char *)&dqbuf, sizeof(struct dqblk), 1, qfi) == 0) 351251662Sdim dqbuf = zerodqbuf; 352251662Sdim if ((fup = lookup(id, type)) == 0) 353218887Sdim fup = &zerofileusage; 354218887Sdim if (dqbuf.dqb_curinodes == fup->fu_curinodes && 355218887Sdim dqbuf.dqb_curblocks == fup->fu_curblocks) { 356276479Sdim fup->fu_curinodes = 0; 357218887Sdim fup->fu_curblocks = 0; 358218887Sdim continue; 359218887Sdim } 360251662Sdim if (vflag) { 361251662Sdim if (aflag) 362251662Sdim printf("%s: ", fsname); 363251662Sdim printf("%-8s fixed:", fup->fu_name); 364251662Sdim if (dqbuf.dqb_curinodes != fup->fu_curinodes) 365251662Sdim (void)printf("\tinodes %ld -> %ld", 366251662Sdim dqbuf.dqb_curinodes, fup->fu_curinodes); 367251662Sdim if (dqbuf.dqb_curblocks != fup->fu_curblocks) 368251662Sdim (void)printf("\tblocks %ld -> %ld", 369251662Sdim dqbuf.dqb_curblocks, fup->fu_curblocks); 370251662Sdim (void)printf("\n"); 371251662Sdim } 372251662Sdim /* 373251662Sdim * Reset time limit if have a soft limit and were 374251662Sdim * previously under it, but are now over it. 375251662Sdim */ 376251662Sdim if (dqbuf.dqb_bsoftlimit && 377276479Sdim dqbuf.dqb_curblocks < dqbuf.dqb_bsoftlimit && 378218887Sdim fup->fu_curblocks >= dqbuf.dqb_bsoftlimit) 379218887Sdim dqbuf.dqb_btime = 0; 380218887Sdim if (dqbuf.dqb_isoftlimit && 381218887Sdim dqbuf.dqb_curblocks < dqbuf.dqb_isoftlimit && 382218887Sdim fup->fu_curblocks >= dqbuf.dqb_isoftlimit) 383218887Sdim dqbuf.dqb_itime = 0; 384218887Sdim dqbuf.dqb_curinodes = fup->fu_curinodes; 385218887Sdim dqbuf.dqb_curblocks = fup->fu_curblocks; 386218887Sdim if (fseek(qfo, (long)offset, SEEK_SET) < 0) { 387218887Sdim (void) fprintf(stderr, 388218887Sdim "quotacheck: %s: seek failed: %s\n", 389218887Sdim quotafile, strerror(errno)); 390218887Sdim return(1); 391218887Sdim } 392276479Sdim fwrite((char *)&dqbuf, sizeof(struct dqblk), 1, qfo); 393251662Sdim (void) quotactl(fsname, QCMD(Q_SETUSE, type), id, 394218887Sdim (caddr_t)&dqbuf); 395218887Sdim fup->fu_curinodes = 0; 396218887Sdim fup->fu_curblocks = 0; 397226633Sdim } 398218887Sdim fclose(qfi); 399218887Sdim fflush(qfo); 400218887Sdim ftruncate(fileno(qfo), 401218887Sdim (off_t)((highid[type] + 1) * sizeof(struct dqblk))); 402251662Sdim fclose(qfo); 403251662Sdim return (0); 404234353Sdim} 405234353Sdim 406234353Sdim/* 407234353Sdim * Check to see if target appears in list of size cnt. 408234353Sdim */ 409234353Sdimint 410251662Sdimoneof(target, list, cnt) 411234353Sdim register char *target, *list[]; 412276479Sdim int cnt; 413234353Sdim{ 414234353Sdim register int i; 415234353Sdim 416234353Sdim for (i = 0; i < cnt; i++) 417234353Sdim if (strcmp(target, list[i]) == 0) 418234353Sdim return (i); 419234353Sdim return (-1); 420234353Sdim} 421234353Sdim 422234353Sdim/* 423234353Sdim * Determine the group identifier for quota files. 424234353Sdim */ 425234353Sdimint 426234353Sdimgetquotagid() 427276479Sdim{ 428251662Sdim struct group *gr; 429234353Sdim 430234353Sdim if ((gr = getgrnam(quotagroup)) != NULL) 431234353Sdim return (gr->gr_gid); 432234353Sdim return (-1); 433234353Sdim} 434234353Sdim 435234353Sdim/* 436234353Sdim * Check to see if a particular quota is to be enabled. 437251662Sdim */ 438251662Sdimint 439218887Sdimhasquota(fs, type, qfnamep) 440218887Sdim register struct fstab *fs; 441218887Sdim int type; 442218887Sdim char **qfnamep; 443218887Sdim{ 444218887Sdim register char *opt; 445251662Sdim char *cp; 446218887Sdim static char initname, usrname[100], grpname[100]; 447218887Sdim static char buf[BUFSIZ]; 448218887Sdim 449218887Sdim if (!initname) { 450276479Sdim (void)snprintf(usrname, sizeof(usrname), 451218887Sdim "%s%s", qfextension[USRQUOTA], qfname); 452218887Sdim (void)snprintf(grpname, sizeof(grpname), 453218887Sdim "%s%s", qfextension[GRPQUOTA], qfname); 454218887Sdim initname = 1; 455218887Sdim } 456218887Sdim strcpy(buf, fs->fs_mntops); 457218887Sdim for (opt = strtok(buf, ","); opt; opt = strtok(NULL, ",")) { 458218887Sdim if ((cp = index(opt, '=')) != NULL) 459218887Sdim *cp++ = '\0'; 460218887Sdim if (type == USRQUOTA && strcmp(opt, usrname) == 0) 461276479Sdim break; 462251662Sdim if (type == GRPQUOTA && strcmp(opt, grpname) == 0) 463218887Sdim break; 464218887Sdim } 465218887Sdim if (!opt) 466226633Sdim return (0); 467218887Sdim if (cp) 468218887Sdim *qfnamep = cp; 469218887Sdim else { 470218887Sdim (void)snprintf(buf, sizeof(buf), 471218887Sdim "%s/%s.%s", fs->fs_file, qfname, qfextension[type]); 472218887Sdim *qfnamep = buf; 473226633Sdim } 474226633Sdim return (1); 475218887Sdim} 476226633Sdim 477226633Sdim/* 478226633Sdim * Routines to manage the file usage table. 479218887Sdim * 480218887Sdim * Lookup an id of a specific type. 481218887Sdim */ 482226633Sdimstruct fileusage * 483218887Sdimlookup(id, type) 484218887Sdim u_long id; 485226633Sdim int type; 486218887Sdim{ 487226633Sdim register struct fileusage *fup; 488226633Sdim 489218887Sdim for (fup = fuhead[type][id & (FUHASH-1)]; fup != 0; fup = fup->fu_next) 490218887Sdim if (fup->fu_id == id) 491218887Sdim return (fup); 492218887Sdim return (NULL); 493218887Sdim} 494226633Sdim 495226633Sdim/* 496218887Sdim * Add a new file usage id if it does not already exist. 497243830Sdim */ 498243830Sdimstruct fileusage * 499243830Sdimaddid(id, type, name) 500243830Sdim u_long id; 501276479Sdim int type; 502218887Sdim char *name; 503243830Sdim{ 504243830Sdim struct fileusage *fup, **fhp; 505243830Sdim int len; 506276479Sdim 507243830Sdim if ((fup = lookup(id, type)) != NULL) 508218887Sdim return (fup); 509218887Sdim if (name) 510218887Sdim len = strlen(name); 511226633Sdim else 512218887Sdim len = 10; 513218887Sdim if ((fup = calloc(1, sizeof(*fup) + len)) == NULL) 514218887Sdim err("%s", strerror(errno)); 515226633Sdim fhp = &fuhead[type][id & (FUHASH - 1)]; 516226633Sdim fup->fu_next = *fhp; 517226633Sdim *fhp = fup; 518226633Sdim fup->fu_id = id; 519276479Sdim if (id > highid[type]) 520218887Sdim highid[type] = id; 521276479Sdim if (name) 522218887Sdim bcopy(name, fup->fu_name, len + 1); 523234353Sdim else { 524234353Sdim (void)sprintf(fup->fu_name, "%lu", id); 525234353Sdim if (vflag) 526218887Sdim printf("unknown %cid: %lu\n", 527218887Sdim type == USRQUOTA ? 'u' : 'g', id); 528218887Sdim } 529218887Sdim return (fup); 530218887Sdim} 531218887Sdim 532218887Sdim/* 533218887Sdim * Special purpose version of ginode used to optimize pass 534234353Sdim * over all the inodes in numerical order. 535234353Sdim */ 536234353Sdimino_t nextino, lastinum; 537234353Sdimlong readcnt, readpercg, fullcnt, inobufsize, partialcnt, partialsize; 538218887Sdimstruct dinode *inodebuf; 539218887Sdim#define INOBUFSIZE 56*1024 /* size of buffer to read inodes */ 540218887Sdim 541218887Sdimstruct dinode * 542243830Sdimgetnextinode(inumber) 543218887Sdim ino_t inumber; 544218887Sdim{ 545226633Sdim long size; 546226633Sdim daddr_t dblk; 547226633Sdim static struct dinode *dp; 548226633Sdim 549226633Sdim if (inumber != nextino++ || inumber > maxino) 550226633Sdim err("bad inode number %d to nextinode", inumber); 551226633Sdim if (inumber >= lastinum) { 552218887Sdim readcnt++; 553218887Sdim dblk = fsbtodb(&sblock, ino_to_fsba(&sblock, lastinum)); 554218887Sdim if (readcnt % readpercg == 0) { 555218887Sdim size = partialsize; 556239462Sdim lastinum += partialcnt; 557218887Sdim } else { 558226633Sdim size = inobufsize; 559226633Sdim lastinum += fullcnt; 560226633Sdim } 561226633Sdim bread(dblk, (char *)inodebuf, size); 562218887Sdim dp = inodebuf; 563226633Sdim } 564226633Sdim return (dp++); 565226633Sdim} 566226633Sdim 567226633Sdim/* 568226633Sdim * Prepare to scan a set of inodes. 569226633Sdim */ 570226633Sdimvoid 571226633Sdimresetinodebuf() 572226633Sdim{ 573239462Sdim 574218887Sdim nextino = 0; 575218887Sdim lastinum = 0; 576226633Sdim readcnt = 0; 577226633Sdim inobufsize = blkroundup(&sblock, INOBUFSIZE); 578218887Sdim fullcnt = inobufsize / sizeof(struct dinode); 579218887Sdim readpercg = sblock.fs_ipg / fullcnt; 580239462Sdim partialcnt = sblock.fs_ipg % fullcnt; 581239462Sdim partialsize = partialcnt * sizeof(struct dinode); 582239462Sdim if (partialcnt != 0) { 583239462Sdim readpercg++; 584239462Sdim } else { 585243830Sdim partialcnt = fullcnt; 586243830Sdim partialsize = inobufsize; 587243830Sdim } 588226633Sdim if (inodebuf == NULL && 589243830Sdim (inodebuf = malloc((u_int)inobufsize)) == NULL) 590276479Sdim err("%s", strerror(errno)); 591218887Sdim while (nextino < ROOTINO) 592218887Sdim getnextinode(nextino); 593218887Sdim} 594218887Sdim 595218887Sdim/* 596218887Sdim * Free up data structures used to scan inodes. 597226633Sdim */ 598234353Sdimvoid 599226633Sdimfreeinodebuf() 600218887Sdim{ 601226633Sdim 602226633Sdim if (inodebuf != NULL) 603226633Sdim free(inodebuf); 604226633Sdim inodebuf = NULL; 605226633Sdim} 606218887Sdim 607218887Sdim/* 608226633Sdim * Read specified disk blocks. 609226633Sdim */ 610226633Sdimvoid 611226633Sdimbread(bno, buf, cnt) 612226633Sdim daddr_t bno; 613226633Sdim char *buf; 614226633Sdim long cnt; 615218887Sdim{ 616218887Sdim 617226633Sdim if (lseek(fi, (off_t)bno * dev_bsize, SEEK_SET) < 0 || 618226633Sdim read(fi, buf, cnt) != cnt) 619226633Sdim err("block %ld", bno); 620226633Sdim} 621218887Sdim 622218887Sdim#if __STDC__ 623226633Sdim#include <stdarg.h> 624218887Sdim#else 625218887Sdim#include <varargs.h> 626218887Sdim#endif 627218887Sdim 628218887Sdimvoid 629218887Sdim#if __STDC__ 630226633Sdimerr(const char *fmt, ...) 631226633Sdim#else 632226633Sdimerr(fmt, va_alist) 633226633Sdim char *fmt; 634218887Sdim va_dcl 635226633Sdim#endif 636226633Sdim{ 637226633Sdim va_list ap; 638226633Sdim#if __STDC__ 639218887Sdim va_start(ap, fmt); 640218887Sdim#else 641218887Sdim va_start(ap); 642226633Sdim#endif 643226633Sdim (void)fprintf(stderr, "quotacheck: "); 644226633Sdim (void)vfprintf(stderr, fmt, ap); 645226633Sdim va_end(ap); 646226633Sdim (void)fprintf(stderr, "\n"); 647226633Sdim exit(1); 648226633Sdim /* NOTREACHED */ 649226633Sdim} 650226633Sdim 651226633Sdim