The branch main has been updated by des:

URL: 
https://cgit.FreeBSD.org/src/commit/?id=fa272a5276865a97b01823fe6546940eaaf1b164

commit fa272a5276865a97b01823fe6546940eaaf1b164
Author:     Dag-Erling Smørgrav <[email protected]>
AuthorDate: 2025-11-14 14:28:40 +0000
Commit:     Dag-Erling Smørgrav <[email protected]>
CommitDate: 2025-11-14 14:29:05 +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
---
 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

Reply via email to