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
This commit is contained in:
@@ -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
|
||||
|
||||
+25
-22
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user