+#if ENABLE_FEATURE_SEAMLESS_GZ || ENABLE_FEATURE_SEAMLESS_BZ2
+#if !(ENABLE_FEATURE_SEAMLESS_GZ && ENABLE_FEATURE_SEAMLESS_BZ2)
+#define vfork_compressor(tar_fd, gzip) vfork_compressor(tar_fd)
+#endif
+/* Don't inline: vfork scares gcc and pessimizes code */
+static void NOINLINE vfork_compressor(int tar_fd, int gzip)
+{
+ pid_t gzipPid;
+#if ENABLE_FEATURE_SEAMLESS_GZ && ENABLE_FEATURE_SEAMLESS_BZ2
+ const char *zip_exec = (gzip == 1) ? "gzip" : "bzip2";
+#elif ENABLE_FEATURE_SEAMLESS_GZ
+ const char *zip_exec = "gzip";
+#else /* only ENABLE_FEATURE_SEAMLESS_BZ2 */
+ 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;
+ struct fd_pair gzipDataPipe;
+#if WAIT_FOR_CHILD
+ struct fd_pair gzipStatusPipe;
+ xpiped_pair(gzipStatusPipe);
+#endif
+ xpiped_pair(gzipDataPipe);
+
+ signal(SIGPIPE, SIG_IGN); /* we only want EPIPE on errors */
+
+#if defined(__GNUC__) && __GNUC__
+ /* Avoid vfork clobbering */
+ (void) &zip_exec;
+#endif
+
+ gzipPid = vfork();
+ if (gzipPid < 0)
+ bb_perror_msg_and_die("vfork");
+
+ 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(tar_fd, 1);
+ /* exec gzip/bzip2 program/applet */
+ BB_EXECLP(zip_exec, zip_exec, "-f", NULL);
+ vfork_exec_errno = errno;
+ _exit(EXIT_FAILURE);
+ }
+
+ /* parent */
+ xmove_fd(gzipDataPipe.wr, tar_fd);
+ 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 /* ENABLE_FEATURE_SEAMLESS_GZ || ENABLE_FEATURE_SEAMLESS_BZ2 */
+
+
+/* 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)