1 /*- 2 * SPDX-License-Identifier: BSD-3-Clause 3 * 4 * Copyright (c) 1980, 1990, 1993 5 * The Regents of the University of California. All rights reserved. 6 * 7 * This code is derived from software contributed to Berkeley by 8 * Robert Elz at The University of Melbourne. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 3. Neither the name of the University nor the names of its contributors 19 * may be used to endorse or promote products derived from this software 20 * without specific prior written permission. 21 * 22 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 25 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 32 * SUCH DAMAGE. 33 */ 34 35 /* 36 * Fix up / report on disk quotas & usage 37 */ 38 #include <sys/param.h> 39 #include <sys/disklabel.h> 40 #include <sys/mount.h> 41 #include <sys/stat.h> 42 43 #include <ufs/ufs/dinode.h> 44 #include <ufs/ufs/quota.h> 45 #include <ufs/ffs/fs.h> 46 47 #include <err.h> 48 #include <errno.h> 49 #include <fcntl.h> 50 #include <fstab.h> 51 #include <grp.h> 52 #include <libufs.h> 53 #include <libutil.h> 54 #include <pwd.h> 55 #include <stdint.h> 56 #include <stdio.h> 57 #include <stdlib.h> 58 #include <string.h> 59 #include <unistd.h> 60 61 #include "quotacheck.h" 62 63 const char *qfname = QUOTAFILENAME; 64 const char *qfextension[] = INITQFNAMES; 65 const char *quotagroup = QUOTAGROUP; 66 67 union { 68 struct fs sblk; 69 char dummy[MAXBSIZE]; 70 } sb_un; 71 #define sblock sb_un.sblk 72 union { 73 struct cg cgblk; 74 char dummy[MAXBSIZE]; 75 } cg_un; 76 #define cgblk cg_un.cgblk 77 long dev_bsize = 1; 78 ino_t maxino; 79 80 union dinode { 81 struct ufs1_dinode dp1; 82 struct ufs2_dinode dp2; 83 }; 84 #define DIP(dp, field) \ 85 ((sblock.fs_magic == FS_UFS1_MAGIC) ? \ 86 (dp)->dp1.field : (dp)->dp2.field) 87 88 #define HASUSR 1 89 #define HASGRP 2 90 91 struct fileusage { 92 struct fileusage *fu_next; 93 u_long fu_curinodes; 94 u_long fu_curblocks; 95 u_long fu_id; 96 char fu_name[1]; 97 /* actually bigger */ 98 }; 99 #define FUHASH 1024 /* must be power of two */ 100 struct fileusage *fuhead[MAXQUOTAS][FUHASH]; 101 102 int aflag; /* all file systems */ 103 int cflag; /* convert format to 32 or 64 bit size */ 104 int gflag; /* check group quotas */ 105 int uflag; /* check user quotas */ 106 int vflag; /* verbose */ 107 int fi; /* open disk file descriptor */ 108 109 struct fileusage * 110 addid(u_long, int, char *, const char *); 111 void blkread(ufs2_daddr_t, char *, long); 112 void freeinodebuf(void); 113 union dinode * 114 getnextinode(ino_t); 115 int getquotagid(void); 116 struct fileusage * 117 lookup(u_long, int); 118 int oneof(char *, char*[], int); 119 void printchanges(const char *, int, struct dqblk *, struct fileusage *, 120 u_long); 121 void setinodebuf(ino_t); 122 int update(const char *, struct quotafile *, int); 123 void usage(void); 124 125 int 126 main(int argc, char *argv[]) 127 { 128 struct fstab *fs; 129 struct passwd *pw; 130 struct group *gr; 131 struct quotafile *qfu, *qfg; 132 int i, argnum, maxrun, errs, ch; 133 long done = 0; 134 char *name; 135 136 errs = maxrun = 0; 137 while ((ch = getopt(argc, argv, "ac:guvl:")) != -1) { 138 switch(ch) { 139 case 'a': 140 aflag++; 141 break; 142 case 'c': 143 if (cflag) 144 usage(); 145 cflag = atoi(optarg); 146 break; 147 case 'g': 148 gflag++; 149 break; 150 case 'u': 151 uflag++; 152 break; 153 case 'v': 154 vflag++; 155 break; 156 case 'l': 157 maxrun = atoi(optarg); 158 break; 159 default: 160 usage(); 161 } 162 } 163 argc -= optind; 164 argv += optind; 165 if ((argc == 0 && !aflag) || (argc > 0 && aflag)) 166 usage(); 167 if (cflag && cflag != 32 && cflag != 64) 168 usage(); 169 if (!gflag && !uflag) { 170 gflag++; 171 uflag++; 172 } 173 if (gflag) { 174 setgrent(); 175 while ((gr = getgrent()) != NULL) 176 (void) addid((u_long)gr->gr_gid, GRPQUOTA, gr->gr_name, 177 NULL); 178 endgrent(); 179 } 180 if (uflag) { 181 setpwent(); 182 while ((pw = getpwent()) != NULL) 183 (void) addid((u_long)pw->pw_uid, USRQUOTA, pw->pw_name, 184 NULL); 185 endpwent(); 186 } 187 /* 188 * The maxrun (-l) option is now deprecated. 189 */ 190 if (maxrun > 0) 191 warnx("the -l option is now deprecated"); 192 if (aflag) 193 exit(checkfstab(uflag, gflag)); 194 if (setfsent() == 0) 195 errx(1, "%s: can't open", FSTAB); 196 while ((fs = getfsent()) != NULL) { 197 if (((argnum = oneof(fs->fs_file, argv, argc)) >= 0 || 198 (argnum = oneof(fs->fs_spec, argv, argc)) >= 0) && 199 (name = blockcheck(fs->fs_spec))) { 200 done |= 1 << argnum; 201 qfu = NULL; 202 if (uflag) 203 qfu = quota_open(fs, USRQUOTA, O_CREAT|O_RDWR); 204 qfg = NULL; 205 if (gflag) 206 qfg = quota_open(fs, GRPQUOTA, O_CREAT|O_RDWR); 207 if (qfu == NULL && qfg == NULL) 208 continue; 209 errs += chkquota(name, qfu, qfg); 210 if (qfu) 211 quota_close(qfu); 212 if (qfg) 213 quota_close(qfg); 214 } 215 } 216 endfsent(); 217 for (i = 0; i < argc; i++) 218 if ((done & (1 << i)) == 0) 219 fprintf(stderr, "%s not found in %s\n", 220 argv[i], FSTAB); 221 exit(errs); 222 } 223 224 void 225 usage(void) 226 { 227 (void)fprintf(stderr, "%s\n%s\n", 228 "usage: quotacheck [-guv] [-c 32 | 64] [-l maxrun] -a", 229 " quotacheck [-guv] [-c 32 | 64] filesystem ..."); 230 exit(1); 231 } 232 233 /* 234 * Scan the specified file system to check quota(s) present on it. 235 */ 236 int 237 chkquota(char *specname, struct quotafile *qfu, struct quotafile *qfg) 238 { 239 struct fileusage *fup; 240 union dinode *dp; 241 struct fs *fs; 242 int i, ret, mode, errs = 0; 243 u_int32_t cg; 244 ino_t curino, ino, inosused, userino = 0, groupino = 0; 245 dev_t dev, userdev = 0, groupdev = 0; 246 struct stat sb; 247 const char *mntpt; 248 char *cp; 249 250 if (qfu != NULL) 251 mntpt = quota_fsname(qfu); 252 else if (qfg != NULL) 253 mntpt = quota_fsname(qfg); 254 else 255 errx(1, "null quotafile information passed to chkquota()\n"); 256 if (cflag) { 257 if (vflag && qfu != NULL) 258 printf("%s: convert user quota to %d bits\n", 259 mntpt, cflag); 260 if (qfu != NULL && quota_convert(qfu, cflag) < 0) { 261 if (errno == EBADF) 262 errx(1, 263 "%s: cannot convert an active quota file", 264 mntpt); 265 err(1, "user quota conversion to size %d failed", 266 cflag); 267 } 268 if (vflag && qfg != NULL) 269 printf("%s: convert group quota to %d bits\n", 270 mntpt, cflag); 271 if (qfg != NULL && quota_convert(qfg, cflag) < 0) { 272 if (errno == EBADF) 273 errx(1, 274 "%s: cannot convert an active quota file", 275 mntpt); 276 err(1, "group quota conversion to size %d failed", 277 cflag); 278 } 279 } 280 if ((fi = open(specname, O_RDONLY, 0)) < 0) { 281 warn("%s", specname); 282 return (1); 283 } 284 if ((stat(mntpt, &sb)) < 0) { 285 warn("%s", mntpt); 286 return (1); 287 } 288 dev = sb.st_dev; 289 if (vflag) { 290 (void)printf("*** Checking "); 291 if (qfu) 292 (void)printf("user%s", qfg ? " and " : ""); 293 if (qfg) 294 (void)printf("group"); 295 (void)printf(" quotas for %s (%s)\n", specname, mntpt); 296 } 297 if (qfu) { 298 if (stat(quota_qfname(qfu), &sb) == 0) { 299 userino = sb.st_ino; 300 userdev = sb.st_dev; 301 } 302 } 303 if (qfg) { 304 if (stat(quota_qfname(qfg), &sb) == 0) { 305 groupino = sb.st_ino; 306 groupdev = sb.st_dev; 307 } 308 } 309 sync(); 310 if ((ret = sbget(fi, &fs, UFS_STDSB, UFS_NOCSUM)) != 0) { 311 switch (ret) { 312 case ENOENT: 313 warn("Cannot find file system superblock"); 314 return (1); 315 default: 316 warn("Unable to read file system superblock"); 317 return (1); 318 } 319 } 320 bcopy(fs, &sblock, fs->fs_sbsize); 321 free(fs); 322 dev_bsize = sblock.fs_fsize / fsbtodb(&sblock, 1); 323 maxino = sblock.fs_ncg * sblock.fs_ipg; 324 for (cg = 0; cg < sblock.fs_ncg; cg++) { 325 ino = cg * sblock.fs_ipg; 326 setinodebuf(ino); 327 blkread(fsbtodb(&sblock, cgtod(&sblock, cg)), (char *)(&cgblk), 328 sblock.fs_cgsize); 329 if (sblock.fs_magic == FS_UFS2_MAGIC) 330 inosused = cgblk.cg_initediblk; 331 else 332 inosused = sblock.fs_ipg; 333 /* 334 * If we are using soft updates, then we can trust the 335 * cylinder group inode allocation maps to tell us which 336 * inodes are allocated. We will scan the used inode map 337 * to find the inodes that are really in use, and then 338 * read only those inodes in from disk. 339 */ 340 if (sblock.fs_flags & FS_DOSOFTDEP) { 341 if (!cg_chkmagic(&cgblk)) 342 errx(1, "CG %d: BAD MAGIC NUMBER\n", cg); 343 cp = &cg_inosused(&cgblk)[(inosused - 1) / CHAR_BIT]; 344 for ( ; inosused > 0; inosused -= CHAR_BIT, cp--) { 345 if (*cp == 0) 346 continue; 347 for (i = 1 << (CHAR_BIT - 1); i > 0; i >>= 1) { 348 if (*cp & i) 349 break; 350 inosused--; 351 } 352 break; 353 } 354 if (inosused <= 0) 355 continue; 356 } 357 for (curino = 0; curino < inosused; curino++, ino++) { 358 if ((dp = getnextinode(ino)) == NULL || 359 ino < UFS_ROOTINO || 360 (mode = DIP(dp, di_mode) & IFMT) == 0) 361 continue; 362 /* 363 * XXX: Do not account for UIDs or GIDs that appear 364 * to be negative to prevent generating 100GB+ 365 * quota files. 366 */ 367 if ((int)DIP(dp, di_uid) < 0 || 368 (int)DIP(dp, di_gid) < 0) { 369 if (vflag) { 370 if (aflag) 371 (void)printf("%s: ", mntpt); 372 (void)printf("out of range UID/GID (%u/%u) ino=%ju\n", 373 DIP(dp, di_uid), DIP(dp,di_gid), 374 (uintmax_t)ino); 375 } 376 continue; 377 } 378 379 /* 380 * Do not account for file system snapshot files 381 * or the actual quota data files to be consistent 382 * with how they are handled inside the kernel. 383 */ 384 #ifdef SF_SNAPSHOT 385 if (DIP(dp, di_flags) & SF_SNAPSHOT) 386 continue; 387 #endif 388 if ((ino == userino && dev == userdev) || 389 (ino == groupino && dev == groupdev)) 390 continue; 391 if (qfg) { 392 fup = addid((u_long)DIP(dp, di_gid), GRPQUOTA, 393 NULL, mntpt); 394 fup->fu_curinodes++; 395 if (mode == IFREG || mode == IFDIR || 396 mode == IFLNK) 397 fup->fu_curblocks += DIP(dp, di_blocks); 398 } 399 if (qfu) { 400 fup = addid((u_long)DIP(dp, di_uid), USRQUOTA, 401 NULL, mntpt); 402 fup->fu_curinodes++; 403 if (mode == IFREG || mode == IFDIR || 404 mode == IFLNK) 405 fup->fu_curblocks += DIP(dp, di_blocks); 406 } 407 } 408 } 409 freeinodebuf(); 410 if (qfu) 411 errs += update(mntpt, qfu, USRQUOTA); 412 if (qfg) 413 errs += update(mntpt, qfg, GRPQUOTA); 414 close(fi); 415 (void)fflush(stdout); 416 return (errs); 417 } 418 419 /* 420 * Update a specified quota file. 421 */ 422 int 423 update(const char *fsname, struct quotafile *qf, int type) 424 { 425 struct fileusage *fup; 426 u_long id, lastid, highid = 0; 427 struct dqblk dqbuf; 428 struct stat sb; 429 static struct dqblk zerodqbuf; 430 static struct fileusage zerofileusage; 431 432 /* 433 * Scan the on-disk quota file and record any usage changes. 434 */ 435 lastid = quota_maxid(qf); 436 for (id = 0; id <= lastid; id++) { 437 if (quota_read(qf, &dqbuf, id) < 0) 438 dqbuf = zerodqbuf; 439 if ((fup = lookup(id, type)) == NULL) 440 fup = &zerofileusage; 441 if (fup->fu_curinodes || fup->fu_curblocks || 442 dqbuf.dqb_bsoftlimit || dqbuf.dqb_bhardlimit || 443 dqbuf.dqb_isoftlimit || dqbuf.dqb_ihardlimit) 444 highid = id; 445 if (dqbuf.dqb_curinodes == fup->fu_curinodes && 446 dqbuf.dqb_curblocks == fup->fu_curblocks) { 447 fup->fu_curinodes = 0; 448 fup->fu_curblocks = 0; 449 continue; 450 } 451 printchanges(fsname, type, &dqbuf, fup, id); 452 dqbuf.dqb_curinodes = fup->fu_curinodes; 453 dqbuf.dqb_curblocks = fup->fu_curblocks; 454 (void) quota_write_usage(qf, &dqbuf, id); 455 fup->fu_curinodes = 0; 456 fup->fu_curblocks = 0; 457 } 458 459 /* 460 * Walk the hash table looking for ids with non-zero usage 461 * that are not currently recorded in the quota file. E.g. 462 * ids that are past the end of the current file. 463 */ 464 for (id = 0; id < FUHASH; id++) { 465 for (fup = fuhead[type][id]; fup != NULL; fup = fup->fu_next) { 466 if (fup->fu_id <= lastid) 467 continue; 468 if (fup->fu_curinodes == 0 && fup->fu_curblocks == 0) 469 continue; 470 bzero(&dqbuf, sizeof(struct dqblk)); 471 if (fup->fu_id > highid) 472 highid = fup->fu_id; 473 printchanges(fsname, type, &dqbuf, fup, fup->fu_id); 474 dqbuf.dqb_curinodes = fup->fu_curinodes; 475 dqbuf.dqb_curblocks = fup->fu_curblocks; 476 (void) quota_write_usage(qf, &dqbuf, fup->fu_id); 477 fup->fu_curinodes = 0; 478 fup->fu_curblocks = 0; 479 } 480 } 481 /* 482 * If this is old format file, then size may be smaller, 483 * so ensure that we only truncate when it will make things 484 * smaller, and not if it will grow an old format file. 485 */ 486 if (highid < lastid && 487 stat(quota_qfname(qf), &sb) == 0 && 488 sb.st_size > (off_t)((highid + 2) * sizeof(struct dqblk))) 489 truncate(quota_qfname(qf), 490 (((off_t)highid + 2) * sizeof(struct dqblk))); 491 return (0); 492 } 493 494 /* 495 * Check to see if target appears in list of size cnt. 496 */ 497 int 498 oneof(char *target, char *list[], int cnt) 499 { 500 int i; 501 502 for (i = 0; i < cnt; i++) 503 if (strcmp(target, list[i]) == 0) 504 return (i); 505 return (-1); 506 } 507 508 /* 509 * Determine the group identifier for quota files. 510 */ 511 int 512 getquotagid(void) 513 { 514 struct group *gr; 515 516 if ((gr = getgrnam(quotagroup)) != NULL) 517 return (gr->gr_gid); 518 return (-1); 519 } 520 521 /* 522 * Routines to manage the file usage table. 523 * 524 * Lookup an id of a specific type. 525 */ 526 struct fileusage * 527 lookup(u_long id, int type) 528 { 529 struct fileusage *fup; 530 531 for (fup = fuhead[type][id & (FUHASH-1)]; fup != NULL; fup = fup->fu_next) 532 if (fup->fu_id == id) 533 return (fup); 534 return (NULL); 535 } 536 537 /* 538 * Add a new file usage id if it does not already exist. 539 */ 540 struct fileusage * 541 addid(u_long id, int type, char *name, const char *fsname) 542 { 543 struct fileusage *fup, **fhp; 544 int len; 545 546 if ((fup = lookup(id, type)) != NULL) 547 return (fup); 548 if (name) 549 len = strlen(name); 550 else 551 len = 0; 552 if ((fup = calloc(1, sizeof(*fup) + len)) == NULL) 553 errx(1, "calloc failed"); 554 fhp = &fuhead[type][id & (FUHASH - 1)]; 555 fup->fu_next = *fhp; 556 *fhp = fup; 557 fup->fu_id = id; 558 if (name) 559 bcopy(name, fup->fu_name, len + 1); 560 else { 561 (void)sprintf(fup->fu_name, "%lu", id); 562 if (vflag) { 563 if (aflag && fsname != NULL) 564 (void)printf("%s: ", fsname); 565 printf("unknown %cid: %lu\n", 566 type == USRQUOTA ? 'u' : 'g', id); 567 } 568 } 569 return (fup); 570 } 571 572 /* 573 * Special purpose version of ginode used to optimize pass 574 * over all the inodes in numerical order. 575 */ 576 static ino_t nextino, lastinum, lastvalidinum; 577 static long readcnt, readpercg, fullcnt, inobufsize, partialcnt, partialsize; 578 static caddr_t inodebuf; 579 #define INOBUFSIZE 56*1024 /* size of buffer to read inodes */ 580 581 union dinode * 582 getnextinode(ino_t inumber) 583 { 584 long size; 585 ufs2_daddr_t dblk; 586 union dinode *dp; 587 static caddr_t nextinop; 588 589 if (inumber != nextino++ || inumber > lastvalidinum) 590 errx(1, "bad inode number %ju to nextinode", 591 (uintmax_t)inumber); 592 if (inumber >= lastinum) { 593 readcnt++; 594 dblk = fsbtodb(&sblock, ino_to_fsba(&sblock, lastinum)); 595 if (readcnt % readpercg == 0) { 596 size = partialsize; 597 lastinum += partialcnt; 598 } else { 599 size = inobufsize; 600 lastinum += fullcnt; 601 } 602 /* 603 * If blkread returns an error, it will already have zeroed 604 * out the buffer, so we do not need to do so here. 605 */ 606 blkread(dblk, inodebuf, size); 607 nextinop = inodebuf; 608 } 609 dp = (union dinode *)nextinop; 610 if (sblock.fs_magic == FS_UFS1_MAGIC) 611 nextinop += sizeof(struct ufs1_dinode); 612 else 613 nextinop += sizeof(struct ufs2_dinode); 614 return (dp); 615 } 616 617 /* 618 * Prepare to scan a set of inodes. 619 */ 620 void 621 setinodebuf(ino_t inum) 622 { 623 624 if (inum % sblock.fs_ipg != 0) 625 errx(1, "bad inode number %ju to setinodebuf", (uintmax_t)inum); 626 lastvalidinum = inum + sblock.fs_ipg - 1; 627 nextino = inum; 628 lastinum = inum; 629 readcnt = 0; 630 if (inodebuf != NULL) 631 return; 632 inobufsize = blkroundup(&sblock, INOBUFSIZE); 633 fullcnt = inobufsize / ((sblock.fs_magic == FS_UFS1_MAGIC) ? 634 sizeof(struct ufs1_dinode) : sizeof(struct ufs2_dinode)); 635 readpercg = sblock.fs_ipg / fullcnt; 636 partialcnt = sblock.fs_ipg % fullcnt; 637 partialsize = partialcnt * ((sblock.fs_magic == FS_UFS1_MAGIC) ? 638 sizeof(struct ufs1_dinode) : sizeof(struct ufs2_dinode)); 639 if (partialcnt != 0) { 640 readpercg++; 641 } else { 642 partialcnt = fullcnt; 643 partialsize = inobufsize; 644 } 645 if ((inodebuf = malloc((unsigned)inobufsize)) == NULL) 646 errx(1, "cannot allocate space for inode buffer"); 647 } 648 649 /* 650 * Free up data structures used to scan inodes. 651 */ 652 void 653 freeinodebuf(void) 654 { 655 656 if (inodebuf != NULL) 657 free(inodebuf); 658 inodebuf = NULL; 659 } 660 661 /* 662 * Read specified disk blocks. 663 */ 664 void 665 blkread(ufs2_daddr_t bno, char *buf, long cnt) 666 { 667 668 if (lseek(fi, (off_t)bno * dev_bsize, SEEK_SET) < 0 || 669 read(fi, buf, cnt) != cnt) 670 errx(1, "blkread failed on block %ld", (long)bno); 671 } 672 673 /* 674 * Display updated block and i-node counts. 675 */ 676 void 677 printchanges(const char *fsname, int type, struct dqblk *dp, 678 struct fileusage *fup, u_long id) 679 { 680 if (!vflag) 681 return; 682 if (aflag) 683 (void)printf("%s: ", fsname); 684 if (fup->fu_name[0] == '\0') 685 (void)printf("%-8lu fixed ", id); 686 else 687 (void)printf("%-8s fixed ", fup->fu_name); 688 switch (type) { 689 690 case GRPQUOTA: 691 (void)printf("(group):"); 692 break; 693 694 case USRQUOTA: 695 (void)printf("(user): "); 696 break; 697 698 default: 699 (void)printf("(unknown quota type %d)", type); 700 break; 701 } 702 if (dp->dqb_curinodes != fup->fu_curinodes) 703 (void)printf("\tinodes %lu -> %lu", (u_long)dp->dqb_curinodes, 704 (u_long)fup->fu_curinodes); 705 if (dp->dqb_curblocks != fup->fu_curblocks) 706 (void)printf("\tblocks %lu -> %lu", 707 (u_long)dp->dqb_curblocks, 708 (u_long)fup->fu_curblocks); 709 (void)printf("\n"); 710 } 711