sbase

suckless unix tools
git clone git://git.suckless.org/sbase
Log | Files | Refs | README | LICENSE

du.c (2108B)


      1 /* See LICENSE file for copyright and license details. */
      2 #include <sys/stat.h>
      3 #include <sys/types.h>
      4 
      5 #include <errno.h>
      6 #include <fcntl.h>
      7 #include <limits.h>
      8 #include <stdint.h>
      9 #include <stdlib.h>
     10 #include <stdio.h>
     11 #include <unistd.h>
     12 
     13 #include "fs.h"
     14 #include "util.h"
     15 
     16 static size_t maxdepth = SIZE_MAX;
     17 static size_t blksize  = 512;
     18 
     19 static int aflag = 0;
     20 static int sflag = 0;
     21 static int hflag = 0;
     22 
     23 static void
     24 printpath(off_t n, const char *path)
     25 {
     26 	if (hflag)
     27 		printf("%s\t%s\n", humansize(n * blksize), path);
     28 	else
     29 		printf("%jd\t%s\n", (intmax_t)n, path);
     30 }
     31 
     32 static off_t
     33 nblks(blkcnt_t blocks)
     34 {
     35 	return (512 * blocks + blksize - 1) / blksize;
     36 }
     37 
     38 static void
     39 du(int dirfd, const char *path, struct stat *st, void *data, struct recursor *r)
     40 {
     41 	off_t *total = data, subtotal;
     42 
     43 	subtotal = nblks(st->st_blocks);
     44 	if (S_ISDIR(st->st_mode))
     45 		recurse(dirfd, path, &subtotal, r);
     46 	*total += subtotal;
     47 
     48 	if (!r->depth)
     49 		printpath(*total, r->path);
     50 	else if (!sflag && r->depth <= maxdepth && (S_ISDIR(st->st_mode) || aflag))
     51 		printpath(subtotal, r->path);
     52 }
     53 
     54 static void
     55 usage(void)
     56 {
     57 	eprintf("usage: %s [-a | -s] [-d depth] [-h] [-k] [-H | -L | -P] [-x] [file ...]\n", argv0);
     58 }
     59 
     60 int
     61 main(int argc, char *argv[])
     62 {
     63 	struct recursor r = { .fn = du, .follow = 'P' };
     64 	off_t n = 0;
     65 	int kflag = 0, dflag = 0;
     66 	char *bsize;
     67 
     68 	ARGBEGIN {
     69 	case 'a':
     70 		aflag = 1;
     71 		break;
     72 	case 'd':
     73 		dflag = 1;
     74 		maxdepth = estrtonum(EARGF(usage()), 0, MIN(LLONG_MAX, SIZE_MAX));
     75 		break;
     76 	case 'h':
     77 		hflag = 1;
     78 		break;
     79 	case 'k':
     80 		kflag = 1;
     81 		break;
     82 	case 's':
     83 		sflag = 1;
     84 		break;
     85 	case 'x':
     86 		r.flags |= SAMEDEV;
     87 		break;
     88 	case 'H':
     89 	case 'L':
     90 	case 'P':
     91 		r.follow = ARGC();
     92 		break;
     93 	default:
     94 		usage();
     95 	} ARGEND
     96 
     97 	if ((aflag && sflag) || (dflag && sflag))
     98 		usage();
     99 
    100 	bsize = getenv("BLOCKSIZE");
    101 	if (bsize)
    102 		blksize = estrtonum(bsize, 1, MIN(LLONG_MAX, SIZE_MAX));
    103 	if (kflag)
    104 		blksize = 1024;
    105 
    106 	if (!argc) {
    107 		recurse(AT_FDCWD, ".", &n, &r);
    108 	} else {
    109 		for (; *argv; argc--, argv++) {
    110 			n = 0;
    111 			recurse(AT_FDCWD, *argv, &n, &r);
    112 		}
    113 	}
    114 
    115 	return fshut(stdout, "<stdout>") || recurse_status;
    116 }