The branch stable/13 has been updated by des:

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

commit a2630fec78b60844e68cae8b9e1f65b7322a5f05
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-19 11:20:30 +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)
    (cherry picked from commit 179fa1d81c73ab7ef231e17da73f230e4f8ee5a2)
---
 usr.sbin/quot/quot.8             |  3 ++-
 usr.sbin/quot/quot.c             | 47 ++++++++++++++++++++++------------------
 usr.sbin/quot/tests/quot_test.sh | 19 ++++++++++++++++
 3 files changed, 47 insertions(+), 22 deletions(-)

diff --git a/usr.sbin/quot/quot.8 b/usr.sbin/quot/quot.8
index 0338457f6aeb..b777aef7288e 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 February 8, 1994
+.Dd November 13, 2025
 .Dt QUOT 8
 .Os
 .Sh NAME
@@ -65,6 +65,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 28a7173e7340..acde6e411091 100644
--- a/usr.sbin/quot/quot.c
+++ b/usr.sbin/quot/quot.c
@@ -40,9 +40,10 @@
 #include <ufs/ffs/fs.h>
 
 #include <err.h>
+#include <errno.h>
 #include <fcntl.h>
 #include <fstab.h>
-#include <errno.h>
+#include <inttypes.h>
 #include <libufs.h>
 #include <paths.h>
 #include <pwd.h>
@@ -480,43 +481,47 @@ douser(int fd, struct fs *super, char *name)
 static void
 donames(int fd, struct fs *super, char *name)
 {
-       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;
                }
                errno = 0;
                if ((dp = get_inode(fd,super,inode))
                    && !isfree(super, dp)) {
                        printf("%s\t",user(DIP(super, dp, di_uid))->name);
                        /* now skip whitespace */
-                       while ((c = getchar()) == ' ' || c == '\t');
+                       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 {
                        if (errno) {
                                err(1, "%s", name);
                        }
                        /* skip this line */
-                       while ((c = getchar()) != EOF && c != '\n');
                }
-               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 7da9d23ca11f..fd3d6df7b021 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:" >expect
        printf "%5d\t%5d\t%-8s\n" 8 2 "#0" >>expect
+       printf "%s\n" "/dev/$dev" >ninput
+       echo "/dev/$dev:" >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
@@ -49,6 +64,10 @@ quot_test()
        # that everything gets flushed to the memory disk.
        atf_check mount -ur /dev/$dev
        atf_check -o file:expect quot -fkN /dev/$dev
+       # 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