Implement the "wait" checkpoint action.
This action instructs tar to pause until given signal is delivered. The newer genfile tool uses this action for communication between genfile and tar in exec mode. This eliminates race conitions and speeds up the tests based on exec mode. * doc/tar.texi: Document changes. * paxutils: Upgrade. * src/checkpoint.c: Implement the wait action. * src/common.h (decode_signal): New proto. * src/tar.c (decode_signal): New function. (set_stat_signal): Rewrite. * tests/dirrem01.at: Adjust genfile and tar command line arguments to use the new feature. * tests/dirrem02.at: Likewise. * tests/filerem01.at: Likewise. * tests/filerem02.at: Likewise. * tests/grow.at: Likewise. * tests/sptrcreat.at: Likewise. * tests/sptrdiff00.at: Likewise. * tests/sptrdiff01.at: Likewise. * tests/truncate.at: Likewise.
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
/* Checkpoint management for tar.
|
||||
|
||||
Copyright 2007, 2013-2014, 2016-2017 Free Software Foundation, Inc.
|
||||
Copyright 2007, 2013-2014, 2016-2018 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU tar.
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
#include <sys/ioctl.h>
|
||||
#include <termios.h>
|
||||
#include "fprintftime.h"
|
||||
#include <signal.h>
|
||||
|
||||
enum checkpoint_opcode
|
||||
{
|
||||
@@ -32,7 +33,8 @@ enum checkpoint_opcode
|
||||
cop_ttyout,
|
||||
cop_sleep,
|
||||
cop_exec,
|
||||
cop_totals
|
||||
cop_totals,
|
||||
cop_wait
|
||||
};
|
||||
|
||||
struct checkpoint_action
|
||||
@@ -43,6 +45,7 @@ struct checkpoint_action
|
||||
{
|
||||
time_t time;
|
||||
char *command;
|
||||
int signal;
|
||||
} v;
|
||||
};
|
||||
|
||||
@@ -52,6 +55,16 @@ static unsigned checkpoint;
|
||||
/* List of checkpoint actions */
|
||||
static struct checkpoint_action *checkpoint_action, *checkpoint_action_tail;
|
||||
|
||||
/* State of the checkpoint system */
|
||||
enum {
|
||||
CHKP_INIT, /* Needs initialization */
|
||||
CHKP_COMPILE, /* Actions are being compiled */
|
||||
CHKP_RUN /* Actions are being run */
|
||||
};
|
||||
static int checkpoint_state;
|
||||
/* Blocked signals */
|
||||
static sigset_t sigs;
|
||||
|
||||
static struct checkpoint_action *
|
||||
alloc_action (enum checkpoint_opcode opcode)
|
||||
{
|
||||
@@ -85,6 +98,12 @@ checkpoint_compile_action (const char *str)
|
||||
{
|
||||
struct checkpoint_action *act;
|
||||
|
||||
if (checkpoint_state == CHKP_INIT)
|
||||
{
|
||||
sigemptyset (&sigs);
|
||||
checkpoint_state = CHKP_COMPILE;
|
||||
}
|
||||
|
||||
if (strcmp (str, ".") == 0 || strcmp (str, "dot") == 0)
|
||||
alloc_action (cop_dot);
|
||||
else if (strcmp (str, "bell") == 0)
|
||||
@@ -117,6 +136,12 @@ checkpoint_compile_action (const char *str)
|
||||
}
|
||||
else if (strcmp (str, "totals") == 0)
|
||||
alloc_action (cop_totals);
|
||||
else if (strncmp (str, "wait=", 5) == 0)
|
||||
{
|
||||
act = alloc_action (cop_wait);
|
||||
act->v.signal = decode_signal (str + 5);
|
||||
sigaddset (&sigs, act->v.signal);
|
||||
}
|
||||
else
|
||||
FATAL_ERROR ((0, 0, _("%s: unknown checkpoint action"), str));
|
||||
}
|
||||
@@ -124,15 +149,22 @@ checkpoint_compile_action (const char *str)
|
||||
void
|
||||
checkpoint_finish_compile (void)
|
||||
{
|
||||
if (checkpoint_option)
|
||||
if (checkpoint_state == CHKP_COMPILE)
|
||||
{
|
||||
if (!checkpoint_action)
|
||||
/* Provide a historical default */
|
||||
checkpoint_compile_action ("echo");
|
||||
sigprocmask (SIG_BLOCK, &sigs, NULL);
|
||||
|
||||
if (checkpoint_option)
|
||||
{
|
||||
if (!checkpoint_action)
|
||||
/* Provide a historical default */
|
||||
checkpoint_compile_action ("echo");
|
||||
}
|
||||
else if (checkpoint_action)
|
||||
/* Otherwise, set default checkpoint rate */
|
||||
checkpoint_option = DEFAULT_CHECKPOINT;
|
||||
|
||||
checkpoint_state = CHKP_RUN;
|
||||
}
|
||||
else if (checkpoint_action)
|
||||
/* Otherwise, set default checkpoint rate */
|
||||
checkpoint_option = DEFAULT_CHECKPOINT;
|
||||
}
|
||||
|
||||
static const char *checkpoint_total_format[] = {
|
||||
@@ -390,6 +422,13 @@ run_checkpoint_actions (bool do_write)
|
||||
case cop_totals:
|
||||
compute_duration ();
|
||||
print_total_stats ();
|
||||
break;
|
||||
|
||||
case cop_wait:
|
||||
{
|
||||
int n;
|
||||
sigwait (&sigs, &n);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -798,6 +798,8 @@ void set_exit_status (int val);
|
||||
|
||||
void request_stdin (const char *option);
|
||||
|
||||
int decode_signal (const char *);
|
||||
|
||||
/* Where an option comes from: */
|
||||
enum option_source
|
||||
{
|
||||
|
||||
25
src/tar.c
25
src/tar.c
@@ -976,36 +976,37 @@ stat_on_signal (int signo)
|
||||
#endif
|
||||
}
|
||||
|
||||
static void
|
||||
set_stat_signal (const char *name)
|
||||
int
|
||||
decode_signal (const char *name)
|
||||
{
|
||||
static struct sigtab
|
||||
{
|
||||
char const *name;
|
||||
int signo;
|
||||
} const sigtab[] = {
|
||||
{ "SIGUSR1", SIGUSR1 },
|
||||
{ "USR1", SIGUSR1 },
|
||||
{ "SIGUSR2", SIGUSR2 },
|
||||
{ "USR2", SIGUSR2 },
|
||||
{ "SIGHUP", SIGHUP },
|
||||
{ "HUP", SIGHUP },
|
||||
{ "SIGINT", SIGINT },
|
||||
{ "INT", SIGINT },
|
||||
{ "SIGQUIT", SIGQUIT },
|
||||
{ "QUIT", SIGQUIT }
|
||||
};
|
||||
struct sigtab const *p;
|
||||
char const *s = name;
|
||||
|
||||
if (strncmp (s, "SIG", 3) == 0)
|
||||
s += 3;
|
||||
for (p = sigtab; p < sigtab + sizeof (sigtab) / sizeof (sigtab[0]); p++)
|
||||
if (strcmp (p->name, name) == 0)
|
||||
{
|
||||
stat_on_signal (p->signo);
|
||||
return;
|
||||
}
|
||||
if (strcmp (p->name, s) == 0)
|
||||
return p->signo;
|
||||
FATAL_ERROR ((0, 0, _("Unknown signal name: %s"), name));
|
||||
}
|
||||
|
||||
static void
|
||||
set_stat_signal (const char *name)
|
||||
{
|
||||
stat_on_signal (decode_signal (name));
|
||||
}
|
||||
|
||||
|
||||
struct textual_date
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user