Changelog | 13 +++++ Makefile.in | 9 ++-- bylabel.c | 8 ++-- common.c | 4 +- common.h | 8 ++-- configure.in | 17 +++++++ edquota.8 | 4 +- edquota.c | 12 +++++- quot.c | 2 +- quota.1 | 43 ++++++++++++++---- quota.c | 17 +++++-- quotacheck.c | 14 ++++-- quotacheck_v2.c | 6 +- quotagrpadmins | 4 +- quotaio.c | 2 +- quotaio_v2.c | 2 +- quotaon.8 | 19 +++++--- quotaon.c | 14 ++++-- quotaon_xfs.c | 62 +++++++++++++++---------- quotaops.c | 29 +++++++----- quotastats.c | 7 ++- quotasys.c | 136 ++++++++++++++++++++++++++++++++++--------------------- quotasys.h | 6 ++- quotatab | 4 +- repquota.8 | 9 +++- repquota.c | 28 +++++++++-- rquota_svc.c | 2 +- warnquota.conf | 16 +++--- xqmstats.c | 3 +- 29 files changed, 331 insertions(+), 169 deletions(-) diff --git a/Changelog b/Changelog index 4e8e4bf..f6b6e37 100644 --- a/Changelog +++ b/Changelog @@ -1,3 +1,16 @@ +Changes in quota-tools from 3.14 to 3.15 +* pot.o is now compiled with CFLAGS (Ladislav Michnovic) +* use -fPIE for compilation when available (Jan Kara, Ladislav Michnovic) +* fixed some more problems XFS quotaon (Kouta Ooizumi, Jan Kara) +* fixed two mistakes in quotaon(8) manpage (Utako Kusaka) +* added option -A to quota(1) to report all NFS mountpoints (Jan Kara) +* fixed XFS handling to work with loopback mounted devices (Jan Kara) +* fixed mountpoints scanning to make XFS -x delete command work (Jan Kara) +* fixes of signed vs unsigned int issues (Jan Kara) +* fixed a format string bug in reporting of raw grace times in repquota (Jan Kara) +* added repquota(8) option for better parsable output (Jan Kara) +* fixed error handling in edquota(8) when creating tmp file (Jan Kara) + Changes in quota-tools from 3.13 to 3.14 * updated Polish translations (Jakub Bogusz) * print user/group names in error messages when cannot get quota information (Michal Marek, Jan Kara) diff --git a/Makefile.in b/Makefile.in index c4a1ecc..8846cb8 100644 --- a/Makefile.in +++ b/Makefile.in @@ -1,7 +1,7 @@ PROGS = quotacheck quotaon quota quot repquota warnquota quotastats xqmstats edquota setquota convertquota rpc.rquotad SOURCES = bylabel.c common.c convertquota.c edquota.c pot.c quot.c quota.c quotacheck.c quotacheck_v1.c quotacheck_v2.c quotaio.c quotaio_rpc.c quotaio_v1.c quotaio_v2.c quotaio_xfs.c quotaio_generic.c quotaon.c quotaon_xfs.c quotaops.c quotastats.c quotasys.c repquota.c rquota_client.c rquota_server.c rquota_svc.c setquota.c warnquota.c xqmstats.c svc_socket.c VERSIONDEF = -DQUOTA_VERSION=\"3.14\" -CFLAGS = @CFLAGS@ @EXT2_DIRECT@ -D_GNU_SOURCE -Wall -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 $(VERSIONDEF) +CFLAGS = @CFLAGS@ @DEFS@ @EXT2_DIRECT@ -Wall $(VERSIONDEF) EXT2LIBS = @EXT2LIBS@ RPCSRC = rquota.h rquota_xdr.c rquota_clnt.c LIBS = @LIBS@ @@ -44,7 +44,7 @@ LIBOBJS += @LIBMALLOC@ .PHONY: all clean clobber realclean pot mo inst_mo .%.d: %.c - set -e; $(CC) -MM -MG $(CPPFLAGS) $< | \ + set -e; $(CC) -MM -MG $(CPPFLAGS) $(CFLAGS) $< | \ sed 's/\($*\)\.o[ :]*/\1.o $@ : /g' > $@; \ [ -s $@ ] || rm -f $@ @@ -96,8 +96,8 @@ install: all @INSTMO@ -mkdir -p $(ROOTDIR)$(mandir)/man8 -$(INSTALL) -m 755 -d $(ROOTDIR)$(includedir)/rpcsvc -$(INSTALL) -m 644 rquota.h rquota.x $(ROOTDIR)$(includedir)/rpcsvc - -$(INSTALL) -s -m $(DEF_SBIN_MODE) quota $(ROOTDIR)$(bindir) - -$(INSTALL) -s -m $(DEF_SBIN_MODE) rpc.rquotad $(ROOTDIR)$(sbindir) + -$(INSTALL) -m $(DEF_SBIN_MODE) quota $(ROOTDIR)$(bindir) + -$(INSTALL) -m $(DEF_SBIN_MODE) rpc.rquotad $(ROOTDIR)$(sbindir) -$(INSTALL) -m $(DEF_MAN_MODE) *.1 $(ROOTDIR)$(mandir)/man1 -$(INSTALL) -m $(DEF_MAN_MODE) *.2 $(ROOTDIR)$(mandir)/man2 -$(INSTALL) -m $(DEF_MAN_MODE) *.3 $(ROOTDIR)$(mandir)/man3 @@ -131,7 +131,6 @@ rpc.rquotad: rquota_server.o rquota_svc.o svc_socket.o $(LIBOBJS) $(CC) $(LDFLAGS) -o $@ $^ $(LIBS) pot.o: pot.c pot.h - $(CC) $(CFLAGS) -c $< rquota.h: rquota.x $(RPCGEN) -h -o $@ $< diff --git a/bylabel.c b/bylabel.c index ebf3a9e..37d761a 100644 --- a/bylabel.c +++ b/bylabel.c @@ -90,7 +90,7 @@ static int get_label_uuid(const char *device, char **label, char *uuid) memcpy(uuid, e2sb.s_uuid, sizeof(e2sb.s_uuid)); namesize = sizeof(e2sb.s_volume_name); *label = smalloc(namesize + 1); - sstrncpy(*label, e2sb.s_volume_name, namesize); + sstrncpy(*label, (char *)e2sb.s_volume_name, namesize); rv = 0; } else if (lseek(fd, 0, SEEK_SET) == 0 @@ -100,7 +100,7 @@ static int get_label_uuid(const char *device, char **label, char *uuid) memcpy(uuid, xfsb.s_uuid, sizeof(xfsb.s_uuid)); namesize = sizeof(xfsb.s_fsname); *label = smalloc(namesize + 1); - sstrncpy(*label, xfsb.s_fsname, namesize); + sstrncpy(*label, (char *)xfsb.s_fsname, namesize); rv = 0; } else if (lseek(fd, 65536, SEEK_SET) == 65536 @@ -109,7 +109,7 @@ static int get_label_uuid(const char *device, char **label, char *uuid) memcpy(uuid, reisersb.s_uuid, sizeof(reisersb.s_uuid)); namesize = sizeof(reisersb.s_volume_name); *label = smalloc(namesize + 1); - sstrncpy(*label, reisersb.s_volume_name, namesize); + sstrncpy(*label, (char *)reisersb.s_volume_name, namesize); rv = 0; } close(fd); @@ -245,7 +245,7 @@ static char *get_spec_by_uuid(const char *s) uuid[i] = ((fromhex(s[0]) << 4) | fromhex(s[1])); s += 2; } - return get_spec_by_x(UUID, uuid); + return get_spec_by_x(UUID, (char *)uuid); bad_uuid: errstr(_("Found an invalid UUID: %s\n"), s); diff --git a/common.c b/common.c index a53728f..f1e8cfb 100644 --- a/common.c +++ b/common.c @@ -94,13 +94,13 @@ void *srealloc(void *ptr, size_t size) return ret; } -void sstrncpy(char *d, const char *s, int len) +void sstrncpy(char *d, const char *s, size_t len) { strncpy(d, s, len); d[len - 1] = 0; } -void sstrncat(char *d, const char *s, int len) +void sstrncat(char *d, const char *s, size_t len) { strncat(d, s, len); d[len - 1] = 0; diff --git a/common.h b/common.h index 2085571..28bd2f0 100644 --- a/common.h +++ b/common.h @@ -19,10 +19,10 @@ extern char *progname; /* Finish programs being */ -void die(int, char *, ...) __attribute__ ((__format__ (__printf__, 2, 3))); +void die(int, char *, ...) __attribute__((__noreturn__, __format__(__printf__, 2, 3))); /* Print an error */ -void errstr(char *, ...) __attribute__ ((__format__ (__printf__, 1, 2))); +void errstr(char *, ...) __attribute__((__format__(__printf__, 1, 2))); /* If use_syslog is called, all error reports using errstr() and die() are * written to syslog instead of stderr */ @@ -35,10 +35,10 @@ void *smalloc(size_t); void *srealloc(void *, size_t); /* Safe strncpy - always finishes string */ -void sstrncpy(char *, const char *, int); +void sstrncpy(char *, const char *, size_t); /* Safe strncat - always finishes string */ -void sstrncat(char *, const char *, int); +void sstrncat(char *, const char *, size_t); /* Safe version of strdup() */ char *sstrdup(const char *s); diff --git a/configure.in b/configure.in index 6177da2..951e6a0 100644 --- a/configure.in +++ b/configure.in @@ -2,9 +2,26 @@ dnl Process this file with autoconf to produce a configure script. AC_INIT(quota.c) dnl Checks for programs. +AC_GNU_SOURCE AC_PROG_CC AC_HEADER_STDC AC_PROG_INSTALL +AC_SYS_LARGEFILE + +dnl Check for compiler options +AC_MSG_CHECKING(whether compiler supports PIE) +oldCFLAGS="$CFLAGS" +CFLAGS="$CFLAGS -fPIE" +oldLDFLAGS="$LDFLAGS" +LDFLAGS="$LDFLAGS -pie" +AC_LINK_IFELSE([AC_LANG_PROGRAM([[]])], compilepie="yes") +if test "x$compilepie" != "xyes"; then + CFLAGS="$oldCFLAGS" + LDFLAGS="$oldLDFLAGS" + AC_MSG_RESULT(no) +else + AC_MSG_RESULT(yes) +fi dnl Checks for libraries. AC_ARG_ENABLE(ldapmail, [ --enable-ldapmail=[yes/no/try] Enable ldap mail address lookups [default=no].], diff --git a/edquota.8 b/edquota.8 index 320c00a..2c3c304 100644 --- a/edquota.8 +++ b/edquota.8 @@ -77,7 +77,7 @@ reads the temporary file and modifies the binary quota files to reflect the changes made. .LP The editor invoked is -.BR vi (1) +.BR vitmp (1) unless either the .SB EDITOR or the @@ -150,7 +150,7 @@ mounted filesystems table .PD .SH SEE ALSO .BR quota (1), -.BR vi (1), +.BR vitmp (1), .BR quotactl (2), .BR quotacheck (8), .BR quotaon (8), diff --git a/edquota.c b/edquota.c index c1ff914..9d654ee 100644 --- a/edquota.c +++ b/edquota.c @@ -251,7 +251,16 @@ int main(int argc, char **argv) strcpy(tmpfil, tmpdir); strcat(tmpfil, "/EdP.aXXXXXX"); tmpfd = mkstemp(tmpfil); - fchown(tmpfd, getuid(), getgid()); + if (tmpfd < 0) { + errstr(_("Cannot create temporary file: %s\n"), strerror(errno)); + ret = -1; + goto out; + } + if (fchown(tmpfd, getuid(), getgid()) < 0) { + errstr(_("Cannot change owner of temporary file: %s\n"), strerror(errno)); + ret = -1; + goto out; + } ret = 0; if (flags & FL_EDIT_PERIOD) { if (writetimes(handles, tmpfd) < 0) { @@ -318,6 +327,7 @@ int main(int argc, char **argv) freeprivs(curprivs); } } +out: if (dispose_handle_list(handles) == -1) ret = -1; diff --git a/quot.c b/quot.c index 2184f80..77701b5 100644 --- a/quot.c +++ b/quot.c @@ -339,7 +339,7 @@ static void acctXFS(xfs_bstat_t *p) static void checkXFS(const char *file, char *fsdir) { xfs_fsop_bulkreq_t bulkreq; - __s64 last = 0; + __u64 last = 0; __s32 count; int i; int sts; diff --git a/quota.1 b/quota.1 index 355649c..601dced 100644 --- a/quota.1 +++ b/quota.1 @@ -7,18 +7,25 @@ quota \- display disk usage and limits .B -F .I format-name ] [ -.BR -guvsilw \ | -.B q -] +.B -guqvswi +] [ +.BR -l \ | +[ +.BR -Q \ |\ -A +]] .br .B quota [ .B -F .I format-name ] [ -.BR -uvsilw \ | -.B q -] +.B -qvswi +] [ +.BR -l \ | +[ +.BR -Q \ |\ -A +]] +.B -u .IR user ... .br .B quota @@ -26,10 +33,24 @@ quota \- display disk usage and limits .B -F .I format-name ] [ -.BR -gvsilw \ | -.B q -] +.B -qvswi +] [ +.BR -l \ | +[ +.BR -Q \ |\ -A +]] +.B -g .IR group ... +.br +.B quota +[ +.B -F +.I format-name +] [ +.B -qvswugQ +] +.B -f +.IR filesystem ... .SH DESCRIPTION .B quota displays users' disk usage and limits. @@ -79,6 +100,10 @@ ignore mountpoints mounted by automounter .B -l, --local-only report quotas only on local filesystems (ie. ignore NFS mounted filesystems). .TP +.B -A, --all-nfs +report quotas for all NFS filesystems even if they report to be on the same +device. +.TP .B -q, --quiet Print a more terse message, containing only information diff --git a/quota.c b/quota.c index 0126059..221ccb8 100644 --- a/quota.c +++ b/quota.c @@ -43,6 +43,7 @@ #include #include #include +#include #include #include #include @@ -71,6 +72,7 @@ #define FL_NOWRAP 256 #define FL_FSLIST 512 #define FL_NUMNAMES 1024 +#define FL_NFSALL 2048 int flags, fmt = -1; char *progname; @@ -78,9 +80,9 @@ char *progname; void usage(void) { errstr( "%s%s%s%s%s", - _("Usage: quota [-guqvsw] [-l | -Q] [-i] [-F quotaformat]\n"), - _("\tquota [-qvsw] [-l | -Q] [-i] [-F quotaformat] -u username ...\n"), - _("\tquota [-qvsw] [-l | -Q] [-i] [-F quotaformat] -g groupname ...\n"), + _("Usage: quota [-guqvsw] [-l | [-Q | -A]] [-i] [-F quotaformat]\n"), + _("\tquota [-qvsw] [-l | [-Q | -A]] [-i] [-F quotaformat] -u username ...\n"), + _("\tquota [-qvsw] [-l | [-Q | -A]] [-i] [-F quotaformat] -g groupname ...\n"), _("\tquota [-qvswugQ] [-F quotaformat] -f filesystem ...\n"), _("\n\ -u, --user display quota for user\n\ @@ -97,6 +99,7 @@ void usage(void) -i, --no-autofs do not query autofs mountpoints\n\ -F, --format=formatname display quota of a specific format\n\ -f, --filesystem-list display quota information only for given filesystems\n\ +-A, --nfs-all display quota for all NFS mountpoints\n\ -h, --help display this help message and exit\n\ -V, --version display version information and exit\n\n")); fprintf(stderr, _("Bugs to: %s\n"), MY_EMAIL); @@ -126,7 +129,7 @@ int showquotas(int type, qid_t id, int mntcnt, char **mnt) time(&now); id2name(id, type, name); - handles = create_handle_list(mntcnt, mnt, type, fmt, IOI_READONLY, ((flags & FL_NOAUTOFS) ? MS_NO_AUTOFS : 0) | ((flags & FL_LOCALONLY) ? MS_LOCALONLY : 0)); + handles = create_handle_list(mntcnt, mnt, type, fmt, IOI_READONLY, ((flags & FL_NOAUTOFS) ? MS_NO_AUTOFS : 0) | ((flags & FL_LOCALONLY) ? MS_LOCALONLY : 0) | ((flags & FL_NFSALL) ? MS_NFS_ALL : 0)); qlist = getprivs(id, handles, !!(flags & FL_QUIETREFUSE)); over = 0; for (q = qlist; q; q = q->dq_next) { @@ -229,13 +232,14 @@ int main(int argc, char **argv) { "format", 1, NULL, 'F' }, { "no-wrap", 0, NULL, 'w' }, { "filesystem-list", 0, NULL, 'f' }, + { "all-nfs", 0, NULL, 'A' }, { NULL, 0, NULL, 0 } }; gettexton(); progname = basename(argv[0]); - while ((ret = getopt_long(argc, argv, "guqvsVliQF:wf", long_opts, NULL)) != -1) { + while ((ret = getopt_long(argc, argv, "guqvsVliQF:wfA", long_opts, NULL)) != -1) { switch (ret) { case 'g': flags |= FL_GROUP; @@ -274,6 +278,9 @@ int main(int argc, char **argv) case 'f': flags |= FL_FSLIST; break; + case 'A': + flags |= FL_NFSALL; + break; case 'V': version(); exit(0); diff --git a/quotacheck.c b/quotacheck.c index 1f11296..a12c112 100644 --- a/quotacheck.c +++ b/quotacheck.c @@ -3,7 +3,7 @@ * Utility to check disk quotas * * Some parts of this utility are copied from old quotacheck by - * Marco van Wieringen and Edvard Tuinder + * Marco van Wieringen and Edvard Tuinder * * New quota format implementation - Jan Kara - Sponsored by SuSE CR */ @@ -516,7 +516,10 @@ static int scan_dir(char *pathname) if ((dp = opendir(pathname)) == (DIR *) NULL) die(2, _("\nCan open directory %s: %s\n"), pathname, strerror(errno)); - chdir(pathname); + if (chdir(pathname)) { + errstr(_("Cannot chdir to %s: %s\n"), pathname, strerror(errno)); + goto out; + } if (flags & FL_VERYVERBOSE) blit(pathname); while ((de = readdir(dp)) != (struct dirent *)NULL) { @@ -601,7 +604,8 @@ int ask_yn(char *q, int def) printf("%s [%c]: ", q, def ? 'y' : 'n'); fflush(stdout); while (1) { - fgets(a, sizeof(a)-1, stdin); + if (!fgets(a, sizeof(a)-1, stdin)) + a[0] = '\0'; if (a[0] == '\n') return def; if (!strcasecmp(a, "y\n")) @@ -1039,11 +1043,11 @@ static void check_all(void) continue; } cfmt = fmt; - if (uwant && hasquota(mnt, USRQUOTA)) + if (uwant && hasquota(mnt, USRQUOTA, 0)) ucheck = 1; else ucheck = 0; - if (gwant && hasquota(mnt, GRPQUOTA)) + if (gwant && hasquota(mnt, GRPQUOTA, 0)) gcheck = 1; else gcheck = 0; diff --git a/quotacheck_v2.c b/quotacheck_v2.c index fe607a1..f567a2a 100644 --- a/quotacheck_v2.c +++ b/quotacheck_v2.c @@ -223,7 +223,7 @@ static void check_read_blk(int fd, uint blk, dqbuf_t buf) } } -static int check_tree_ref(uint blk, uint ref, uint blocks, int check_use, uint * corrupted, +static int check_tree_ref(uint blk, uint ref, uint blocks, int check_use, int * corrupted, uint * lblk) { if (check_blkref(ref, blocks) < 0) { @@ -239,7 +239,7 @@ static int check_tree_ref(uint blk, uint ref, uint blocks, int check_use, uint * } /* Check block with structures */ -static int check_data_blk(int fd, uint blk, int type, uint blocks, uint * corrupted, uint * lblk) +static int check_data_blk(int fd, uint blk, int type, uint blocks, int * corrupted, uint * lblk) { dqbuf_t buf = getdqbuf(); struct v2_disk_dqdbheader *head = (struct v2_disk_dqdbheader *)buf; @@ -265,7 +265,7 @@ static int check_data_blk(int fd, uint blk, int type, uint blocks, uint * corrup } /* Check one tree block */ -static int check_tree_blk(int fd, uint blk, int depth, int type, uint blocks, uint * corrupted, +static int check_tree_blk(int fd, uint blk, int depth, int type, uint blocks, int * corrupted, uint * lblk) { dqbuf_t buf = getdqbuf(); diff --git a/quotagrpadmins b/quotagrpadmins index a1f2f46..e3d5549 100644 --- a/quotagrpadmins +++ b/quotagrpadmins @@ -4,5 +4,5 @@ # Comments begin with hash in the beginning of the line # In this file you specify users responsible for space used by the group -users: root -mygroup: chief +# users: root +# mygroup: chief diff --git a/quotaio.c b/quotaio.c index b194666..bb87c4e 100644 --- a/quotaio.c +++ b/quotaio.c @@ -42,7 +42,7 @@ struct quota_handle *init_io(struct mntent *mnt, int type, int fmt, int flags) struct quota_handle *h = smalloc(sizeof(struct quota_handle)); const char *mnt_fsname = NULL; - if (!hasquota(mnt, type)) + if (!hasquota(mnt, type, 0)) goto out_handle; if (!(mnt_fsname = get_device_name(mnt->mnt_fsname))) goto out_handle; diff --git a/quotaio_v2.c b/quotaio_v2.c index bf4aed0..39d0517 100644 --- a/quotaio_v2.c +++ b/quotaio_v2.c @@ -471,7 +471,7 @@ static int do_insert_tree(struct quota_handle *h, struct dquot *dquot, uint * tr /* Wrapper for inserting quota structure into tree */ static inline void dq_insert_tree(struct quota_handle *h, struct dquot *dquot) { - int tmp = V2_DQTREEOFF; + uint tmp = V2_DQTREEOFF; if (do_insert_tree(h, dquot, &tmp, 0) < 0) die(2, _("Cannot write quota (id %u): %s\n"), (uint) dquot->dq_id, strerror(errno)); diff --git a/quotaon.8 b/quotaon.8 index 3b199dd..c15d13d 100644 --- a/quotaon.8 +++ b/quotaon.8 @@ -3,7 +3,7 @@ .SH NAME quotaon, quotaoff \- turn filesystem quotas on and off .SH SYNOPSIS -.B /usr/sbin/quotaon +.B /sbin/quotaon [ .B \-vugfp ] [ @@ -12,7 +12,7 @@ quotaon, quotaoff \- turn filesystem quotas on and off ] .IR filesystem .\|.\|. .br -.B /usr/sbin/quotaon +.B /sbin/quotaon [ .B \-avugfp ] [ @@ -20,7 +20,7 @@ quotaon, quotaoff \- turn filesystem quotas on and off .I format-name ] .LP -.B /usr/sbin/quotaoff +.B /sbin/quotaoff [ .B \-vugp ] @@ -30,7 +30,7 @@ quotaon, quotaoff \- turn filesystem quotas on and off ] .IR filesystem .\|.\|. .br -.B /usr/sbin/quotaoff +.B /sbin/quotaoff [ .B \-avugp ] @@ -152,7 +152,7 @@ ignored for other filesystem types. It can only be used on a filesystem with quota previously turned off. .TP .B -x, --xfs-command enforce -Switch off limit enforcement for XFS filesystems (perform +Switch on/off limit enforcement for XFS filesystems (perform quota accounting only). This option is only applicable to XFS, and is silently ignored for other filesystem types. @@ -172,15 +172,18 @@ boot option. .PP To turn off quota limit enforcement on any XFS filesystem, first make sure that quota accounting and enforcement are both turned on using -.BR "repquota -s" . +.B "repquota -v" +.IR filesystem . Then, use -.B "quotaoff -vo" +.B "quotaoff -v +.I filesystem to disable limit enforcement. This may be done while the filesystem is mounted. .PP Turning on quota limit enforcement on an XFS filesystem is achieved using -.BR "quotaon -v" . +.B "quotaon -v" +.IR filesystem . This may be done while the filesystem is mounted. .SH FILES .PD 0 diff --git a/quotaon.c b/quotaon.c index 8d3034f..98a8124 100644 --- a/quotaon.c +++ b/quotaon.c @@ -174,7 +174,7 @@ static int newstate(struct mntent *mnt, int type, char *extra) ret = xfs_newstate(mnt, type, extra, sflags); } else { - if (!hasquota(mnt, type)) + if (!hasquota(mnt, type, 0)) return 0; usefmt = get_qf_name(mnt, type, fmt == -1 ? kernel_formats : (1 << fmt), NF_FORMAT, &extra); if (usefmt < 0) { @@ -234,6 +234,12 @@ static int quotaonoff(char *quotadev, char *quotadir, char *quotafile, int type, if (kernel_iface == IFACE_GENERIC) { qcmd = QCMD(Q_QUOTAON, type); kqf = util2kernfmt(fmt); + if ((QFMT_VFS_OLD == kqf) && + system("/sbin/modprobe -k quota_v1")) + ; /* ignore return code */ + else if ((QFMT_VFS_V0 == kqf) && + system("/sbin/modprobe -k quota_v2")) + ; /* ignore return code */ } else { qcmd = QCMD(Q_6_5_QUOTAON, type); @@ -301,7 +307,7 @@ int v1_newstate(struct mntent *mnt, int type, char *file, int flags) return 1; if ((flags & STATEFLAG_OFF) && hasmntopt(mnt, MNTOPT_RSQUASH)) errs += quotarsquashonoff(dev, type, flags); - if (hasquota(mnt, type)) + if (hasquota(mnt, type, 0)) errs += quotaonoff((char *)dev, mnt->mnt_dir, file, type, QF_VFSOLD, flags); if ((flags & STATEFLAG_ON) && hasmntopt(mnt, MNTOPT_RSQUASH)) errs += quotarsquashonoff(dev, type, flags); @@ -319,7 +325,7 @@ int v2_newstate(struct mntent *mnt, int type, char *file, int flags) if (!dev) return 1; - if (hasquota(mnt, type)) + if (hasquota(mnt, type, 0)) errs = quotaonoff((char *)dev, mnt->mnt_dir, file, type, QF_VFSV0, flags); free((char *)dev); return errs; @@ -346,7 +352,7 @@ int main(int argc, char **argv) else if (!kernel_formats) errstr(_("Warning: No quota format detected in the kernel.\n")); - if (init_mounts_scan(mntcnt, mntpoints, 0) < 0) + if (init_mounts_scan(mntcnt, mntpoints, MS_XFS_DISABLED) < 0) return 1; while ((mnt = get_next_mount())) { if (nfs_fstype(mnt->mnt_type)) { diff --git a/quotaon_xfs.c b/quotaon_xfs.c index a9aed6f..5707619 100644 --- a/quotaon_xfs.c +++ b/quotaon_xfs.c @@ -21,10 +21,11 @@ * Ensure we don't attempt to go into a dodgey state. */ -static int xfs_state_check(int qcmd, int type, int flags, char *dev, int roothack, int *xopts) +static int xfs_state_check(int qcmd, int type, int flags, char *dev, int roothack, int xopts) { struct xfs_mem_dqinfo info; int state; + char *acctstr = ""; /* we never want to operate via -a in XFS quota */ if (flags & STATEFLAG_ALL) @@ -57,13 +58,11 @@ static int xfs_state_check(int qcmd, int type, int flags, char *dev, int roothac return 1; case Q_XFS_QUOTAON: if (roothack) { - *xopts |= (type == USRQUOTA) ? - XFS_QUOTA_UDQ_ACCT : XFS_QUOTA_GDQ_ACCT; printf(_("Enabling %s quota on root filesystem" " (reboot to take effect)\n"), type2name(type)); return 1; } - errstr(_("Enable XFS %s quota during mount\n"), + errstr(_("Enable XFS %s quota accounting during mount\n"), type2name(type)); return -1; case Q_XFS_QUOTAOFF: @@ -79,20 +78,26 @@ static int xfs_state_check(int qcmd, int type, int flags, char *dev, int roothac return -1; case Q_XFS_QUOTAON: if (roothack) { - *xopts |= (type == USRQUOTA) ? - XFS_QUOTA_UDQ_ACCT : XFS_QUOTA_GDQ_ACCT; printf(_("Enabling %s quota on root filesystem" " (reboot to take effect)\n"), type2name(type)); return 1; } - printf(_("Enabling %s quota accounting on %s\n"), type2name(type), dev); - *xopts |= (type == USRQUOTA) ? XFS_QUOTA_UDQ_ACCT : XFS_QUOTA_GDQ_ACCT; - return 1; + if (xopts & XFS_QUOTA_UDQ_ENFD || xopts & XFS_QUOTA_GDQ_ENFD) { + printf(_("Enabling %s quota enforcement on %s\n"), type2name(type), dev); + return 1; + } + errstr(_("Already accounting %s quota on %s\n"), + type2name(type), dev); + return -1; case Q_XFS_QUOTAOFF: - printf(_("Disabling %s quota accounting on %s\n"), - type2name(type), dev); - *xopts |= (type == USRQUOTA) ? XFS_QUOTA_UDQ_ACCT : XFS_QUOTA_GDQ_ACCT; - return 1; + if (xopts & XFS_QUOTA_UDQ_ACCT || xopts & XFS_QUOTA_GDQ_ACCT) { + printf(_("Disabling %s quota accounting on %s\n"), + type2name(type), dev); + return 1; + } + errstr(_("Quota enforcement already disabled for %s on %s\n"), + type2name(type), dev); + return -1; } break; @@ -100,7 +105,7 @@ static int xfs_state_check(int qcmd, int type, int flags, char *dev, int roothac switch (qcmd) { case Q_XFS_QUOTARM: errstr(_("Cannot delete %s quota on %s - " - "switch quota enforcement off first\n"), + "switch quota enforcement and accounting off first\n"), type2name(type), dev); return -1; case Q_XFS_QUOTAON: @@ -108,9 +113,16 @@ static int xfs_state_check(int qcmd, int type, int flags, char *dev, int roothac type2name(type), dev); return -1; case Q_XFS_QUOTAOFF: - printf(_("Disabling %s quota enforcement on %s\n"), - type2name(type), dev); - *xopts |= (type == USRQUOTA) ? XFS_QUOTA_UDQ_ENFD : XFS_QUOTA_GDQ_ENFD; + if (xopts == XFS_QUOTA_UDQ_ACCT || xopts == XFS_QUOTA_GDQ_ACCT) { + errstr(_("Cannot switch off %s quota" + "accounting on %s when enforcement is on\n"), + type2name(type), dev); + return -1; + } + if (xopts & XFS_QUOTA_UDQ_ACCT || xopts & XFS_QUOTA_GDQ_ACCT) + acctstr = _("and accounting "); + printf(_("Disabling %s quota enforcement %son %s\n"), + type2name(type), acctstr, dev); return 1; } break; @@ -119,7 +131,7 @@ static int xfs_state_check(int qcmd, int type, int flags, char *dev, int roothac return -1; } -static int xfs_onoff(char *dev, int type, int flags, int roothack, int *xopts) +static int xfs_onoff(char *dev, int type, int flags, int roothack, int xopts) { int qoff, qcmd, check; @@ -129,7 +141,7 @@ static int xfs_onoff(char *dev, int type, int flags, int roothack, int *xopts) if (check != 1) return (check < 0); - if (quotactl(QCMD(qcmd, type), dev, 0, (void *)xopts) < 0) { + if (quotactl(QCMD(qcmd, type), dev, 0, (void *)&xopts) < 0) { errstr(_("quotactl on %s: %s\n"), dev, strerror(errno)); return 1; } @@ -140,7 +152,7 @@ static int xfs_onoff(char *dev, int type, int flags, int roothack, int *xopts) return 0; } -static int xfs_delete(char *dev, int type, int flags, int roothack, int *xopts) +static int xfs_delete(char *dev, int type, int flags, int roothack, int xopts) { int qcmd, check; @@ -149,7 +161,7 @@ static int xfs_delete(char *dev, int type, int flags, int roothack, int *xopts) if (check != 1) return (check < 0); - if (quotactl(QCMD(qcmd, type), dev, 0, (void *)xopts) < 0) { + if (quotactl(QCMD(qcmd, type), dev, 0, (void *)&xopts) < 0) { errstr(_("Failed to delete quota: %s\n"), strerror(errno)); return 1; @@ -199,22 +211,22 @@ int xfs_newstate(struct mntent *mnt, int type, char *xarg, int flags) xopts |= (type == USRQUOTA) ? (XFS_QUOTA_UDQ_ACCT | XFS_QUOTA_UDQ_ENFD) : (XFS_QUOTA_GDQ_ACCT | XFS_QUOTA_GDQ_ENFD); - err = xfs_onoff((char *)dev, type, flags, roothack, &xopts); + err = xfs_onoff((char *)dev, type, flags, roothack, xopts); } else if (strcmp(xarg, "account") == 0) { /* only useful if we want root accounting only */ if (!roothack || !(flags & STATEFLAG_ON)) goto done; xopts |= (type == USRQUOTA) ? XFS_QUOTA_UDQ_ACCT : XFS_QUOTA_GDQ_ACCT; - err = xfs_onoff((char *)dev, type, flags, roothack, &xopts); + err = xfs_onoff((char *)dev, type, flags, roothack, xopts); } else if (strcmp(xarg, "enforce") == 0) { xopts |= (type == USRQUOTA) ? XFS_QUOTA_UDQ_ENFD : XFS_QUOTA_GDQ_ENFD; - err = xfs_onoff((char *)dev, type, flags, roothack, &xopts); + err = xfs_onoff((char *)dev, type, flags, roothack, xopts); } else if (strcmp(xarg, "delete") == 0) { xopts |= (type == USRQUOTA) ? XFS_USER_QUOTA : XFS_GROUP_QUOTA; - err = xfs_delete((char *)dev, type, flags, roothack, &xopts); + err = xfs_delete((char *)dev, type, flags, roothack, xopts); } else die(1, _("Invalid argument \"%s\"\n"), xarg); diff --git a/quotaops.c b/quotaops.c index 868279c..9bd09c8 100644 --- a/quotaops.c +++ b/quotaops.c @@ -97,8 +97,8 @@ struct dquot *getprivs(qid_t id, struct quota_handle **handles, int quiet) int j, ngroups; uid_t euid; gid_t gidset[NGROUPS], *gidsetp; - char name[MAXNAMELEN]; #endif + char name[MAXNAMELEN]; for (i = 0; handles[i]; i++) { #if defined(BSD_BEHAVIOUR) @@ -154,9 +154,12 @@ struct dquot *getprivs(qid_t id, struct quota_handle **handles, int quiet) if (!(q = handles[i]->qh_ops->read_dquot(handles[i], id))) { /* If rpc.rquotad is not running filesystem might be just without quotas... */ if (errno != ENOENT && (errno != ECONNREFUSED || !quiet)) { + const char *err_text = strerror(errno); + id2name(id, handles[i]->qh_type, name); - errstr(_("error while getting quota from %s for %s (id %u): %s\n"), - handles[i]->qh_quotadev, name, id, strerror(errno)); + errstr(_("error while getting %s quota on %s for %s [id %u]: %s\n"), + type2name(handles[i]->qh_type), + handles[i]->qh_quotadev, name, id, err_text); } continue; } @@ -218,7 +221,7 @@ int editprivs(char *tmpfile) setuid(getuid()); if (!(ed = getenv("VISUAL"))) if (!(ed = getenv("EDITOR"))) - ed = _PATH_VI; + ed = "/bin/vitmp"; i = 0; ed = actp = sstrdup(ed); while (actp) { @@ -253,9 +256,9 @@ int writeprivs(struct dquot *qlist, int outfd, char *name, int quotatype) struct dquot *q; FILE *fd; - ftruncate(outfd, 0); - lseek(outfd, 0, SEEK_SET); - if (!(fd = fdopen(dup(outfd), "w"))) + if (ftruncate(outfd, 0) || + lseek(outfd, 0, SEEK_SET) || + !(fd = fdopen(dup(outfd), "w"))) die(1, _("Cannot duplicate descriptor of file to write to: %s\n"), strerror(errno)); #if defined(ALT_FORMAT) @@ -438,9 +441,9 @@ int writeindividualtimes(struct dquot *qlist, int outfd, char *name, int quotaty time_t now; char btimestr[MAXTIMELEN], itimestr[MAXTIMELEN]; - ftruncate(outfd, 0); - lseek(outfd, 0, SEEK_SET); - if (!(fd = fdopen(dup(outfd), "w"))) + if (ftruncate(outfd, 0) || + lseek(outfd, 0, SEEK_SET) || + !(fd = fdopen(dup(outfd), "w"))) die(1, _("Cannot duplicate descriptor of file to write to: %s\n"), strerror(errno)); fprintf(fd, _("Times to enforce softlimit for %s %s (%cid %d):\n"), @@ -540,9 +543,9 @@ int writetimes(struct quota_handle **handles, int outfd) if (!handles[0]) return 0; - ftruncate(outfd, 0); - lseek(outfd, 0, SEEK_SET); - if ((fd = fdopen(dup(outfd), "w")) == NULL) + if (ftruncate(outfd, 0) || + lseek(outfd, 0, SEEK_SET) || + !(fd = fdopen(dup(outfd), "w"))) die(1, _("Cannot duplicate descriptor of file to edit: %s\n"), strerror(errno)); #if defined(ALT_FORMAT) diff --git a/quotastats.c b/quotastats.c index e8498ff..95aef84 100644 --- a/quotastats.c +++ b/quotastats.c @@ -45,10 +45,13 @@ static int get_proc_num(char *name) sstrncat(namebuf, name, PATH_MAX); if (!(f = fopen(namebuf, "r"))) { - errstr(_("Cannot read stat file %s: %s\n"), namebuf, strerror(errno)); + errstr(_("Cannot read stat file %s: %m\n"), namebuf); return -1; } - fscanf(f, "%d", &ret); + if (fscanf(f, "%d", &ret) < 0) { + errstr(_("Failed to read file %s: %m\n"), namebuf); + ret = -1; + } fclose(f); return ret; } diff --git a/quotasys.c b/quotasys.c index a62f79a..a8e2e1b 100644 --- a/quotasys.c +++ b/quotasys.c @@ -366,10 +366,10 @@ void space2str(qsize_t space, char *buf, int format) if (format) for (i = 3; i > 0; i--) if (space >= (1LL << (QUOTABLOCK_BITS*i))*100) { - sprintf(buf, "%Lu%c", (space+(1 << (QUOTABLOCK_BITS*i))-1) >> (QUOTABLOCK_BITS*i), suffix[i]); + sprintf(buf, "%Lu%c", (unsigned long long)(space+(1 << (QUOTABLOCK_BITS*i))-1) >> (QUOTABLOCK_BITS*i), suffix[i]); return; } - sprintf(buf, "%Lu", space); + sprintf(buf, "%Lu", (unsigned long long)space); } /* @@ -390,21 +390,85 @@ void number2str(unsigned long long num, char *buf, int format) sprintf(buf, "%Lu", num); } +/* Return if given option has nonempty argument */ +static char *hasmntoptarg(struct mntent *mnt, char *opt) +{ + char *p = hasmntopt(mnt, opt); + + if (!p) + return NULL; + p += strlen(opt); + if (*p == '=' && p[1] != ',') + return p+1; + return NULL; +} + +static char *get_loop_device_name(struct mntent *mnt, dev_t *dev) +{ + char *opt; + + if (!(opt = hasmntoptarg(mnt, MNTOPT_LOOP))) + return NULL; + + char loopdev[PATH_MAX]; + unsigned i; + + /* Copy the device name */ + for (i = 0; *opt && *opt != ',' && i < sizeof(loopdev)-1; ++opt, ++i) + loopdev[i] = *opt; + loopdev[i] = 0; + + struct stat st; + if (stat(loopdev, &st) < 0) { + errstr(_("Cannot stat() loopback device %s: %s\n"), loopdev, strerror(errno)); + return NULL; + } + if (!S_ISBLK(st.st_mode)) { + errstr(_("Loopback device %s isn't block device!\n"), loopdev); + return NULL; + } + if (dev) + *dev = st.st_rdev; + return sstrdup(loopdev); +} + /* * Check for XFS filesystem with quota accounting enabled */ -static int hasxfsquota(struct mntent *mnt, int type) +static int hasxfsquota(struct mntent *mnt, int type, int flags) { - int ret = 0; + int rc, ret = 0; u_int16_t sbflags; struct xfs_mem_dqinfo info; - const char *dev = get_device_name(mnt->mnt_fsname); + const char *dev; + char *opt, *endopt; + + if (flags & MS_XFS_DISABLED) + return 1; + dev = get_device_name(mnt->mnt_fsname); if (!dev) - return ret; + return 0; + /* Loopback mounted device with a loopback device in the arguments? */ + if ((opt = hasmntopt(mnt, MNTOPT_LOOP)) && (opt = strchr(opt, '='))) { + free((char *)dev); + endopt = strchr(opt+1, ','); + if (!endopt) + dev = strdup(opt+1); + else + dev = strndup(opt+1, endopt-opt-1); + if (!dev) + return 0; + } memset(&info, 0, sizeof(struct xfs_mem_dqinfo)); - if (!quotactl(QCMD(Q_XFS_GETQSTAT, type), dev, 0, (void *)&info)) { + rc = quotactl(QCMD(Q_XFS_GETQSTAT, type), dev, 0, (void *)&info); + if (rc && errno == ENOTBLK) { + free((char *)dev); + if ((dev = get_loop_device_name(mnt, NULL))) + rc = quotactl(QCMD(Q_XFS_GETQSTAT, type), dev, 0, (void *)&info); + } + if (!rc) { sbflags = (info.qs_flags & 0xff00) >> 8; if (type == USRQUOTA && (info.qs_flags & XFS_QUOTA_UDQ_ACCT)) ret = 1; @@ -428,29 +492,16 @@ static int hasxfsquota(struct mntent *mnt, int type) return ret; } -/* Return if given option has nonempty argument */ -char *hasmntoptarg(struct mntent *mnt, char *opt) -{ - char *p = hasmntopt(mnt, opt); - - if (!p) - return NULL; - p += strlen(opt); - if (*p == '=' && p[1] != ',') - return p+1; - return NULL; -} - /* * Check to see if a particular quota is to be enabled (filesystem mounted with proper option) */ -int hasquota(struct mntent *mnt, int type) +int hasquota(struct mntent *mnt, int type, int flags) { if (!correct_fstype(mnt->mnt_type) || hasmntopt(mnt, MNTOPT_NOQUOTA)) return 0; if (!strcmp(mnt->mnt_type, MNTTYPE_XFS)) - return hasxfsquota(mnt, type); + return hasxfsquota(mnt, type, flags); if (nfs_fstype(mnt->mnt_type)) /* NFS always has quota or better there is no good way how to detect it */ return 1; @@ -873,7 +924,7 @@ static int cache_mnt_table(int flags) /* Further we are not interested in mountpoints without quotas and we don't want to touch them */ - if (!hasquota(mnt, USRQUOTA) && !hasquota(mnt, GRPQUOTA)) { + if (!hasquota(mnt, USRQUOTA, flags) && !hasquota(mnt, GRPQUOTA, flags)) { free((char *)devname); continue; } @@ -913,32 +964,9 @@ static int cache_mnt_table(int flags) free((char *)devname); continue; /* We just ignore bind mounts... */ } - else if ((opt = hasmntopt(mnt, MNTOPT_LOOP))) { - char loopdev[PATH_MAX]; - int i; - - if (!(opt = strchr(opt, '='))) { - errstr(_("Cannot find device of loopback mount in options for %s. Skipping.\n"), devname); - free((char *)devname); - continue; - } - /* Copy the device name */ - for (opt++, i = 0; *opt && i < sizeof(loopdev)-1 && *opt != ','; opt++, i++) - loopdev[i] = *opt; - loopdev[i] = 0; - if (stat(loopdev, &st) < 0) { /* Can't stat loopback device? */ - errstr(_("Cannot stat() loopback device %s: %s\n"), opt, strerror(errno)); - free((char *)devname); - continue; - } - if (!S_ISBLK(st.st_mode)) { - errstr(_("Loopback device %s is not block device!\n"), opt); - free((char *)devname); - continue; - } - dev = st.st_rdev; + else if ((opt = get_loop_device_name(mnt, &dev))) { free((char *)devname); - devname = sstrdup(loopdev); + devname = opt; } else { if (!S_ISBLK(st.st_mode) && !S_ISCHR(st.st_mode)) goto unsupporteddev; @@ -955,9 +983,13 @@ static int cache_mnt_table(int flags) continue; } if (nfs_fstype(mnt->mnt_type)) { - /* For network filesystems we must get device from root */ - dev = st.st_dev; - for (i = 0; i < mnt_entries_cnt && mnt_entries[i].me_dev != dev; i++); + if (!(flags & MS_NFS_ALL)) { + /* For network filesystems we must get device from root */ + dev = st.st_dev; + for (i = 0; i < mnt_entries_cnt && mnt_entries[i].me_dev != dev; i++); + } + else /* Always behave as if the device was unique */ + i = mnt_entries_cnt; } } if (i == mnt_entries_cnt) { /* New mounted device? */ @@ -1124,7 +1156,7 @@ restart: break; } if (i == mnt_entries_cnt) { - errstr(_("Mountpoint (or device) %s not found.\n"), sd->sd_name); + errstr(_("Mountpoint (or device) %s not found or has no quota enabled.\n"), sd->sd_name); goto restart; } *pos = i; diff --git a/quotasys.h b/quotasys.h index 578cdb5..642eed3 100644 --- a/quotasys.h +++ b/quotasys.h @@ -96,7 +96,8 @@ void space2str(qsize_t, char *, int); void number2str(unsigned long long, char *, int); /* Check to see if particular quota is to be enabled */ -int hasquota(struct mntent *mnt, int type); +/* Recognizes MS_XFS_DISABLED flag */ +int hasquota(struct mntent *mnt, int type, int flags); /* Flags for get_qf_name() */ #define NF_EXIST 1 /* Check whether file exists */ @@ -130,6 +131,9 @@ int kern_quota_on(const char *dev, int type, int fmt); #define MS_NO_AUTOFS 0x02 /* Ignore autofs mountpoints */ #define MS_QUIET 0x04 /* Be quiet with error reporting */ #define MS_LOCALONLY 0x08 /* Ignore nfs mountpoints */ +#define MS_XFS_DISABLED 0x10 /* Return also XFS mountpoints with quota disabled */ +#define MS_NFS_ALL 0x20 /* Don't filter NFS mountpoints on the same device */ + /* Initialize mountpoints scan */ int init_mounts_scan(int dcnt, char **dirs, int flags); diff --git a/quotatab b/quotatab index 0ba9957..380a6e6 100644 --- a/quotatab +++ b/quotatab @@ -5,5 +5,5 @@ # Comments begin with hash in the beginning of the line # Example of description -/dev/loop0: This is loopback device -/dev/hda4: Your home directory +#/dev/loop0: This is loopback device +#/dev/hda4: Your home directory diff --git a/repquota.8 b/repquota.8 index cb2f196..43a0652 100644 --- a/repquota.8 +++ b/repquota.8 @@ -5,7 +5,7 @@ repquota \- summarize quotas for a filesystem .SH SYNOPSIS .B /usr/sbin/repquota [ -.B \-vsiug +.B \-vspiug ] [ .B \-c | @@ -22,7 +22,7 @@ repquota \- summarize quotas for a filesystem .LP .B /usr/sbin/repquota [ -.B \-avtsiug +.B \-avtpsiug ] [ .B \-c | @@ -95,6 +95,11 @@ Don't resolve UIDs/GIDs to names. This can speedup printing a lot. Try to report used space, number of used inodes and limits in more appropriate units than the default ones. .TP +.B -p, --raw-grace +When user is in grace period, report time in seconds since epoch when his grace +time runs out (or has run out). Field is '0' when no grace time is in effect. +This is especially useful when parsing output by a script. +.TP .B -i, --no-autofs Ignore mountpoints mounted by automounter. .TP diff --git a/repquota.c b/repquota.c index ab57894..4420566 100644 --- a/repquota.c +++ b/repquota.c @@ -34,6 +34,7 @@ #define FL_NONAME 64 /* Don't translate ids to names */ #define FL_NOCACHE 128 /* Don't cache dquots before resolving */ #define FL_NOAUTOFS 256 /* Ignore autofs mountpoints */ +#define FL_RAWGRACE 512 /* Print grace times in seconds since epoch */ int flags, fmt = -1; char **mnt; @@ -50,6 +51,7 @@ static void usage(void) -g, --group display information about groups\n\ -s, --human-readable show numbers in human friendly units (MB, GB, ...)\n\ -t, --truncate-names truncate names to 8 characters\n\ +-p, --raw-grace print grace time in seconds since epoch\n\ -n, --no-names do not translate uid/gid to name\n\ -i, --no-autofs avoid autofs mountpoints\n\ -c, --batch-translation translate big number of ids at once\n\ @@ -73,6 +75,7 @@ static void parse_options(int argcnt, char **argstr) { "group", 0, NULL, 'g' }, { "help", 0, NULL, 'h' }, { "truncate-names", 0, NULL, 't' }, + { "raw-grace", 0, NULL, 'p' }, { "human-readable", 0, NULL, 's' }, { "no-names", 0, NULL, 'n' }, { "cache", 0, NULL, 'c' }, @@ -82,7 +85,7 @@ static void parse_options(int argcnt, char **argstr) { NULL, 0, NULL, 0 } }; - while ((ret = getopt_long(argcnt, argstr, "VavughtsncCiF:", long_opts, NULL)) != -1) { + while ((ret = getopt_long(argcnt, argstr, "VavughtspncCiF:", long_opts, NULL)) != -1) { switch (ret) { case '?': case 'h': @@ -105,6 +108,9 @@ static void parse_options(int argcnt, char **argstr) case 't': flags |= FL_TRUNCNAMES; break; + case 'p': + flags |= FL_RAWGRACE; + break; case 's': flags |= FL_SHORTNUMS; break; @@ -174,9 +180,15 @@ static void print(struct dquot *dquot, char *name) if (flags & FL_TRUNCNAMES) pname[PRINTNAMELEN] = 0; if (entry->dqb_bsoftlimit && toqb(entry->dqb_curspace) >= entry->dqb_bsoftlimit) - difftime2str(entry->dqb_btime, time); + if (flags & FL_RAWGRACE) + sprintf(time, "%Lu", (unsigned long long)entry->dqb_btime); + else + difftime2str(entry->dqb_btime, time); else - time[0] = 0; + if (flags & FL_RAWGRACE) + strcpy(time, "0"); + else + time[0] = 0; space2str(toqb(entry->dqb_curspace), numbuf[0], flags & FL_SHORTNUMS); space2str(entry->dqb_bsoftlimit, numbuf[1], flags & FL_SHORTNUMS); space2str(entry->dqb_bhardlimit, numbuf[2], flags & FL_SHORTNUMS); @@ -185,9 +197,15 @@ static void print(struct dquot *dquot, char *name) overlim(entry->dqb_curinodes, entry->dqb_isoftlimit, entry->dqb_ihardlimit), numbuf[0], numbuf[1], numbuf[2], time); if (entry->dqb_isoftlimit && entry->dqb_curinodes >= entry->dqb_isoftlimit) - difftime2str(entry->dqb_itime, time); + if (flags & FL_RAWGRACE) + sprintf(time, "%Lu", (unsigned long long)entry->dqb_itime); + else + difftime2str(entry->dqb_itime, time); else - time[0] = 0; + if (flags & FL_RAWGRACE) + strcpy(time, "0"); + else + time[0] = 0; number2str(entry->dqb_curinodes, numbuf[0], flags & FL_SHORTNUMS); number2str(entry->dqb_isoftlimit, numbuf[1], flags & FL_SHORTNUMS); number2str(entry->dqb_ihardlimit, numbuf[2], flags & FL_SHORTNUMS); diff --git a/rquota_svc.c b/rquota_svc.c index ce95710..f81199f 100644 --- a/rquota_svc.c +++ b/rquota_svc.c @@ -140,7 +140,7 @@ static void parse_options(int argc, char **argv) break; case 'p': port = strtol(optarg, &endptr, 0); - if (*endptr || port <= 0) { + if (*endptr || port <= 0 || port > 0xffff) { errstr(_("Illegal port number: %s\n"), optarg); show_help(); exit(1); diff --git a/warnquota.conf b/warnquota.conf index d80f7ae..3f13af1 100644 --- a/warnquota.conf +++ b/warnquota.conf @@ -4,16 +4,16 @@ # and even blank lines # values can be quoted: -MAIL_CMD = "/usr/my/sendmail/instead/sendmail -t" -FROM = "bas@localhost" +MAIL_CMD = "/usr/sbin/sendmail -t" +FROM = "root@localhost" # but they don't have to be: -SUBJECT = Hey, user, clean up your account! -CC_TO = "sysadm@localhost" +SUBJECT = NOTE: You are exceeding your allocatted disk space limits +CC_TO = "root@localhost" # If you set this variable CC will be used only when user has less than # specified grace time left (examples of possible times: 5 seconds, 1 minute, # 12 hours, 5 days) # CC_BEFORE = 2 days -SUPPORT = "support@myhost.com" +SUPPORT = "root@myhost.com" PHONE = "(123) 456-1111 or (222) 333-4444" # Text in the beginning of the mail (if not specified, default text is used) # This way text can be split to more lines @@ -21,11 +21,11 @@ PHONE = "(123) 456-1111 or (222) 333-4444" # The expressions %i, %h, %d, and %% are substituted for user/group name, # host name, domain name, and '%' respectively. For backward compatibility # %s behaves as %i but is deprecated. -MESSAGE = Hello user %i, I've noticed you use too much space\ - on my disk in %h.%d.|Delete your files on the following filesystems:| +MESSAGE = Your disk usage has exceeded the agreeded limits on %h.%d.|\ + Please delete any unnecessary files on the following filesystems:| # Text in the end of the mail (if not specified, default text using SUPPORT and PHONE # is created) -SIGNATURE = See you!| Your admin of %h| +SIGNATURE = root@%h.%d # Following text is used for mails about group exceeding quotas GROUP_MESSAGE = Hello, a group '%i' you're member of use too much space at %h.|\ I chose you to do the cleanup.|Delete group files on the following filesystems:| diff --git a/xqmstats.c b/xqmstats.c index 84e8edf..9054de0 100644 --- a/xqmstats.c +++ b/xqmstats.c @@ -38,7 +38,8 @@ int main(int argc, char **argv) } } while (!feof(stats)) { - fgets(buffer, 256, stats); + if (!fgets(buffer, 256, stats)) + continue; if (sscanf(buffer, "qm %u %u %u %u %u %u %u %u\n", &values[0], &values[1], &values[2], &values[3], &values[4], &values[5], &values[6], &values[7]) == 8)