X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;f=bacula%2Fsrc%2Ffiled%2Fjob.c;h=0c40531ad67dbe6019659b9740e64792941a4474;hb=99e6d4a3be04f173b4bcd6ec77e1d1d63a3f2153;hp=ed8833fba977a0c0dbd123c95f3795a643797941;hpb=d4fc620cb2b7b1d11184fc162e6746979a1da320;p=bacula%2Fbacula diff --git a/bacula/src/filed/job.c b/bacula/src/filed/job.c index ed8833fba9..0c40531ad6 100644 --- a/bacula/src/filed/job.c +++ b/bacula/src/filed/job.c @@ -7,7 +7,7 @@ * */ /* - Copyright (C) 2000-2004 Kern Sibbald and John Walker + Copyright (C) 2000-2005 Kern Sibbald This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as @@ -31,10 +31,11 @@ extern char my_name[]; extern CLIENT *me; /* our client resource */ - + /* Imported functions */ extern int status_cmd(JCR *jcr); - +extern int qstatus_cmd(JCR *jcr); + /* Forward referenced functions */ static int backup_cmd(JCR *jcr); static int bootstrap_cmd(JCR *jcr); @@ -66,30 +67,32 @@ static void set_options(findFOPTS *fo, const char *opts); struct s_cmds { const char *cmd; int (*func)(JCR *); + int monitoraccess; /* specify if monitors have access to this function */ }; -/* - * The following are the recognized commands from the Director. +/* + * The following are the recognized commands from the Director. */ static struct s_cmds cmds[] = { - {"backup", backup_cmd}, - {"cancel", cancel_cmd}, - {"setdebug=", setdebug_cmd}, - {"estimate", estimate_cmd}, - {"exclude", exclude_cmd}, - {"Hello", hello_cmd}, - {"include", include_cmd}, - {"fileset", fileset_cmd}, - {"JobId=", job_cmd}, - {"level = ", level_cmd}, - {"restore", restore_cmd}, - {"session", session_cmd}, - {"status", status_cmd}, - {"storage ", storage_cmd}, - {"verify", verify_cmd}, - {"bootstrap", bootstrap_cmd}, - {"RunBeforeJob", runbefore_cmd}, - {"RunAfterJob", runafter_cmd}, + {"backup", backup_cmd, 0}, + {"cancel", cancel_cmd, 0}, + {"setdebug=", setdebug_cmd, 0}, + {"estimate", estimate_cmd, 0}, + {"exclude", exclude_cmd, 0}, + {"Hello", hello_cmd, 1}, + {"include", include_cmd, 0}, + {"fileset", fileset_cmd, 0}, + {"JobId=", job_cmd, 0}, + {"level = ", level_cmd, 0}, + {"restore", restore_cmd, 0}, + {"session", session_cmd, 0}, + {"status", status_cmd, 1}, + {".status", qstatus_cmd, 1}, + {"storage ", storage_cmd, 0}, + {"verify", verify_cmd, 0}, + {"bootstrap", bootstrap_cmd, 0}, + {"RunBeforeJob", runbefore_cmd, 0}, + {"RunAfterJob", runafter_cmd, 0}, {NULL, NULL} /* list terminator */ }; @@ -107,6 +110,7 @@ static char runafter[] = "RunAfterJob %s\n"; /* Responses sent to Director */ static char errmsg[] = "2999 Invalid command\n"; static char no_auth[] = "2998 No Authorization\n"; +static char illegal_cmd[] = "2997 Illegal command for a Director with Monitor directive enabled\n"; static char OKinc[] = "2000 OK include\n"; static char OKest[] = "2000 OK estimate files=%u bytes=%s\n"; static char OKexc[] = "2000 OK exclude\n"; @@ -142,7 +146,7 @@ static char read_open[] = "read open session = %s %ld %ld %ld %ld %ld %ld\n"; static char read_data[] = "read data %d\n"; static char read_close[] = "read close session %d\n"; -/* +/* * Accept requests from a Director * * NOTE! We are running as a separate thread @@ -161,7 +165,7 @@ static char read_close[] = "read close session %d\n"; */ void *handle_client_request(void *dirp) { - int i; + int i; bool found, quit; JCR *jcr; BSOCK *dir = (BSOCK *)dirp; @@ -173,7 +177,7 @@ void *handle_client_request(void *dirp) jcr->last_fname = get_pool_memory(PM_FNAME); jcr->last_fname[0] = 0; jcr->client_name = get_memory(strlen(my_name) + 1); - pm_strcpy(&jcr->client_name, my_name); + pm_strcpy(jcr->client_name, my_name); dir->jcr = jcr; enable_backup_privileges(NULL, 1 /* ignore_errors */); @@ -183,27 +187,34 @@ void *handle_client_request(void *dirp) /* Read command */ if (bnet_recv(dir) < 0) { - break; /* connection terminated */ + break; /* connection terminated */ } dir->msg[dir->msglen] = 0; Dmsg1(100, "msg); found = false; for (i=0; cmds[i].cmd; i++) { if (strncmp(cmds[i].cmd, dir->msg, strlen(cmds[i].cmd)) == 0) { + found = true; /* indicate command found */ if (!jcr->authenticated && cmds[i].func != hello_cmd) { bnet_fsend(dir, no_auth); + bnet_sig(dir, BNET_EOD); + break; + } + if ((jcr->authenticated) && (!cmds[i].monitoraccess) && (jcr->director->monitor)) { + Dmsg1(100, "Command %s illegal.\n", cmds[i].cmd); + bnet_fsend(dir, illegal_cmd); + bnet_sig(dir, BNET_EOD); break; } - found = true; /* indicate command found */ Dmsg1(100, "Executing %s command.\n", cmds[i].cmd); - if (!cmds[i].func(jcr)) { /* do command */ - quit = true; /* error or fully terminated, get out */ + if (!cmds[i].func(jcr)) { /* do command */ + quit = true; /* error or fully terminated, get out */ Dmsg0(20, "Quit command loop due to command error or Job done.\n"); } break; } } - if (!found) { /* command not found */ + if (!found) { /* command not found */ bnet_fsend(dir, errmsg); quit = true; break; @@ -218,6 +229,7 @@ void *handle_client_request(void *dirp) if (jcr->RunAfterJob && !job_canceled(jcr)) { run_cmd(jcr, jcr->RunAfterJob, "ClientRunAfterJob"); } + dequeue_messages(jcr); /* send any queued messages */ /* Inform Director that we are done */ bnet_sig(dir, BNET_TERMINATE); @@ -226,15 +238,29 @@ void *handle_client_request(void *dirp) FF_PKT *ff = (FF_PKT *)jcr->ff; findFILESET *fileset = ff->fileset; if (fileset) { - int i, j; + int i, j, k; /* Delete FileSet Include lists */ for (i=0; iinclude_list.size(); i++) { findINCEXE *incexe = (findINCEXE *)fileset->include_list.get(i); for (j=0; jopts_list.size(); j++) { findFOPTS *fo = (findFOPTS *)incexe->opts_list.get(j); + for (k=0; kregex.size(); k++) { + regfree((regex_t *)fo->regex.get(k)); + } fo->regex.destroy(); + fo->regexdir.destroy(); + fo->regexfile.destroy(); fo->wild.destroy(); + fo->wilddir.destroy(); + fo->wildfile.destroy(); fo->base.destroy(); + fo->fstype.destroy(); + if (fo->reader) { + free(fo->reader); + } + if (fo->writer) { + free(fo->writer); + } } incexe->opts_list.destroy(); incexe->name_list.destroy(); @@ -247,8 +273,13 @@ void *handle_client_request(void *dirp) for (j=0; jopts_list.size(); j++) { findFOPTS *fo = (findFOPTS *)incexe->opts_list.get(j); fo->regex.destroy(); + fo->regexdir.destroy(); + fo->regexfile.destroy(); fo->wild.destroy(); + fo->wilddir.destroy(); + fo->wildfile.destroy(); fo->base.destroy(); + fo->fstype.destroy(); } incexe->opts_list.destroy(); incexe->name_list.destroy(); @@ -265,7 +296,7 @@ void *handle_client_request(void *dirp) } /* - * Hello from Director he must identify himself and provide his + * Hello from Director he must identify himself and provide his * password. */ static int hello_cmd(JCR *jcr) @@ -275,7 +306,7 @@ static int hello_cmd(JCR *jcr) return 0; } Dmsg0(120, "OK Authenticate\n"); - jcr->authenticated = TRUE; + jcr->authenticated = true; return 1; } @@ -296,7 +327,7 @@ static int cancel_cmd(JCR *jcr) P(cjcr->mutex); cjcr->store_bsock->timed_out = 1; cjcr->store_bsock->terminated = 1; -/* +/* * #if !defined(HAVE_CYGWIN) && !defined(HAVE_WIN32) */ #if !defined(HAVE_CYGWIN) @@ -327,9 +358,9 @@ static int setdebug_cmd(JCR *jcr) Dmsg1(110, "setdebug_cmd: %s", dir->msg); if (sscanf(dir->msg, "setdebug=%d trace=%d", &level, &trace_flag) != 2 || level < 0) { - pm_strcpy(&jcr->errmsg, dir->msg); + pm_strcpy(jcr->errmsg, dir->msg); bnet_fsend(dir, "2991 Bad setdebug command: %s\n", jcr->errmsg); - return 0; + return 0; } debug_level = level; set_trace(trace_flag); @@ -343,13 +374,13 @@ static int estimate_cmd(JCR *jcr) char ed2[50]; if (sscanf(dir->msg, estimatecmd, &jcr->listing) != 1) { - pm_strcpy(&jcr->errmsg, dir->msg); + pm_strcpy(jcr->errmsg, dir->msg); Jmsg(jcr, M_FATAL, 0, _("Bad estimate command: %s"), jcr->errmsg); bnet_fsend(dir, "2992 Bad estimate command.\n"); return 0; } make_estimate(jcr); - bnet_fsend(dir, OKest, jcr->num_files_examined, + bnet_fsend(dir, OKest, jcr->num_files_examined, edit_uint64_with_commas(jcr->JobBytes, ed2)); bnet_sig(dir, BNET_EOD); return 1; @@ -364,10 +395,10 @@ static int job_cmd(JCR *jcr) POOLMEM *sd_auth_key; sd_auth_key = get_memory(dir->msglen); - if (sscanf(dir->msg, jobcmd, &jcr->JobId, jcr->Job, + if (sscanf(dir->msg, jobcmd, &jcr->JobId, jcr->Job, &jcr->VolSessionId, &jcr->VolSessionTime, sd_auth_key) != 5) { - pm_strcpy(&jcr->errmsg, dir->msg); + pm_strcpy(jcr->errmsg, dir->msg); Jmsg(jcr, M_FATAL, 0, _("Bad Job Command: %s"), jcr->errmsg); bnet_fsend(dir, BADjob); free_pool_memory(sd_auth_key); @@ -387,7 +418,7 @@ static int runbefore_cmd(JCR *jcr) Dmsg1(100, "runbefore_cmd: %s", dir->msg); if (sscanf(dir->msg, runbefore, cmd) != 1) { - pm_strcpy(&jcr->errmsg, dir->msg); + pm_strcpy(jcr->errmsg, dir->msg); Jmsg1(jcr, M_FATAL, 0, _("Bad RunBeforeJob command: %s\n"), jcr->errmsg); bnet_fsend(dir, "2905 Bad RunBeforeJob command.\n"); free_memory(cmd); @@ -414,7 +445,7 @@ static int runafter_cmd(JCR *jcr) Dmsg1(100, "runafter_cmd: %s", dir->msg); if (sscanf(dir->msg, runafter, msg) != 1) { - pm_strcpy(&jcr->errmsg, dir->msg); + pm_strcpy(jcr->errmsg, dir->msg); Jmsg1(jcr, M_FATAL, 0, _("Bad RunAfter command: %s\n"), jcr->errmsg); bnet_fsend(dir, "2905 Bad RunAfterJob command.\n"); free_memory(msg); @@ -425,7 +456,7 @@ static int runafter_cmd(JCR *jcr) free_pool_memory(jcr->RunAfterJob); } jcr->RunAfterJob = get_pool_memory(PM_FNAME); - pm_strcpy(&jcr->RunAfterJob, msg); + pm_strcpy(jcr->RunAfterJob, msg); free_pool_memory(msg); return bnet_fsend(dir, OKRunAfter); } @@ -436,23 +467,28 @@ static int run_cmd(JCR *jcr, char *cmd, const char *name) int status; BPIPE *bpipe; char line[MAXSTRING]; - + ecmd = edit_job_codes(jcr, ecmd, cmd, ""); bpipe = open_bpipe(ecmd, 0, "r"); free_pool_memory(ecmd); if (bpipe == NULL) { - Jmsg(jcr, M_FATAL, 0, _("%s could not execute\n"), name); - set_jcr_job_status(jcr, JS_FatalError); + berrno be; + Jmsg(jcr, M_FATAL, 0, _("%s could not execute. ERR=%s\n"), name, + be.strerror()); return 0; } while (fgets(line, sizeof(line), bpipe->rfd)) { + int len = strlen(line); + if (len > 0 && line[len-1] != '\n') { + bstrncat(line, "\n", sizeof(line)); + } Jmsg(jcr, M_INFO, 0, _("%s: %s"), name, line); } status = close_bpipe(bpipe); if (status != 0) { - Jmsg(jcr, M_FATAL, 0, _("%s returned non-zero status=%d\n"), name, - status); - set_jcr_job_status(jcr, JS_FatalError); + berrno be; + Jmsg(jcr, M_FATAL, 0, _("%s returned non-zero status=%d. ERR=%s\n"), name, + status, be.strerror(status)); return 0; } return 1; @@ -520,8 +556,9 @@ static void add_fname_to_list(JCR *jcr, char *fname, int list) case '<': p++; /* skip over < */ if ((ffd = fopen(p, "r")) == NULL) { + berrno be; Jmsg(jcr, M_FATAL, 0, _("Cannot open %s file: %s. ERR=%s\n"), - list==INC_LIST?"included":"excluded", p, strerror(errno)); + list==INC_LIST?"included":"excluded", p, be.strerror()); return; } /* Copy File options */ @@ -553,8 +590,8 @@ static void add_fname_to_list(JCR *jcr, char *fname, int list) } } -/* - * +/* + * * Get list of files/directories to include from Director * */ @@ -572,12 +609,12 @@ static int include_cmd(JCR *jcr) return bnet_fsend(dir, OKinc); } -static bool init_fileset(JCR *jcr) +static bool init_fileset(JCR *jcr) { FF_PKT *ff; findFILESET *fileset; - if (!jcr->ff) { + if (!jcr->ff) { return false; } ff = (FF_PKT *)jcr->ff; @@ -603,8 +640,13 @@ static findFOPTS *start_options(FF_PKT *ff) findFOPTS *fo = (findFOPTS *)malloc(sizeof(findFOPTS)); memset(fo, 0, sizeof(findFOPTS)); fo->regex.init(1, true); + fo->regexdir.init(1, true); + fo->regexfile.init(1, true); fo->wild.init(1, true); + fo->wilddir.init(1, true); + fo->wildfile.init(1, true); fo->base.init(1, true); + fo->fstype.init(1, true); incexe->current_opts = fo; incexe->opts_list.append(fo); } @@ -651,8 +693,9 @@ static void add_file_to_fileset(JCR *jcr, const char *fname, findFILESET *filese case '<': p++; /* skip over < */ if ((ffd = fopen(p, "r")) == NULL) { + berrno be; Jmsg(jcr, M_FATAL, 0, _("Cannot open FileSet input file: %s. ERR=%s\n"), - p, strerror(errno)); + p, be.strerror()); return; } while (fgets(buf, sizeof(buf), ffd)) { @@ -667,7 +710,7 @@ static void add_file_to_fileset(JCR *jcr, const char *fname, findFILESET *filese } } - + static void add_fileset(JCR *jcr, const char *item) { FF_PKT *ff = (FF_PKT *)jcr->ff; @@ -675,15 +718,35 @@ static void add_fileset(JCR *jcr, const char *item) int state = fileset->state; findFOPTS *current_opts; + /* Get code, optional subcode, and position item past the dividing space */ Dmsg1(100, "%s\n", item); int code = item[0]; - if (item[1] == ' ') { /* If string follows */ - item += 2; /* point to string */ + if (code != '\0') { + ++item; + } + int subcode = ' '; /* A space is always a valid subcode */ + if (item[0] != '\0' && item[0] != ' ') { + subcode = item[0]; + ++item; + } + if (*item == ' ') { + ++item; } + /* Skip all lines we receive after an error */ if (state == state_error) { return; } + + /* + * The switch tests the code for validity. + * The subcode is always good if it is a space, otherwise we must confirm. + * We set state to state_error first assuming the subcode is invalid, + * requiring state to be set in cases below that handle subcodes. + */ + if (subcode != ' ') { + state = state_error; + } switch (code) { case 'I': /* New include */ @@ -711,24 +774,72 @@ static void add_fileset(JCR *jcr, const char *item) break; case 'R': current_opts = start_options(ff); - current_opts->regex.append(bstrdup(item)); + regex_t *preg; + int rc; + char prbuf[500]; + preg = (regex_t *)malloc(sizeof(regex_t)); + if (current_opts->flags & FO_IGNORECASE) { + rc = regcomp(preg, item, REG_EXTENDED|REG_ICASE); + } else { + rc = regcomp(preg, item, REG_EXTENDED); + } + if (rc != 0) { + regerror(rc, preg, prbuf, sizeof(prbuf)); + regfree(preg); + free(preg); + Jmsg(jcr, M_FATAL, 0, "REGEX %s compile error. ERR=%s\n", item, prbuf); + state = state_error; + break; + } state = state_options; + if (subcode == ' ') { + current_opts->regex.append(preg); + } else if (subcode == 'D') { + current_opts->regexdir.append(preg); + } else if (subcode == 'F') { + current_opts->regexfile.append(preg); + } else { + state = state_error; + } break; case 'B': current_opts = start_options(ff); current_opts->base.append(bstrdup(item)); state = state_options; break; + case 'X': + current_opts = start_options(ff); + current_opts->fstype.append(bstrdup(item)); + state = state_options; + break; case 'W': current_opts = start_options(ff); - current_opts->wild.append(bstrdup(item)); state = state_options; + if (subcode == ' ') { + current_opts->wild.append(bstrdup(item)); + } else if (subcode == 'D') { + current_opts->wilddir.append(bstrdup(item)); + } else if (subcode == 'F') { + current_opts->wildfile.append(bstrdup(item)); + } else { + state = state_error; + } break; - case 'O': + case 'O': current_opts = start_options(ff); set_options(current_opts, item); state = state_options; break; + case 'D': + current_opts = start_options(ff); + current_opts->reader = bstrdup(item); + state = state_options; + break; + case 'T': + current_opts = start_options(ff); + current_opts->writer = bstrdup(item); + state = state_options; + break; default: Jmsg(jcr, M_FATAL, 0, "Invalid FileSet command: %s\n", item); state = state_error; @@ -751,12 +862,33 @@ static bool term_fileset(JCR *jcr) for (k=0; kregex.size(); k++) { Dmsg1(400, "R %s\n", (char *)fo->regex.get(k)); } + for (k=0; kregexdir.size(); k++) { + Dmsg1(400, "RD %s\n", (char *)fo->regexdir.get(k)); + } + for (k=0; kregexfile.size(); k++) { + Dmsg1(400, "RF %s\n", (char *)fo->regexfile.get(k)); + } for (k=0; kwild.size(); k++) { Dmsg1(400, "W %s\n", (char *)fo->wild.get(k)); } + for (k=0; kwilddir.size(); k++) { + Dmsg1(400, "WD %s\n", (char *)fo->wilddir.get(k)); + } + for (k=0; kwildfile.size(); k++) { + Dmsg1(400, "WF %s\n", (char *)fo->wildfile.get(k)); + } for (k=0; kbase.size(); k++) { Dmsg1(400, "B %s\n", (char *)fo->base.get(k)); } + for (k=0; kfstype.size(); k++) { + Dmsg1(400, "X %s\n", (char *)fo->fstype.get(k)); + } + if (fo->reader) { + Dmsg1(400, "D %s\n", fo->reader); + } + if (fo->writer) { + Dmsg1(400, "T %s\n", fo->writer); + } } for (j=0; jname_list.size(); j++) { Dmsg1(400, "F %s\n", (char *)incexe->name_list.get(j)); @@ -770,12 +902,27 @@ static bool term_fileset(JCR *jcr) for (k=0; kregex.size(); k++) { Dmsg1(400, "R %s\n", (char *)fo->regex.get(k)); } + for (k=0; kregexdir.size(); k++) { + Dmsg1(400, "RD %s\n", (char *)fo->regexdir.get(k)); + } + for (k=0; kregexfile.size(); k++) { + Dmsg1(400, "RF %s\n", (char *)fo->regexfile.get(k)); + } for (k=0; kwild.size(); k++) { Dmsg1(400, "W %s\n", (char *)fo->wild.get(k)); } + for (k=0; kwilddir.size(); k++) { + Dmsg1(400, "WD %s\n", (char *)fo->wilddir.get(k)); + } + for (k=0; kwildfile.size(); k++) { + Dmsg1(400, "WF %s\n", (char *)fo->wildfile.get(k)); + } for (k=0; kbase.size(); k++) { Dmsg1(400, "B %s\n", (char *)fo->base.get(k)); } + for (k=0; kfstype.size(); k++) { + Dmsg1(400, "X %s\n", (char *)fo->fstype.get(k)); + } } for (j=0; jname_list.size(); j++) { Dmsg1(400, "F %s\n", (char *)incexe->name_list.get(j)); @@ -809,6 +956,12 @@ static void set_options(findFOPTS *fo, const char *opts) case 'h': /* no recursion */ fo->flags |= FO_NO_RECURSION; break; + case 'H': /* no hard link handling */ + fo->flags |= FO_NO_HARDLINK; + break; + case 'i': + fo->flags |= FO_IGNORECASE; + break; case 'M': /* MD5 */ fo->flags |= FO_MD5; break; @@ -818,6 +971,8 @@ static void set_options(findFOPTS *fo, const char *opts) case 'p': /* use portable data format */ fo->flags |= FO_PORTABLE; break; + case 'R': /* Resource forks and Finder Info */ + fo->flags |= FO_HFSPLUS; case 'r': /* read fifo */ fo->flags |= FO_READFIFO; break; @@ -833,6 +988,9 @@ static void set_options(findFOPTS *fo, const char *opts) case 'k': fo->flags |= FO_KEEPATIME; break; + case 'A': + fo->flags |= FO_ACL; + break; case 'V': /* verify options */ /* Copy Verify Options */ for (j=0; *p && *p != ':'; p++) { @@ -856,11 +1014,11 @@ static void set_options(findFOPTS *fo, const char *opts) break; } } -} +} /* - * Director is passing his Fileset + * Director is passing his Fileset */ static int fileset_cmd(JCR *jcr) { @@ -910,13 +1068,14 @@ static int bootstrap_cmd(JCR *jcr) unlink(jcr->RestoreBootstrap); free_pool_memory(jcr->RestoreBootstrap); } - Mmsg(&fname, "%s/%s.%s.bootstrap", me->working_directory, me->hdr.name, + Mmsg(fname, "%s/%s.%s.bootstrap", me->working_directory, me->hdr.name, jcr->Job); Dmsg1(400, "bootstrap=%s\n", fname); jcr->RestoreBootstrap = fname; bs = fopen(fname, "a+"); /* create file */ if (!bs) { - /* + berrno be; + /* * Suck up what he is sending to us so that he will then * read our error message. */ @@ -924,7 +1083,7 @@ static int bootstrap_cmd(JCR *jcr) { } Jmsg(jcr, M_FATAL, 0, _("Could not create bootstrap file %s: ERR=%s\n"), - jcr->RestoreBootstrap, strerror(errno)); + jcr->RestoreBootstrap, be.strerror()); free_pool_memory(jcr->RestoreBootstrap); jcr->RestoreBootstrap = NULL; set_jcr_job_status(jcr, JS_ErrorTerminated); @@ -961,24 +1120,24 @@ static int level_cmd(JCR *jcr) /* Base backup requested? */ if (strcmp(level, "base") == 0) { jcr->JobLevel = L_BASE; - /* Full backup requested? */ + /* Full backup requested? */ } else if (strcmp(level, "full") == 0) { jcr->JobLevel = L_FULL; - /* + /* * Backup requested since