Beispiel #1
0
/**
 * 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;
}
Beispiel #2
0
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;
}
Beispiel #3
0
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;
}
Beispiel #5
0
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;
}
Beispiel #6
0
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);
}
Beispiel #7
0
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;
}
Beispiel #8
0
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;
}
Beispiel #9
0
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;
}
Beispiel #11
0
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;
}
Beispiel #12
0
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;
}
Beispiel #13
0
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;
}
Beispiel #14
0
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;
}
Beispiel #15
0
/* 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();
}
Beispiel #17
0
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;
}
Beispiel #18
0
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;
}
Beispiel #19
0
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;
}
Beispiel #21
0
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;
}
Beispiel #22
0
/**
 * 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;
}