/* Recursively scan a directory tree for all dirs, and fork off a process for * each dir to read all the files in that dir * * Copyright (C) 2009 Red Hat, Inc. All Rights Reserved. * Written by David Howells (dhowells@redhat.com) * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public Licence * as published by the Free Software Foundation; either version * 2 of the Licence, or (at your option) any later version. */ #include #include #include #include #include #include #include #include #include #include static char *prog, *exefile; /* * */ static __attribute__((noreturn)) void clean_up_and_exit(int ret) { pid_t pid; int wstatus; for (;;) { pid = wait(&wstatus); if (pid == -1) { switch (errno) { case ECHILD: exit(ret); default: exit(1); } } if (WIFEXITED(wstatus)) { if (WEXITSTATUS(wstatus) == 0) continue; if (ret > 0) ret = WEXITSTATUS(wstatus); continue; } if (WIFSIGNALED(wstatus)) { ret = WTERMSIG(wstatus) + 128; continue; } ret = 126; } } /* * */ static void read_file(char *filename, int depth) { ssize_t size; char buf[4096]; int fd; printf("%*.*sread %s\n", depth, depth, "", filename); fd = open(filename, O_RDONLY, 0); if (fd == -1) clean_up_and_exit(4); for (;;) { size = read(fd, buf, sizeof(buf)); if (size == 0) return; if (size == -1) clean_up_and_exit(5); } } /* * */ static int dot_filter(const struct dirent *entry) { return entry->d_name[0] != '.'; } /* * */ static __attribute__((noreturn)) void scan_directory(char *dirname, int depth) { struct dirent **entries, *entry; struct stat st; int nent, loop; if (depth == 30) clean_up_and_exit(0); printf("%*.*sscan %s\n", depth, depth, "", dirname); nent = scandir(".", &entries, dot_filter, alphasort); if (nent == -1) clean_up_and_exit(1); /* firstly deal with all the subdirs */ for (loop = 0; loop < nent; loop++) { entry = entries[loop]; if (stat(entry->d_name, &st) == -1) { if (errno == ENOENT) continue; clean_up_and_exit(2); } if (S_ISDIR(st.st_mode)) if (fork() == 0) { char dbuf[16]; sprintf(dbuf, "%d", depth + 1); if (chdir(entry->d_name) < 0) { perror(entry->d_name); clean_up_and_exit(8); } execl(exefile, prog, "--exec-done", entry->d_name, dbuf, NULL); perror(prog); clean_up_and_exit(9); } } /* then read all the regular files in that directory */ for (loop = 0; loop < nent; loop++) { entry = entries[loop]; if (stat(entry->d_name, &st) == -1) { if (errno == ENOENT) continue; clean_up_and_exit(3); } if (S_ISREG(st.st_mode)) read_file(entry->d_name, depth + 1); } clean_up_and_exit(0); } /* * */ int main(int argc, char **argv) { prog = argv[0]; if (argv[0][0] == '/') exefile = argv[0]; else exefile = "/proc/self/exe"; if (argc == 4 && strcmp(argv[1], "--exec-done") == 0) { scan_directory(argv[2], atoi(argv[3])); } else { for (argv++; *argv; argv++) { if (fork() == 0) { if (chdir(*argv) < 0) { perror(*argv); clean_up_and_exit(8); } execl(exefile, prog, "--exec-done", *argv, "0", NULL); perror(prog); clean_up_and_exit(9); } } } clean_up_and_exit(0); }