Finish conversion of edquota to work with 64-bit quotas.
Add -h option to request "humanized" values such as 1M, 1G, 1T, etc. Discussed with: Dag-Erling Smorgrav Sponsored by: Rsync.net
This commit is contained in:
parent
1b3515f39b
commit
08dc3a5e5c
@ -4,6 +4,7 @@
|
||||
PROG= edquota
|
||||
MAN= edquota.8
|
||||
|
||||
CSTD= c99
|
||||
WARNS?= 4
|
||||
|
||||
DPADD= ${LIBUTIL}
|
||||
|
@ -42,6 +42,7 @@
|
||||
.Op Fl u
|
||||
.Op Fl f Ar fspath
|
||||
.Op Fl p Ar proto-username
|
||||
.Op Fl h
|
||||
.Ar username ...
|
||||
.Nm
|
||||
.Op Fl u
|
||||
@ -55,6 +56,7 @@
|
||||
.Fl g
|
||||
.Op Fl f Ar fspath
|
||||
.Op Fl p Ar proto-groupname
|
||||
.Op Fl h
|
||||
.Ar groupname ...
|
||||
.Nm
|
||||
.Fl g
|
||||
@ -97,6 +99,14 @@ unless the environment variable
|
||||
specifies otherwise.
|
||||
.Pp
|
||||
The quotas may then be modified, new quotas added, etc.
|
||||
Block quotas can be specified in bytes (B), kilobytes (K),
|
||||
megabytes (M), terabytes (T), pedabytes (P), or exabytes (E).
|
||||
If no units are specified, kilobytes are assumed.
|
||||
If the
|
||||
.Fl h
|
||||
flag is specified, the editor will always display the
|
||||
block usage and limits in a more human readable format
|
||||
rather than displaying them in the historic kilobyte format.
|
||||
Setting a quota to zero indicates that no quota should be imposed.
|
||||
Setting a hard limit to one indicates that no allocations should
|
||||
be permitted.
|
||||
@ -159,6 +169,9 @@ and
|
||||
.Ar ihlim
|
||||
values is omitted, it is assumed to be zero, therefore
|
||||
indicating that no particular quota should be imposed.
|
||||
Block quotas can be specified in bytes (B), kilobytes (K),
|
||||
megabytes (M), terabytes (T), pedabytes (P), or exabytes (E).
|
||||
If no units are specified, kilobytes are assumed.
|
||||
.Pp
|
||||
If invoked with the
|
||||
.Fl f
|
||||
|
@ -72,10 +72,22 @@ __FBSDID("$FreeBSD$");
|
||||
|
||||
#include "pathnames.h"
|
||||
|
||||
/* Let's be paranoid about block size */
|
||||
#if 10 > DEV_BSHIFT
|
||||
#define dbtokb(db) \
|
||||
((off_t)(db) >> (10-DEV_BSHIFT))
|
||||
#elif 10 < DEV_BSHIFT
|
||||
#define dbtokb(db) \
|
||||
((off_t)(db) << (DEV_BSHIFT-10))
|
||||
#else
|
||||
#define dbtokb(db) (db)
|
||||
#endif
|
||||
|
||||
const char *qfname = QUOTAFILENAME;
|
||||
const char *qfextension[] = INITQFNAMES;
|
||||
const char *quotagroup = QUOTAGROUP;
|
||||
char tmpfil[] = _PATH_TMP;
|
||||
int hflag;
|
||||
|
||||
struct quotause {
|
||||
struct quotause *next;
|
||||
@ -87,9 +99,11 @@ struct quotause {
|
||||
#define FOUND 0x01
|
||||
|
||||
int alldigits(const char *s);
|
||||
int cvtatos(time_t, char *, time_t *);
|
||||
char *cvtstoa(time_t);
|
||||
int cvtatos(u_int64_t, char *, u_int64_t *);
|
||||
char *cvtstoa(u_int64_t);
|
||||
u_int64_t cvtval(u_int64_t, char);
|
||||
int editit(char *);
|
||||
char *fmthumanval(int64_t);
|
||||
void freeprivs(struct quotause *);
|
||||
int getentry(const char *, int);
|
||||
struct quotause *getprivs(long, int, char *);
|
||||
@ -106,11 +120,10 @@ main(int argc, char *argv[])
|
||||
{
|
||||
struct quotause *qup, *protoprivs, *curprivs;
|
||||
long id, protoid;
|
||||
uintmax_t lim;
|
||||
int i, quotatype, range, tmpfd;
|
||||
uid_t startuid, enduid;
|
||||
u_int64_t *limp;
|
||||
char *protoname, *cp, *oldoptarg, *end;
|
||||
u_int64_t lim;
|
||||
char *protoname, *cp, *endpt, *oldoptarg;
|
||||
int eflag = 0, tflag = 0, pflag = 0, ch;
|
||||
char *fspath = NULL;
|
||||
char buf[MAXLOGNAME];
|
||||
@ -123,7 +136,7 @@ main(int argc, char *argv[])
|
||||
protoprivs = NULL;
|
||||
curprivs = NULL;
|
||||
protoname = NULL;
|
||||
while ((ch = getopt(argc, argv, "ugtf:p:e:")) != -1) {
|
||||
while ((ch = getopt(argc, argv, "ughtf:p:e:")) != -1) {
|
||||
switch(ch) {
|
||||
case 'f':
|
||||
fspath = optarg;
|
||||
@ -135,6 +148,9 @@ main(int argc, char *argv[])
|
||||
case 'g':
|
||||
quotatype = GRPQUOTA;
|
||||
break;
|
||||
case 'h':
|
||||
hflag++;
|
||||
break;
|
||||
case 'u':
|
||||
quotatype = USRQUOTA;
|
||||
break;
|
||||
@ -142,45 +158,44 @@ main(int argc, char *argv[])
|
||||
tflag++;
|
||||
break;
|
||||
case 'e':
|
||||
if ((qup = malloc(sizeof(*qup))) == NULL)
|
||||
if ((qup = malloc(sizeof(*qup) + BUFSIZ)) == NULL)
|
||||
errx(2, "out of memory");
|
||||
bzero(qup, sizeof(*qup));
|
||||
bzero(qup, sizeof(*qup) + BUFSIZ);
|
||||
i = 0;
|
||||
oldoptarg = optarg;
|
||||
for (cp = optarg; (cp = strsep(&optarg, ":")) != NULL;
|
||||
i++) {
|
||||
if (cp != oldoptarg)
|
||||
*(cp - 1) = ':';
|
||||
limp = NULL;
|
||||
switch (i) {
|
||||
case 0:
|
||||
strlcpy(qup->fsname, cp,
|
||||
sizeof(qup->fsname));
|
||||
break;
|
||||
case 1:
|
||||
limp = &qup->dqblk.dqb_bsoftlimit;
|
||||
break;
|
||||
lim = strtoll(cp, &endpt, 10);
|
||||
qup->dqblk.dqb_bsoftlimit =
|
||||
cvtval(lim, *endpt);
|
||||
continue;
|
||||
case 2:
|
||||
limp = &qup->dqblk.dqb_bhardlimit;
|
||||
break;
|
||||
lim = strtoll(cp, &endpt, 10);
|
||||
qup->dqblk.dqb_bhardlimit =
|
||||
cvtval(lim, *endpt);
|
||||
continue;
|
||||
case 3:
|
||||
limp = &qup->dqblk.dqb_isoftlimit;
|
||||
break;
|
||||
qup->dqblk.dqb_isoftlimit =
|
||||
strtoll(cp, NULL, 10);
|
||||
continue;
|
||||
case 4:
|
||||
limp = &qup->dqblk.dqb_ihardlimit;
|
||||
break;
|
||||
qup->dqblk.dqb_ihardlimit =
|
||||
strtoll(cp, NULL, 10);
|
||||
continue;
|
||||
default:
|
||||
warnx("incorrect quota specification: "
|
||||
"%s", oldoptarg);
|
||||
usage();
|
||||
break; /* XXX: report an error */
|
||||
}
|
||||
if (limp != NULL) {
|
||||
lim = strtoumax(cp, &end, 10);
|
||||
if (end == cp || *end != '\0' || lim > UINT64_MAX)
|
||||
errx(1, "invalid limit: %s", cp);
|
||||
*limp = (u_int64_t)lim;
|
||||
}
|
||||
}
|
||||
qup->dqblk.dqb_bsoftlimit =
|
||||
btodb((off_t)qup->dqblk.dqb_bsoftlimit * 1024);
|
||||
@ -285,10 +300,10 @@ static void
|
||||
usage(void)
|
||||
{
|
||||
fprintf(stderr, "%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n",
|
||||
"usage: edquota [-u] [-f fspath] [-p username] username ...",
|
||||
"usage: edquota [-u] [-f fspath] [-p username] [-h] username ...",
|
||||
" edquota [-u] -e fspath[:bslim[:bhlim[:islim[:ihlim]]]] [-e ...]",
|
||||
" username ...",
|
||||
" edquota -g [-f fspath] [-p groupname] groupname ...",
|
||||
" edquota -g [-f fspath] [-p groupname] [-h] groupname ...",
|
||||
" edquota -g -e fspath[:bslim[:bhlim[:islim[:ihlim]]]] [-e ...]",
|
||||
" groupname ...",
|
||||
" edquota [-u] -t [-f fspath]",
|
||||
@ -314,14 +329,17 @@ getentry(const char *name, int quotatype)
|
||||
if ((pw = getpwnam(name)))
|
||||
return (pw->pw_uid);
|
||||
warnx("%s: no such user", name);
|
||||
sleep(3);
|
||||
break;
|
||||
case GRPQUOTA:
|
||||
if ((gr = getgrnam(name)))
|
||||
return (gr->gr_gid);
|
||||
warnx("%s: no such group", name);
|
||||
sleep(3);
|
||||
break;
|
||||
default:
|
||||
warnx("%d: unknown quota type", quotatype);
|
||||
sleep(3);
|
||||
break;
|
||||
}
|
||||
sleep(1);
|
||||
@ -499,21 +517,36 @@ writeprivs(struct quotause *quplist, int outfd, char *name, int quotatype)
|
||||
err(1, "%s", tmpfil);
|
||||
fprintf(fd, "Quotas for %s %s:\n", qfextension[quotatype], name);
|
||||
for (qup = quplist; qup; qup = qup->next) {
|
||||
fprintf(fd, "%s: %s %lu, limits (soft = %lu, hard = %lu)\n",
|
||||
qup->fsname, "kbytes in use:",
|
||||
(unsigned long)(dbtob(qup->dqblk.dqb_curblocks) / 1024),
|
||||
(unsigned long)(dbtob(qup->dqblk.dqb_bsoftlimit) / 1024),
|
||||
(unsigned long)(dbtob(qup->dqblk.dqb_bhardlimit) / 1024));
|
||||
fprintf(fd, "%s %lu, limits (soft = %lu, hard = %lu)\n",
|
||||
fprintf(fd, "%s: in use: %s, ", qup->fsname,
|
||||
fmthumanval(qup->dqblk.dqb_curblocks));
|
||||
fprintf(fd, "limits (soft = %s, ",
|
||||
fmthumanval(qup->dqblk.dqb_bsoftlimit));
|
||||
fprintf(fd, "hard = %s)\n",
|
||||
fmthumanval(qup->dqblk.dqb_bhardlimit));
|
||||
fprintf(fd, "%s %llu, limits (soft = %llu, hard = %llu)\n",
|
||||
"\tinodes in use:",
|
||||
(unsigned long)qup->dqblk.dqb_curinodes,
|
||||
(unsigned long)qup->dqblk.dqb_isoftlimit,
|
||||
(unsigned long)qup->dqblk.dqb_ihardlimit);
|
||||
qup->dqblk.dqb_curinodes,
|
||||
qup->dqblk.dqb_isoftlimit,
|
||||
qup->dqblk.dqb_ihardlimit);
|
||||
}
|
||||
fclose(fd);
|
||||
return (1);
|
||||
}
|
||||
|
||||
char *
|
||||
fmthumanval(int64_t blocks)
|
||||
{
|
||||
static char buf[7], numbuf[20];
|
||||
|
||||
if (hflag) {
|
||||
humanize_number(buf, sizeof(buf) - (blocks < 0 ? 0 : 1),
|
||||
dbtob(blocks), "", HN_AUTOSCALE, HN_NOSPACE);
|
||||
return (buf);
|
||||
}
|
||||
snprintf(numbuf, 20, "%lluK", dbtokb(blocks));
|
||||
return(numbuf);
|
||||
}
|
||||
|
||||
/*
|
||||
* Merge changes to an ASCII file into a quotause list.
|
||||
*/
|
||||
@ -522,8 +555,9 @@ readprivs(struct quotause *quplist, char *inname)
|
||||
{
|
||||
struct quotause *qup;
|
||||
FILE *fd;
|
||||
unsigned long bhardlimit, bsoftlimit, curblocks;
|
||||
unsigned long ihardlimit, isoftlimit, curinodes;
|
||||
u_int64_t ihardlimit, isoftlimit, curinodes;
|
||||
u_int64_t bhardlimit, bsoftlimit, curblocks;
|
||||
char bhardunits, bsoftunits, curblockunits;
|
||||
int cnt;
|
||||
char *cp;
|
||||
struct dqblk dqblk;
|
||||
@ -549,21 +583,40 @@ readprivs(struct quotause *quplist, char *inname)
|
||||
return (0);
|
||||
}
|
||||
cnt = sscanf(cp,
|
||||
" kbytes in use: %lu, limits (soft = %lu, hard = %lu)",
|
||||
&curblocks, &bsoftlimit, &bhardlimit);
|
||||
if (cnt != 3) {
|
||||
" in use: %llu%c, limits (soft = %llu%c, hard = %llu%c)",
|
||||
&curblocks, &curblockunits, &bsoftlimit, &bsoftunits,
|
||||
&bhardlimit, &bhardunits);
|
||||
/*
|
||||
* The next three check for old-style input formats.
|
||||
*/
|
||||
if (cnt != 6)
|
||||
cnt = sscanf(cp,
|
||||
" in use: %llu%c, limits (soft = %llu%c hard = %llu%c",
|
||||
&curblocks, &curblockunits, &bsoftlimit,
|
||||
&bsoftunits, &bhardlimit, &bhardunits);
|
||||
if (cnt != 6)
|
||||
cnt = sscanf(cp,
|
||||
" in use: %llu%c, limits (soft = %llu%c hard = %llu%c)",
|
||||
&curblocks, &curblockunits, &bsoftlimit,
|
||||
&bsoftunits, &bhardlimit, &bhardunits);
|
||||
if (cnt != 6)
|
||||
cnt = sscanf(cp,
|
||||
" in use: %llu%c, limits (soft = %llu%c, hard = %llu%c",
|
||||
&curblocks, &curblockunits, &bsoftlimit,
|
||||
&bsoftunits, &bhardlimit, &bhardunits);
|
||||
if (cnt != 6) {
|
||||
warnx("%s:%s: bad format", fsp, cp);
|
||||
return (0);
|
||||
}
|
||||
dqblk.dqb_curblocks = btodb((off_t)curblocks * 1024);
|
||||
dqblk.dqb_bsoftlimit = btodb((off_t)bsoftlimit * 1024);
|
||||
dqblk.dqb_bhardlimit = btodb((off_t)bhardlimit * 1024);
|
||||
dqblk.dqb_curblocks = cvtval(curblocks, curblockunits);
|
||||
dqblk.dqb_bsoftlimit = cvtval(bsoftlimit, bsoftunits);
|
||||
dqblk.dqb_bhardlimit = cvtval(bhardlimit, bhardunits);
|
||||
if ((cp = strtok(line2, "\n")) == NULL) {
|
||||
warnx("%s: %s: bad format", fsp, line2);
|
||||
return (0);
|
||||
}
|
||||
cnt = sscanf(cp,
|
||||
"\tinodes in use: %lu, limits (soft = %lu, hard = %lu)",
|
||||
"\tinodes in use: %llu, limits (soft = %llu, hard = %llu)",
|
||||
&curinodes, &isoftlimit, &ihardlimit);
|
||||
if (cnt != 3) {
|
||||
warnx("%s: %s: bad format", fsp, line2);
|
||||
@ -598,8 +651,8 @@ readprivs(struct quotause *quplist, char *inname)
|
||||
qup->dqblk.dqb_isoftlimit = dqblk.dqb_isoftlimit;
|
||||
qup->dqblk.dqb_ihardlimit = dqblk.dqb_ihardlimit;
|
||||
qup->flags |= FOUND;
|
||||
if (dqblk.dqb_curblocks == qup->dqblk.dqb_curblocks &&
|
||||
dqblk.dqb_curinodes == qup->dqblk.dqb_curinodes)
|
||||
/* No easy way to check change in curblocks */
|
||||
if (dqblk.dqb_curinodes == qup->dqblk.dqb_curinodes)
|
||||
break;
|
||||
warnx("%s: cannot change current allocation", fsp);
|
||||
break;
|
||||
@ -658,8 +711,7 @@ readtimes(struct quotause *quplist, char *inname)
|
||||
FILE *fd;
|
||||
int cnt;
|
||||
char *cp;
|
||||
time_t itime, btime, iseconds, bseconds;
|
||||
long l_itime, l_btime;
|
||||
u_int64_t itime, btime, iseconds, bseconds;
|
||||
char *fsp, bunits[10], iunits[10], line1[BUFSIZ];
|
||||
|
||||
fd = fopen(inname, "r");
|
||||
@ -682,14 +734,12 @@ readtimes(struct quotause *quplist, char *inname)
|
||||
return (0);
|
||||
}
|
||||
cnt = sscanf(cp,
|
||||
" block grace period: %ld %s file grace period: %ld %s",
|
||||
&l_btime, bunits, &l_itime, iunits);
|
||||
" block grace period: %llu %s file grace period: %llu %s",
|
||||
&btime, bunits, &itime, iunits);
|
||||
if (cnt != 4) {
|
||||
warnx("%s:%s: bad format", fsp, cp);
|
||||
return (0);
|
||||
}
|
||||
btime = l_btime;
|
||||
itime = l_itime;
|
||||
if (cvtatos(btime, bunits, &bseconds) == 0)
|
||||
return (0);
|
||||
if (cvtatos(itime, iunits, &iseconds) == 0)
|
||||
@ -723,21 +773,21 @@ readtimes(struct quotause *quplist, char *inname)
|
||||
* Convert seconds to ASCII times.
|
||||
*/
|
||||
char *
|
||||
cvtstoa(time_t secs)
|
||||
cvtstoa(u_int64_t secs)
|
||||
{
|
||||
static char buf[20];
|
||||
|
||||
if (secs % (24 * 60 * 60) == 0) {
|
||||
secs /= 24 * 60 * 60;
|
||||
sprintf(buf, "%ld day%s", (long)secs, secs == 1 ? "" : "s");
|
||||
sprintf(buf, "%llu day%s", secs, secs == 1 ? "" : "s");
|
||||
} else if (secs % (60 * 60) == 0) {
|
||||
secs /= 60 * 60;
|
||||
sprintf(buf, "%ld hour%s", (long)secs, secs == 1 ? "" : "s");
|
||||
sprintf(buf, "%llu hour%s", secs, secs == 1 ? "" : "s");
|
||||
} else if (secs % 60 == 0) {
|
||||
secs /= 60;
|
||||
sprintf(buf, "%ld minute%s", (long)secs, secs == 1 ? "" : "s");
|
||||
sprintf(buf, "%llu minute%s", secs, secs == 1 ? "" : "s");
|
||||
} else
|
||||
sprintf(buf, "%ld second%s", (long)secs, secs == 1 ? "" : "s");
|
||||
sprintf(buf, "%llu second%s", secs, secs == 1 ? "" : "s");
|
||||
return (buf);
|
||||
}
|
||||
|
||||
@ -745,7 +795,7 @@ cvtstoa(time_t secs)
|
||||
* Convert ASCII input times to seconds.
|
||||
*/
|
||||
int
|
||||
cvtatos(time_t period, char *units, time_t *seconds)
|
||||
cvtatos(u_int64_t period, char *units, u_int64_t *seconds)
|
||||
{
|
||||
|
||||
if (bcmp(units, "second", 6) == 0)
|
||||
@ -757,13 +807,60 @@ cvtatos(time_t period, char *units, time_t *seconds)
|
||||
else if (bcmp(units, "day", 3) == 0)
|
||||
*seconds = period * 24 * 60 * 60;
|
||||
else {
|
||||
printf("%s: bad units, specify %s\n", units,
|
||||
warnx("%s: bad units, specify %s\n", units,
|
||||
"days, hours, minutes, or seconds");
|
||||
return (0);
|
||||
}
|
||||
return (1);
|
||||
}
|
||||
|
||||
/*
|
||||
* Convert a limit to number of disk blocks.
|
||||
*/
|
||||
u_int64_t
|
||||
cvtval(u_int64_t limit, char units)
|
||||
{
|
||||
|
||||
switch(units) {
|
||||
case 'B':
|
||||
case 'b':
|
||||
limit = btodb(limit);
|
||||
break;
|
||||
case '\0': /* historic behavior */
|
||||
case ',': /* historic behavior */
|
||||
case ')': /* historic behavior */
|
||||
case 'K':
|
||||
case 'k':
|
||||
limit *= btodb(1024);
|
||||
break;
|
||||
case 'M':
|
||||
case 'm':
|
||||
limit *= btodb(1048576);
|
||||
break;
|
||||
case 'G':
|
||||
case 'g':
|
||||
limit *= btodb(1073741824);
|
||||
break;
|
||||
case 'T':
|
||||
case 't':
|
||||
limit *= btodb(1099511627776);
|
||||
break;
|
||||
case 'P':
|
||||
case 'p':
|
||||
limit *= btodb(1125899906842624);
|
||||
break;
|
||||
case 'E':
|
||||
case 'e':
|
||||
limit *= btodb(1152921504606846976);
|
||||
break;
|
||||
default:
|
||||
warnx("%llu%c: unknown units, specify K, M, G, T, P, or E\n",
|
||||
limit, units);
|
||||
break;
|
||||
}
|
||||
return (limit);
|
||||
}
|
||||
|
||||
/*
|
||||
* Free a list of quotause structures.
|
||||
*/
|
||||
@ -833,6 +930,7 @@ hasquota(struct fstab *fs, int type, char **qfnamep)
|
||||
}
|
||||
if (statfs(fs->fs_file, &sfb) != 0) {
|
||||
warn("cannot statfs mount point %s", fs->fs_file);
|
||||
sleep(3);
|
||||
return (0);
|
||||
}
|
||||
if (strcmp(fs->fs_file, sfb.f_mntonname)) {
|
||||
|
Loading…
x
Reference in New Issue
Block a user