/** * Make the current environment persistent * @param[in] filename where to store * @param[in] dirname what to store (all files in this dir) * @return 0 on success, anything else in case of failure * * Note: This function will also be used on the host! See note in the header * of this file. */ int envfs_save(char *filename, char *dirname) { struct envfs_super *super; int envfd, size, ret; struct action_data data; void *buf = NULL; data.writep = NULL; data.base = dirname; /* first pass: calculate size */ recursive_action(dirname, ACTION_RECURSE, file_size_action, NULL, &data, 0); size = (unsigned long)data.writep; buf = xzalloc(size + sizeof(struct envfs_super)); data.writep = buf + sizeof(struct envfs_super); super = (struct envfs_super *)buf; super->magic = ENVFS_32(ENVFS_MAGIC); super->major = ENVFS_MAJOR; super->minor = ENVFS_MINOR; super->size = ENVFS_32(size); /* second pass: copy files to buffer */ recursive_action(dirname, ACTION_RECURSE, file_save_action, NULL, &data, 0); super->crc = ENVFS_32(crc32(0, buf + sizeof(struct envfs_super), size)); super->sb_crc = ENVFS_32(crc32(0, buf, sizeof(struct envfs_super) - 4)); envfd = open(filename, O_WRONLY | O_CREAT, S_IRUSR | S_IWUSR); if (envfd < 0) { printf("Open %s %s\n", filename, errno_str()); ret = envfd; goto out1; } if (write(envfd, buf, size + sizeof(struct envfs_super)) < sizeof(struct envfs_super)) { perror("write"); ret = -1; /* FIXME */ goto out; } ret = 0; out: close(envfd); out1: free(buf); return ret; }
int chgrp_main(int argc, char **argv) { long gid; int recursiveFlag; int retval = EXIT_SUCCESS; char *p; recursiveFlag = bb_getopt_ulflags(argc, argv, "R"); if (argc - optind < 2) { bb_show_usage(); } argv += optind; /* Find the selected group */ gid = strtoul(*argv, &p, 10); /* maybe it's already numeric */ if (*p || (p == *argv)) { /* trailing chars or nonnumeric */ gid = my_getgrnam(*argv); } ++argv; /* Ok, ready to do the deed now */ do { if (! recursive_action (*argv, recursiveFlag, FALSE, FALSE, fileAction, fileAction, &gid)) { retval = EXIT_FAILURE; } } while (*++argv); return retval; }
int chgrp_main(int argc, char **argv) { long gid; int recursiveFlag; int retval = EXIT_SUCCESS; recursiveFlag = bb_getopt_ulflags(argc, argv, "R"); if (argc - optind < 2) { bb_show_usage(); } argv += optind; /* Find the selected group */ gid = get_ug_id(*argv, my_getgrnam); ++argv; /* Ok, ready to do the deed now */ do { if (! recursive_action (*argv, recursiveFlag, FALSE, FALSE, fileAction, fileAction, &gid)) { retval = EXIT_FAILURE; } } while (*++argv); return retval; }
int DEPMOD_MAIN(int argc, char *argv[], int all, const char *system_map, const char *base_dir, const char *module_dir, const char *file_syms) { int ret; if (all) { if ((ret = addksyms(file_syms)) != -1) { recursive_action(module_dir, TRUE, FALSE, FALSE, add_module, 0, NULL); resolve(); ret = prtdepend(base_dir, module_dir, flag_dry) || ret; } } else { /* not stdmode */ if ((ret = addksyms(file_syms)) != -1) { for (; argc > 0 && ret != -1; ++argv, --argc) loadobj(*argv, file_syms != NULL); resolve(); ret = prtdepend(base_dir, module_dir, flag_dry) || ret; } } return ret; }
int chmod_main(int ATTRIBUTE_UNUSED argc, char **argv) { int retval = EXIT_SUCCESS; int recursiveFlag = FALSE; int count; char *smode; char **p; char *p0; char opt = '-'; ++argv; count = 0; for (p = argv ; *p ; p++) { p0 = p[0]; if (p0[0] == opt) { if ((p0[1] == '-') && !p0[2]) { opt = 0; /* Disable further option processing. */ continue; } if (p0[1] == 'R') { char *s = p0 + 2; while (*s == 'R') { ++s; } if (*s) { bb_show_usage(); } recursiveFlag = TRUE; continue; } if (count) { bb_show_usage(); } } argv[count] = p0; ++count; } argv[count] = NULL; if (count < 2) { bb_show_usage(); } smode = *argv; ++argv; /* Ok, ready to do the deed now */ do { if (! recursive_action (*argv, recursiveFlag, TRUE, FALSE, fileAction, fileAction, smode)) { retval = EXIT_FAILURE; } } while (*++argv); return retval; }
static int writeTarFile(const char* tarName, int verboseFlag, char **argv, char** excludeList) { int tarFd=-1; int errorFlag=FALSE; ssize_t size; struct TarBallInfo tbInfo; tbInfo.verboseFlag = verboseFlag; tbInfo.hlInfoHead = NULL; /* Make sure there is at least one file to tar up. */ if (*argv == NULL) error_msg_and_die("Cowardly refusing to create an empty archive"); /* Open the tar file for writing. */ if (!strcmp(tarName, "-")) tbInfo.tarFd = fileno(stdout); else tbInfo.tarFd = open (tarName, O_WRONLY | O_CREAT | O_TRUNC, 0644); if (tbInfo.tarFd < 0) { perror_msg( "Error opening '%s'", tarName); freeHardLinkInfo(&tbInfo.hlInfoHead); return ( FALSE); } tbInfo.excludeList=excludeList; /* Store the stat info for the tarball's file, so * can avoid including the tarball into itself.... */ if (fstat(tbInfo.tarFd, &tbInfo.statBuf) < 0) error_msg_and_die(io_error, tarName, strerror(errno)); /* Read the directory/files and iterate over them one at a time */ while (*argv != NULL) { if (recursive_action(*argv++, TRUE, FALSE, FALSE, writeFileToTarball, writeFileToTarball, (void*) &tbInfo) == FALSE) { errorFlag = TRUE; } } /* Write two empty blocks to the end of the archive */ for (size=0; size<(2*TAR_BLOCK_SIZE); size++) { write(tbInfo.tarFd, "\0", 1); } /* To be pedantically correct, we would check if the tarball * is smaller than 20 tar blocks, and pad it if it was smaller, * but that isn't necessary for GNU tar interoperability, and * so is considered a waste of space */ /* Hang up the tools, close up shop, head home */ close(tarFd); if (errorFlag == TRUE) { error_msg("Error exit delayed from previous errors"); freeHardLinkInfo(&tbInfo.hlInfoHead); return(FALSE); } freeHardLinkInfo(&tbInfo.hlInfoHead); return( TRUE); }
static int grep_dir(const char *dir) { int matched = 0; recursive_action(dir, /* recurse= */ 1, /* followLinks= */ 0, /* depthFirst= */ 1, /* fileAction= */ file_action_grep, /* dirAction= */ NULL, /* userData= */ &matched, /* depth= */ 0); return matched; }
int chcon_main(int argc, char **argv) { char *reference_file; char *fname; int i, errors = 0; #if ENABLE_FEATURE_CHCON_LONG_OPTIONS applet_long_options = chcon_longopts; #endif opt_complementary = "-1" /* at least 1 param */ ":?" /* error if exclusivity constraints are violated */ #if ENABLE_FEATURE_CHCON_LONG_OPTIONS ":\xff--urtl:u--\xff:r--\xff:t--\xff:l--\xff" #endif ":f--v:v--f"; /* 'verbose' and 'quiet' are exclusive */ getopt32(argv, "Rchfu:r:t:l:v", &user, &role, &type, &range, &reference_file); argv += optind; #if ENABLE_FEATURE_CHCON_LONG_OPTIONS if (option_mask32 & OPT_REFERENCE) { /* FIXME: lgetfilecon() should be used when '-h' is specified. But current implementation follows the original one. */ if (getfilecon(reference_file, &specified_context) < 0) bb_perror_msg_and_die("getfilecon('%s') failed", reference_file); } else #endif if ((option_mask32 & OPT_COMPONENT_SPECIFIED) == 0) { specified_context = *argv++; /* specified_context is never NULL - * "-1" in opt_complementary prevents this. */ if (!argv[0]) bb_error_msg_and_die("too few arguments"); } for (i = 0; (fname = argv[i]) != NULL; i++) { int fname_len = strlen(fname); while (fname_len > 1 && fname[fname_len - 1] == '/') fname_len--; fname[fname_len] = '\0'; if (recursive_action(fname, 1<<option_mask32 & OPT_RECURSIVE, change_filedir_context, change_filedir_context, NULL, 0) != TRUE) errors = 1; } return errors; }
int chmod_main(int argc, char **argv) { int i; int opt; int recursiveFlag = FALSE; int opt_eq_modeFlag = FALSE; /* do normal option parsing */ while ((opt = getopt(argc, argv, "Rrwxst")) > 0) { switch (opt) { case 'R': recursiveFlag = TRUE; break; case 'r': case 'w': case 'x': case 's': case 't': opt_eq_modeFlag = TRUE; break; default: show_usage(); } } if (opt_eq_modeFlag == TRUE) { optind--; } if (argc > optind && argc > 2 && argv[optind]) { /* Parse the specified mode */ mode_t mode; if (parse_mode(argv[optind], &mode) == FALSE) { error_msg_and_die( "unknown mode: %s", argv[optind]); } } else { error_msg_and_die(too_few_args); } /* Ok, ready to do the deed now */ for (i = optind + 1; i < argc; i++) { if (recursive_action (argv[i], recursiveFlag, FALSE, FALSE, fileAction, fileAction, argv[optind]) == FALSE) { return EXIT_FAILURE; } } return EXIT_SUCCESS; }
int unlink_recursive(const char *path, char **failedpath) { struct data data = {}; int ret; if (failedpath) *failedpath = NULL; ret = recursive_action(path, ACTION_RECURSE | ACTION_DEPTHFIRST, file_action, dir_action, &data, 0); if (!ret && failedpath) *failedpath = unlink_recursive_failedpath; return ret ? 0 : -errno; }
int chmod_main(int argc, char **argv) { int retval = EXIT_SUCCESS; char *arg, **argp; char *smode; /* Convert first encountered -r into ar, -w into aw etc * so that getopt would not eat it */ argp = argv; while ((arg = *++argp)) { /* Mode spec must be the first arg (sans -R etc) */ /* (protect against mishandling e.g. "chmod 644 -r") */ if (arg[0] != '-') { arg = NULL; break; } /* An option. Not a -- or valid option? */ if (arg[1] && !strchr("-"OPT_STR, arg[1])) { arg[0] = 'a'; break; } } /* Parse options */ opt_complementary = "-2"; getopt32(argv, ("-"OPT_STR) + 1); /* Reuse string */ argv += optind; /* Restore option-like mode if needed */ if (arg) arg[0] = '-'; /* Ok, ready to do the deed now */ smode = *argv++; do { if (!recursive_action(*argv, OPT_RECURSE, // recurse fileAction, // file action fileAction, // dir action smode, // user data 0) // depth ) { retval = EXIT_FAILURE; } } while (*++argv); return retval; }
int chown_main(int argc, char **argv) { int flags; int retval = EXIT_SUCCESS; char *groupName; flags = bb_getopt_ulflags(argc, argv, "Rh"); if (flags & FLAG_h) chown_func = lchown; if (argc - optind < 2) { bb_show_usage(); } argv += optind; /* First, check if there is a group name here */ if ((groupName = strchr(*argv, '.')) == NULL) { groupName = strchr(*argv, ':'); } /* Check for the username and groupname */ if (groupName) { *groupName++ = '\0'; gid = get_ug_id(groupName, bb_xgetgrnam); } if (--groupName != *argv) uid = get_ug_id(*argv, bb_xgetpwnam); ++argv; /* Ok, ready to do the deed now */ do { if (! recursive_action (*argv, (flags & FLAG_R), FALSE, FALSE, fileAction, fileAction, NULL)) { retval = EXIT_FAILURE; } } while (*++argv); return retval; }
static int writeTarFile(const int tar_fd, const int verboseFlag, const unsigned long dereferenceFlag, const llist_t *include, const llist_t *exclude, const int gzip) { pid_t gzipPid = 0; int errorFlag = FALSE; struct TarBallInfo tbInfo; tbInfo.hlInfoHead = NULL; fchmod(tar_fd, 0644); tbInfo.tarFd = tar_fd; tbInfo.verboseFlag = verboseFlag; /* Store the stat info for the tarball's file, so * can avoid including the tarball into itself.... */ if (fstat(tbInfo.tarFd, &tbInfo.statBuf) < 0) bb_perror_msg_and_die("cannot stat tar file"); if ((ENABLE_FEATURE_TAR_GZIP || ENABLE_FEATURE_TAR_BZIP2) && gzip) { int gzipDataPipe[2] = { -1, -1 }; int gzipStatusPipe[2] = { -1, -1 }; volatile int vfork_exec_errno = 0; const char *zip_exec = (gzip == 1) ? "gzip" : "bzip2"; if (pipe(gzipDataPipe) < 0 || pipe(gzipStatusPipe) < 0) bb_perror_msg_and_die("pipe"); signal(SIGPIPE, SIG_IGN); /* we only want EPIPE on errors */ #if defined(__GNUC__) && __GNUC__ /* Avoid vfork clobbering */ (void) &include; (void) &errorFlag; (void) &zip_exec; #endif gzipPid = vfork(); if (gzipPid == 0) { dup2(gzipDataPipe[0], 0); close(gzipDataPipe[1]); dup2(tbInfo.tarFd, 1); close(gzipStatusPipe[0]); fcntl(gzipStatusPipe[1], F_SETFD, FD_CLOEXEC); /* close on exec shows success */ BB_EXECLP(zip_exec, zip_exec, "-f", NULL); vfork_exec_errno = errno; close(gzipStatusPipe[1]); exit(-1); } else if (gzipPid > 0) { close(gzipDataPipe[0]); close(gzipStatusPipe[1]); while (1) { char buf; int n = full_read(gzipStatusPipe[0], &buf, 1); if (n == 0 && vfork_exec_errno != 0) { errno = vfork_exec_errno; bb_perror_msg_and_die("cannot exec %s", zip_exec); } else if ((n < 0) && (errno == EAGAIN || errno == EINTR)) continue; /* try it again */ break; } close(gzipStatusPipe[0]); tbInfo.tarFd = gzipDataPipe[1]; } else bb_perror_msg_and_die("vfork gzip"); } tbInfo.excludeList = exclude; /* Read the directory/files and iterate over them one at a time */ while (include) { if (!recursive_action(include->data, TRUE, dereferenceFlag, FALSE, writeFileToTarball, writeFileToTarball, &tbInfo, 0)) { errorFlag = TRUE; } include = include->link; } /* Write two empty blocks to the end of the archive */ memset(bb_common_bufsiz1, 0, 2*TAR_BLOCK_SIZE); xwrite(tbInfo.tarFd, bb_common_bufsiz1, 2*TAR_BLOCK_SIZE); /* To be pedantically correct, we would check if the tarball * is smaller than 20 tar blocks, and pad it if it was smaller, * but that isn't necessary for GNU tar interoperability, and * so is considered a waste of space */ /* Close so the child process (if any) will exit */ close(tbInfo.tarFd); /* Hang up the tools, close up shop, head home */ if (ENABLE_FEATURE_CLEAN_UP) freeHardLinkInfo(&tbInfo.hlInfoHead); if (errorFlag) bb_error_msg("error exit delayed from previous errors"); if (gzipPid) { int status; if (waitpid(gzipPid, &status, 0) == -1) bb_perror_msg("waitpid"); else if (!WIFEXITED(status) || WEXITSTATUS(status)) /* gzip was killed or has exited with nonzero! */ errorFlag = TRUE; } return errorFlag; }
int find_main(int argc, char **argv) { int dereference = FALSE; int i, firstopt, status = EXIT_SUCCESS; for (firstopt = 1; firstopt < argc; firstopt++) { if (argv[firstopt][0] == '-') break; } /* Parse any options */ for (i = firstopt; i < argc; i++) { if (strcmp(argv[i], "-follow") == 0) dereference = TRUE; else if (strcmp(argv[i], "-print") == 0) { ; } else if (strcmp(argv[i], "-name") == 0) { if (++i == argc) error_msg_and_die("option `-name' requires an argument"); pattern = argv[i]; #ifdef BB_FEATURE_FIND_TYPE } else if (strcmp(argv[i], "-type") == 0) { if (++i == argc) error_msg_and_die("option `-type' requires an argument"); type_mask = find_type(argv[i]); #endif #ifdef BB_FEATURE_FIND_PERM } else if (strcmp(argv[i], "-perm") == 0) { char *end; if (++i == argc) error_msg_and_die("option `-perm' requires an argument"); perm_mask = strtol(argv[i], &end, 8); if (end[0] != '\0') error_msg_and_die("invalid argument `%s' to `-perm'", argv[i]); if (perm_mask > 07777) error_msg_and_die("invalid argument `%s' to `-perm'", argv[i]); if ((perm_char = argv[i][0]) == '-') perm_mask = -perm_mask; #endif #ifdef BB_FEATURE_FIND_MTIME } else if (strcmp(argv[i], "-mtime") == 0) { char *end; if (++i == argc) error_msg_and_die("option `-mtime' requires an argument"); mtime_days = strtol(argv[i], &end, 10); if (end[0] != '\0') error_msg_and_die("invalid argument `%s' to `-mtime'", argv[i]); if ((mtime_char = argv[i][0]) == '-') mtime_days = -mtime_days; #endif #ifdef BB_FEATURE_FIND_NEWER } else if (strcmp(argv[i], "-newer") == 0) { struct stat stat_newer; if (++i == argc) error_msg_and_die("option `-newer' requires an argument"); if (stat (argv[i], &stat_newer) != 0) error_msg_and_die("file %s not found", argv[i]); newer_mtime = stat_newer.st_mtime; #endif } else show_usage(); } if (firstopt == 1) { if (recursive_action(".", TRUE, dereference, FALSE, fileAction, fileAction, NULL) == FALSE) status = EXIT_FAILURE; } else { for (i = 1; i < firstopt; i++) { if (recursive_action(argv[i], TRUE, dereference, FALSE, fileAction, fileAction, NULL) == FALSE) status = EXIT_FAILURE; } } return status; }
/* gcc 4.2.1 inlines it, making code bigger */ static NOINLINE int writeTarFile(int tar_fd, int verboseFlag, int dereferenceFlag, const llist_t *include, const llist_t *exclude, int gzip) { int errorFlag = FALSE; struct TarBallInfo tbInfo; tbInfo.hlInfoHead = NULL; tbInfo.tarFd = tar_fd; tbInfo.verboseFlag = verboseFlag; /* Store the stat info for the tarball's file, so * can avoid including the tarball into itself.... */ if (fstat(tbInfo.tarFd, &tbInfo.statBuf) < 0) bb_perror_msg_and_die("cannot stat tar file"); #if ENABLE_FEATURE_SEAMLESS_GZ || ENABLE_FEATURE_SEAMLESS_BZ2 if (gzip) vfork_compressor(tbInfo.tarFd, gzip); #endif tbInfo.excludeList = exclude; /* Read the directory/files and iterate over them one at a time */ while (include) { if (!recursive_action(include->data, ACTION_RECURSE | (dereferenceFlag ? ACTION_FOLLOWLINKS : 0), writeFileToTarball, writeFileToTarball, &tbInfo, 0)) { errorFlag = TRUE; } include = include->link; } /* Write two empty blocks to the end of the archive */ memset(block_buf, 0, 2*TAR_BLOCK_SIZE); xwrite(tbInfo.tarFd, block_buf, 2*TAR_BLOCK_SIZE); /* To be pedantically correct, we would check if the tarball * is smaller than 20 tar blocks, and pad it if it was smaller, * but that isn't necessary for GNU tar interoperability, and * so is considered a waste of space */ /* Close so the child process (if any) will exit */ close(tbInfo.tarFd); /* Hang up the tools, close up shop, head home */ if (ENABLE_FEATURE_CLEAN_UP) freeHardLinkInfo(&tbInfo.hlInfoHead); if (errorFlag) bb_error_msg("error exit delayed from previous errors"); #if ENABLE_FEATURE_SEAMLESS_GZ || ENABLE_FEATURE_SEAMLESS_BZ2 if (gzip) { int status; if (safe_waitpid(-1, &status, 0) == -1) bb_perror_msg("waitpid"); else if (!WIFEXITED(status) || WEXITSTATUS(status)) /* gzip was killed or has exited with nonzero! */ errorFlag = TRUE; } #endif return errorFlag; }
extern int cp_mv_main(int argc, char **argv) { volatile int i; int c; RESERVE_BB_BUFFER(baseDestName,BUFSIZ + 1); pBaseDestName = baseDestName; /* available globally */ if (*applet_name == 'c' && *(applet_name + 1) == 'p') dz_i = is_cp; else dz_i = is_mv; if (argc < 3) goto exit_show_usage; if (dz_i == is_cp) { recursiveFlag = preserveFlag = forceFlag = FALSE; followLinks = TRUE; while ((c = getopt(argc, argv, "adpRf")) != EOF) { switch (c) { case 'a': followLinks = FALSE; preserveFlag = TRUE; recursiveFlag = TRUE; break; case 'd': followLinks = FALSE; break; case 'p': preserveFlag = TRUE; break; case 'R': recursiveFlag = TRUE; break; case 'f': forceFlag = TRUE; break; default: goto exit_show_usage; } } if ((argc - optind) < 2) { goto exit_show_usage; } } else { /* (dz_i == is_mv) */ /* Initialize optind to 1, since in libc5 optind * is not initialized until getopt() is called * (or until sneaky programmers force it...). */ optind = 1; recursiveFlag = preserveFlag = TRUE; followLinks = FALSE; } if (strlen(argv[argc - 1]) > BUFSIZ) { error_msg(name_too_long); goto exit_false; } strcpy(baseDestName, argv[argc - 1]); baseDestLen = strlen(baseDestName); if (baseDestLen == 0) goto exit_false; destDirFlag = is_directory(baseDestName, TRUE, &destStatBuf); if (argc - optind > 2 && destDirFlag == FALSE) { error_msg(not_a_directory, baseDestName); goto exit_false; } for (i = optind; i < (argc-1); i++) { size_t srcLen; volatile int flags_memo; int status; baseSrcName=argv[i]; if ((srcLen = strlen(baseSrcName)) > BUFSIZ) name_too_long__exit(); if (srcLen == 0) continue; /* "" */ srcDirFlag = is_directory(baseSrcName, followLinks, &srcStatBuf); if ((flags_memo = (recursiveFlag == TRUE && srcDirFlag == TRUE && destDirFlag == TRUE))) { struct stat sb; int state = 0; char *pushd, *d, *p; if ((pushd = getcwd(NULL, BUFSIZ + 1)) == NULL) { perror_msg("getcwd()"); continue; } if (chdir(baseDestName) < 0) { perror_msg("chdir(%s)", baseSrcName); continue; } if ((d = getcwd(NULL, BUFSIZ + 1)) == NULL) { perror_msg("getcwd()"); continue; } while (!state && *d != '\0') { if (stat(d, &sb) < 0) { /* stat not lstat - always dereference targets */ perror_msg("stat(%s)", d); state = -1; continue; } if ((sb.st_ino == srcStatBuf.st_ino) && (sb.st_dev == srcStatBuf.st_dev)) { error_msg("Cannot %s `%s' into a subdirectory of itself, " "`%s/%s'", applet_name, baseSrcName, baseDestName, baseSrcName); state = -1; continue; } if ((p = strrchr(d, '/')) != NULL) { *p = '\0'; } } if (chdir(pushd) < 0) { perror_msg("chdir(%s)", pushd); free(pushd); free(d); continue; } free(pushd); free(d); if (state < 0) continue; else fill_baseDest_buf(baseDestName, &baseDestLen); } status = setjmp(catch); if (status == 0) { mv_Action_first_time = 1; if (recursive_action(baseSrcName, recursiveFlag, followLinks, FALSE, cp_mv_Action, cp_mv_Action, NULL) == FALSE) goto exit_false; if (dz_i == is_mv && recursive_action(baseSrcName, recursiveFlag, followLinks, TRUE, rm_Action, rm_Action, NULL) == FALSE) goto exit_false; } if (flags_memo) *(baseDestName + baseDestLen) = '\0'; } FREE_BB_BUFFER(baseDestName); return EXIT_SUCCESS; exit_false: FREE_BB_BUFFER(baseDestName); return EXIT_FAILURE; exit_show_usage: FREE_BB_BUFFER(baseDestName); show_usage(); }
static int writeTarFile(const int tar_fd, const int verboseFlag, const unsigned long dereferenceFlag, const llist_t *include, const llist_t *exclude, const int gzip) { pid_t gzipPid = 0; int errorFlag = FALSE; struct TarBallInfo tbInfo; tbInfo.hlInfoHead = NULL; fchmod(tar_fd, 0644); tbInfo.tarFd = tar_fd; tbInfo.verboseFlag = verboseFlag; /* Store the stat info for the tarball's file, so * can avoid including the tarball into itself.... */ if (fstat(tbInfo.tarFd, &tbInfo.statBuf) < 0) bb_perror_msg_and_die("cannot stat tar file"); #if ENABLE_FEATURE_TAR_GZIP || ENABLE_FEATURE_TAR_BZIP2 if (gzip) { #if ENABLE_FEATURE_TAR_GZIP && ENABLE_FEATURE_TAR_BZIP2 const char *zip_exec = (gzip == 1) ? "gzip" : "bzip2"; #elif ENABLE_FEATURE_TAR_GZIP const char *zip_exec = "gzip"; #else /* only ENABLE_FEATURE_TAR_BZIP2 */ const char *zip_exec = "bzip2"; #endif // On Linux, vfork never unpauses parent early, although standard // allows for that. Do we want to waste bytes checking for it? #define WAIT_FOR_CHILD 0 volatile int vfork_exec_errno = 0; #if WAIT_FOR_CHILD struct fd_pair gzipStatusPipe; #endif struct fd_pair gzipDataPipe; xpiped_pair(gzipDataPipe); #if WAIT_FOR_CHILD xpiped_pair(gzipStatusPipe); #endif signal(SIGPIPE, SIG_IGN); /* we only want EPIPE on errors */ #if defined(__GNUC__) && __GNUC__ /* Avoid vfork clobbering */ (void) &include; (void) &errorFlag; (void) &zip_exec; #endif gzipPid = vfork(); if (gzipPid < 0) bb_perror_msg_and_die("vfork gzip"); if (gzipPid == 0) { /* child */ /* NB: close _first_, then move fds! */ close(gzipDataPipe.wr); #if WAIT_FOR_CHILD close(gzipStatusPipe.rd); /* gzipStatusPipe.wr will close only on exec - * parent waits for this close to happen */ fcntl(gzipStatusPipe.wr, F_SETFD, FD_CLOEXEC); #endif xmove_fd(gzipDataPipe.rd, 0); xmove_fd(tbInfo.tarFd, 1); /* exec gzip/bzip2 program/applet */ BB_EXECLP(zip_exec, zip_exec, "-f", NULL); vfork_exec_errno = errno; _exit(1); } /* parent */ xmove_fd(gzipDataPipe.wr, tbInfo.tarFd); close(gzipDataPipe.rd); #if WAIT_FOR_CHILD close(gzipStatusPipe.wr); while (1) { char buf; int n; /* Wait until child execs (or fails to) */ n = full_read(gzipStatusPipe.rd, &buf, 1); if (n < 0 /* && errno == EAGAIN */) continue; /* try it again */ } close(gzipStatusPipe.rd); #endif if (vfork_exec_errno) { errno = vfork_exec_errno; bb_perror_msg_and_die("cannot exec %s", zip_exec); } } #endif tbInfo.excludeList = exclude; /* Read the directory/files and iterate over them one at a time */ while (include) { if (!recursive_action(include->data, ACTION_RECURSE | (dereferenceFlag ? ACTION_FOLLOWLINKS : 0), writeFileToTarball, writeFileToTarball, &tbInfo, 0)) { errorFlag = TRUE; } include = include->link; } /* Write two empty blocks to the end of the archive */ memset(block_buf, 0, 2*TAR_BLOCK_SIZE); xwrite(tbInfo.tarFd, block_buf, 2*TAR_BLOCK_SIZE); /* To be pedantically correct, we would check if the tarball * is smaller than 20 tar blocks, and pad it if it was smaller, * but that isn't necessary for GNU tar interoperability, and * so is considered a waste of space */ /* Close so the child process (if any) will exit */ close(tbInfo.tarFd); /* Hang up the tools, close up shop, head home */ if (ENABLE_FEATURE_CLEAN_UP) freeHardLinkInfo(&tbInfo.hlInfoHead); if (errorFlag) bb_error_msg("error exit delayed from previous errors"); if (gzipPid) { #if ENABLE_FEATURE_TAR_GZIP || ENABLE_FEATURE_TAR_BZIP2 int status; if (safe_waitpid(gzipPid, &status, 0) == -1) bb_perror_msg("waitpid"); else if (!WIFEXITED(status) || WEXITSTATUS(status)) /* gzip was killed or has exited with nonzero! */ errorFlag = TRUE; #endif } return errorFlag; }
int find_main(int argc, char **argv) { int dereference = FALSE; int i, firstopt, status = EXIT_SUCCESS; for (firstopt = 1; firstopt < argc; firstopt++) { if (argv[firstopt][0] == '-') break; } /* Parse any options */ for (i = firstopt; i < argc; i++) { if (strcmp(argv[i], "-follow") == 0) dereference = TRUE; else if (strcmp(argv[i], "-print") == 0) { ; } else if (strcmp(argv[i], "-name") == 0) { if (++i == argc) bb_error_msg_and_die(msg_req_arg, "-name"); pattern = argv[i]; #ifdef CONFIG_FEATURE_FIND_TYPE } else if (strcmp(argv[i], "-type") == 0) { if (++i == argc) bb_error_msg_and_die(msg_req_arg, "-type"); type_mask = find_type(argv[i]); #endif #ifdef CONFIG_FEATURE_FIND_PERM } else if (strcmp(argv[i], "-perm") == 0) { char *end; if (++i == argc) bb_error_msg_and_die(msg_req_arg, "-perm"); perm_mask = strtol(argv[i], &end, 8); if ((end[0] != '\0') || (perm_mask > 07777)) bb_error_msg_and_die(msg_invalid_arg, argv[i], "-perm"); if ((perm_char = argv[i][0]) == '-') perm_mask = -perm_mask; #endif #ifdef CONFIG_FEATURE_FIND_MTIME } else if (strcmp(argv[i], "-mtime") == 0) { char *end; if (++i == argc) bb_error_msg_and_die(msg_req_arg, "-mtime"); mtime_days = strtol(argv[i], &end, 10); if (end[0] != '\0') bb_error_msg_and_die(msg_invalid_arg, argv[i], "-mtime"); if ((mtime_char = argv[i][0]) == '-') mtime_days = -mtime_days; #endif #ifdef CONFIG_FEATURE_FIND_XDEV } else if (strcmp(argv[i], "-xdev") == 0) { struct stat stbuf; xdev_count = ( firstopt - 1 ) ? ( firstopt - 1 ) : 1; xdev_dev = xmalloc ( xdev_count * sizeof( dev_t )); if ( firstopt == 1 ) { if ( stat ( ".", &stbuf ) < 0 ) bb_error_msg_and_die("could not stat '.'" ); xdev_dev [0] = stbuf. st_dev; } else { for (i = 1; i < firstopt; i++) { if ( stat ( argv [i], &stbuf ) < 0 ) bb_error_msg_and_die("could not stat '%s'", argv [i] ); xdev_dev [i-1] = stbuf. st_dev; } } #endif #ifdef CONFIG_FEATURE_FIND_NEWER } else if (strcmp(argv[i], "-newer") == 0) { struct stat stat_newer; if (++i == argc) bb_error_msg_and_die(msg_req_arg, "-newer"); if (stat (argv[i], &stat_newer) != 0) bb_error_msg_and_die("file %s not found", argv[i]); newer_mtime = stat_newer.st_mtime; #endif #ifdef CONFIG_FEATURE_FIND_INUM } else if (strcmp(argv[i], "-inum") == 0) { char *end; if (++i == argc) bb_error_msg_and_die(msg_req_arg, "-inum"); inode_num = strtol(argv[i], &end, 10); if (end[0] != '\0') bb_error_msg_and_die(msg_invalid_arg, argv[i], "-inum"); #endif #ifdef CONFIG_FEATURE_FIND_EXEC } else if (strcmp(argv[i], "-exec") == 0) { int b_pos; char *cmd_string = ""; while (i++) { if (i == argc) bb_error_msg_and_die(msg_req_arg, "-exec"); if (*argv[i] == ';') break; cmd_string = bb_xasprintf("%s %s", cmd_string, argv[i]); } if (*cmd_string == 0) bb_error_msg_and_die(msg_req_arg, "-exec"); cmd_string++; exec_str = xmalloc(sizeof(char *)); while ((b_pos = strstr(cmd_string, "{}") - cmd_string), (b_pos >= 0)) { num_matches++; exec_str = xrealloc(exec_str, (num_matches + 1) * sizeof(char *)); exec_str[num_matches - 1] = bb_xstrndup(cmd_string, b_pos); cmd_string += b_pos + 2; } exec_str[num_matches] = bb_xstrdup(cmd_string); exec_opt = 1; #endif } else bb_show_usage(); } if (firstopt == 1) { if (! recursive_action(".", TRUE, dereference, FALSE, fileAction, fileAction, NULL)) status = EXIT_FAILURE; } else { for (i = 1; i < firstopt; i++) { if (! recursive_action(argv[i], TRUE, dereference, FALSE, fileAction, fileAction, NULL)) status = EXIT_FAILURE; } } return status; }
int run_parts_main(int argc, char **argv) { const char *umask_p = "22"; llist_t *arg_list = NULL; unsigned n; int ret; #if ENABLE_FEATURE_RUN_PARTS_LONG_OPTIONS applet_long_options = runparts_longopts; #endif /* We require exactly one argument: the directory name */ opt_complementary = "=1:a::"; getopt32(argv, "a:u:t"USE_FEATURE_RUN_PARTS_FANCY("l"), &arg_list, &umask_p); umask(xstrtou_range(umask_p, 8, 0, 07777)); n = 1; while (arg_list && n < NUM_CMD) { cmd[n] = arg_list->data; arg_list = arg_list->link; n++; } /* cmd[n] = NULL; - is already zeroed out */ /* run-parts has to sort executables by name before running them */ recursive_action(argv[optind], ACTION_RECURSE|ACTION_FOLLOWLINKS, act, /* file action */ act, /* dir action */ NULL, /* user data */ 1 /* depth */ ); if (!names) return 0; qsort(names, cur, sizeof(char *), bb_alphasort); n = 0; while (1) { char *name = *names++; if (!name) break; if (option_mask32 & (RUN_PARTS_OPT_t | RUN_PARTS_OPT_l)) { puts(name); continue; } cmd[0] = name; ret = wait4pid(spawn(cmd)); if (ret == 0) continue; n = 1; if (ret < 0) bb_perror_msg("failed to exec %s", name); else /* ret > 0 */ bb_error_msg("%s exited with return code %d", name, ret); } return n; }
/* * Walk down all the directories under the specified * location, and do something (something specified * by the fileAction and dirAction function pointers). * * Unfortunately, while nftw(3) could replace this and reduce * code size a bit, nftw() wasn't supported before GNU libc 2.1, * and so isn't sufficiently portable to take over since glibc2.1 * is so stinking huge. */ int recursive_action(const char *fileName, int recurse, int followLinks, int depthFirst, int (*fileAction) (const char *fileName, struct stat * statbuf, void* userData), int (*dirAction) (const char *fileName, struct stat * statbuf, void* userData), void* userData) { int status; struct stat statbuf; struct dirent *next; if (followLinks) status = stat(fileName, &statbuf); else status = lstat(fileName, &statbuf); if (status < 0) { #ifdef DEBUG_RECURS_ACTION fprintf(stderr, "status=%d followLinks=%d TRUE=%d\n", status, followLinks, TRUE); #endif perror_msg("%s", fileName); return FALSE; } if (! followLinks && (S_ISLNK(statbuf.st_mode))) { if (fileAction == NULL) return TRUE; else return fileAction(fileName, &statbuf, userData); } if (! recurse) { if (S_ISDIR(statbuf.st_mode)) { if (dirAction != NULL) return (dirAction(fileName, &statbuf, userData)); else return TRUE; } } if (S_ISDIR(statbuf.st_mode)) { DIR *dir; if (dirAction != NULL && ! depthFirst) { status = dirAction(fileName, &statbuf, userData); if (! status) { perror_msg("%s", fileName); return FALSE; } else if (status == SKIP) return TRUE; } dir = opendir(fileName); if (!dir) { perror_msg("%s", fileName); return FALSE; } status = TRUE; while ((next = readdir(dir)) != NULL) { char *nextFile; if ((strcmp(next->d_name, "..") == 0) || (strcmp(next->d_name, ".") == 0)) { continue; } nextFile = concat_path_file(fileName, next->d_name); if (! recursive_action(nextFile, TRUE, followLinks, depthFirst, fileAction, dirAction, userData)) { status = FALSE; } free(nextFile); } closedir(dir); if (dirAction != NULL && depthFirst) { if (! dirAction(fileName, &statbuf, userData)) { perror_msg("%s", fileName); return FALSE; } } if (! status) return FALSE; } else { if (fileAction == NULL) return TRUE; else return fileAction(fileName, &statbuf, userData); } return TRUE; }
static int envfs_load_data(struct envfs_super *super, void *buf, size_t size, const char *dir, unsigned flags) { int fd, ret = 0; char *str, *tmp; int headerlen_full; /* for envfs < 1.0 */ struct envfs_inode_end inode_end_dummy; inode_end_dummy.mode = ENVFS_32(S_IRWXU | S_IRWXG | S_IRWXO); inode_end_dummy.magic = ENVFS_32(ENVFS_INODE_END_MAGIC); while (size) { struct envfs_inode *inode; struct envfs_inode_end *inode_end; uint32_t inode_size, inode_headerlen, namelen; inode = buf; buf += sizeof(struct envfs_inode); if (ENVFS_32(inode->magic) != ENVFS_INODE_MAGIC) { printf("envfs: wrong magic\n"); ret = -EIO; goto out; } inode_size = ENVFS_32(inode->size); inode_headerlen = ENVFS_32(inode->headerlen); namelen = strlen(inode->data) + 1; if (super->major < 1) inode_end = &inode_end_dummy; else inode_end = buf + PAD4(namelen); debug("loading %s size %d namelen %d headerlen %d\n", inode->data, inode_size, namelen, inode_headerlen); str = concat_path_file(dir, inode->data); headerlen_full = PAD4(inode_headerlen); buf += headerlen_full; if (ENVFS_32(inode_end->magic) != ENVFS_INODE_END_MAGIC) { printf("envfs: wrong inode_end_magic\n"); ret = -EIO; goto out; } tmp = strdup(str); make_directory(dirname(tmp)); free(tmp); if (S_ISLNK(ENVFS_32(inode_end->mode))) { debug("symlink: %s -> %s\n", str, (char*)buf); if (!strcmp(buf, basename(str))) { unlink(str); } else { ret = symlink(buf, str); if (ret < 0) printf("symlink: %s -> %s : %s\n", str, (char*)buf, strerror(-errno)); } free(str); } else { struct stat s; if (flags & ENV_FLAG_NO_OVERWRITE && !stat(str, &s)) { printf("skip %s\n", str); goto skip; } fd = open(str, O_WRONLY | O_CREAT | O_TRUNC, 0644); free(str); if (fd < 0) { printf("Open %s\n", errno_str()); ret = fd; goto out; } ret = write(fd, buf, inode_size); if (ret < inode_size) { perror("write"); ret = -errno; close(fd); goto out; } close(fd); } skip: buf += PAD4(inode_size); size -= headerlen_full + PAD4(inode_size) + sizeof(struct envfs_inode); } recursive_action(dir, ACTION_RECURSE | ACTION_DEPTHFIRST, NULL, dir_remove_action, NULL, 0); ret = 0; out: return ret; }
/** * Make the current environment persistent * @param[in] filename where to store * @param[in] dirname what to store (all files in this dir) * @param[in] flags superblock flags (refer ENVFS_FLAGS_* macros) * @return 0 on success, anything else in case of failure * * Note: This function will also be used on the host! See note in the header * of this file. */ int envfs_save(const char *filename, const char *dirname, unsigned flags) { struct envfs_super *super; int envfd, size, ret; struct action_data data = {}; void *buf = NULL, *wbuf; struct envfs_entry *env; if (!filename) filename = default_environment_path_get(); if (!dirname) dirname = "/env"; data.writep = NULL; data.base = dirname; #ifdef __BAREBOX__ defaultenv_load(TMPDIR, 0); #endif if (flags & ENVFS_FLAGS_FORCE_BUILT_IN) { size = 0; /* force no content */ } else { /* first pass: calculate size */ recursive_action(dirname, ACTION_RECURSE, file_action, NULL, &data, 0); recursive_action("/.defaultenv", ACTION_RECURSE, file_remove_action, NULL, &data, 0); size = 0; for (env = data.env; env; env = env->next) { size += PAD4(env->size); size += sizeof(struct envfs_inode); size += PAD4(strlen(env->name) + 1); size += sizeof(struct envfs_inode_end); } } buf = xzalloc(size + sizeof(struct envfs_super)); data.writep = buf + sizeof(struct envfs_super); super = buf; super->magic = ENVFS_32(ENVFS_MAGIC); super->major = ENVFS_MAJOR; super->minor = ENVFS_MINOR; super->size = ENVFS_32(size); super->flags = ENVFS_32(flags); if (!(flags & ENVFS_FLAGS_FORCE_BUILT_IN)) { /* second pass: copy files to buffer */ env = data.env; while (env) { struct envfs_entry *next = env->next; envfs_save_inode(&data, env); free(env->buf); free(env->name); free(env); env = next; } } super->crc = ENVFS_32(crc32(0, buf + sizeof(struct envfs_super), size)); super->sb_crc = ENVFS_32(crc32(0, buf, sizeof(struct envfs_super) - 4)); envfd = open(filename, O_WRONLY | O_CREAT, S_IRUSR | S_IWUSR); if (envfd < 0) { printf("could not open %s: %s\n", filename, errno_str()); ret = -errno; goto out1; } ret = protect(envfd, ~0, 0, 0); /* ENOSYS and EOPNOTSUPP aren't errors here, many devices don't need it */ if (ret && errno != ENOSYS && errno != EOPNOTSUPP) { printf("could not unprotect %s: %s\n", filename, errno_str()); goto out; } ret = erase(envfd, ~0, 0); /* ENOSYS and EOPNOTSUPP aren't errors here, many devices don't need it */ if (ret && errno != ENOSYS && errno != EOPNOTSUPP) { printf("could not erase %s: %s\n", filename, errno_str()); goto out; } size += sizeof(struct envfs_super); wbuf = buf; while (size) { ssize_t now = write(envfd, wbuf, size); if (now < 0) { ret = -errno; goto out; } wbuf += now; size -= now; } ret = protect(envfd, ~0, 0, 1); /* ENOSYS and EOPNOTSUPP aren't errors here, many devices don't need it */ if (ret && errno != ENOSYS && errno != EOPNOTSUPP) { printf("could not protect %s: %s\n", filename, errno_str()); goto out; } ret = 0; out: close(envfd); out1: free(buf); #ifdef __BAREBOX__ unlink_recursive(TMPDIR, NULL); #endif return ret; }
static inline int writeTarFile(const int tar_fd, const int verboseFlag, const unsigned long dereferenceFlag, const llist_t *include, const llist_t *exclude, const int gzip) { #ifdef CONFIG_FEATURE_TAR_GZIP int gzipDataPipe[2] = { -1, -1 }; int gzipStatusPipe[2] = { -1, -1 }; pid_t gzipPid = 0; volatile int vfork_exec_errno = 0; #endif int errorFlag = FALSE; ssize_t size; struct TarBallInfo tbInfo; tbInfo.hlInfoHead = NULL; fchmod(tar_fd, 0644); tbInfo.tarFd = tar_fd; tbInfo.verboseFlag = verboseFlag; /* Store the stat info for the tarball's file, so * can avoid including the tarball into itself.... */ if (fstat(tbInfo.tarFd, &tbInfo.statBuf) < 0) bb_perror_msg_and_die("Couldnt stat tar file"); #ifdef CONFIG_FEATURE_TAR_GZIP if (gzip) { if (pipe(gzipDataPipe) < 0 || pipe(gzipStatusPipe) < 0) { bb_perror_msg_and_die("Failed to create gzip pipe"); } signal(SIGPIPE, SIG_IGN); /* we only want EPIPE on errors */ # if __GNUC__ /* Avoid vfork clobbering */ (void) &include; (void) &errorFlag; # endif gzipPid = vfork(); if (gzipPid == 0) { dup2(gzipDataPipe[0], 0); close(gzipDataPipe[1]); if (tbInfo.tarFd != 1) dup2(tbInfo.tarFd, 1); close(gzipStatusPipe[0]); fcntl(gzipStatusPipe[1], F_SETFD, FD_CLOEXEC); /* close on exec shows sucess */ execl("/bin/gzip", "gzip", "-f", 0); vfork_exec_errno = errno; close(gzipStatusPipe[1]); exit(-1); } else if (gzipPid > 0) { close(gzipDataPipe[0]); close(gzipStatusPipe[1]); while (1) { char buf; int n = bb_full_read(gzipStatusPipe[0], &buf, 1); if (n == 0 && vfork_exec_errno != 0) { errno = vfork_exec_errno; bb_perror_msg_and_die("Could not exec gzip process"); } else if ((n < 0) && (errno == EAGAIN || errno == EINTR)) continue; /* try it again */ break; } close(gzipStatusPipe[0]); tbInfo.tarFd = gzipDataPipe[1]; } else { bb_perror_msg_and_die("Failed to vfork gzip process"); } } #endif tbInfo.excludeList = exclude; /* Read the directory/files and iterate over them one at a time */ while (include) { if (!recursive_action(include->data, TRUE, dereferenceFlag, FALSE, writeFileToTarball, writeFileToTarball, (void *) &tbInfo)) { errorFlag = TRUE; } include = include->link; } /* Write two empty blocks to the end of the archive */ for (size = 0; size < (2 * TAR_BLOCK_SIZE); size++) { write(tbInfo.tarFd, "\0", 1); } /* To be pedantically correct, we would check if the tarball * is smaller than 20 tar blocks, and pad it if it was smaller, * but that isn't necessary for GNU tar interoperability, and * so is considered a waste of space */ /* Hang up the tools, close up shop, head home */ close(tbInfo.tarFd); if (errorFlag) bb_error_msg("Error exit delayed from previous errors"); freeHardLinkInfo(&tbInfo.hlInfoHead); #ifdef CONFIG_FEATURE_TAR_GZIP if (gzip && gzipPid) { if (waitpid(gzipPid, NULL, 0) == -1) printf("Couldnt wait ?"); } #endif return !errorFlag; }