Testing to do: (painful)
- that console command line options work
- blocksize recognition code.
+- multiple simultaneous Volumes
For 1.30 release:
-- Fix restore of hard linked file.
- Implement FileOptions (see end of this document)
- Implement Bacula plugins -- design API
- Make bcopy read through bad tape records.
- Program files (i.e. execute a program to read/write files).
Pass read date of last backup, size of file last time.
- Add Signature type to File DB record.
+- Make Restore report an error if FD or SD term codes are not OK.
- CD into subdirectory when open()ing files for backup to
speed up things. Test with testfind().
- Add prefixlinks to where or not where absolute links to FD.
- Implement Bar code handling
- Why is catreq.c:111 Find vol called twice for a job?
- Find out why Full saves run slower and slower (hashing?)
-- Figure out how to allow multiple simultaneous file Volumes on a single device.
- Why are save/restore of device different sizes (sparse?) Yup! Fix it.
- Implement some way for the Console to dynamically create a job.
- Restore to a particular time -- e.g. before date, after date.
a block and a record.
- Figure out how to do a bare metal Windows restore
- Put system type returned by FD into catalog.
+- Need to specify MaximumConcurrentJobs in the Job resource.
- Possibly add email to Watchdog if drive is unmounted too
long and a job is waiting on the drive.
- Strip trailing slashes from Include directory names in the FD.
- Use read_record.c in SD code.
- Why don't we get an error message from Win32 FD when bootstrap
file cannot be created for restore command?
-- Need to specify MaximumConcurrentJobs in the Job resource.
- When Marking a file in Restore that is a hard link, also
mark the link so that the data will be reloaded.
- Restore program that errors in SD due to no tape reports
OK incorrectly in output.
- After unmount, if restore job started, ask to mount.
-- Make Restore report an error if FD or SD term codes are not OK.
- Convert all %x substitution variables, which are hard to remember
and read to %(variable-name). Idea from TMDA.
- Add JobLevel in FD status (but make sure it is defined).
- Remove NextId for SQLite. Optimize.
- Strip trailing / from Include
- Move all SQL statements into a single location.
-- Cleanup db_update_media and db_update_pool
- Add UA rc and history files.
- put termcap (used by console) in ./configure and
allow -with-termcap-dir.
- Get correct error status from run_program or open_bpipe().
- Restrict permissions on File Volumes (now 0640).
- Umasked 022 daemons
+- Fix restore of hard linked file.
+- Figure out how to allow multiple simultaneous file Volumes on a single device.
+- Cleanup db_update_media and db_update_pool
+
/* Forward referenced subroutines */
static void store_inc(LEX *lc, struct res_items *item, int index, int pass);
+static void store_applyto(LEX *lc, struct res_items *item, int index, int pass);
static void store_backup(LEX *lc, struct res_items *item, int index, int pass);
static void store_restore(LEX *lc, struct res_items *item, int index, int pass);
static void store_jobtype(LEX *lc, struct res_items *item, int index, int pass);
{"name", store_name, ITEM(res_fo.hdr.name), 0, ITEM_REQUIRED, 0},
{"description", store_str, ITEM(res_fo.hdr.desc), 0, 0, 0},
{"replace", store_replace, ITEM(res_fo.replace), REPLACE_ALWAYS, ITEM_DEFAULT, 0},
+ {"applyto", store_applyto, NULL, 0, 0, 0},
{NULL, NULL, NULL, 0, 0, 0}
};
case R_FILESET:
sendit(sock, "FileSet: name=%s\n", res->res_fs.hdr.name);
for (i=0; i<res->res_fs.num_includes; i++)
- sendit(sock, " Inc: %s\n", res->res_fs.include_array[i]);
+ sendit(sock, " Inc: %s\n", res->res_fs.include_array[i]->name);
for (i=0; i<res->res_fs.num_excludes; i++)
- sendit(sock, " Exc: %s\n", res->res_fs.exclude_array[i]);
+ sendit(sock, " Exc: %s\n", res->res_fs.exclude_array[i]->name);
break;
case R_SCHEDULE:
if (res->res_sch.run) {
break;
case R_FILESET:
if ((num=res->res_fs.num_includes)) {
- while (--num >= 0)
+ while (--num >= 0) {
free(res->res_fs.include_array[num]);
+ }
free(res->res_fs.include_array);
}
if ((num=res->res_fs.num_excludes)) {
- while (--num >= 0)
+ while (--num >= 0) {
free(res->res_fs.exclude_array[num]);
+ }
free(res->res_fs.exclude_array);
}
break;
int token, i;
int options = lc->options;
int keyword;
- char *fname;
char inc_opts[100];
int inc_opts_len;
case T_IDENTIFIER:
case T_UNQUOTED_STRING:
case T_QUOTED_STRING:
- fname = (char *)malloc(lc->str_len + inc_opts_len + 1);
- strcpy(fname, inc_opts);
- strcat(fname, lc->str);
+ INCEXE *incexe;
+ incexe = (INCEXE *)malloc(lc->str_len + sizeof(INCEXE));
+ memset(incexe, 0, sizeof(INCEXE));
+ bstrncpy(incexe->opts, inc_opts, sizeof(incexe->opts));
+ strcpy(incexe->name, lc->str);
if (res_all.res_fs.have_MD5) {
- MD5Update(&res_all.res_fs.md5c, (unsigned char *) fname, inc_opts_len + lc->str_len);
+ MD5Update(&res_all.res_fs.md5c, (unsigned char *)incexe,
+ sizeof(INCEXE) + lc->str_len);
}
if (item->code == 0) { /* include */
if (res_all.res_fs.num_includes == res_all.res_fs.include_size) {
res_all.res_fs.include_size += 10;
if (res_all.res_fs.include_array == NULL) {
- res_all.res_fs.include_array = (char **) malloc(sizeof(char *) * res_all.res_fs.include_size);
+ res_all.res_fs.include_array = (INCEXE **)malloc(sizeof(INCEXE *) * res_all.res_fs.include_size);
} else {
- res_all.res_fs.include_array = (char **) realloc(res_all.res_fs.include_array,
- sizeof(char *) * res_all.res_fs.include_size);
+ res_all.res_fs.include_array = (INCEXE **)realloc(res_all.res_fs.include_array,
+ sizeof(INCEXE *) * res_all.res_fs.include_size);
}
}
- res_all.res_fs.include_array[res_all.res_fs.num_includes++] =
- fname;
+ res_all.res_fs.include_array[res_all.res_fs.num_includes++] = incexe;
} else { /* exclude */
if (res_all.res_fs.num_excludes == res_all.res_fs.exclude_size) {
res_all.res_fs.exclude_size += 10;
if (res_all.res_fs.exclude_array == NULL) {
- res_all.res_fs.exclude_array = (char **)malloc(sizeof(char *) * res_all.res_fs.exclude_size);
+ res_all.res_fs.exclude_array = (INCEXE **)malloc(sizeof(INCEXE *) * res_all.res_fs.exclude_size);
} else {
- res_all.res_fs.exclude_array = (char **)realloc(res_all.res_fs.exclude_array,
- sizeof(char *) * res_all.res_fs.exclude_size);
+ res_all.res_fs.exclude_array = (INCEXE **)realloc(res_all.res_fs.exclude_array,
+ sizeof(INCEXE *) * res_all.res_fs.exclude_size);
}
}
- res_all.res_fs.exclude_array[res_all.res_fs.num_excludes++] =
- fname;
+ res_all.res_fs.exclude_array[res_all.res_fs.num_excludes++] = incexe;
}
break;
default:
lc->options = options;
set_bit(index, res_all.hdr.item_present);
}
+
+/* Store FileOptions ApplyTo info */
+static void store_applyto(LEX *lc, struct res_items *item, int index, int pass)
+{
+ int token;
+ char *applyto;
+
+ if (pass == 1) {
+ /* Pickup ApplyTo string
+ */
+ while ((token = lex_get_token(lc, T_ALL)) != T_EOB) {
+ switch (token) {
+ case T_COMMA:
+ case T_EOL:
+ continue;
+
+ case T_IDENTIFIER:
+ case T_UNQUOTED_STRING:
+ case T_QUOTED_STRING:
+ applyto = (char *)malloc(lc->str_len + 1);
+ strcpy(applyto, lc->str);
+ res_all.res_fo.num_applyto++;
+ if (res_all.res_fo.applyto == NULL) {
+ res_all.res_fo.applyto = (char **)malloc(sizeof(char *) * res_all.res_fo.num_applyto);
+ } else {
+ res_all.res_fo.applyto = (char **)realloc(res_all.res_fo.applyto,
+ sizeof(char *) * res_all.res_fo.num_applyto);
+ }
+ res_all.res_fo.applyto[res_all.res_fo.num_applyto-1] = applyto;
+ break;
+ default:
+ scan_err1(lc, "Expected a filename, got: %s", lc->str);
+ }
+ }
+ } else { /* pass 2 */
+ while (lex_get_token(lc, T_ALL) != T_EOB)
+ {}
+ }
+ scan_to_eol(lc);
+ set_bit(index, res_all.hdr.item_present);
+}
/*
* Resource codes -- they must be sequential for indexing
*/
-#define R_FIRST 1001
-
-#define R_DIRECTOR 1001
-#define R_CLIENT 1002
-#define R_JOB 1003
-#define R_STORAGE 1004
-#define R_CATALOG 1005
-#define R_SCHEDULE 1006
-#define R_FILESET 1007
-#define R_GROUP 1008
-#define R_POOL 1009
-#define R_MSGS 1010
-#define R_COUNTER 1011
-#define R_FILEOPTIONS 1012
-
-#define R_LAST R_FILEOPTIONS
+#define R_FIRST 1001
+
+#define R_DIRECTOR 1001
+#define R_CLIENT 1002
+#define R_JOB 1003
+#define R_STORAGE 1004
+#define R_CATALOG 1005
+#define R_SCHEDULE 1006
+#define R_FILESET 1007
+#define R_GROUP 1008
+#define R_POOL 1009
+#define R_MSGS 1010
+#define R_COUNTER 1011
+#define R_FILEOPTIONS 1012
+
+#define R_LAST R_FILEOPTIONS
/*
* Some resource attributes
*/
-#define R_NAME 1020
-#define R_ADDRESS 1021
-#define R_PASSWORD 1022
-#define R_TYPE 1023
-#define R_BACKUP 1024
+#define R_NAME 1020
+#define R_ADDRESS 1021
+#define R_PASSWORD 1022
+#define R_TYPE 1023
+#define R_BACKUP 1024
/* Used for certain KeyWord tables */
-struct s_kw {
+struct s_kw {
char *name;
- int token;
+ int token;
};
/* Job Level keyword structure */
struct s_jl {
- char *level_name; /* level keyword */
- int level; /* level */
- int job_type; /* JobType permitting this level */
+ char *level_name; /* level keyword */
+ int level; /* level */
+ int job_type; /* JobType permitting this level */
};
/* Job Type keyword structure */
/* Definition of the contents of each Resource */
/*
- * Director Resource
+ * Director Resource
*
*/
struct s_res_dir {
- RES hdr;
- int DIRport; /* where we listen -- UA port server port */
- char *DIRaddr; /* bind address */
- char *password; /* Password for UA access */
- char *query_file; /* SQL query file */
- char *working_directory; /* WorkingDirectory */
- char *pid_directory; /* PidDirectory */
- char *subsys_directory; /* SubsysDirectory */
+ RES hdr;
+ int DIRport; /* where we listen -- UA port server port */
+ char *DIRaddr; /* bind address */
+ char *password; /* Password for UA access */
+ char *query_file; /* SQL query file */
+ char *working_directory; /* WorkingDirectory */
+ char *pid_directory; /* PidDirectory */
+ char *subsys_directory; /* SubsysDirectory */
struct s_res_msgs *messages; /* Daemon message handler */
- int MaxConcurrentJobs;
- utime_t FDConnectTimeout; /* timeout for connect in seconds */
- utime_t SDConnectTimeout; /* timeout in seconds */
+ int MaxConcurrentJobs;
+ utime_t FDConnectTimeout; /* timeout for connect in seconds */
+ utime_t SDConnectTimeout; /* timeout in seconds */
};
typedef struct s_res_dir DIRRES;
*
*/
struct s_res_client {
- RES hdr;
+ RES hdr;
- int FDport; /* Where File daemon listens */
- int AutoPrune; /* Do automatic pruning? */
- utime_t FileRetention; /* file retention period in seconds */
- utime_t JobRetention; /* job retention period in seconds */
+ int FDport; /* Where File daemon listens */
+ int AutoPrune; /* Do automatic pruning? */
+ utime_t FileRetention; /* file retention period in seconds */
+ utime_t JobRetention; /* job retention period in seconds */
char *address;
char *password;
struct s_res_cat *catalog; /* Catalog resource */
*
*/
struct s_res_store {
- RES hdr;
+ RES hdr;
- int SDport; /* port where Directors connect */
- int SDDport; /* data port for File daemon */
+ int SDport; /* port where Directors connect */
+ int SDDport; /* data port for File daemon */
char *address;
char *password;
char *media_type;
char *dev_name;
- int autochanger; /* set if autochanger */
+ int autochanger; /* set if autochanger */
};
typedef struct s_res_store STORE;
*
*/
struct s_res_cat {
- RES hdr;
+ RES hdr;
- int DBport; /* Port -- not yet implemented */
+ int DBport; /* Port -- not yet implemented */
char *address;
char *db_password;
char *db_user;
*
*/
struct s_res_job {
- RES hdr;
-
- int JobType; /* job type (backup, verify, restore */
- int level; /* default backup/verify level */
- int RestoreJobId; /* What -- JobId to restore */
- char *RestoreWhere; /* Where on disk to restore -- directory */
- char *RestoreBootstrap; /* Bootstrap file */
- char *RunBeforeJob; /* Run program before Job */
- char *RunAfterJob; /* Run program after Job */
- char *WriteBootstrap; /* Where to write bootstrap Job updates */
- int replace; /* How (overwrite, ..) */
- utime_t MaxRunTime; /* max run time in seconds */
- utime_t MaxStartDelay; /* max start delay in seconds */
- int PrefixLinks; /* prefix soft links with Where path */
- int PruneJobs; /* Force pruning of Jobs */
- int PruneFiles; /* Force pruning of Files */
- int PruneVolumes; /* Force pruning of Volumes */
- int SpoolAttributes; /* Set to spool attributes in SD */
+ RES hdr;
+
+ int JobType; /* job type (backup, verify, restore */
+ int level; /* default backup/verify level */
+ int RestoreJobId; /* What -- JobId to restore */
+ char *RestoreWhere; /* Where on disk to restore -- directory */
+ char *RestoreBootstrap; /* Bootstrap file */
+ char *RunBeforeJob; /* Run program before Job */
+ char *RunAfterJob; /* Run program after Job */
+ char *WriteBootstrap; /* Where to write bootstrap Job updates */
+ int replace; /* How (overwrite, ..) */
+ utime_t MaxRunTime; /* max run time in seconds */
+ utime_t MaxStartDelay; /* max start delay in seconds */
+ int PrefixLinks; /* prefix soft links with Where path */
+ int PruneJobs; /* Force pruning of Jobs */
+ int PruneFiles; /* Force pruning of Files */
+ int PruneVolumes; /* Force pruning of Volumes */
+ int SpoolAttributes; /* Set to spool attributes in SD */
struct s_res_msgs *messages; /* How and where to send messages */
struct s_res_sch *schedule; /* When -- Automatic schedule */
struct s_res_client *client; /* Who to backup */
struct s_res_fs *fileset; /* What to backup -- Fileset */
struct s_res_store *storage; /* Where is device -- Storage daemon */
- struct s_res_pool *pool; /* Where is media -- Media Pool */
+ struct s_res_pool *pool; /* Where is media -- Media Pool */
};
typedef struct s_res_job JOB;
* File Options Resource (options for Includes)
*/
struct s_res_fo {
- RES hdr;
+ RES hdr;
- char opts[20]; /* Options string */
- int replace; /* How (overwrite, ...) */
- struct s_applyto *applyto; /* applyto strings */
+ char opts[20]; /* Options string */
+ int replace; /* How (overwrite, ...) */
+ char **applyto; /* applyto strings */
+ int num_applyto; /* number of appyto strings */
};
typedef struct s_res_fo FILEOPTIONS;
struct s_incexc_item {
- char opts[20]; /* options string */
- struct s_res_fo *fileopts; /* file options */
- char name[1]; /* include/exclude name */
+ char opts[20]; /* options string */
+ FILEOPTIONS **fileopts; /* file options array */
+ int num_fileopts; /* number of above */
+ char name[1]; /* include/exclude name */
};
+typedef struct s_incexc_item INCEXE;
/*
* FileSet Resource
*
*/
struct s_res_fs {
- RES hdr;
+ RES hdr;
- /* ***FIXME*** each include must have chain of FileOptions */
- char **include_array;
- int num_includes;
- int include_size;
- char **exclude_array;
+ INCEXE **include_array; /* array of incexe structures */
+ int num_includes; /* number in array */
+ int include_size; /* array size */
+ INCEXE **exclude_array;
int num_excludes;
int exclude_size;
- int have_MD5; /* set if MD5 initialized */
- struct MD5Context md5c; /* MD5 of include/exclude */
- char MD5[30]; /* base 64 representation of MD5 */
+ int have_MD5; /* set if MD5 initialized */
+ struct MD5Context md5c; /* MD5 of include/exclude */
+ char MD5[30]; /* base 64 representation of MD5 */
};
typedef struct s_res_fs FILESET;
*
*/
struct s_res_sch {
- RES hdr;
+ RES hdr;
struct s_run *run;
};
*
*/
struct s_res_group {
- RES hdr;
+ RES hdr;
};
typedef struct s_res_group GROUP;
* Counter Resource
*/
struct s_res_counter {
- RES hdr;
+ RES hdr;
- int32_t MinValue; /* Minimum value */
- int32_t MaxValue; /* Maximum value */
- int Global; /* global/local */
- char *WrapCounter; /* Wrap counter name */
+ int32_t MinValue; /* Minimum value */
+ int32_t MaxValue; /* Maximum value */
+ int Global; /* global/local */
+ char *WrapCounter; /* Wrap counter name */
};
typedef struct s_res_counter COUNTER;
*
*/
struct s_res_pool {
- RES hdr;
+ RES hdr;
struct s_res_counter counter; /* Counter resources */
- char *pool_type; /* Pool type */
- char *label_format; /* Label format string */
- int use_catalog; /* maintain catalog for media */
- int catalog_files; /* maintain file entries in catalog */
- int use_volume_once; /* write on volume only once */
- int accept_any_volume; /* accept any volume */
- uint32_t max_volumes; /* max number of volumes */
- utime_t VolRetention; /* volume retention period in seconds */
- utime_t VolUseDuration; /* duration volume can be used */
- uint32_t MaxVolJobs; /* Maximum jobs on the Volume */
- uint32_t MaxVolFiles; /* Maximum files on the Volume */
- uint64_t MaxVolBytes; /* Maximum bytes on the Volume */
- int AutoPrune; /* default for pool auto prune */
- int Recycle; /* default for media recycle yes/no */
+ char *pool_type; /* Pool type */
+ char *label_format; /* Label format string */
+ int use_catalog; /* maintain catalog for media */
+ int catalog_files; /* maintain file entries in catalog */
+ int use_volume_once; /* write on volume only once */
+ int accept_any_volume; /* accept any volume */
+ uint32_t max_volumes; /* max number of volumes */
+ utime_t VolRetention; /* volume retention period in seconds */
+ utime_t VolUseDuration; /* duration volume can be used */
+ uint32_t MaxVolJobs; /* Maximum jobs on the Volume */
+ uint32_t MaxVolFiles; /* Maximum files on the Volume */
+ uint64_t MaxVolBytes; /* Maximum bytes on the Volume */
+ int AutoPrune; /* default for pool auto prune */
+ int Recycle; /* default for media recycle yes/no */
};
typedef struct s_res_pool POOL;
* resource structure definitions.
*/
union u_res {
- struct s_res_dir res_dir;
- struct s_res_client res_client;
- struct s_res_store res_store;
- struct s_res_cat res_cat;
- struct s_res_job res_job;
- struct s_res_fs res_fs;
- struct s_res_sch res_sch;
- struct s_res_group res_group;
- struct s_res_pool res_pool;
- struct s_res_msgs res_msgs;
+ struct s_res_dir res_dir;
+ struct s_res_client res_client;
+ struct s_res_store res_store;
+ struct s_res_cat res_cat;
+ struct s_res_job res_job;
+ struct s_res_fs res_fs;
+ struct s_res_sch res_sch;
+ struct s_res_group res_group;
+ struct s_res_pool res_pool;
+ struct s_res_msgs res_msgs;
struct s_res_counter res_counter;
- struct s_res_fo res_fo;
+ struct s_res_fo res_fo;
RES hdr;
};
/* Run structure contained in Schedule Resource */
struct s_run {
- struct s_run *next; /* points to next run record */
- int level; /* level override */
+ struct s_run *next; /* points to next run record */
+ int level; /* level override */
int job_type;
- POOL *pool; /* Pool override */
- STORE *storage; /* Storage override */
- MSGS *msgs; /* Messages override */
+ POOL *pool; /* Pool override */
+ STORE *storage; /* Storage override */
+ MSGS *msgs; /* Messages override */
char *since;
int level_no;
- int minute; /* minute to run job */
- time_t last_run; /* last time run */
- time_t next_run; /* next time to run */
+ int minute; /* minute to run job */
+ time_t last_run; /* last time run */
+ time_t next_run; /* next time to run */
char hour[nbytes_for_bits(24)]; /* bit set for each hour */
char mday[nbytes_for_bits(31)]; /* bit set for each day of month */
char month[nbytes_for_bits(12)]; /* bit set for each month */
{
FILESET *fileset;
BSOCK *fd;
- int i, j;
- char *msgsave;
+ int i;
fd = jcr->file_bsock;
fileset = jcr->fileset;
BPIPE *bpipe;
FILE *ffd;
char buf[1000];
- char *o, *p, *q;
+ char *p;
int optlen, stat;
+ INCEXE *ie;
Dmsg1(120, "dird>filed: include file: %s\n", fileset->include_array[i]);
- o = p = fileset->include_array[i];
- skip_nonspaces(&p); /* skip options */
- skip_spaces(&p);
- q = p; /* save end of options */
+ ie = fileset->include_array[i];
+ p = ie->name;
switch (*p++) {
case '|':
fd->msg = edit_job_codes(jcr, fd->msg, p, "");
goto bail_out;
}
/* Copy File options */
- optlen = q - o;
- for (j=0; j < optlen; j++) {
- buf[j] = *o++;
- }
+ strcpy(buf, ie->opts);
+ optlen = strlen(buf);
while (fgets(buf+optlen, sizeof(buf)-optlen, bpipe->rfd)) {
fd->msglen = Mmsg(&fd->msg, "%s", buf);
Dmsg2(200, "Including len=%d: %s", fd->msglen, fd->msg);
goto bail_out;
}
/* Copy File options */
- optlen = q - o;
- for (j=0; j < optlen; j++) {
- buf[j] = *o++;
- }
+ strcpy(buf, ie->opts);
+ optlen = strlen(buf);
while (fgets(buf+optlen, sizeof(buf)-optlen, ffd)) {
fd->msglen = Mmsg(&fd->msg, "%s", buf);
if (!bnet_send(fd)) {
fclose(ffd);
break;
default:
- msgsave = fd->msg;
- fd->msg = fileset->include_array[i];
- fd->msglen = strlen(fileset->include_array[i]);
+ strcpy(fd->msg, ie->opts);
+ pm_strcat(&fd->msg, ie->name);
+ fd->msglen = strlen(fd->msg);
if (!bnet_send(fd)) {
Jmsg(jcr, M_FATAL, 0, _(">filed: write error on socket\n"));
goto bail_out;
}
- fd->msg = msgsave;
break;
}
}
FILESET *fileset;
BSOCK *fd;
int i;
- char *msgsave;
fd = jcr->file_bsock;
fileset = jcr->fileset;
- msgsave = fd->msg;
fd->msglen = sprintf(fd->msg, exc);
bnet_send(fd);
for (i=0; i < fileset->num_excludes; i++) {
- fd->msglen = strlen(fileset->exclude_array[i]);
- Dmsg1(120, "dird>filed: exclude file: %s\n", fileset->exclude_array[i]);
- fd->msg = fileset->exclude_array[i];
+ pm_strcpy(&fd->msg, fileset->exclude_array[i]->name);
+ fd->msglen = strlen(fd->msg);
+ Dmsg1(120, "dird>filed: exclude file: %s\n", fileset->exclude_array[i]->name);
if (!bnet_send(fd)) {
Jmsg(jcr, M_FATAL, 0, _(">filed: write error on socket\n"));
set_jcr_job_status(jcr, JS_ErrorTerminated);
}
}
bnet_sig(fd, BNET_EOD);
- fd->msg = msgsave;
if (!response(fd, OKexc, "Exclude")) {
set_jcr_job_status(jcr, JS_ErrorTerminated);
return 0;