/* findnull.c --- Find non-emtpy files consisting entirely of null bytes Copyright (C) 2001 Colin Walters This program is hereby placed in the public domain. */ #define _GNU_SOURCE #include #include #include #include #include #include #include #include #include #include void usage(void); void fatal_error(const char *__restrict format, ...); int null_file_p(const char *filename); int print_if_null_file(const char *filename, const struct stat *buf, int flag); void print_null_files_in_dir(const char *filename); static int n_excluded; static int max_excluded; static char **excluded; static int verbose = 0; int main(int argc, char **argv) { struct fstab *fsentry; if (argc > 1) verbose = !strcmp(argv[1], "-v"); if (argc > 2) verbose += !strcmp(argv[2], "-v"); n_excluded = 0; max_excluded = 8; if (!(excluded = malloc(sizeof(char *) * max_excluded))) fatal_error("malloc failed: %s", strerror(errno)); if (!setfsent()) fatal_error("setfsent failed: %s", strerror(errno)); while ((fsentry = getfsent()) != NULL) { if (strcmp(fsentry->fs_vfstype, "xfs") || strcmp(fsentry->fs_vfstype, "none")) { if (n_excluded++ > max_excluded) if (!(excluded = realloc(excluded, max_excluded *= 2))) fatal_error("realloc failed: %s", strerror(errno)); excluded[n_excluded-1] = strdup(fsentry->fs_file); if (verbose) fprintf(stderr, "excluding %s\n", excluded[n_excluded-1]); } } endfsent(); print_null_files_in_dir("/"); exit(0); } void fatal_error(const char *__restrict format, ...) { va_list args; va_start(args, format); vfprintf(stderr, format, args); exit(1); } int null_file_p(const char *filename) { static char buf[8192]; size_t num; int retval = 0; FILE *fp; if (!(fp = fopen(filename, "r"))) { perror("fopen"); return -1; } while ((num = fread(buf, sizeof(char), sizeof(buf), fp)) > 0) { size_t n; for (n = 0; n < num; n++) if (buf[n] != '\0') { retval = 0; goto cleanup; } } if (num < 0) { perror("fread"); retval = -1; goto cleanup; } retval = 1; cleanup: fclose(fp); return retval; } void print_null_files_in_dir(const char *filename) { struct dirent *ent; struct stat buf; int i; DIR *cur; if (verbose > 1) fprintf(stderr, "checking dir %s\n", filename); for (i = 0; i < n_excluded; i++) if (!strncmp(filename, excluded[i], strlen(excluded[i]))) { if (verbose) fprintf(stderr, "dir %s is excluded\n", filename); return; } if (!(cur = opendir(filename))) fatal_error("opendir failed on %s: %s", filename, strerror(errno)); while ((ent = readdir(cur)) != NULL) { int ret = 0; char *curname; if (ent->d_name[0] == '\0' || !strncmp(ent->d_name, ".", 2) || !strncmp(ent->d_name, "..", 3)) continue; if (! ({ /* Make things look a bit prettier */ if (!strncmp(filename, "/", 2)) asprintf(&curname, "/%s", ent->d_name); else asprintf(&curname, "%s/%s", filename, ent->d_name); curname; })) fatal_error("out of memory"); if (verbose > 1) fprintf(stderr, "checking entry %s\n", curname); if (lstat(curname, &buf)) perror("stat"); else if (S_ISDIR(buf.st_mode)) print_null_files_in_dir(curname); else if (S_ISREG(buf.st_mode) && buf.st_size > 0 && ((ret = null_file_p(curname)) == 1)) fprintf(stdout, "%s\n", curname); if (ret < 0) fprintf(stderr, "failed to test %s\n", curname); free(curname); } if (verbose > 1) fprintf(stderr, "exiting dir %s\n", filename); closedir(cur); }