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
This commit is contained in:
@@ -22,11 +22,13 @@ int open_transformer(int src_fd,
|
||||
|
||||
#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 @@ int open_transformer(int src_fd,
|
||||
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 */
|
||||
|
202
archival/tar.c
202
archival/tar.c
@@ -84,26 +84,26 @@ struct TarHeader { /* byte offset */
|
||||
*/
|
||||
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 @@ static int writeFileToTarball(const char *fileName, struct stat *statbuf,
|
||||
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;
|
||||
#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)
|
||||
{
|
||||
pid_t gzipPid = 0;
|
||||
int errorFlag = FALSE;
|
||||
struct TarBallInfo tbInfo;
|
||||
|
||||
@@ -523,80 +599,8 @@ static int writeTarFile(const int tar_fd, const int verboseFlag,
|
||||
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 @@ static int writeTarFile(const int tar_fd, const int verboseFlag,
|
||||
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
|
||||
|
Reference in New Issue
Block a user