micro-utils/src/coreutils/du/du.c

112 lines
1.8 KiB
C

#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <dirent.h>
#include <stdint.h>
#include "get_stat.h"
#include "make_path.h"
#include "human.h"
char h_flag;
char s_flag;
char c_flag;
off_t total;
void print(off_t size, const char *filename) {
if (h_flag)
printf("%s\t%s\n", mu_humansize(size * 512, 1024), filename);
else
printf("%jd\t%s\n", (intmax_t)size / 2, filename);
}
off_t du(const char *path, int recurs_flag) {
struct stat sb;
if (mu_get_lstat("du", path, &sb))
return 0;
off_t sum = sb.st_blocks;
if (c_flag)
total += sum;
if (S_ISDIR(sb.st_mode)) {
DIR *dp = opendir(path);
if (!dp) {
fprintf(stderr, "du: %s\n", strerror(errno));
return 0;
}
struct dirent *ep;
while ((ep = readdir(dp)) != NULL) {
if (!strcmp(ep->d_name, ".") || !strcmp(ep->d_name, ".."))
continue;
char *new_path = mu_make_path("du", path, ep->d_name);
if (new_path == NULL)
return 0;
sum += du(new_path, 1);
free(new_path);
}
closedir(dp);
if (!s_flag && recurs_flag) {
print(sum, path);
return sum;
}
/* Silent mode */
else if (!recurs_flag)
print(sum, path);
}
else if (!recurs_flag)
print(sum, path);
return sum;
}
int main(int argc, char **argv) {
int opt;
while ((opt = getopt(argc, argv, "hsc")) != -1) {
switch (opt) {
case 'h':
h_flag = 1;
break;
case 's':
s_flag = 1;
break;
case 'c':
c_flag = 1;
break;
default:
printf("du [hsc] [src1 src2...]\n\t-h Sizes in human readable format\n\t-s Display only a total for each argument\n\t-c produce a grand total\n");
return 0;
}
}
if (argv[optind] == NULL)
du(".", 0);
else {
argv += optind;
argc -= optind;
for (int i = 0; i < argc; i++)
du(argv[i], 0);
}
if (c_flag)
print(total, "total");
return 0;
}