Audit du(1) and refactor recurse()
While auditing du(1) I realized that there's no way the over 100 lines of procedures in du() would pass the audit. Instead, I decided to rewrite this section using recurse() from libutil. However, the issue was that you'd need some kind of payload to count the number of bytes in the subdirectories and use them in the higher hierarchies. The solution is to add a "void *data" data pointer to each recurse- function-prototype, which we might also be able to use in other recurse-applications. recurse() itself had to be augmented with a recurse_samedev-flag, which basically prevents recurse from leaving the current device. Now, let's take a closer look at the audit: 1) Removing the now unnecessary util-functions push, pop, xrealpath, rename print() to printpath(), localize some global variables. 2) Only pass the block count to nblks instead of the entire stat- pointer. 3) Fix estrtonum to use the minimum of LLONG_MAX and SIZE_MAX. 4) Use idiomatic argv+argc-loop 5) Report proper exit-status.
This commit is contained in:
parent
00ca97b279
commit
01de5df8e6
6
chgrp.c
6
chgrp.c
|
@ -14,7 +14,7 @@ static gid_t gid = -1;
|
||||||
static int ret = 0;
|
static int ret = 0;
|
||||||
|
|
||||||
static void
|
static void
|
||||||
chgrp(const char *path, int depth)
|
chgrp(const char *path, int depth, void *data)
|
||||||
{
|
{
|
||||||
char *chownf_name;
|
char *chownf_name;
|
||||||
int (*chownf)(const char *, uid_t, gid_t);
|
int (*chownf)(const char *, uid_t, gid_t);
|
||||||
|
@ -31,7 +31,7 @@ chgrp(const char *path, int depth)
|
||||||
weprintf("%s %s:", chownf_name, path);
|
weprintf("%s %s:", chownf_name, path);
|
||||||
ret = 1;
|
ret = 1;
|
||||||
} else if (Rflag) {
|
} else if (Rflag) {
|
||||||
recurse(path, chgrp, depth);
|
recurse(path, chgrp, depth, NULL);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -80,7 +80,7 @@ main(int argc, char *argv[])
|
||||||
ret = 1;
|
ret = 1;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
chgrp(*argv, 0);
|
chgrp(*argv, 0, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
|
|
6
chmod.c
6
chmod.c
|
@ -9,7 +9,7 @@ static mode_t mask = 0;
|
||||||
static int ret = 0;
|
static int ret = 0;
|
||||||
|
|
||||||
static void
|
static void
|
||||||
chmodr(const char *path, int depth)
|
chmodr(const char *path, int depth, void *data)
|
||||||
{
|
{
|
||||||
struct stat st;
|
struct stat st;
|
||||||
mode_t m;
|
mode_t m;
|
||||||
|
@ -25,7 +25,7 @@ chmodr(const char *path, int depth)
|
||||||
weprintf("chmod %s:", path);
|
weprintf("chmod %s:", path);
|
||||||
ret = 1;
|
ret = 1;
|
||||||
} else if (Rflag)
|
} else if (Rflag)
|
||||||
recurse(path, chmodr, depth);
|
recurse(path, chmodr, depth, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -80,7 +80,7 @@ done:
|
||||||
usage();
|
usage();
|
||||||
|
|
||||||
for (--argc, ++argv; *argv; argc--, argv++)
|
for (--argc, ++argv; *argv; argc--, argv++)
|
||||||
chmodr(*argv, 0);
|
chmodr(*argv, 0, NULL);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
6
chown.c
6
chown.c
|
@ -16,7 +16,7 @@ static gid_t gid = -1;
|
||||||
static int ret = 0;
|
static int ret = 0;
|
||||||
|
|
||||||
static void
|
static void
|
||||||
chownpwgr(const char *path, int depth)
|
chownpwgr(const char *path, int depth, void *data)
|
||||||
{
|
{
|
||||||
char *chownf_name;
|
char *chownf_name;
|
||||||
int (*chownf)(const char *, uid_t, gid_t);
|
int (*chownf)(const char *, uid_t, gid_t);
|
||||||
|
@ -33,7 +33,7 @@ chownpwgr(const char *path, int depth)
|
||||||
weprintf("%s %s:", chownf_name, path);
|
weprintf("%s %s:", chownf_name, path);
|
||||||
ret = 1;
|
ret = 1;
|
||||||
} else if (Rflag) {
|
} else if (Rflag) {
|
||||||
recurse(path, chownpwgr, depth);
|
recurse(path, chownpwgr, depth, NULL);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -97,7 +97,7 @@ main(int argc, char *argv[])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (argc--, argv++; *argv; argc--, argv++)
|
for (argc--, argv++; *argv; argc--, argv++)
|
||||||
chownpwgr(*argv, 0);
|
chownpwgr(*argv, 0, NULL);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
178
du.c
178
du.c
|
@ -2,140 +2,56 @@
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
|
|
||||||
#include <dirent.h>
|
#include <errno.h>
|
||||||
|
#include <limits.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <stdio.h>
|
||||||
#include <unistd.h>
|
|
||||||
|
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
|
|
||||||
|
static size_t maxdepth = SIZE_MAX;
|
||||||
static size_t blksize = 512;
|
static size_t blksize = 512;
|
||||||
static char file[PATH_MAX];
|
|
||||||
static size_t depth = -1;
|
|
||||||
static size_t curdepth = 0;
|
|
||||||
|
|
||||||
static int aflag = 0;
|
static int aflag = 0;
|
||||||
static int dflag = 0;
|
|
||||||
static int sflag = 0;
|
static int sflag = 0;
|
||||||
static int kflag = 0;
|
|
||||||
static int hflag = 0;
|
static int hflag = 0;
|
||||||
static int xflag = 0;
|
static int ret = 0;
|
||||||
static int HLPflag = 'P';
|
|
||||||
|
|
||||||
static char *
|
|
||||||
xrealpath(const char *pathname, char *resolved)
|
|
||||||
{
|
|
||||||
char *r;
|
|
||||||
|
|
||||||
r = realpath(pathname, resolved);
|
|
||||||
if (!r)
|
|
||||||
eprintf("realpath: %s:", pathname);
|
|
||||||
return r;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
print(size_t n, char *path)
|
printpath(size_t n, const char *path)
|
||||||
{
|
{
|
||||||
if (hflag)
|
if (hflag)
|
||||||
printf("%s\t%s\n", humansize(n * blksize), path);
|
printf("%s\t%s\n", humansize(n * blksize), path);
|
||||||
else
|
else
|
||||||
printf("%lu\t%s\n", n, path);
|
printf("%zu\t%s\n", n, path);
|
||||||
}
|
|
||||||
|
|
||||||
static char *
|
|
||||||
push(const char *path)
|
|
||||||
{
|
|
||||||
char *cwd;
|
|
||||||
|
|
||||||
cwd = agetcwd();
|
|
||||||
if (chdir(path) < 0)
|
|
||||||
weprintf("chdir: %s:", path);
|
|
||||||
return cwd;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
pop(char *path)
|
|
||||||
{
|
|
||||||
if (chdir(path) < 0)
|
|
||||||
weprintf("chdir: %s:", path);
|
|
||||||
free(path);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static size_t
|
static size_t
|
||||||
nblks(struct stat *st)
|
nblks(blkcnt_t blocks)
|
||||||
{
|
{
|
||||||
return (512 * st->st_blocks + blksize - 1) / blksize;
|
return (512 * blocks + blksize - 1) / blksize;
|
||||||
}
|
}
|
||||||
|
|
||||||
static size_t
|
void
|
||||||
du(const char *path, char follow)
|
du(const char *path, int depth, void *total)
|
||||||
{
|
{
|
||||||
struct dirent *dent;
|
struct stat st;
|
||||||
struct stat pst, st;
|
size_t subtotal = 0;
|
||||||
DIR *dp;
|
|
||||||
size_t n = 0, m, t;
|
|
||||||
int r;
|
|
||||||
char *cwd;
|
|
||||||
|
|
||||||
if (lstat(path, &pst) < 0)
|
if (lstat(path, &st) < 0) {
|
||||||
eprintf("stat: %s:", path);
|
if (!depth || errno != ENOENT)
|
||||||
n = nblks(&pst);
|
weprintf("stat %s:", path);
|
||||||
|
if (!depth)
|
||||||
if (!(S_ISDIR(pst.st_mode) ||
|
ret = 1;
|
||||||
(follow != 'P' && S_ISLNK(pst.st_mode) &&
|
return;
|
||||||
stat(path, &pst) == 0 && S_ISDIR(pst.st_mode))))
|
|
||||||
goto done;
|
|
||||||
|
|
||||||
follow = follow == 'H' ? 'P' : follow;
|
|
||||||
|
|
||||||
dp = opendir(path);
|
|
||||||
if (!dp) {
|
|
||||||
weprintf("opendir %s:", path);
|
|
||||||
goto done;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
cwd = push(path);
|
recurse(path, du, depth, &subtotal);
|
||||||
while ((dent = readdir(dp))) {
|
*((size_t *)total) += subtotal + nblks(st.st_blocks);
|
||||||
if (strcmp(dent->d_name, ".") == 0 ||
|
|
||||||
strcmp(dent->d_name, "..") == 0)
|
|
||||||
continue;
|
|
||||||
if (lstat(dent->d_name, &st) < 0)
|
|
||||||
eprintf("stat: %s:", dent->d_name);
|
|
||||||
if (xflag && st.st_dev != pst.st_dev)
|
|
||||||
continue;
|
|
||||||
if (S_ISDIR(st.st_mode) ||
|
|
||||||
(follow != 'P' && S_ISLNK(st.st_mode) &&
|
|
||||||
stat(dent->d_name, &st) == 0 && S_ISDIR(st.st_mode))) {
|
|
||||||
t = curdepth;
|
|
||||||
curdepth++;
|
|
||||||
n += du(dent->d_name, follow);
|
|
||||||
curdepth = t;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
m = nblks(&st);
|
|
||||||
n += m;
|
|
||||||
if (aflag && !sflag) {
|
|
||||||
if (S_ISLNK(st.st_mode)) {
|
|
||||||
r = snprintf(file, sizeof(file), "%s/%s",
|
|
||||||
cwd, dent->d_name);
|
|
||||||
if (r >= sizeof(file) || r < 0)
|
|
||||||
eprintf("path too long\n");
|
|
||||||
} else {
|
|
||||||
xrealpath(dent->d_name, file);
|
|
||||||
}
|
|
||||||
if (!dflag || (depth != -1 && curdepth < depth))
|
|
||||||
print(m, file);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
pop(cwd);
|
|
||||||
closedir(dp);
|
|
||||||
|
|
||||||
done:
|
if (!sflag && depth <= maxdepth && (S_ISDIR(st.st_mode) || aflag))
|
||||||
if (!sflag && (!dflag || (depth != -1 && curdepth <= depth)))
|
printpath(subtotal + nblks(st.st_blocks), path);
|
||||||
print(n, xrealpath(path, file));
|
|
||||||
return n;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -147,7 +63,8 @@ usage(void)
|
||||||
int
|
int
|
||||||
main(int argc, char *argv[])
|
main(int argc, char *argv[])
|
||||||
{
|
{
|
||||||
size_t n;
|
int kflag = 0, dflag = 0;
|
||||||
|
size_t n = 0;
|
||||||
char *bsize;
|
char *bsize;
|
||||||
|
|
||||||
ARGBEGIN {
|
ARGBEGIN {
|
||||||
|
@ -156,24 +73,24 @@ main(int argc, char *argv[])
|
||||||
break;
|
break;
|
||||||
case 'd':
|
case 'd':
|
||||||
dflag = 1;
|
dflag = 1;
|
||||||
depth = estrtonum(EARGF(usage()), 0, MIN(LLONG_MAX, SIZE_MAX));
|
maxdepth = estrtonum(EARGF(usage()), 0, MIN(LLONG_MAX, SIZE_MAX));
|
||||||
break;
|
|
||||||
case 's':
|
|
||||||
sflag = 1;
|
|
||||||
break;
|
|
||||||
case 'k':
|
|
||||||
kflag = 1;
|
|
||||||
break;
|
break;
|
||||||
case 'h':
|
case 'h':
|
||||||
hflag = 1;
|
hflag = 1;
|
||||||
break;
|
break;
|
||||||
|
case 'k':
|
||||||
|
kflag = 1;
|
||||||
|
break;
|
||||||
|
case 's':
|
||||||
|
sflag = 1;
|
||||||
|
break;
|
||||||
|
case 'x':
|
||||||
|
recurse_samedev = 1;
|
||||||
|
break;
|
||||||
case 'H':
|
case 'H':
|
||||||
case 'L':
|
case 'L':
|
||||||
case 'P':
|
case 'P':
|
||||||
HLPflag = ARGC();
|
recurse_follow = ARGC();
|
||||||
break;
|
|
||||||
case 'x':
|
|
||||||
xflag = 1;
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
usage();
|
usage();
|
||||||
|
@ -184,22 +101,21 @@ main(int argc, char *argv[])
|
||||||
|
|
||||||
bsize = getenv("BLOCKSIZE");
|
bsize = getenv("BLOCKSIZE");
|
||||||
if (bsize)
|
if (bsize)
|
||||||
blksize = estrtonum(bsize, 0, LONG_MAX);
|
blksize = estrtonum(bsize, 0, MIN(LLONG_MAX, SIZE_MAX));
|
||||||
|
|
||||||
if (kflag)
|
if (kflag)
|
||||||
blksize = 1024;
|
blksize = 1024;
|
||||||
|
|
||||||
if (argc < 1) {
|
if (!argc) {
|
||||||
n = du(".", HLPflag);
|
du(".", 0, &n);
|
||||||
if (sflag)
|
if (sflag && !ret)
|
||||||
print(n, xrealpath(".", file));
|
printpath(nblks(n), ".");
|
||||||
} else {
|
} else {
|
||||||
for (; argc > 0; argc--, argv++) {
|
for (; *argv; argc--, argv++) {
|
||||||
curdepth = 0;
|
du(argv[0], 0, &n);
|
||||||
n = du(argv[0], HLPflag);
|
if (sflag && !ret)
|
||||||
if (sflag)
|
printpath(n, argv[0]);
|
||||||
print(n, xrealpath(argv[0], file));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return 0;
|
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
2
fs.h
2
fs.h
|
@ -12,4 +12,4 @@ extern int rm_rflag;
|
||||||
extern int rm_status;
|
extern int rm_status;
|
||||||
|
|
||||||
int cp(const char *, const char *, int);
|
int cp(const char *, const char *, int);
|
||||||
void rm(const char *, int);
|
void rm(const char *, int, void *);
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
/* See LICENSE file for copyright and license details. */
|
/* See LICENSE file for copyright and license details. */
|
||||||
#include <dirent.h>
|
#include <dirent.h>
|
||||||
|
#include <errno.h>
|
||||||
#include <limits.h>
|
#include <limits.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
@ -11,20 +12,27 @@
|
||||||
#include "../util.h"
|
#include "../util.h"
|
||||||
|
|
||||||
int recurse_follow = 'P';
|
int recurse_follow = 'P';
|
||||||
|
int recurse_samedev = 0;
|
||||||
|
|
||||||
void
|
void
|
||||||
recurse(const char *path, void (*fn)(const char *, int), int depth)
|
recurse(const char *path, void (*fn)(const char *, int, void *), int depth, void *data)
|
||||||
{
|
{
|
||||||
struct dirent *d;
|
struct dirent *d;
|
||||||
struct stat lst, st;
|
struct stat lst, st, dst;
|
||||||
DIR *dp;
|
DIR *dp;
|
||||||
size_t len;
|
size_t len;
|
||||||
char *buf;
|
char *buf;
|
||||||
|
|
||||||
if (lstat(path, &lst) < 0)
|
if (lstat(path, &lst) < 0) {
|
||||||
eprintf("lstat %s:", path);
|
if (errno != ENOENT)
|
||||||
if (stat(path, &st) < 0)
|
weprintf("lstat %s:", path);
|
||||||
eprintf("stat %s:", path);
|
return;
|
||||||
|
}
|
||||||
|
if (stat(path, &st) < 0) {
|
||||||
|
if (errno != ENOENT)
|
||||||
|
weprintf("stat %s:", path);
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (!S_ISDIR(lst.st_mode) && !(S_ISLNK(lst.st_mode) && S_ISDIR(st.st_mode) &&
|
if (!S_ISDIR(lst.st_mode) && !(S_ISLNK(lst.st_mode) && S_ISDIR(st.st_mode) &&
|
||||||
!(recurse_follow == 'P' || (recurse_follow == 'H' && depth > 0))))
|
!(recurse_follow == 'P' || (recurse_follow == 'H' && depth > 0))))
|
||||||
return;
|
return;
|
||||||
|
@ -36,9 +44,13 @@ recurse(const char *path, void (*fn)(const char *, int), int depth)
|
||||||
while ((d = readdir(dp))) {
|
while ((d = readdir(dp))) {
|
||||||
if (!strcmp(d->d_name, ".") || !strcmp(d->d_name, ".."))
|
if (!strcmp(d->d_name, ".") || !strcmp(d->d_name, ".."))
|
||||||
continue;
|
continue;
|
||||||
buf = emalloc(len + (path[len] != '/') + strlen(d->d_name) + 1);
|
buf = emalloc(len + (path[len - 1] != '/') + strlen(d->d_name) + 1);
|
||||||
sprintf(buf, "%s%s%s", path, (path[len] == '/') ? "" : "/", d->d_name);
|
sprintf(buf, "%s%s%s", path, (path[len - 1] == '/') ? "" : "/", d->d_name);
|
||||||
fn(buf, depth + 1);
|
if (recurse_samedev && lstat(buf, &dst) < 0) {
|
||||||
|
if (errno != ENOENT)
|
||||||
|
weprintf("stat %s:", buf);
|
||||||
|
} else if (!(recurse_samedev && dst.st_dev != lst.st_dev))
|
||||||
|
fn(buf, depth + 1, data);
|
||||||
free(buf);
|
free(buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -10,10 +10,10 @@ int rm_rflag = 0;
|
||||||
int rm_status = 0;
|
int rm_status = 0;
|
||||||
|
|
||||||
void
|
void
|
||||||
rm(const char *path, int depth)
|
rm(const char *path, int depth, void *data)
|
||||||
{
|
{
|
||||||
if (rm_rflag)
|
if (rm_rflag)
|
||||||
recurse(path, rm, depth);
|
recurse(path, rm, depth, NULL);
|
||||||
if (remove(path) < 0) {
|
if (remove(path) < 0) {
|
||||||
if (!rm_fflag)
|
if (!rm_fflag)
|
||||||
weprintf("remove %s:", path);
|
weprintf("remove %s:", path);
|
||||||
|
|
2
mv.c
2
mv.c
|
@ -19,7 +19,7 @@ mv(const char *s1, const char *s2, int depth)
|
||||||
cp_HLPflag = 'P';
|
cp_HLPflag = 'P';
|
||||||
rm_rflag = 1;
|
rm_rflag = 1;
|
||||||
cp(s1, s2, depth);
|
cp(s1, s2, depth);
|
||||||
rm(s1, 0);
|
rm(s1, 0, NULL);
|
||||||
return (mv_status = cp_status || rm_status);
|
return (mv_status = cp_status || rm_status);
|
||||||
}
|
}
|
||||||
mv_status = 1;
|
mv_status = 1;
|
||||||
|
|
2
rm.c
2
rm.c
|
@ -31,7 +31,7 @@ main(int argc, char *argv[])
|
||||||
}
|
}
|
||||||
|
|
||||||
for (; *argv; argc--, argv++)
|
for (; *argv; argc--, argv++)
|
||||||
rm(*argv, 0);
|
rm(*argv, 0, NULL);
|
||||||
|
|
||||||
return rm_status;
|
return rm_status;
|
||||||
}
|
}
|
||||||
|
|
6
tar.c
6
tar.c
|
@ -234,10 +234,10 @@ print(char * fname, int l, char b[BLKSIZ])
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
c(const char *path, int depth)
|
c(const char *path, int depth, void *data)
|
||||||
{
|
{
|
||||||
archive(path);
|
archive(path);
|
||||||
recurse(path, c, depth);
|
recurse(path, c, depth, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -316,7 +316,7 @@ main(int argc, char *argv[])
|
||||||
tarfile = stdout;
|
tarfile = stdout;
|
||||||
}
|
}
|
||||||
chdir(dir);
|
chdir(dir);
|
||||||
c(argv[0], 0);
|
c(argv[0], 0, NULL);
|
||||||
break;
|
break;
|
||||||
case 't':
|
case 't':
|
||||||
case 'x':
|
case 'x':
|
||||||
|
|
3
util.h
3
util.h
|
@ -66,7 +66,8 @@ char *humansize(double);
|
||||||
mode_t parsemode(const char *, mode_t, mode_t);
|
mode_t parsemode(const char *, mode_t, mode_t);
|
||||||
void putword(const char *);
|
void putword(const char *);
|
||||||
extern int recurse_follow;
|
extern int recurse_follow;
|
||||||
void recurse(const char *, void (*)(const char *, int), int);
|
extern int recurse_samedev;
|
||||||
|
void recurse(const char *, void (*)(const char *, int, void *), int, void *);
|
||||||
#undef strtonum
|
#undef strtonum
|
||||||
long long strtonum(const char *, long long, long long, const char **);
|
long long strtonum(const char *, long long, long long, const char **);
|
||||||
long long enstrtonum(int, const char *, long long, long long);
|
long long enstrtonum(int, const char *, long long, long long);
|
||||||
|
|
Loading…
Reference in New Issue
Block a user