*/
#include "metaplugin.h"
+#include "smartlock.h"
#include <sys/stat.h>
#include <signal.h>
#include <sys/select.h>
PLUGIN_DESCRIPTION,
};
+#define _STR(x) __STR(x)
+#define __STR(x) #x
+
+#ifdef VERSIONGIT
+ #define VERSIONGIT_STR _STR(VERSIONGIT)
+#else
+ #define VERSIONGIT_STR "/unknown"
+#endif
+
/*
* Plugin called here when it is first loaded
*/
bfuncs = lbfuncs; /* set Bacula function pointers */
binfo = lbinfo;
- Dmsg3(DINFO, "%s Plugin version %s %s (c) 2020 by Inteos\n", PLUGINNAME, PLUGIN_VERSION, PLUGIN_DATE);
+ Dmsg4(DINFO, "%s Plugin version %s%s %s (c) 2021 by Inteos\n", PLUGINNAME, PLUGIN_VERSION, VERSIONGIT_STR, PLUGIN_DATE);
*pinfo = &pluginInfo; /* return pointer to our info */
*pfuncs = &pluginFuncs; /* return pointer to our functions */
}
#endif
-/*
- * Main PLUGIN class constructor.
- */
-METAPLUGIN::METAPLUGIN(bpContext *bpctx) :
- backend_cmd(PM_FNAME),
- ctx(NULL),
- backend_available(false),
- backend_error(PM_MESSAGE),
- mode(NONE),
- JobId(0),
- JobName(NULL),
- since(0),
- where(NULL),
- regexwhere(NULL),
- replace(0),
- robjsent(false),
- estimate(false),
- listing(None),
- nodata(false),
- nextfile(false),
- openerror(false),
- pluginobject(false),
- pluginobjectsent(false),
- readacl(false),
- readxattr(false),
- skipextract(false),
- last_type(0),
- fname(PM_FNAME),
- lname(PM_FNAME),
- robjbuf(NULL),
- plugin_obj_cat(PM_FNAME),
- plugin_obj_type(PM_FNAME),
- plugin_obj_name(PM_FNAME),
- plugin_obj_src(PM_FNAME),
- plugin_obj_uuid(PM_FNAME),
- plugin_obj_size(PM_FNAME),
- acldatalen(0),
- acldata(PM_MESSAGE),
- xattrdatalen(0),
- xattrdata(PM_MESSAGE),
- metadatas_list(10, true),
- prevjobname(NULL)
-{
- /* TODO: we have a ctx variable stored internally, decide if we use it
- * for every method or rip it off as not required in our code */
- ctx = bpctx;
-}
-
-/*
- * Main PLUGIN class destructor, handles variable freeing on delete.
- *
- * in:
- * none
- * out:
- * freed internal variables and class allocated during job execution
- */
-METAPLUGIN::~METAPLUGIN()
-{
- /* free standard variables */
- free_and_null_pool_memory(robjbuf);
-}
-
/*
* Check if a parameter (param) exist in ConfigFile variables set by user.
* The checking ignore case of the parameter.
*/
bRC backendctx_jobend_func(PTCOMM *ptcomm, void *cp)
{
- bpContext * ctx = (bpContext*)cp;
+ bpContext *ctx = (bpContext *)cp;
bRC status = bRC_OK;
if (send_endjob(ctx, ptcomm) != bRC_OK){
return backend.foreach_command_status(backendctx_jobend_func, ctx);
}
+/**
+ * @brief Callback used for sending a `cancel event` to the selected backend
+ *
+ * @param ptcomm the backend communication object
+ * @param cp a bpContext - for Bacula debug and jobinfo messages
+ * @return bRC bRC_OK when success
+ */
+bRC backendctx_cancel_func(PTCOMM *ptcomm, void *cp)
+{
+ bpContext * ctx = (bpContext*)cp;
+
+ // cancel procedure
+ // 1. get backend pid
+ // 2. send SIGUSR1 to backend pid
+ // 3. wait default 5 sec or defined in CUSTOMCANCELSLEEP
+ // 4. terminate the backend as usual
+
+ pid_t pid = ptcomm->get_backend_pid();
+ DMSG(ctx, DINFO, "Inform backend about Cancel at PID=%d ...\n", pid)
+ kill(pid, SIGUSR1);
+ int32_t waitsleep = (CUSTOMCANCELSLEEP == 0) * 5 + CUSTOMCANCELSLEEP;
+ bmicrosleep(waitsleep, 1);
+ DMSG(ctx, DINFO, "Terminate backend at PID=%d\n", pid);
+ ptcomm->terminate(ctx);
+ return bRC_OK;
+}
+
+/**
+ * @brief Send `cancel event` to every backend and terminate it.
+ *
+ * @param ctx bpContext - for Bacula debug and jobinfo messages
+ * @return bRC bRC_OK when success, bRC_Error if not
+ */
+bRC METAPLUGIN::cancel_all_backends(bpContext *ctx)
+{
+ METAPLUGIN *pctx = (METAPLUGIN *)ctx->pContext;
+ // the cancel procedure: for all backends execute cancel func
+ return pctx->backend.foreach_command_status(backendctx_cancel_func, ctx);
+}
+
/*
* Send a "Job Info" protocol procedure parameters.
*
"regress_error_backup_abort",
"regress_metadata_support",
"regress_standard_error_backup",
+ "regress_cancel_backup",
NULL,
};
#endif
bRC METAPLUGIN::handlePluginEvent(bpContext *ctx, bEvent *event, void *value)
{
bRC status;
- POOL_MEM tmp;
+
+ // extract original plugin context, basically it should be `this`
+ METAPLUGIN *pctx = (METAPLUGIN *)ctx->pContext;
+ // this ensures that handlePluginEvent is thread safe for extracted pContext
+ smart_lock<smart_mutex> lg(&pctx->mutex);
+
+ if (job_cancelled) {
+ return bRC_Error;
+ }
switch (event->eventType)
{
break;
case bEventJobEnd:
- status = bRC_OK;
DMSG(ctx, D3, "bEventJobEnd value=%s\n", NPRT((char *)value));
- status = terminate_all_backends(ctx);
- return status;
+ return terminate_all_backends(ctx);
case bEventLevel:
char lvl;
return parse_plugin_restoreobj(ctx, (restore_object_pkt *) value);
case bEventCancelCommand:
- DMSG(ctx, D3, "bEventCancelCommand value=%s\n", NPRT((char *)value));
- /*
- TODO: The code can set a flag (better if protected via a global mutex), and we
- TODO: can send a kill USR1 or TERM signal to the backend if the variable is
- TODO: protected with the global mutex and available easily.
- TODO: PETITION: Our plugin (RHV WhiteBearSolutions) search the packet E CANCEL.
- TODO: If you modify this behaviour, please you notify us.
- */
- if (backend.ctx != NULL) {
- // XXX: something is going different then designed here, as backend.ctx is NULL
- bsscanf("CANCEL", "%s", tmp.c_str());
- backend.ctx->signal_error(ctx, tmp.c_str());
- }
- break;
+ DMSG2(ctx, D3, "bEventCancelCommand self = %p pctx = %p\n", this, pctx);
+ // TODO: PETITION: Our plugin (RHV WhiteBearSolutions) search the packet E CANCEL.
+ // TODO: If you modify this behaviour, please you notify us.
+ // TODO: RPK[20210623]: The information about a new procedure was sent to Eric
+ pctx->job_cancelled = true;
+ return cancel_all_backends(ctx);
default:
// enabled only for Debug
}
io->status = rc;
if (backend.ctx->is_eod()){
- /* TODO: we signal EOD as rc=0, so no need to explicity check for EOD, right? */
+ // TODO: we signal EOD as rc=0, so no need to explicity check for EOD, right?
io->status = 0;
}
return bRC_OK;
* @param cmd a command string read from backend
* @return metadata_type returned from map
*/
-metadata_type METAPLUGIN::scan_metadata_type(const POOL_MEM &cmd)
+metadata_type METAPLUGIN::scan_metadata_type(bpContext *ctx, const POOL_MEM &cmd)
{
DMSG1(ctx, DDEBUG, "scan_metadata_type checking: %s\n", cmd.c_str());
for (int i = 0; plugin_metadata_map[i].command != NULL; i++)
{
static int rw = 0; // this variable handles single debug message
+ {
+ // synchronie access to job_cancelled variable
+ smart_lock<smart_mutex> lg(&mutex);
+ if (job_cancelled) {
+ return bRC_Error;
+ }
+ }
+
/* assume no error from the very beginning */
io->status = 0;
io->io_errno = 0;
int32_t nfi;
int reqparams = 2;
+ {
+ // synchronie access to job_cancelled variable
+ smart_lock<smart_mutex> lg(&mutex);
+ if (job_cancelled) {
+ return bRC_Error;
+ }
+ }
+
/* The first file in Full backup, is the RestoreObject */
if (!estimate && mode == BACKUP_FULL && robjsent == false) {
ConfigFile ini;
-
- /* robj for the first time, allocate the buffer */
- if (!robjbuf){
- robjbuf = get_pool_memory(PM_FNAME);
- }
-
ini.register_items(plugin_items_dump, sizeof(struct ini_items));
sp->restore_obj.object_name = (char *)INI_RESTORE_OBJECT_NAME;
- sp->restore_obj.object_len = ini.serialize(&robjbuf);
- sp->restore_obj.object = robjbuf;
+ sp->restore_obj.object_len = ini.serialize(robjbuf.c_str());
+ sp->restore_obj.object = robjbuf.c_str();
sp->type = FT_PLUGIN_CONFIG;
DMSG0(ctx, DINFO, "Prepared RestoreObject sent.\n");
return bRC_OK;
}
continue;
}
- metadata_type mtype = scan_metadata_type(cmd);
+ metadata_type mtype = scan_metadata_type(ctx, cmd);
if (mtype != plugin_meta_invalid) {
DMSG1(ctx, DDEBUG, "metaData handling: %d\n", mtype);
if (perform_read_metadata_info(ctx, mtype, sp) != bRC_OK) {
{
POOL_MEM cmd(PM_FNAME);
+ {
+ // synchronie access to job_cancelled variable
+ smart_lock<smart_mutex> lg(&mutex);
+ if (job_cancelled) {
+ return bRC_Error;
+ }
+ }
+
if (!estimate){
/* The current file was the restore object, so just ask for the next file */
if (mode == BACKUP_FULL && robjsent == false) {
POOL_MEM cmd(PM_FNAME);
char type;
+ {
+ // synchronie access to job_cancelled variable
+ smart_lock<smart_mutex> lg(&mutex);
+ if (job_cancelled) {
+ return bRC_Error;
+ }
+ }
+
skipextract = false;
acldatalen = 0;
xattrdatalen = 0;
*/
bRC METAPLUGIN::handleXACLdata(bpContext *ctx, struct xacl_pkt *xacl)
{
+ {
+ // synchronie access to job_cancelled variable
+ smart_lock<smart_mutex> lg(&mutex);
+ if (job_cancelled) {
+ return bRC_Error;
+ }
+ }
+
switch (xacl->func)
{
case BACL_BACKUP:
return bRC_OK;
}
+ {
+ // synchronie access to job_cancelled variable
+ smart_lock<smart_mutex> lg(&mutex);
+ if (job_cancelled) {
+ return bRC_Error;
+ }
+ }
+
if (listing == None) {
listing = Query;
Mmsg(cmd, "%s query=%s", qp->command, qp->parameter);
if (values.size() > 1){
ow.end_list();
}
-
- /* allocate working buffer, we use robjbuf variable for that as it will be freed at dtor */
- if (!robjbuf){
- robjbuf = get_pool_memory(PM_MESSAGE);
- }
-
- pm_strcpy(&robjbuf, ow.get_output(OT_END));
- qp->result = robjbuf;
+ pm_strcpy(robjbuf, ow.get_output(OT_END));
+ qp->result = robjbuf.c_str();
}
return ret;
*/
bRC METAPLUGIN::metadataRestore(bpContext *ctx, struct meta_pkt *mp)
{
+ {
+ // synchronie access to job_cancelled variable
+ smart_lock<smart_mutex> lg(&mutex);
+ if (job_cancelled) {
+ return bRC_Error;
+ }
+ }
+
if (!skipextract){
POOL_MEM cmd(PM_FNAME);
{
if ((!CUSTOMNAMESPACE && isourpluginfname(PLUGINPREFIX, fname)) || (CUSTOMNAMESPACE && isourpluginfname(PLUGINNAMESPACE, fname)))
{
- if (::checkFile != NULL){
- return ::checkFile(ctx, fname);
+ // synchronie access to job_cancelled variable
+ smart_lock<smart_mutex> lg(&mutex);
+ if (!job_cancelled) {
+ if (::checkFile != NULL) {
+ return ::checkFile(ctx, fname);
+ }
}
return bRC_Seen;
}
{
int JobId;
char *exepath;
- METAPLUGIN *self = New(METAPLUGIN(ctx));
+ METAPLUGIN *self = New(METAPLUGIN);
POOL_MEM exepath_clean(PM_FNAME);
if (!self)
return bRC_Error;
ctx->pContext = (void*) self;
+ pthread_t mythid = pthread_self();
+ DMSG2(ctx, DVDEBUG, "pContext = %p thid = %p\n", self, mythid);
/* setup the backend command */
getBaculaVar(bVarExePath, (void *)&exepath);
static bRC handlePluginEvent(bpContext *ctx, bEvent *event, void *value)
{
ASSERT_CTX;
-
- DMSG(ctx, D1, "handlePluginEvent (%i)\n", event->eventType);
+ pthread_t mythid = pthread_self();
METAPLUGIN *self = pluginclass(ctx);
+ DMSG3(ctx, D1, "handlePluginEvent (%i) pContext = %p thid = %p\n", event->eventType, self, mythid);
return self->handlePluginEvent(ctx, event, value);
}
static bRC startBackupFile(bpContext *ctx, struct save_pkt *sp)
{
ASSERT_CTX;
- if (!sp)
+ if (!sp) {
return bRC_Error;
+ }
DMSG0(ctx, D1, "startBackupFile.\n");
METAPLUGIN *self = pluginclass(ctx);
#include "pluginlib.h"
#include "ptcomm.h"
+#include "smartmutex.h"
#include "lib/ini.h"
#include "pluginlib/commctx.h"
#include "pluginlib/smartalist.h"
extern const char *PLUGIN_DESCRIPTION;
// Plugin linking time variables
-extern const char *PLUGINPREFIX; /// is used for prefixing every Job and Debug messages generted by a plugin
-extern const char *PLUGINNAME; /// should match the backend $pluginname$ used for Handshake procedure
-extern const bool CUSTOMNAMESPACE; /// defines if metaplugin should send `Namespace=...` backend plugin parameter using PLUGINNAMESPACE variable
-extern const bool CUSTOMPREVJOBNAME; /// defines if metaplugin should send `PrevJobName=...` backend plugin parameter from bacula variable
-extern const char *PLUGINNAMESPACE; /// custom backend plugin namespace used as file name prefix
-extern const char *PLUGINAPI;
-extern const char *BACKEND_CMD;
+extern const char *PLUGINPREFIX; /// is used for prefixing every Job and Debug messages generted by a plugin
+extern const char *PLUGINNAME; /// should match the backend $pluginname$ used for Handshake procedure
+extern const bool CUSTOMNAMESPACE; /// defines if metaplugin should send `Namespace=...` backend plugin parameter using PLUGINNAMESPACE variable
+extern const bool CUSTOMPREVJOBNAME; /// defines if metaplugin should send `PrevJobName=...` backend plugin parameter from bacula variable
+extern const char *PLUGINNAMESPACE; /// custom backend plugin namespace used as file name prefix
+extern const char *PLUGINAPI; /// the plugin api string which should match backend expectations
+extern const char *BACKEND_CMD; /// a backend execution command path
+extern const int32_t CUSTOMCANCELSLEEP; /// custom wait time for backend between USR1 and terminate procedures
/// defines if metaplugin should handle local filesystem restore with Bacula Core functions
/// `false` means metaplugin will redirect local restore to backend
bRC queryParameter(bpContext *ctx, struct query_pkt *qp);
bRC metadataRestore(bpContext *ctx, struct meta_pkt *mp);
void setup_backend_command(bpContext *ctx, POOL_MEM &exepath);
- METAPLUGIN(bpContext *bpctx);
+ METAPLUGIN() :
+ backend_cmd(PM_FNAME),
+ job_cancelled(false),
+ backend_available(false),
+ backend_error(PM_MESSAGE),
+ mode(NONE),
+ JobId(0),
+ JobName(NULL),
+ since(0),
+ where(NULL),
+ regexwhere(NULL),
+ replace(0),
+ robjsent(false),
+ estimate(false),
+ listing(None),
+ nodata(false),
+ nextfile(false),
+ openerror(false),
+ pluginobject(false),
+ pluginobjectsent(false),
+ readacl(false),
+ readxattr(false),
+ skipextract(false),
+ last_type(0),
+ fname(PM_FNAME),
+ lname(PM_FNAME),
+ robjbuf(PM_MESSAGE),
+ plugin_obj_cat(PM_FNAME),
+ plugin_obj_type(PM_FNAME),
+ plugin_obj_name(PM_FNAME),
+ plugin_obj_src(PM_FNAME),
+ plugin_obj_uuid(PM_FNAME),
+ plugin_obj_size(PM_FNAME),
+ acldatalen(0),
+ acldata(PM_MESSAGE),
+ xattrdatalen(0),
+ xattrdata(PM_MESSAGE),
+ metadatas_list(10, true),
+ prevjobname(NULL)
+ {}
#if __cplusplus > 201103L
- METAPLUGIN() = delete;
METAPLUGIN(METAPLUGIN&) = delete;
METAPLUGIN(METAPLUGIN&&) = delete;
#endif
- ~METAPLUGIN();
+ ~METAPLUGIN() {}
private:
enum LISTING
Query,
};
- // TODO: define a variable which will signal job cancel
- bpContext *ctx; // Bacula Plugin Context
+ bool job_cancelled; // it signal the metaplugin that job was cancelled
+ smart_mutex mutex; // mutex to synchronize data access
bool backend_available; // When `False` then backend program is unuseable or unavailable
POOL_MEM backend_error; // Holds the error string when backend program is unavailable
MODE mode; // Plugin mode of operation
COMMCTX<PTCOMM> backend; // the backend context list for multiple backend execution for a single job
POOL_MEM fname; // current file name to backup (grabbed from backend)
POOL_MEM lname; // current LSTAT data if any
- POOLMEM *robjbuf; // the buffer for restore object data
+ POOL_MEM robjbuf; // the buffer for restore object data
POOL_MEM plugin_obj_cat; // Plugin object Category
POOL_MEM plugin_obj_type; // Plugin object Type
POOL_MEM plugin_obj_name; // Plugin object Name
bRC perform_read_metadata_info(bpContext *ctx, metadata_type type, struct save_pkt *sp);
bRC perform_file_index_query(bpContext *ctx);
// bRC perform_write_metadata_info(bpContext *ctx, struct meta_pkt *mp);
- metadata_type scan_metadata_type(const POOL_MEM &cmd);
+ metadata_type scan_metadata_type(bpContext *ctx, const POOL_MEM &cmd);
const char *prepare_metadata_type(metadata_type type);
int check_ini_param(char *param);
bool check_plugin_param(const char *param, alist *params);
bRC switch_or_run_backend(bpContext *ctx, char *command);
bRC terminate_current_backend(bpContext *ctx);
bRC terminate_all_backends(bpContext *ctx);
+ bRC cancel_all_backends(bpContext *ctx);
bRC signal_finish_all_backends(bpContext *ctx);
bRC render_param(bpContext *ctx, POOLMEM *param, INI_ITEM_HANDLER *handler, char *key, item_value val);
};
#include <fcntl.h>
#include <string.h>
#include <errno.h>
+#include <signal.h>
#ifndef LOGDIR
#define LOGDIR "/tmp"
#endif
+#define EXIT_BACKEND_NOMEMORY 255
+#define EXIT_BACKEND_LOGFILE_ERROR 1
+#define EXIT_BACKEND_HEADER_TOOSHORT 2
+#define EXIT_BACKEND_MESSAGE_TOOLONG 3
+#define EXIT_BACKEND_DATA_COMMAND_REQ 4
+#define EXIT_BACKEND_SIGNAL_HANDLER_ERROR 5
+#define EXIT_BACKEND_CANCEL 6
+
extern const char *PLUGINPREFIX;
extern const char *PLUGINNAME;
bool regress_backup_other_file = false;
bool regress_metadata_support = false;
bool regress_standard_error_backup = false;
+bool regress_cancel_backup = false;
#define BUFLEN 4096
if (len < 8){
LOG("#> Err: header too short");
close(logfd);
- exit(2);
+ exit(EXIT_BACKEND_HEADER_TOOSHORT);
}
if (header[0] == 'F'){
LOG(">> EOD >>");
if (header[0] == 'T'){
LOG(">> TERM >>");
close(logfd);
- exit(0);
+ exit(EXIT_SUCCESS);
}
size = atoi(header+1);
if (size > BIGBUFLEN){
LOG("#> Err: message too long");
close(logfd);
- exit(3);
+ exit(EXIT_BACKEND_MESSAGE_TOOLONG);
}
if (header[0] == 'C'){
LOG("<< TERM <<");
}
+static bool jobcancelled = false;
+
+static void catch_function(int signo)
+{
+ LOG("#CANCELLED#");
+ jobcancelled = true;
+}
+
/**
* @brief Perform test backup.
*/
snprintf(fileindex_link, 256, "%s/bucket/%d/vm1.iso", PLUGINPREFIX, mypid);
// Backup Loop
+ if (regress_error_backup_no_files) {
+ write_plugin('E', "No files found for pattern container1/otherobject\n");
+ signal_eod();
+ return;
+ }
+
+ // first file
snprintf(buf, BIGBUFLEN, "FNAME:%s\n", fileindex_link); // we use it here
write_plugin('C', buf);
write_plugin('C', "STAT:F 1048576 100 100 100640 2\n"); // this will be the first file hardlinked
write_plugin('I', "TEST5Acl");
signal_eod();
- if (regress_error_backup_no_files) {
- write_plugin('E', "No files found for pattern container1/otherobject\n");
- signal_eod();
- return;
+ if (regress_cancel_backup)
+ {
+ LOG("#Cancel wait started...");
+ while (!jobcancelled)
+ sleep(1);
+ LOG("#Cancel event received, EXIT");
+ exit(EXIT_BACKEND_CANCEL);
}
// next file
signal_eod();
}
+/**
+ * @brief Perform test estimate
+ */
void perform_estimate(){
/* Estimate Loop (5) */
snprintf(buf, BIGBUFLEN, "FNAME:%s/bucket/%d/vm1.iso\n", PLUGINPREFIX, mypid);
write_plugin('C', "OK\n");
} else {
write_plugin('E', "Error DATA command required.");
- exit (1);
+ exit(EXIT_BACKEND_DATA_COMMAND_REQ);
}
}
buf = (char*)malloc(BIGBUFLEN);
if (buf == NULL){
- exit(255);
+ exit(EXIT_BACKEND_NOMEMORY);
}
buflog = (char*)malloc(BUFLEN);
if (buflog == NULL){
- exit(255);
+ exit(EXIT_BACKEND_NOMEMORY);
}
listing = (char*)malloc(BUFLEN);
if (listing == NULL){
- exit(255);
+ exit(EXIT_BACKEND_NOMEMORY);
}
query = (char*)malloc(BUFLEN);
if (query == NULL){
- exit(255);
+ exit(EXIT_BACKEND_NOMEMORY);
}
mypid = getpid();
snprintf(buf, 4096, "%s/%s_backend_%d.log", LOGDIR, PLUGINNAME, mypid);
logfd = open(buf, O_CREAT|O_TRUNC|O_WRONLY, 0640);
if (logfd < 0){
- exit (1);
+ exit(EXIT_BACKEND_LOGFILE_ERROR);
}
//sleep(30);
// "regress_backup_plugin_objects",
// "regress_error_backup_abort",
// "regress_standard_error_backup",
- if (strcmp(buf, "regress_error_plugin_params=1\n") == 0){
+ // "regress_cancel_backup",
+
+ if (strcmp(buf, "regress_error_plugin_params=1\n") == 0) {
regress_error_plugin_params = true;
continue;
}
- if (strcmp(buf, "regress_error_start_job=1\n") == 0){
+ if (strcmp(buf, "regress_error_start_job=1\n") == 0) {
regress_error_start_job = true;
continue;
}
- if (strcmp(buf, "regress_error_backup_no_files=1\n") == 0){
+ if (strcmp(buf, "regress_error_backup_no_files=1\n") == 0) {
regress_error_backup_no_files = true;
continue;
}
- if (strcmp(buf, "regress_error_backup_stderr=1\n") == 0){
+ if (strcmp(buf, "regress_error_backup_stderr=1\n") == 0) {
regress_error_backup_stderr = true;
continue;
}
- if (strcmp(buf, "regress_error_estimate_stderr=1\n") == 0){
+ if (strcmp(buf, "regress_error_estimate_stderr=1\n") == 0) {
regress_error_estimate_stderr = true;
continue;
}
- if (strcmp(buf, "regress_error_listing_stderr=1\n") == 0){
+ if (strcmp(buf, "regress_error_listing_stderr=1\n") == 0) {
regress_error_listing_stderr = true;
continue;
}
- if (strcmp(buf, "regress_error_restore_stderr=1\n") == 0){
+ if (strcmp(buf, "regress_error_restore_stderr=1\n") == 0) {
regress_error_restore_stderr = true;
continue;
}
- if (strcmp(buf, "regress_backup_plugin_objects=1\n") == 0){
+ if (strcmp(buf, "regress_backup_plugin_objects=1\n") == 0) {
regress_backup_plugin_objects = true;
continue;
}
- if (strcmp(buf, "regress_error_backup_abort=1\n") == 0){
+ if (strcmp(buf, "regress_error_backup_abort=1\n") == 0) {
regress_error_backup_abort = true;
continue;
}
- if (strcmp(buf, "regress_backup_other_file=1\n") == 0){
+ if (strcmp(buf, "regress_backup_other_file=1\n") == 0) {
regress_backup_other_file = true;
continue;
}
- if (strcmp(buf, "regress_metadata_support=1\n") == 0){
+ if (strcmp(buf, "regress_metadata_support=1\n") == 0) {
regress_metadata_support = true;
continue;
}
- if (strcmp(buf, "regress_standard_error_backup=1\n") == 0){
+ if (strcmp(buf, "regress_standard_error_backup=1\n") == 0) {
regress_standard_error_backup = true;
continue;
}
+ if (strcmp(buf, "regress_cancel_backup=1\n") == 0) {
+ regress_cancel_backup = true;
+ if (signal(SIGUSR1, catch_function) == SIG_ERR){
+ LOG("Cannot setup signal handler!");
+ exit(EXIT_BACKEND_SIGNAL_HANDLER_ERROR);
+ }
+ continue;
+ }
if (sscanf(buf, "listing=%s\n", buf) == 1){
strcpy(listing, buf);
continue;