/* System-dependent calls for tar.
- Copyright (C) 2003, 2004, 2005, 2006 Free Software Foundation, Inc.
+ Copyright (C) 2003, 2004, 2005, 2006, 2007,
+ 2008, 2010 Free Software Foundation, Inc.
This program is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the
- Free Software Foundation; either version 2, or (at your option) any later
+ Free Software Foundation; either version 3, or (at your option) any later
version.
This program is distributed in the hope that it will be useful, but
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
#include <system.h>
-#include <getline.h>
-#include <setenv.h>
#include "common.h"
+#include <priv-set.h>
#include <rmt.h>
#include <signal.h>
}
void
-sys_drain_input_pipe (void)
-{
-}
-
-void
-sys_wait_for_child (pid_t child_pid)
+sys_wait_for_child (pid_t child_pid, bool eof)
{
}
&& archive_stat.st_ino == dev_null_stat.st_ino));
}
-/* Manage to fully drain a pipe we might be reading, so to not break it on
- the producer after the EOF block. FIXME: one of these days, GNU tar
- might become clever enough to just stop working, once there is no more
- work to do, we might have to revise this area in such time. */
-
-void
-sys_drain_input_pipe (void)
-{
- size_t r;
-
- if (access_mode == ACCESS_READ
- && ! _isrmt (archive)
- && (S_ISFIFO (archive_stat.st_mode) || S_ISSOCK (archive_stat.st_mode)))
- while ((r = rmtread (archive, record_start->buffer, record_size)) != 0
- && r != SAFE_READ_ERROR)
- continue;
-}
-
void
-sys_wait_for_child (pid_t child_pid)
+sys_wait_for_child (pid_t child_pid, bool eof)
{
if (child_pid)
{
}
if (WIFSIGNALED (wait_status))
- ERROR ((0, 0, _("Child died with signal %d"),
- WTERMSIG (wait_status)));
+ {
+ int sig = WTERMSIG (wait_status);
+ if (!(!eof && sig == SIGPIPE))
+ FATAL_ERROR ((0, 0, _("Child died with signal %d"), sig));
+ }
else if (WEXITSTATUS (wait_status) != 0)
- ERROR ((0, 0, _("Child returned status %d"),
- WEXITSTATUS (wait_status)));
+ FATAL_ERROR ((0, 0, _("Child returned status %d"),
+ WEXITSTATUS (wait_status)));
}
}
child = xfork ();
if (child == 0)
{
+ priv_set_restore_linkdir ();
execlp (shell, "-sh", "-i", (char *) 0);
exec_fatal (shell);
}
}
}
+static void wait_for_grandchild (pid_t pid) __attribute__ ((__noreturn__));
+
+/* Propagate any failure of the grandchild back to the parent. */
+static void
+wait_for_grandchild (pid_t pid)
+{
+ int wait_status;
+ int exit_code = 0;
+
+ while (waitpid (pid, &wait_status, 0) == -1)
+ if (errno != EINTR)
+ {
+ waitpid_error (use_compress_program_option);
+ break;
+ }
+
+ if (WIFSIGNALED (wait_status))
+ raise (WTERMSIG (wait_status));
+ else if (WEXITSTATUS (wait_status) != 0)
+ exit_code = WEXITSTATUS (wait_status);
+
+ exit (exit_code);
+}
+
/* Set ARCHIVE for writing, then compressing an archive. */
pid_t
sys_child_open_for_compress (void)
int child_pipe[2];
pid_t grandchild_pid;
pid_t child_pid;
- int wait_status;
xpipe (parent_pipe);
child_pid = xfork ();
/* The new born child tar is here! */
- program_name = _("tar (child)");
+ set_program_name (_("tar (child)"));
+ signal (SIGPIPE, SIG_DFL);
xdup2 (parent_pipe[PREAD], STDIN_FILENO);
xclose (parent_pipe[PWRITE]);
}
xdup2 (archive, STDOUT_FILENO);
}
+ priv_set_restore_linkdir ();
execlp (use_compress_program_option, use_compress_program_option, NULL);
exec_fatal (use_compress_program_option);
}
{
/* The newborn grandchild tar is here! Launch the compressor. */
- program_name = _("tar (grandchild)");
+ set_program_name (_("tar (grandchild)"));
xdup2 (child_pipe[PWRITE], STDOUT_FILENO);
xclose (child_pipe[PREAD]);
+ priv_set_restore_linkdir ();
execlp (use_compress_program_option, use_compress_program_option,
(char *) 0);
exec_fatal (use_compress_program_option);
archive_write_error (status);
}
- /* Propagate any failure of the grandchild back to the parent. */
-
- while (waitpid (grandchild_pid, &wait_status, 0) == -1)
- if (errno != EINTR)
- {
- waitpid_error (use_compress_program_option);
- break;
- }
-
- if (WIFSIGNALED (wait_status))
- {
- kill (child_pid, WTERMSIG (wait_status));
- exit_status = TAREXIT_FAILURE;
- }
- else if (WEXITSTATUS (wait_status) != 0)
- exit_status = WEXITSTATUS (wait_status);
-
- exit (exit_status);
+ wait_for_grandchild (grandchild_pid);
}
/* Set ARCHIVE for uncompressing, then reading an archive. */
int child_pipe[2];
pid_t grandchild_pid;
pid_t child_pid;
- int wait_status;
xpipe (parent_pipe);
child_pid = xfork ();
/* The newborn child tar is here! */
- program_name = _("tar (child)");
+ set_program_name (_("tar (child)"));
+ signal (SIGPIPE, SIG_DFL);
xdup2 (parent_pipe[PWRITE], STDOUT_FILENO);
xclose (parent_pipe[PREAD]);
if (archive < 0)
open_fatal (archive_name_array[0]);
xdup2 (archive, STDIN_FILENO);
+ priv_set_restore_linkdir ();
execlp (use_compress_program_option, use_compress_program_option,
"-d", (char *) 0);
exec_fatal (use_compress_program_option);
{
/* The newborn grandchild tar is here! Launch the uncompressor. */
- program_name = _("tar (grandchild)");
+ set_program_name (_("tar (grandchild)"));
xdup2 (child_pipe[PREAD], STDIN_FILENO);
xclose (child_pipe[PWRITE]);
+ priv_set_restore_linkdir ();
execlp (use_compress_program_option, use_compress_program_option,
"-d", (char *) 0);
exec_fatal (use_compress_program_option);
xclose (STDOUT_FILENO);
- /* Propagate any failure of the grandchild back to the parent. */
-
- while (waitpid (grandchild_pid, &wait_status, 0) == -1)
- if (errno != EINTR)
- {
- waitpid_error (use_compress_program_option);
- break;
- }
-
- if (WIFSIGNALED (wait_status))
- {
- kill (child_pid, WTERMSIG (wait_status));
- exit_status = TAREXIT_FAILURE;
- }
- else if (WEXITSTATUS (wait_status) != 0)
- exit_status = WEXITSTATUS (wait_status);
-
- exit (exit_status);
+ wait_for_grandchild (grandchild_pid);
}
\f
static void
-dec_to_env (char *envar, uintmax_t num)
+dec_to_env (char const *envar, uintmax_t num)
{
char buf[UINTMAX_STRSIZE_BOUND];
char *numstr;
}
static void
-time_to_env (char *envar, struct timespec t)
+time_to_env (char const *envar, struct timespec t)
{
char buf[TIMESPEC_STRSIZE_BOUND];
if (setenv (envar, code_timespec (t, buf), 1) != 0)
}
static void
-oct_to_env (char *envar, unsigned long num)
+oct_to_env (char const *envar, unsigned long num)
{
char buf[1+1+(sizeof(unsigned long)*CHAR_BIT+2)/3];
}
static void
-str_to_env (char *envar, char const *str)
+str_to_env (char const *envar, char const *str)
{
if (str)
{
}
static void
-chr_to_env (char *envar, char c)
+chr_to_env (char const *envar, char c)
{
char buf[2];
buf[0] = c;
stat_to_env (char *name, char type, struct tar_stat_info *st)
{
str_to_env ("TAR_VERSION", PACKAGE_VERSION);
+ str_to_env ("TAR_ARCHIVE", *archive_name_cursor);
+ dec_to_env ("TAR_VOLUME", archive_name_cursor - archive_name_array + 1);
+ dec_to_env ("TAR_BLOCKING_FACTOR", blocking_factor);
+ str_to_env ("TAR_FORMAT",
+ archive_format_string (current_format == DEFAULT_FORMAT ?
+ archive_format : current_format));
chr_to_env ("TAR_FILETYPE", type);
oct_to_env ("TAR_MODE", st->stat.st_mode);
str_to_env ("TAR_FILENAME", name);
}
}
-static pid_t pid;
+static pid_t global_pid;
static RETSIGTYPE (*pipe_handler) (int sig);
int
xpipe (p);
pipe_handler = signal (SIGPIPE, SIG_IGN);
- pid = xfork ();
+ global_pid = xfork ();
- if (pid != 0)
+ if (global_pid != 0)
{
xclose (p[PREAD]);
return p[PWRITE];
argv[2] = to_command_option;
argv[3] = NULL;
+ priv_set_restore_linkdir ();
execv ("/bin/sh", argv);
exec_fatal (file_name);
{
int status;
- if (pid < 0)
+ if (global_pid < 0)
return;
signal (SIGPIPE, pipe_handler);
- while (waitpid (pid, &status, 0) == -1)
+ while (waitpid (global_pid, &status, 0) == -1)
if (errno != EINTR)
{
- pid = -1;
+ global_pid = -1;
waitpid_error (to_command_option);
return;
}
{
if (!ignore_command_error_option && WEXITSTATUS (status))
ERROR ((0, 0, _("%lu: Child returned status %d"),
- (unsigned long) pid, WEXITSTATUS (status)));
+ (unsigned long) global_pid, WEXITSTATUS (status)));
}
else if (WIFSIGNALED (status))
{
WARN ((0, 0, _("%lu: Child terminated on signal %d"),
- (unsigned long) pid, WTERMSIG (status)));
+ (unsigned long) global_pid, WTERMSIG (status)));
}
else
ERROR ((0, 0, _("%lu: Child terminated on unknown reason"),
- (unsigned long) pid));
+ (unsigned long) global_pid));
- pid = -1;
+ global_pid = -1;
}
int
char *argv[4];
char uintbuf[UINTMAX_STRSIZE_BOUND];
int p[2];
+ static RETSIGTYPE (*saved_handler) (int sig);
xpipe (p);
- pipe_handler = signal (SIGPIPE, SIG_IGN);
+ saved_handler = signal (SIGPIPE, SIG_IGN);
pid = xfork ();
int rc;
int status;
- char *buf;
+ char *buf = NULL;
size_t size = 0;
FILE *fp;
while (waitpid (pid, &status, 0) == -1)
if (errno != EINTR)
{
+ signal (SIGPIPE, saved_handler);
waitpid_error (info_script_option);
return -1;
}
+ signal (SIGPIPE, saved_handler);
+
if (WIFEXITED (status))
{
if (WEXITSTATUS (status) == 0 && rc > 0)
setenv ("TAR_VERSION", PACKAGE_VERSION, 1);
setenv ("TAR_ARCHIVE", *archive_name, 1);
setenv ("TAR_VOLUME", STRINGIFY_BIGINT (volume_number, uintbuf), 1);
+ setenv ("TAR_BLOCKING_FACTOR",
+ STRINGIFY_BIGINT (blocking_factor, uintbuf), 1);
setenv ("TAR_SUBCOMMAND", subcommand_string (subcommand_option), 1);
setenv ("TAR_FORMAT",
archive_format_string (current_format == DEFAULT_FORMAT ?
argv[0] = "/bin/sh";
argv[1] = "-c";
- argv[2] = (char*) info_script_option;
+ argv[2] = (char *) info_script_option;
argv[3] = NULL;
+ priv_set_restore_linkdir ();
execv (argv[0], argv);
exec_fatal (info_script_option);
}
+void
+sys_exec_checkpoint_script (const char *script_name,
+ const char *archive_name,
+ int checkpoint_number)
+{
+ pid_t pid;
+ char *argv[4];
+ char uintbuf[UINTMAX_STRSIZE_BOUND];
+
+ pid = xfork ();
+
+ if (pid != 0)
+ {
+ /* Master */
+
+ int status;
+
+ while (waitpid (pid, &status, 0) == -1)
+ if (errno != EINTR)
+ {
+ waitpid_error (script_name);
+ break;
+ }
+
+ return;
+ }
+
+ /* Child */
+ setenv ("TAR_VERSION", PACKAGE_VERSION, 1);
+ setenv ("TAR_ARCHIVE", archive_name, 1);
+ setenv ("TAR_CHECKPOINT", STRINGIFY_BIGINT (checkpoint_number, uintbuf), 1);
+ setenv ("TAR_BLOCKING_FACTOR",
+ STRINGIFY_BIGINT (blocking_factor, uintbuf), 1);
+ setenv ("TAR_SUBCOMMAND", subcommand_string (subcommand_option), 1);
+ setenv ("TAR_FORMAT",
+ archive_format_string (current_format == DEFAULT_FORMAT ?
+ archive_format : current_format), 1);
+ argv[0] = "/bin/sh";
+ argv[1] = "-c";
+ argv[2] = (char *) script_name;
+ argv[3] = NULL;
+
+ priv_set_restore_linkdir ();
+ execv (argv[0], argv);
+
+ exec_fatal (script_name);
+}
#endif /* not MSDOS */