tar: move vfork into separate function (smaller code)
open_transformer: more informative error messages
function old new delta
vfork_compressor - 210 +210
writeTarFile 547 299 -248
------------------------------------------------------------------------------
(add/remove: 1/0 grow/shrink: 0/1 up/down: 210/-248) Total: -38 bytes
diff --git a/archival/libunarchive/open_transformer.c b/archival/libunarchive/open_transformer.c
index 3c551de..8fb8602 100644
--- a/archival/libunarchive/open_transformer.c
+++ b/archival/libunarchive/open_transformer.c
@@ -22,11 +22,13 @@
#if BB_MMU
pid = fork();
+ if (pid == -1)
+ bb_perror_msg_and_die("can't fork");
#else
pid = vfork();
-#endif
if (pid == -1)
- bb_perror_msg_and_die("fork failed");
+ bb_perror_msg_and_die("can't vfork");
+#endif
if (pid == 0) {
/* child process */
@@ -49,7 +51,7 @@
argv[2] = (char*)"-";
argv[3] = NULL;
BB_EXECVP(transform_prog, argv);
- bb_perror_msg_and_die("exec failed");
+ bb_perror_msg_and_die("can't exec %s", transform_prog);
}
#endif
/* notreached */
diff --git a/archival/tar.c b/archival/tar.c
index 0c90ac0..0aa216c 100644
--- a/archival/tar.c
+++ b/archival/tar.c
@@ -84,26 +84,26 @@
*/
typedef struct HardLinkInfo HardLinkInfo;
struct HardLinkInfo {
- HardLinkInfo *next; /* Next entry in list */
- dev_t dev; /* Device number */
- ino_t ino; /* Inode number */
- short linkCount; /* (Hard) Link Count */
- char name[1]; /* Start of filename (must be last) */
+ HardLinkInfo *next; /* Next entry in list */
+ dev_t dev; /* Device number */
+ ino_t ino; /* Inode number */
+ short linkCount; /* (Hard) Link Count */
+ char name[1]; /* Start of filename (must be last) */
};
/* Some info to be carried along when creating a new tarball */
typedef struct TarBallInfo TarBallInfo;
struct TarBallInfo {
- int tarFd; /* Open-for-write file descriptor
- for the tarball */
- struct stat statBuf; /* Stat info for the tarball, letting
- us know the inode and device that the
- tarball lives, so we can avoid trying
- to include the tarball into itself */
- int verboseFlag; /* Whether to print extra stuff or not */
- const llist_t *excludeList; /* List of files to not include */
- HardLinkInfo *hlInfoHead; /* Hard Link Tracking Information */
- HardLinkInfo *hlInfo; /* Hard Link Info for the current file */
+ int tarFd; /* Open-for-write file descriptor
+ * for the tarball */
+ struct stat statBuf; /* Stat info for the tarball, letting
+ * us know the inode and device that the
+ * tarball lives, so we can avoid trying
+ * to include the tarball into itself */
+ int verboseFlag; /* Whether to print extra stuff or not */
+ const llist_t *excludeList; /* List of files to not include */
+ HardLinkInfo *hlInfoHead; /* Hard Link Tracking Information */
+ HardLinkInfo *hlInfo; /* Hard Link Info for the current file */
};
/* A nice enum with all the possible tar file content types */
@@ -503,11 +503,87 @@
return TRUE;
}
-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)
+#if ENABLE_FEATURE_TAR_GZIP || ENABLE_FEATURE_TAR_BZIP2
+/* Don't inline: vfork scares gcc and pessimizes code */
+static void NOINLINE vfork_compressor(int tar_fd, int gzip)
{
- pid_t gzipPid = 0;
+ pid_t gzipPid;
+#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;
+ 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("can't 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(1);
+ }
+
+ /* 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_TAR_GZIP || ENABLE_FEATURE_TAR_BZIP2 */
+
+
+/* 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;
@@ -523,80 +599,8 @@
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);
- }
- }
+ if (gzip)
+ vfork_compressor(tbInfo.tarFd, gzip);
#endif
tbInfo.excludeList = exclude;
@@ -630,20 +634,22 @@
if (errorFlag)
bb_error_msg("error exit delayed from previous errors");
- if (gzipPid) {
+#if ENABLE_FEATURE_TAR_GZIP || ENABLE_FEATURE_TAR_BZIP2
+ if (gzip) {
int status;
- if (safe_waitpid(gzipPid, &status, 0) == -1)
+ 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;
}
#else
-int writeTarFile(const int tar_fd, const int verboseFlag,
- const unsigned long dereferenceFlag, const llist_t *include,
- const llist_t *exclude, const int gzip);
+int writeTarFile(int tar_fd, int verboseFlag,
+ int dereferenceFlag, const llist_t *include,
+ const llist_t *exclude, int gzip);
#endif /* FEATURE_TAR_CREATE */
#if ENABLE_FEATURE_TAR_FROM