/* * Gets called for every file/folder in /sys/fs/cgroup/cpu,cpuacct (or * wherever cpuacct is mounted on the system). Calls walk_directory with the * read_cpuacct_procs callback on every folder it finds, such as "system". */ static int read_cpuacct_root (const char *dirname, const char *filename, void *user_data) { char abs_path[PATH_MAX]; struct stat statbuf; int status; ssnprintf (abs_path, sizeof (abs_path), "%s/%s", dirname, filename); status = lstat (abs_path, &statbuf); if (status != 0) { ERROR ("cgroups plugin: stat (%s) failed.", abs_path); return (-1); } if (S_ISDIR (statbuf.st_mode)) { status = walk_directory (abs_path, read_cpuacct_procs, /* user_data = */ NULL, /* include_hidden = */ 0); return (status); } return (0); }
static int read_syshugepages(const char* path, const char* node) { static const char hugepages_dir[] = "hugepages"; DIR *dir; struct dirent *result; char path2[PATH_MAX]; struct entry_info e_info; long lim; dir = opendir(path); if (dir == NULL) { ERROR("%s: cannot open directory %s", g_plugin_name, path); return -1; } errno = 0; if ((lim = pathconf(path, _PC_NAME_MAX)) == -1) { /* Limit not defined if errno == 0, otherwise error */ if (errno != 0) { ERROR("%s: pathconf failed", g_plugin_name); closedir(dir); return -1; } else { lim = PATH_MAX; } } /* read "hugepages-XXXXXkB" entries */ while ((result = readdir(dir)) != NULL) { if (strncmp(result->d_name, hugepages_dir, sizeof(hugepages_dir)-1)) { /* not node dir */ errno = 0; continue; } /* /sys/devices/system/node/node?/hugepages/ */ ssnprintf(path2, (size_t) lim, "%s/%s", path, result->d_name); e_info.d_name = result->d_name; e_info.node = node; walk_directory(path2, read_hugepage_entry, &e_info, 0); errno = 0; } /* Check if NULL return from readdir() was an error */ if (errno != 0) { ERROR("%s: readdir failed", g_plugin_name); closedir(dir); return -1; } closedir(dir); return 0; }
static int read_acpi (void) /* {{{ */ { int status; int battery_counter = 0; if (access (PROC_ACPI_PATH, R_OK) != 0) return (ENOENT); status = walk_directory (PROC_ACPI_PATH, read_acpi_callback, /* user_data = */ &battery_counter, /* include hidden */ 0); return (status); } /* }}} int read_acpi */
int impl_fuse_context::find_files(LPCWSTR file_name, PFillFindData fill_find_data, PDOKAN_FILE_INFO dokan_file_info) { if ((!ops_.readdir && !ops_.getdir) || !ops_.getattr) return -EINVAL; std::string fname = unixify(wchar_to_utf8_cstr(file_name)); CHECKED(check_and_resolve(&fname)); walk_data wd; wd.ctx = this; wd.dirname = fname; if (*fname.rbegin() != '/') wd.dirname.append("/"); wd.delegate = fill_find_data; wd.DokanFileInfo = dokan_file_info; if (ops_.readdir) { impl_file_handle *hndl = reinterpret_cast<impl_file_handle *>(dokan_file_info->Context); if (hndl != NULL) { fuse_file_info finfo(hndl->make_finfo()); return ops_.readdir(fname.c_str(), &wd, &walk_directory, 0, &finfo); } else return ops_.readdir(fname.c_str(), &wd, &walk_directory, 0, NULL); } else { CHECKED( ops_.getdir(fname.c_str(), (fuse_dirh_t)&wd, &walk_directory_getdir)); // Convert returned data The getdir_data array will be filled during // getdir() call. // We emulate FUSE behavior and do not pass information directly to Dokan // in walk_directory_getdir callback. This can cause excessive network // traffic // in sshfs because it populates stat buffer cache AFTER calling our // callback. // See: cache.c file, function cache_dirfill() in SSHFS 2.2 for (std::vector<std::string>::const_iterator f = wd.getdir_data.begin(); f != wd.getdir_data.end(); ++f) CHECKED(walk_directory(&wd, f->c_str(), 0, 0)); } return 0; }
static int cgroups_read (void) { cu_mount_t *mnt_list; cu_mount_t *mnt_ptr; _Bool cgroup_found = 0; mnt_list = NULL; if (cu_mount_getlist (&mnt_list) == NULL) { ERROR ("cgroups plugin: cu_mount_getlist failed."); return (-1); } for (mnt_ptr = mnt_list; mnt_ptr != NULL; mnt_ptr = mnt_ptr->next) { /* Find the cgroup mountpoint which contains the cpuacct * controller. */ if ((strcmp(mnt_ptr->type, "cgroup") != 0) || !cu_mount_checkoption(mnt_ptr->options, "cpuacct", /* full = */ 1)) continue; walk_directory (mnt_ptr->dir, read_cpuacct_root, /* user_data = */ NULL, /* include_hidden = */ 0); cgroup_found = 1; /* It doesn't make sense to check other cpuacct mount-points * (if any), they contain the same data. */ break; } cu_mount_freelist (mnt_list); if (!cgroup_found) { WARNING ("cgroups plugin: Unable to find cgroup " "mount-point with the \"cpuacct\" option."); return (-1); } return (0); } /* int cgroup_read */
static void walk_directory(const char *dirname) { assert(dirname); DIR *dir = opendir(dirname); if (dir) { struct dirent *entry; while ((entry = readdir(dir)) != NULL) { if (strcmp(entry->d_name, ".") == 0) continue; if (strcmp(entry->d_name, "..") == 0) continue; // build full path char *path; if (asprintf(&path, "%s/%s", dirname, entry->d_name) == -1) errExit("asprintf"); // check regular so library char *ptr = strstr(entry->d_name, ".so"); if (ptr && is_lib_64(path)) { if (*(ptr + 3) == '\0' || *(ptr + 3) == '.') { parse_elf(path); free(path); continue; } } // check directory // entry->d_type field is supported in glibc since version 2.19 (Feb 2014) // we'll use stat to check for directories struct stat s; if (stat(path, &s) == -1) errExit("stat"); if (S_ISDIR(s.st_mode)) walk_directory(path); } closedir(dir); } }
static int fc_read_dir (fc_directory_conf_t *dir) { int status; dir->files_num = 0; dir->files_size = 0; if (dir->mtime != 0) dir->now = time (NULL); status = walk_directory (dir->path, fc_read_dir_callback, dir, /* include hidden */ (dir->options & FC_HIDDEN) ? 1 : 0); if (status != 0) { WARNING ("filecount plugin: walk_directory (%s) failed.", dir->path); return (-1); } fc_submit_dir (dir); return (0); } /* int fc_read_dir */
void test_walk_directory(void) { walk_directory("/home/weezel/ohj"); }
int main(int argc, char **argv) { #if 0 { //system("cat /proc/self/status"); int i; for (i = 0; i < argc; i++) printf("*%s* ", argv[i]); printf("\n"); } #endif if (argc < 2) { fprintf(stderr, "Error fldd: invalid arguments\n"); usage(); exit(1); } if (strcmp(argv[1], "--help") == 0) { usage(); return 0; } // check program access if (access(argv[1], R_OK)) { fprintf(stderr, "Error fldd: cannot access %s\n", argv[1]); exit(1); } char *quiet = getenv("FIREJAIL_QUIET"); if (quiet && strcmp(quiet, "yes") == 0) arg_quiet = 1; if (strcmp(argv[1], "-h") == 0 || strcmp(argv[1], "--help") == 0 || strcmp(argv[1], "-?") ==0) { usage(); return 0; } int fd = STDOUT_FILENO; // attempt to open the file if (argc == 3) { fd = open(argv[2], O_CREAT | O_TRUNC | O_WRONLY, 0644); if (!fd) { fprintf(stderr, "Error fldd: invalid arguments\n"); usage(); exit(1); } } // initialize local storage lib_paths_init(); // process files struct stat s; if (stat(argv[1], &s) == -1) errExit("stat"); if (S_ISDIR(s.st_mode)) walk_directory(argv[1]); else { if (is_lib_64(argv[1])) parse_elf(argv[1]); else fprintf(stderr, "Warning fldd: %s is not a 64bit program/library\n", argv[1]); } // print libraries and exit storage_print(libs, fd); if (argc == 3) close(fd); return 0; }
static struct imgspec* create_imgspec(int argc, char* argv[]) { struct imgspec* spec = malloc(sizeof(*spec)); if (!spec) error("failed to allocate an image spec"); memset(spec, 0, sizeof(*spec)); spec->sp_root = malloc(sizeof(*spec->sp_root)); if (!spec->sp_root) error("failed to allocate the root entry"); memset(spec->sp_root, 0, sizeof(*spec->sp_root)); spec->sp_name = MICROFS_DEFAULTNAME; spec->sp_shareblocks = 1; spec->sp_lib = hostprog_lib_find_any(); if (!spec->sp_lib) { error("could not determine which hostprog lib to use"); } spec->sp_pagesz = sysconf(_SC_PAGESIZE); spec->sp_blksz = MICROFS_DEFAULBLKSZ; spec->sp_szpad = spec->sp_pagesz; if (argc < 2) usage(argc > 0 ? argv[0] : "microfsmki", stderr, spec); /* Check what the user want. */ int option; char optionbuffer[3]; while ((option = getopt(argc, argv, MKI_OPTIONS)) != EOF) { size_t len; switch (option) { case 'h': usage(argv[0], stdout, spec); break; case 'v': hostprog_verbosity++; break; case 'e': hostprog_werror = 1; break; case 'p': spec->sp_pad = 1; break; case 'q': spec->sp_squashperms = 1; break; case 's': spec->sp_incsocks = 1; break; case 'S': spec->sp_shareblocks = 0; break; case 'b': opt_strtolx(ul, optiontostr(option, optionbuffer), optarg, spec->sp_blksz); if (!microfs_ispow2(spec->sp_blksz)) error("the block size must be a power of two"); if (spec->sp_blksz < MICROFS_MINBLKSZ || spec->sp_blksz > MICROFS_MAXBLKSZ) { error("block size out of boundaries, %llu given;" " min=%d, max=%d", spec->sp_blksz, MICROFS_MINBLKSZ, MICROFS_MAXBLKSZ); } break; case 'u': opt_strtolx(ull, optiontostr(option, optionbuffer), optarg, spec->sp_usrupperbound); break; case 'P': opt_strtolx(ull, optiontostr(option, optionbuffer), optarg, spec->sp_szpad); if (!microfs_ispow2(spec->sp_szpad)) error("the size padding must be a power of two"); break; case 'n': spec->sp_name = optarg; len = strlen(spec->sp_name); if (len > MICROFS_SBNAME_LENGTH) { warning("image name \"%s\" is too long" " it will be truncated from %zu to %d bytes", spec->sp_name, len, MICROFS_SBNAME_LENGTH); } break; case 'c': spec->sp_lib = hostprog_lib_find_byname(optarg); if (!spec->sp_lib) error("could not find a compression library named %s", optarg); break; case 'D': spec->sp_devtable = optarg; break; case 'l': spec->sp_lib_options = optarg; break; default: /* Ignore it. */ warning("unrecognized option -%c", option); break; } } /* The block size should now be correctly set, which means * that the block left shift can be calculated. */ __u64 blksz = spec->sp_blksz; while ((blksz >>= 1) > 0) spec->sp_blkshift++; if (spec->sp_usrupperbound % spec->sp_blksz != 0) error("upper bound must be a multiple of the block size"); if (hostprog_stack_create(&spec->sp_regstack, 64, 64) < 0) error("failed to create the regular file stack"); if (spec->sp_squashperms && spec->sp_devtable) { warning("both -q and -d are set, this might not be a good idea" " - the device table could override some or all permissions"); } spec->sp_upperbound = sizeof(struct microfs_sb); if (spec->sp_pad) spec->sp_upperbound += MICROFS_PADDING; if ((argc - optind) != 2) usage(argv[0], stderr, spec); spec->sp_rootdir = argv[optind + 0]; spec->sp_outfile = argv[optind + 1]; if (!spec->sp_lib->hl_compiled) error("%s support has not been compiled", spec->sp_lib->hl_info->li_name); if (spec->sp_lib->hl_init(&spec->sp_lib_data, spec->sp_blksz) < 0) error("failed to init %s", spec->sp_lib->hl_info->li_name); lib_options(spec); spec->sp_upperbound += spec->sp_lib->hl_info->li_dd_sz; if (spec->sp_lib->hl_info->li_min_blksz == 0 && spec->sp_blksz < spec->sp_pagesz) { warning("block size smaller than page size of host" " - the resulting image can not be used on this host"); } struct stat st; if (stat(spec->sp_rootdir, &st) == 0) { if (!S_ISDIR(st.st_mode)) error("\"%s\" is not a directory", spec->sp_rootdir); } else error("can not stat \"%s\": %s", spec->sp_rootdir, strerror(errno)); struct hostprog_path* path = NULL; if (hostprog_path_create(&path, spec->sp_rootdir, MICROFS_MAXNAMELEN, MICROFS_MAXNAMELEN) != 0) { error("failed to create the path for the rootdir: %s", strerror(errno)); } spec->sp_root->e_mode = st.st_mode; spec->sp_root->e_uid = st.st_uid; spec->sp_root->e_gid = st.st_gid; spec->sp_root->e_size = walk_directory(spec, path, &spec->sp_root->e_firstchild); hostprog_path_destroy(path); if (spec->sp_shareblocks) find_duplicates(spec); if (spec->sp_devtable) devtable_parse(devtable_process_dentry, spec, spec->sp_devtable, MICROFS_ISIZE_WIDTH); if (spec->sp_usrupperbound && spec->sp_upperbound > spec->sp_usrupperbound) { warning("the estimated upper bound %llu is larger than the" " user requested upper bound %llu", spec->sp_upperbound, spec->sp_usrupperbound); } /* Allocate a max block size sized multiple of bytes. */ spec->sp_upperbound = sz_blkceil(spec->sp_upperbound, MICROFS_MAXBLKSZ); if (spec->sp_upperbound > MICROFS_MAXIMGSIZE) { warning("upper bound image size (absolute worst-case scenario)" " of %llu bytes is larger than the max image size of %llu bytes," " there might not be room for everything", spec->sp_upperbound, MICROFS_MAXIMGSIZE); spec->sp_upperbound = MICROFS_MAXIMGSIZE; } int flags = O_RDWR | O_CREAT | O_TRUNC; spec->sp_fd = open(spec->sp_outfile, flags, 0666); if (spec->sp_fd < 0) error("failed to open \"%s\": %s", spec->sp_rootdir, strerror(errno)); /* The worst case compression scenario will always fit in the * buffer since the upper bound for a data size smaller than * a block is always smaller than the upper bound for an entire * block. */ spec->sp_compressionbufsz = spec->sp_lib->hl_upperbound( spec->sp_lib_data, spec->sp_blksz); spec->sp_compressionbuf = malloc(spec->sp_compressionbufsz); if (!spec->sp_compressionbuf) error("failed to allocate the compression buffer"); message(VERBOSITY_1, "Block size: %llu", spec->sp_blksz); message(VERBOSITY_1, "Block shift: %llu", spec->sp_blkshift); message(VERBOSITY_0, "Compression library: %s", spec->sp_lib->hl_info->li_name); message(VERBOSITY_0, "Upper bound image size: %llu bytes", spec->sp_upperbound); message(VERBOSITY_0, "Number of files: %llu", spec->sp_files); message(VERBOSITY_0, "Directories: %llu", spec->sp_dirnodes); message(VERBOSITY_0, "Regular files: %llu", spec->sp_regnodes); message(VERBOSITY_0, "Duplicate files: %llu", spec->sp_duplicatenodes); message(VERBOSITY_0, "Special files: %llu", spec->sp_specnodes); message(VERBOSITY_0, "Skipped files: %llu", spec->sp_skipnodes); message(VERBOSITY_1, "Data size: %llu", spec->sp_datasz); message(VERBOSITY_1, "Real data size: %llu", spec->sp_realdatasz); message(VERBOSITY_1, "Block pointers required: %llu", spec->sp_blkptrs); if (spec->sp_skipnodes) { warning("not all files will be included in the image"); if (hostprog_verbosity < VERBOSITY_1) message(VERBOSITY_0, ">>> use -v to get more information"); } return spec; }
static unsigned int walk_directory(struct imgspec* const spec, struct hostprog_path* const path, struct entry** previous) { struct dirent** dirlst; int dirlst_count; int dirlst_index; __u64 dir_sz = 0; __u64 dir_lvl = hostprog_path_lvls(path); dirlst_count = scandir(path->p_path, &dirlst, NULL, hostprog_scandirsort); if (dirlst_count < 0) error("failed to read \"%s\": %s", path->p_path, strerror(errno)); for (dirlst_index = 0; dirlst_index < dirlst_count; dirlst_index++) { struct dirent* dent = dirlst[dirlst_index]; /* Skip "." and ".." directories, just like mkcramfs. */ if (hostprog_path_dotdir(dent->d_name)) continue; hostprog_path_dirnamelvl(path, dir_lvl); if (hostprog_path_append(path, dent->d_name) != 0) error("failed to add a filename to the hostprog_path"); struct stat st; if (lstat(path->p_path, &st) < 0) { /* Maybe this should be an error? Files missing in the image * could possibly seem like an error to the user. */ warning("skipping \"unlstatable\" file \"%s\": %s", path->p_path, strerror(errno)); spec->sp_skipnodes++; continue; } if (S_ISREG(st.st_mode) || S_ISLNK(st.st_mode)) { /* If the file is a regular file which can not be read, then * it might as well be skipped. * * This should also possibly be an error. */ if (access(path->p_path, R_OK) < 0) { warning("skipping unreadable file \"%s\": %s", path->p_path, strerror(errno)); spec->sp_skipnodes++; continue; } /* Completely empty files seems pretty pointless to include * in the image. */ if (!st.st_size) { message(VERBOSITY_1, ">>> skipping empty file \"%s\"", path->p_path); spec->sp_skipnodes++; continue; } } else if (!spec->sp_incsocks && S_ISSOCK(st.st_mode)) { warning("skipping socket \"%s\"", path->p_path); spec->sp_skipnodes++; continue; } /* Files should never be skipped after this point since that * would mess up the image size estimation. */ struct entry* ent = malloc(sizeof(*ent)); if (!ent) error("failed to alloc an entry for \"%s\"", path->p_path); memset(ent, 0, sizeof(*ent)); ent->e_name = strdup(dent->d_name); if (!ent->e_name) error("failed to copy the entry name for \"%s\"", path->p_path); ent->e_mode = st.st_mode; ent->e_size = st.st_size; ent->e_fd = -1; ENTRY_SET_XID(spec, ent, e_uid, st.st_uid, MICROFS_IUID_WIDTH); ENTRY_SET_XID(spec, ent, e_gid, st.st_gid, MICROFS_IGID_WIDTH); if (S_ISDIR(ent->e_mode)) { ent->e_size = walk_directory(spec, path, &ent->e_firstchild); } else if (S_ISREG(ent->e_mode) || S_ISLNK(ent->e_mode)) { if (ent->e_size > MICROFS_MAXFILESIZE) { error("\"%s\" is too big, max file size is %llu bytes", path->p_path, MICROFS_MAXFILESIZE); } else if (ent->e_size > MICROFS_MAXCRAMSIZE) { warning("\"%s\" is a big file, microfs works best with files" " smaller than %llu bytes", path->p_path, MICROFS_MAXCRAMSIZE); } ent->e_path = strdup(path->p_path); if (!ent->e_path) { error("failed to copy the entry path for \"%s\"", path->p_path); } if (spec->sp_shareblocks) { if (hostprog_stack_push(spec->sp_regstack, ent) < 0) error("failed to push an entry to the regular file stack: %s", strerror(errno)); } } else if (S_ISCHR(ent->e_mode) || S_ISBLK(ent->e_mode)) { ent->e_size = makedev_lim(major(st.st_rdev), minor(st.st_rdev), MICROFS_ISIZE_WIDTH); } else if (S_ISFIFO(ent->e_mode) || S_ISSOCK(ent->e_mode)) { ent->e_size = 0; } else { error("unexpected file mode encountered"); } /* %namelen() could actually fail here if the d_name is too * long, but that will terminate the program, so that is fine. */ dir_sz += update_upperbound(spec, ent, namelen(dent->d_name)); update_stats(spec, ent); message(VERBOSITY_1, "+ %c %s", nodtype(ent->e_mode), path->p_path); *previous = ent; previous = &ent->e_sibling; } free(dirlst); hostprog_path_dirnamelvl(path, dir_lvl); /* This should never happen, but if it ever does, it is * clearly an error. */ if (dir_sz > MICROFS_MAXDIRSIZE) { error("achievement unlocked: the directory size for \"%s\"" " is %llu bytes, the maximum supported size is %llu bytes" " - this is impressive in a very scary way", path->p_path, dir_sz, MICROFS_MAXDIRSIZE); } return dir_sz; }
static int thermal_procfs_read (void) { return walk_directory (dirname_procfs, thermal_procfs_device_read, /* user_data = */ NULL); }
static int fc_read_dir_callback (const char *dirname, const char *filename, void *user_data) { fc_directory_conf_t *dir = user_data; char abs_path[PATH_MAX]; struct stat statbuf; int status; if (dir == NULL) return (-1); ssnprintf (abs_path, sizeof (abs_path), "%s/%s", dirname, filename); status = lstat (abs_path, &statbuf); if (status != 0) { ERROR ("filecount plugin: stat (%s) failed.", abs_path); return (-1); } if (S_ISDIR (statbuf.st_mode) && (dir->options & FC_RECURSIVE)) { status = walk_directory (abs_path, fc_read_dir_callback, dir, /* include hidden = */ (dir->options & FC_HIDDEN) ? 1 : 0); return (status); } else if (!S_ISREG (statbuf.st_mode)) { return (0); } if (dir->name != NULL) { status = fnmatch (dir->name, filename, /* flags = */ 0); if (status != 0) return (0); } if (dir->mtime != 0) { time_t mtime = dir->now; if (dir->mtime < 0) mtime += dir->mtime; else mtime -= dir->mtime; DEBUG ("filecount plugin: Only collecting files that were touched %s %u.", (dir->mtime < 0) ? "after" : "before", (unsigned int) mtime); if (((dir->mtime < 0) && (statbuf.st_mtime < mtime)) || ((dir->mtime > 0) && (statbuf.st_mtime > mtime))) return (0); } if (dir->size != 0) { off_t size; if (dir->size < 0) size = (off_t) ((-1) * dir->size); else size = (off_t) dir->size; if (((dir->size < 0) && (statbuf.st_size > size)) || ((dir->size > 0) && (statbuf.st_size < size))) return (0); } dir->files_num++; dir->files_size += (uint64_t) statbuf.st_size; return (0); } /* int fc_read_dir_callback */