Репозиторий Sisyphus
Последнее обновление: 1 октября 2023 | Пакетов: 18631 | Посещений: 37509491
en ru br
Репозитории ALT
S:4.06.0.7.100b-alt1
5.1: 3.14-alt1
4.1: 3.14-alt1
4.0: 3.14-alt1
3.0: 3.13-alt1
www.altlinux.org/Changes

Группа :: Система/Настройка/Прочее
Пакет: quota

 Главная   Изменения   Спек   Патчи   Sources   Загрузить   Gear   Bugs and FR  Repocop 

Патч: quota-3.14-alt1.patch
Скачать


 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 <sys/param.h>
 #include <getopt.h>
 #include <stdio.h>
+#include <stdlib.h>
 #include <pwd.h>
 #include <grp.h>
 #include <time.h>
@@ -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 <mvw@planets.elm.net> and Edvard Tuinder <ed@elm.ent>
+ *	Marco van Wieringen <mvw@planets.elm.net> and Edvard Tuinder <ed@elm.net>
  * 
  *	New quota format implementation - Jan Kara <jack@suse.cz> - 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)
 
дизайн и разработка: Vladimir Lettiev aka crux © 2004-2005, Andrew Avramenko aka liks © 2007-2008
текущий майнтейнер: Michael Shigorin