01de5df8e6
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.
122 lines
2.0 KiB
C
122 lines
2.0 KiB
C
/* See LICENSE file for copyright and license details. */
|
|
#include <sys/stat.h>
|
|
#include <sys/types.h>
|
|
|
|
#include <errno.h>
|
|
#include <limits.h>
|
|
#include <stdint.h>
|
|
#include <stdlib.h>
|
|
#include <stdio.h>
|
|
|
|
#include "util.h"
|
|
|
|
static size_t maxdepth = SIZE_MAX;
|
|
static size_t blksize = 512;
|
|
|
|
static int aflag = 0;
|
|
static int sflag = 0;
|
|
static int hflag = 0;
|
|
static int ret = 0;
|
|
|
|
static void
|
|
printpath(size_t n, const char *path)
|
|
{
|
|
if (hflag)
|
|
printf("%s\t%s\n", humansize(n * blksize), path);
|
|
else
|
|
printf("%zu\t%s\n", n, path);
|
|
}
|
|
|
|
static size_t
|
|
nblks(blkcnt_t blocks)
|
|
{
|
|
return (512 * blocks + blksize - 1) / blksize;
|
|
}
|
|
|
|
void
|
|
du(const char *path, int depth, void *total)
|
|
{
|
|
struct stat st;
|
|
size_t subtotal = 0;
|
|
|
|
if (lstat(path, &st) < 0) {
|
|
if (!depth || errno != ENOENT)
|
|
weprintf("stat %s:", path);
|
|
if (!depth)
|
|
ret = 1;
|
|
return;
|
|
}
|
|
|
|
recurse(path, du, depth, &subtotal);
|
|
*((size_t *)total) += subtotal + nblks(st.st_blocks);
|
|
|
|
if (!sflag && depth <= maxdepth && (S_ISDIR(st.st_mode) || aflag))
|
|
printpath(subtotal + nblks(st.st_blocks), path);
|
|
}
|
|
|
|
static void
|
|
usage(void)
|
|
{
|
|
eprintf("usage: %s [-a | -s] [-d depth] [-h] [-k] [-H | -L | -P] [-x] [file ...]\n", argv0);
|
|
}
|
|
|
|
int
|
|
main(int argc, char *argv[])
|
|
{
|
|
int kflag = 0, dflag = 0;
|
|
size_t n = 0;
|
|
char *bsize;
|
|
|
|
ARGBEGIN {
|
|
case 'a':
|
|
aflag = 1;
|
|
break;
|
|
case 'd':
|
|
dflag = 1;
|
|
maxdepth = estrtonum(EARGF(usage()), 0, MIN(LLONG_MAX, SIZE_MAX));
|
|
break;
|
|
case 'h':
|
|
hflag = 1;
|
|
break;
|
|
case 'k':
|
|
kflag = 1;
|
|
break;
|
|
case 's':
|
|
sflag = 1;
|
|
break;
|
|
case 'x':
|
|
recurse_samedev = 1;
|
|
break;
|
|
case 'H':
|
|
case 'L':
|
|
case 'P':
|
|
recurse_follow = ARGC();
|
|
break;
|
|
default:
|
|
usage();
|
|
} ARGEND;
|
|
|
|
if ((aflag && sflag) || (dflag && sflag))
|
|
usage();
|
|
|
|
bsize = getenv("BLOCKSIZE");
|
|
if (bsize)
|
|
blksize = estrtonum(bsize, 0, MIN(LLONG_MAX, SIZE_MAX));
|
|
if (kflag)
|
|
blksize = 1024;
|
|
|
|
if (!argc) {
|
|
du(".", 0, &n);
|
|
if (sflag && !ret)
|
|
printpath(nblks(n), ".");
|
|
} else {
|
|
for (; *argv; argc--, argv++) {
|
|
du(argv[0], 0, &n);
|
|
if (sflag && !ret)
|
|
printpath(n, argv[0]);
|
|
}
|
|
}
|
|
|
|
return ret;
|
|
}
|