mirror of
https://github.com/freebsd/freebsd-src.git
synced 2026-10-28 11:25:21 +01:00
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 fa272a5276)
This commit is contained in:
1 parent
b41551753a
commit
179fa1d81c
3 files changed
+47
-22
No files matched your search
@@ -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
|
||||
|
||||
+26
-21
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in new issue
Block a user