git: d019d36707d3 - stable/15 - quot: Rewrite -n mode input parser
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
Date: Wed, 19 Nov 2025 10:57:53 UTC
The branch stable/15 has been updated by des:
URL: https://cgit.FreeBSD.org/src/commit/?id=d019d36707d35a982d527f568dd68179f6f747b2
commit d019d36707d35a982d527f568dd68179f6f747b2
Author: Dag-Erling Smørgrav <des@FreeBSD.org>
AuthorDate: 2025-11-14 14:28:40 +0000
Commit: Dag-Erling Smørgrav <des@FreeBSD.org>
CommitDate: 2025-11-19 10:56:50 +0000
quot: Rewrite -n mode input parser
The existing parser was needlessly complicated and wildly inconsistent
in how it handled invalid input. Rewrite using getline() and treat
invalid input consistently: silently ignore lines that don't begin with
a number, and print a warning if the inode number is out of range.
PR: 290992
MFC after: 1 week
Reviewed by: obrien
Differential Revision: https://reviews.freebsd.org/D53726
(cherry picked from commit fa272a5276865a97b01823fe6546940eaaf1b164)
---
usr.sbin/quot/quot.8 | 3 ++-
usr.sbin/quot/quot.c | 47 +++++++++++++++++++++-------------------
usr.sbin/quot/tests/quot_test.sh | 19 ++++++++++++++++
3 files changed, 46 insertions(+), 23 deletions(-)
diff --git a/usr.sbin/quot/quot.8 b/usr.sbin/quot/quot.8
index 32e666e2a863..69c0a2d84b9b 100644
--- a/usr.sbin/quot/quot.8
+++ b/usr.sbin/quot/quot.8
@@ -27,7 +27,7 @@
.\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
.\" ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
.\"
-.Dd October 15, 2025
+.Dd November 13, 2025
.Dt QUOT 8
.Os
.Sh NAME
@@ -60,6 +60,7 @@ By default, all sizes are reported in 512-byte block counts.
Given a list of inodes (plus some optional data on each line)
in the standard input, for each file print out the owner (plus
the remainder of the input line).
+Lines that do not begin with a number are ignored.
This is traditionally used
in the pipe:
.Bd -literal -offset indent
diff --git a/usr.sbin/quot/quot.c b/usr.sbin/quot/quot.c
index 5dda36ac8499..d2f7646f7041 100644
--- a/usr.sbin/quot/quot.c
+++ b/usr.sbin/quot/quot.c
@@ -41,6 +41,7 @@
#include <errno.h>
#include <fcntl.h>
#include <fstab.h>
+#include <inttypes.h>
#include <libufs.h>
#include <mntopts.h>
#include <paths.h>
@@ -390,41 +391,43 @@ douser(int fd, struct fs *super)
static void
donames(int fd, struct fs *super)
{
- int c;
- ino_t maxino;
- uintmax_t inode;
union dinode *dp;
+ char *end, *line;
+ size_t cap;
+ ssize_t len;
+ intmax_t inode, maxino;
maxino = super->fs_ncg * super->fs_ipg - 1;
- /* first skip the name of the filesystem */
- while ((c = getchar()) != EOF && (c < '0' || c > '9'))
- while ((c = getchar()) != EOF && c != '\n');
- ungetc(c, stdin);
- while (scanf("%ju", &inode) == 1) {
- if (inode > maxino) {
- warnx("illegal inode %ju", inode);
- return;
+ line = NULL;
+ cap = 0;
+ while ((len = getline(&line, &cap, stdin)) > 0) {
+ if (len > 0 && line[len - 1] == '\n')
+ line[--len] = '\0';
+ inode = strtoimax(line, &end, 10);
+ /*
+ * Silently ignore lines that do not begin with a number.
+ * For backward compatibility reasons, we do not require
+ * the optional comment to be preceded by whitespace.
+ */
+ if (end == line)
+ continue;
+ if (inode <= 0 || inode > maxino) {
+ warnx("invalid inode %jd", inode);
+ continue;
}
if ((dp = get_inode(fd, super, inode)) != NULL &&
!isfree(super, dp)) {
printf("%s\t", user(DIP(super, dp, di_uid))->name);
/* now skip whitespace */
- while ((c = getchar()) == ' ' || c == '\t')
- /* nothing */;
+ while (*end == ' ' || *end == '\t')
+ end++;
/* and print out the remainder of the input line */
- while (c != EOF && c != '\n') {
- putchar(c);
- c = getchar();
- }
- putchar('\n');
+ printf("%s\n", end);
} else {
/* skip this line */
- while ((c = getchar()) != EOF && c != '\n')
- /* nothing */;
}
- if (c == EOF)
- break;
}
+ free(line);
}
static void
diff --git a/usr.sbin/quot/tests/quot_test.sh b/usr.sbin/quot/tests/quot_test.sh
index 21088d162a53..c5e6717adca1 100644
--- a/usr.sbin/quot/tests/quot_test.sh
+++ b/usr.sbin/quot/tests/quot_test.sh
@@ -15,6 +15,8 @@ quot_setup()
atf_check mount /dev/$dev "$mnt"
echo "/dev/$dev: ($mnt)" >expect
printf "%5d\t%5d\t%-8s\n" 8 2 "#0" >>expect
+ printf "%s\n" "/dev/$dev" >ninput
+ echo "/dev/$dev: ($mnt)" >nexpect
}
# Create a directory owned by a given UID
@@ -23,12 +25,25 @@ quot_adduid()
local uid=$1
atf_check install -d -o $uid -g 0 mnt/$uid
printf "%5d\t%5d\t%-8s\n" 4 1 "#$uid" >>expect
+ ls -di mnt/$uid >>ninput
+ printf "%s\t%s\n" "#$uid" mnt/$uid >>nexpect
}
# Perform the tests
quot_test()
{
local dev=$(cat dev)
+ # Deliberately add invalid lines to our -n input before the
+ # valid ones to verify that quot does not abort on first
+ # error. Note that quot deliberately ignores initial lines
+ # that don't start with a number, and that after encountering
+ # at least one line that does start with a number, quot would
+ # previously terminate on encountering one that doesn't (now
+ # it simply ignores them). This also tests that we don't
+ # require whitespace between the inode number and the comment.
+ echo "0zero" >>ninput
+ echo "invalid" >>ninput
+ echo "-1minusone" >>ninput
# Create inodes owned by a large number of users to exercise
# hash collisions and rehashing. The code uses an open hash
# table that starts out with only 8 entries and doubles every
@@ -50,6 +65,10 @@ quot_test()
atf_check mount -ur /dev/$dev
atf_check -o file:expect quot -fkN /dev/$dev
atf_check -o file:expect quot -fkN $(realpath mnt)
+ # Test -n option
+ atf_check -o file:nexpect \
+ -e inline:"quot: invalid inode 0\nquot: invalid inode -1\n" \
+ quot -Nn /dev/$dev <ninput
}
# Unmount and release the memory disk