morpheus-base

morpheus base system
git clone git://git.2f30.org/morpheus-base.git
Log | Files | Refs

du.c (3151B)


      1 /* See LICENSE file for copyright and license details. */
      2 #include <dirent.h>
      3 #include <limits.h>
      4 #include <stdio.h>
      5 #include <stdlib.h>
      6 #include <string.h>
      7 #include <sys/stat.h>
      8 #include <sys/types.h>
      9 #include <unistd.h>
     10 
     11 #include "util.h"
     12 
     13 static long blksize = 512;
     14 static char file[PATH_MAX];
     15 static long depth = -1;
     16 static long curdepth = 0;
     17 
     18 static int aflag = 0;
     19 static int dflag = 0;
     20 static int sflag = 0;
     21 static int kflag = 0;
     22 static int hflag = 0;
     23 
     24 static long du(const char *);
     25 static void print(long n, char *path);
     26 
     27 static void
     28 usage(void)
     29 {
     30 	eprintf("usage: %s [-a | -s] [-d depth] [-h] [-k] [file...]\n", argv0);
     31 }
     32 
     33 static char *
     34 xrealpath(const char *pathname, char *resolved)
     35 {
     36 	char *r;
     37 
     38 	r = realpath(pathname, resolved);
     39 	if (!r)
     40 		eprintf("realpath: %s:", pathname);
     41 	return r;
     42 }
     43 
     44 int
     45 main(int argc, char *argv[])
     46 {
     47 	char *bsize;
     48 	long n;
     49 
     50 	ARGBEGIN {
     51 	case 'a':
     52 		aflag = 1;
     53 		break;
     54 	case 'd':
     55 		dflag = 1;
     56 		depth = estrtol(EARGF(usage()), 0);
     57 		break;
     58 	case 's':
     59 		sflag = 1;
     60 		break;
     61 	case 'k':
     62 		kflag = 1;
     63 		break;
     64 	case 'h':
     65 		hflag = 1;
     66 		break;
     67 	default:
     68 		usage();
     69 	} ARGEND;
     70 
     71 	if ((aflag && sflag) || (dflag && sflag))
     72 		usage();
     73 
     74 	bsize = getenv("BLOCKSIZE");
     75 	if (bsize)
     76 		blksize = estrtol(bsize, 0);
     77 
     78 	if (kflag)
     79 		blksize = 1024;
     80 
     81 	if (argc < 1) {
     82 		n = du(".");
     83 		if (sflag)
     84 			print(n, xrealpath(".", file));
     85 	} else {
     86 		for (; argc > 0; argc--, argv++) {
     87 			curdepth = 0;
     88 			n = du(argv[0]);
     89 			if (sflag)
     90 				print(n, xrealpath(argv[0], file));
     91 		}
     92 	}
     93 	return 0;
     94 }
     95 
     96 static void
     97 print(long n, char *path)
     98 {
     99 	if (hflag)
    100 		printf("%s\t%s\n", humansize(n * blksize), path);
    101 	else
    102 		printf("%lu\t%s\n", n, path);
    103 }
    104 
    105 static char *
    106 push(const char *path)
    107 {
    108 	char *cwd;
    109 
    110 	cwd = agetcwd();
    111 	if (chdir(path) < 0)
    112 		eprintf("chdir: %s:", path);
    113 	return cwd;
    114 }
    115 
    116 static void
    117 pop(char *path)
    118 {
    119 	if (chdir(path) < 0)
    120 		eprintf("chdir: %s:", path);
    121 	free(path);
    122 }
    123 
    124 static long
    125 nblks(struct stat *st)
    126 {
    127 	return (512 * st->st_blocks + blksize - 1) / blksize;
    128 }
    129 
    130 static long
    131 du(const char *path)
    132 {
    133 	DIR *dp;
    134 	char *cwd;
    135 	struct dirent *dent;
    136 	struct stat st;
    137 	long n = 0, m, t;
    138 	int r;
    139 
    140 	if (lstat(path, &st) < 0)
    141 		eprintf("stat: %s:", path);
    142 	n = nblks(&st);
    143 
    144 	if (!S_ISDIR(st.st_mode))
    145 		goto done;
    146 
    147 	dp = opendir(path);
    148 	if (!dp) {
    149 		weprintf("opendir %s:", path);
    150 		goto done;
    151 	}
    152 
    153 	cwd = push(path);
    154 	while ((dent = readdir(dp))) {
    155 		if (strcmp(dent->d_name, ".") == 0 ||
    156 		    strcmp(dent->d_name, "..") == 0)
    157 			continue;
    158 		if (lstat(dent->d_name, &st) < 0)
    159 			eprintf("stat: %s:", dent->d_name);
    160 		if (S_ISDIR(st.st_mode)) {
    161 			t = curdepth;
    162 			curdepth++;
    163 			n += du(dent->d_name);
    164 			curdepth = t;
    165 			continue;
    166 		}
    167 		m = nblks(&st);
    168 		n += m;
    169 		if (aflag && !sflag) {
    170 			if (S_ISLNK(st.st_mode)) {
    171 				r = snprintf(file, sizeof(file), "%s/%s",
    172 					     cwd, dent->d_name);
    173 				if (r >= sizeof(file) || r < 0)
    174 					eprintf("path too long\n");
    175 			} else {
    176 				xrealpath(dent->d_name, file);
    177 			}
    178 			if (!dflag || (depth != -1 && curdepth < depth))
    179 				print(m, file);
    180 		}
    181 	}
    182 	pop(cwd);
    183 	closedir(dp);
    184 
    185 done:
    186 	if (!sflag && (!dflag || (depth != -1 && curdepth <= depth)))
    187 		print(n, xrealpath(path, file));
    188 	return n;
    189 }