diff --git a/sbin/quotacheck/quotacheck.8 b/sbin/quotacheck/quotacheck.8 index 5ba2ad76fa3f..e8f4d9ca775a 100644 --- a/sbin/quotacheck/quotacheck.8 +++ b/sbin/quotacheck/quotacheck.8 @@ -40,10 +40,12 @@ .Sh SYNOPSIS .Nm .Op Fl guv +.Op Fl c Ar 32 | 64 .Op Fl l Ar maxrun .Fl a .Nm .Op Fl guv +.Op Fl c Ar 32 | 64 .Ar filesystem ... .Sh DESCRIPTION The @@ -69,6 +71,22 @@ to be read-write with disk quotas. By default only the types of quotas listed in .Pa /etc/fstab are checked. +.It Fl c Ar 32 | 64 +Before performing its checks, +.Nm +will convert the quota file to the specified word size. +A conversion size of 64 is given to request conversion to +the new 64-bit quota file format. +A conversion size of 32 is given to request conversion back to +the old 32-bit quota file format. +The original quota file is left unchanged and moved aside with an +underscore and its format size plus a +.Pa .orig +extension added to its name. +Thus, the original 32-bit +.Pa quota.user +quota file converted to the 64-bit format quota file will be renamed to +.Pa quota.user_32.orig . .It Fl g Only group quotas listed in .Pa /etc/fstab diff --git a/sbin/quotacheck/quotacheck.c b/sbin/quotacheck/quotacheck.c index 026608a419b6..ed9ce753c553 100644 --- a/sbin/quotacheck/quotacheck.c +++ b/sbin/quotacheck/quotacheck.c @@ -110,6 +110,7 @@ struct fileusage { struct fileusage *fuhead[MAXQUOTAS][FUHASH]; int aflag; /* all file systems */ +int cflag; /* convert format to 32 or 64 bit size */ int gflag; /* check group quotas */ int uflag; /* check user quotas */ int vflag; /* verbose */ @@ -143,11 +144,16 @@ main(int argc, char *argv[]) char *name; errs = maxrun = 0; - while ((ch = getopt(argc, argv, "aguvl:")) != -1) { + while ((ch = getopt(argc, argv, "ac:guvl:")) != -1) { switch(ch) { case 'a': aflag++; break; + case 'c': + if (cflag) + usage(); + cflag = atoi(optarg); + break; case 'g': gflag++; break; @@ -168,6 +174,8 @@ main(int argc, char *argv[]) argv += optind; if ((argc == 0 && !aflag) || (argc > 0 && aflag)) usage(); + if (cflag && cflag != 32 && cflag != 64) + usage(); if (!gflag && !uflag) { gflag++; uflag++; @@ -227,8 +235,8 @@ void usage(void) { (void)fprintf(stderr, "%s\n%s\n", - "usage: quotacheck [-guv] [-l maxrun] -a", - " quotacheck [-guv] filesystem ..."); + "usage: quotacheck [-guv] [-c 32 | 64] [-l maxrun] -a", + " quotacheck [-guv] [-c 32 | 64] filesystem ..."); exit(1); } @@ -257,7 +265,31 @@ chkquota(char *specname, struct quotafile *qfu, struct quotafile *qfg) else if (qfg != NULL) mntpt = quota_fsname(qfg); else - err(1, "null quotafile information passed to chkquota()\n"); + errx(1, "null quotafile information passed to chkquota()\n"); + if (cflag) { + if (vflag && qfu != NULL) + printf("%s: convert user quota to %d bits\n", + mntpt, cflag); + if (qfu != NULL && quota_convert(qfu, cflag) < 0) { + if (errno == EBADF) + errx(1, + "%s: cannot convert an active quota file", + mntpt); + err(1, "user quota conversion to size %d failed", + cflag); + } + if (vflag && qfg != NULL) + printf("%s: convert group quota to %d bits\n", + mntpt, cflag); + if (qfg != NULL && quota_convert(qfg, cflag) < 0) { + if (errno == EBADF) + errx(1, + "%s: cannot convert an active quota file", + mntpt); + err(1, "group quota conversion to size %d failed", + cflag); + } + } if ((fi = open(specname, O_RDONLY, 0)) < 0) { warn("%s", specname); return (1); @@ -407,6 +439,7 @@ update(const char *fsname, struct quotafile *qf, int type) struct fileusage *fup; u_long id, lastid, highid = 0; struct dqblk dqbuf; + struct stat sb; static struct dqblk zerodqbuf; static struct fileusage zerofileusage; @@ -459,7 +492,14 @@ update(const char *fsname, struct quotafile *qf, int type) fup->fu_curblocks = 0; } } - if (highid < lastid) + /* + * If this is old format file, then size may be smaller, + * so ensure that we only truncate when it will make things + * smaller, and not if it will grow an old format file. + */ + if (highid < lastid && + stat(quota_qfname(qf), &sb) == 0 && + sb.st_size > (((off_t)highid + 2) * sizeof(struct dqblk))) truncate(quota_qfname(qf), (((off_t)highid + 2) * sizeof(struct dqblk))); return (0);