From da61bf70012fc16847cbcd29b1c65ca8116b23c3 Mon Sep 17 00:00:00 2001 From: Kern Sibbald Date: Thu, 26 Apr 2007 19:40:25 +0000 Subject: [PATCH] First cut implementing backup and restore client. git-svn-id: https://bacula.svn.sourceforge.net/svnroot/bacula/trunk@4638 91ce42f0-d328-0410-95d8-f526ca767f89 --- bacula/src/dird/ua.h | 3 +- bacula/src/dird/ua_restore.c | 50 ++++++-- bacula/src/dird/ua_run.c | 232 +++++++++++++++++++++-------------- bacula/technotes-2.1 | 1 + 4 files changed, 184 insertions(+), 102 deletions(-) diff --git a/bacula/src/dird/ua.h b/bacula/src/dird/ua.h index 476bebc971..9cef36b8a1 100644 --- a/bacula/src/dird/ua.h +++ b/bacula/src/dird/ua.h @@ -101,7 +101,8 @@ struct RESTORE_CTX { utime_t JobTDate; uint32_t TotalFiles; JobId_t JobId; - char ClientName[MAX_NAME_LENGTH]; + char ClientName[MAX_NAME_LENGTH]; /* backup client */ + char RestoreClientName[MAX_NAME_LENGTH]; /* restore client */ char last_jobid[20]; POOLMEM *JobIds; /* User entered string of JobIds */ STORE *store; diff --git a/bacula/src/dird/ua_restore.c b/bacula/src/dird/ua_restore.c index 79d2466d18..e39db95151 100644 --- a/bacula/src/dird/ua_restore.c +++ b/bacula/src/dird/ua_restore.c @@ -66,6 +66,7 @@ static bool insert_dir_into_findex_list(UAContext *ua, RESTORE_CTX *rx, char *di char *date); static void insert_one_file_or_dir(UAContext *ua, RESTORE_CTX *rx, char *date, bool dir); static int get_client_name(UAContext *ua, RESTORE_CTX *rx); +static int get_restore_client_name(UAContext *ua, RESTORE_CTX &rx); static int get_date(UAContext *ua, char *date, int date_len); static int restore_count_handler(void *ctx, int num_fields, char **row); static bool insert_table_into_findex_list(UAContext *ua, RESTORE_CTX *rx, char *table); @@ -223,6 +224,7 @@ int restore_cmd(UAContext *ua, const char *cmd) ua->error_msg(_("No Client resource found!\n")); goto bail_out; } + get_restore_client_name(ua, rx); escaped_bsr_name = escape_filename(jcr->RestoreBootstrap); @@ -230,9 +232,10 @@ int restore_cmd(UAContext *ua, const char *cmd) if (rx.RegexWhere) { escaped_where_name = escape_filename(rx.RegexWhere); Mmsg(ua->cmd, - "run job=\"%s\" client=\"%s\" storage=\"%s\" bootstrap=\"%s\"" - " regexwhere=\"%s\" files=%d catalog=\"%s\"", - job->name(), rx.ClientName, rx.store?rx.store->name():"", + "run job=\"%s\" client=\"%s\" restoreclient=\"%s\" storage=\"%s\"" + " bootstrap=\"%s\" regexwhere=\"%s\" files=%d catalog=\"%s\"", + job->name(), rx.ClientName, rx.RestoreClientName, + rx.store?rx.store->name():"", escaped_bsr_name ? escaped_bsr_name : jcr->RestoreBootstrap, escaped_where_name ? escaped_where_name : rx.RegexWhere, rx.selected_files, ua->catalog->name()); @@ -240,18 +243,20 @@ int restore_cmd(UAContext *ua, const char *cmd) } else if (rx.where) { escaped_where_name = escape_filename(rx.where); Mmsg(ua->cmd, - "run job=\"%s\" client=\"%s\" storage=\"%s\" bootstrap=\"%s\"" - " where=\"%s\" files=%d catalog=\"%s\"", - job->name(), rx.ClientName, rx.store?rx.store->name():"", + "run job=\"%s\" client=\"%s\" restoreclient=\"%s\" storage=\"%s\"" + " bootstrap=\"%s\" where=\"%s\" files=%d catalog=\"%s\"", + job->name(), rx.ClientName, rx.RestoreClientName, + rx.store?rx.store->name():"", escaped_bsr_name ? escaped_bsr_name : jcr->RestoreBootstrap, escaped_where_name ? escaped_where_name : rx.where, rx.selected_files, ua->catalog->name()); } else { Mmsg(ua->cmd, - "run job=\"%s\" client=\"%s\" storage=\"%s\" bootstrap=\"%s\"" - " files=%d catalog=\"%s\"", - job->name(), rx.ClientName, rx.store?rx.store->name():"", + "run job=\"%s\" client=\"%s\" restoreclient=\"%s\" storage=\"%s\"" + " bootstrap=\"%s\" files=%d catalog=\"%s\"", + job->name(), rx.ClientName, rx.RestoreClientName, + rx.store?rx.store->name():"", escaped_bsr_name ? escaped_bsr_name : jcr->RestoreBootstrap, rx.selected_files, ua->catalog->name()); } @@ -327,6 +332,9 @@ static bool has_value(UAContext *ua, int i) return true; } +/* + * This gets the client name from which the backup was made + */ static int get_client_name(UAContext *ua, RESTORE_CTX *rx) { /* If no client name specified yet, get it now */ @@ -334,6 +342,9 @@ static int get_client_name(UAContext *ua, RESTORE_CTX *rx) CLIENT_DBR cr; /* try command line argument */ int i = find_arg_with_value(ua, NT_("client")); + if (i < 0) { + i = find_arg_with_value(ua, NT_("backupclient")); + } if (i >= 0) { if (!has_value(ua, i)) { return 0; @@ -350,6 +361,27 @@ static int get_client_name(UAContext *ua, RESTORE_CTX *rx) return 1; } +/* + * This is where we pick up a client name to restore to. + */ +static int get_restore_client_name(UAContext *ua, RESTORE_CTX &rx) +{ + /* Start with same name as backup client */ + bstrncpy(rx.RestoreClientName, rx.ClientName, sizeof(rx.RestoreClientName)); + + /* try command line argument */ + int i = find_arg_with_value(ua, NT_("restoreclient")); + if (i >= 0) { + if (!has_value(ua, i)) { + return 0; + } + bstrncpy(rx.RestoreClientName, ua->argv[i], sizeof(rx.RestoreClientName)); + return 1; + } + return 1; +} + + /* * The first step in the restore process is for the user to diff --git a/bacula/src/dird/ua_run.c b/bacula/src/dird/ua_run.c index 2171f4afe0..c5603dd3f8 100644 --- a/bacula/src/dird/ua_run.c +++ b/bacula/src/dird/ua_run.c @@ -1,11 +1,3 @@ -/* - * - * Bacula Director -- Run Command - * - * Kern Sibbald, December MMI - * - * Version $Id$ - */ /* Bacula® - The Network Backup Solution @@ -33,14 +25,23 @@ (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich, Switzerland, email:ftf@fsfeurope.org. */ +/* + * + * Bacula Director -- Run Command + * + * Kern Sibbald, December MMI + * + * Version $Id$ + */ #include "bacula.h" #include "dird.h" /* Forward referenced subroutines */ static void select_job_level(UAContext *ua, JCR *jcr); -static bool display_job_parameters(UAContext *ua, JCR *jcr, JOB *job, char *verify_list, - char *jid, const char *replace); +static bool display_job_parameters(UAContext *ua, JCR *jcr, JOB *job, + char *verify_list, char *jid, const char *replace, + char *client_name); static void select_where_regexp(UAContext *ua, JCR *jcr); @@ -63,6 +64,7 @@ int run_cmd(UAContext *ua, const char *cmd) JCR *jcr; char *job_name, *level_name, *jid, *store_name, *pool_name; char *where, *fileset_name, *client_name, *bootstrap, *regexwhere; + char *restore_client_name; const char *replace; char *when, *verify_job_name, *catalog_name; char *previous_job_name; @@ -103,6 +105,8 @@ int run_cmd(UAContext *ua, const char *cmd) "verifylist", /* 20 verify output list */ "migrationjob", /* 21 migration job name */ "pool", /* 22 */ + "backupclient", /* 23 */ + "restoreclient", /* 24 */ NULL}; #define YES_POS 14 @@ -120,6 +124,7 @@ int run_cmd(UAContext *ua, const char *cmd) regexwhere = NULL; when = NULL; client_name = NULL; + restore_client_name = NULL; fileset_name = NULL; bootstrap = NULL; replace = NULL; @@ -196,7 +201,7 @@ int run_cmd(UAContext *ua, const char *cmd) ua->send_msg(_("RegexWhere or Where specified twice.\n")); return 0; } - regexwhere = ua->argv[i]; + regexwhere = ua->argv[i]; if (!acl_access_ok(ua, Where_ACL, regexwhere)) { ua->send_msg(_("Forbidden \"regexwhere\" specified.\n")); return 0; @@ -302,7 +307,22 @@ int run_cmd(UAContext *ua, const char *cmd) pool_name = ua->argv[i]; kw_ok = true; break; - + case 23: /* backupclient */ + if (client_name) { + ua->send_msg(_("Client specified twice.\n")); + return 0; + } + client_name = ua->argv[i]; + kw_ok = true; + break; + case 24: /* restoreclient */ + if (restore_client_name) { + ua->send_msg(_("Restore Client specified twice.\n")); + return 0; + } + restore_client_name = ua->argv[i]; + kw_ok = true; + break; default: break; } @@ -429,6 +449,27 @@ int run_cmd(UAContext *ua, const char *cmd) } Dmsg1(800, "Using client=%s\n", client->name()); + if (restore_client_name) { + client = (CLIENT *)GetResWithName(R_CLIENT, restore_client_name); + if (!client) { + if (*restore_client_name != 0) { + ua->warning_msg(_("Restore Client \"%s\" not found.\n"), restore_client_name); + } + client = select_client_resource(ua); + } + } else { + client = job->client; /* use default */ + } + if (!client) { + return 0; + } else if (!acl_access_ok(ua, Client_ACL, client->name())) { + ua->error_msg(_("No authorization. Client \"%s\".\n"), + client->name()); + return 0; + } + Dmsg1(800, "Using restore client=%s\n", client->name()); + + if (fileset_name) { fileset = (FILESET *)GetResWithName(R_FILESET, fileset_name); if (!fileset) { @@ -498,7 +539,7 @@ int run_cmd(UAContext *ua, const char *cmd) if (jcr->RegexWhere) { free(jcr->RegexWhere); } - jcr->RegexWhere = bstrdup(regexwhere); + jcr->RegexWhere = bstrdup(regexwhere); } if (when) { @@ -584,7 +625,8 @@ try_again: * Prompt User to see if all run job parameters are correct, and * allow him to modify them. */ - if (!display_job_parameters(ua, jcr, job, verify_list, jid, replace)) { + if (!display_job_parameters(ua, jcr, job, verify_list, jid, replace, + client_name)) { goto bail_out; } @@ -603,7 +645,11 @@ try_again: add_prompt(ua, _("Storage")); /* 1 */ add_prompt(ua, _("Job")); /* 2 */ add_prompt(ua, _("FileSet")); /* 3 */ - add_prompt(ua, _("Client")); /* 4 */ + if (jcr->JobType == JT_RESTORE) { + add_prompt(ua, _("Restore Client")); /* 4 */ + } else { + add_prompt(ua, _("Client")); /* 4 */ + } add_prompt(ua, _("When")); /* 5 */ add_prompt(ua, _("Priority")); /* 6 */ if (jcr->JobType == JT_BACKUP || @@ -616,7 +662,7 @@ try_again: } else if (jcr->JobType == JT_RESTORE) { add_prompt(ua, _("Bootstrap")); /* 7 */ add_prompt(ua, _("Where")); /* 8 */ - add_prompt(ua, _("File Relocation"));/* 9 */ + add_prompt(ua, _("File Relocation"));/* 9 */ add_prompt(ua, _("Replace")); /* 10 */ add_prompt(ua, _("JobId")); /* 11 */ } @@ -733,10 +779,10 @@ try_again: if (!get_cmd(ua, _("Please enter path prefix for restore (/ for none): "))) { break; } - if (jcr->RegexWhere) { /* cannot use regexwhere and where */ - free(jcr->RegexWhere); - jcr->RegexWhere = NULL; - } + if (jcr->RegexWhere) { /* cannot use regexwhere and where */ + free(jcr->RegexWhere); + jcr->RegexWhere = NULL; + } if (jcr->where) { free(jcr->where); jcr->where = NULL; @@ -747,9 +793,9 @@ try_again: jcr->where = bstrdup(ua->cmd); goto try_again; case 9: - /* File relocation */ - select_where_regexp(ua, jcr); - goto try_again; + /* File relocation */ + select_where_regexp(ua, jcr); + goto try_again; case 10: /* Replace */ start_prompt(ua, _("Replace:\n")); @@ -813,7 +859,7 @@ static void select_where_regexp(UAContext *ua, JCR *jcr) try_again_reg: ua->send_msg(_("strip_prefix=%s add_prefix=%s add_suffix=%s\n"), - NPRT(strip_prefix), NPRT(add_prefix), NPRT(add_suffix)); + NPRT(strip_prefix), NPRT(add_prefix), NPRT(add_suffix)); start_prompt(ua, _("This will replace your current Where value\n")); add_prompt(ua, _("Strip prefix")); /* 0 */ @@ -827,34 +873,34 @@ try_again_reg: case 0: /* Strip prefix */ if (get_cmd(ua, _("Please enter path prefix to strip: "))) { - if (strip_prefix) bfree(strip_prefix); - strip_prefix = bstrdup(ua->cmd); + if (strip_prefix) bfree(strip_prefix); + strip_prefix = bstrdup(ua->cmd); } goto try_again_reg; case 1: /* Add prefix */ if (get_cmd(ua, _("Please enter path prefix to add (/ for none): "))) { - if (IsPathSeparator(ua->cmd[0]) && ua->cmd[1] == '\0') { - ua->cmd[0] = 0; - } + if (IsPathSeparator(ua->cmd[0]) && ua->cmd[1] == '\0') { + ua->cmd[0] = 0; + } - if (add_prefix) bfree(add_prefix); - add_prefix = bstrdup(ua->cmd); + if (add_prefix) bfree(add_prefix); + add_prefix = bstrdup(ua->cmd); } goto try_again_reg; case 2: /* Add suffix */ if (get_cmd(ua, _("Please enter file suffix to add: "))) { - if (add_suffix) bfree(add_suffix); - add_suffix = bstrdup(ua->cmd); + if (add_suffix) bfree(add_suffix); + add_suffix = bstrdup(ua->cmd); } goto try_again_reg; case 3: /* Add rwhere */ if (get_cmd(ua, _("Please enter a valid regexp (!from!to!): "))) { - if (rwhere) bfree(rwhere); - rwhere = bstrdup(ua->cmd); + if (rwhere) bfree(rwhere); + rwhere = bstrdup(ua->cmd); } goto try_again_reg; @@ -864,27 +910,27 @@ try_again_reg: char *regexp; if (rwhere && rwhere[0] != '\0') { - regs = get_bregexps(rwhere); - ua->send_msg(_("regexwhere=%s\n"), NPRT(rwhere)); + regs = get_bregexps(rwhere); + ua->send_msg(_("regexwhere=%s\n"), NPRT(rwhere)); } else { - int len = bregexp_get_build_where_size(strip_prefix, add_prefix, add_suffix); - regexp = (char *) bmalloc (len * sizeof(char)); - bregexp_build_where(regexp, len, strip_prefix, add_prefix, add_suffix); - regs = get_bregexps(regexp); - ua->send_msg(_("strip_prefix=%s add_prefix=%s add_suffix=%s result=%s\n"), - NPRT(strip_prefix), NPRT(add_prefix), NPRT(add_suffix), NPRT(regexp)); - - bfree(regexp); + int len = bregexp_get_build_where_size(strip_prefix, add_prefix, add_suffix); + regexp = (char *) bmalloc (len * sizeof(char)); + bregexp_build_where(regexp, len, strip_prefix, add_prefix, add_suffix); + regs = get_bregexps(regexp); + ua->send_msg(_("strip_prefix=%s add_prefix=%s add_suffix=%s result=%s\n"), + NPRT(strip_prefix), NPRT(add_prefix), NPRT(add_suffix), NPRT(regexp)); + + bfree(regexp); } if (!regs) { - ua->send_msg(_("Cannot use your regexp\n")); - goto try_again_reg; + ua->send_msg(_("Cannot use your regexp\n")); + goto try_again_reg; } while (get_cmd(ua, _("Please enter filename to test: "))) { - apply_bregexps(ua->cmd, regs, &result); - ua->send_msg(_("%s -> %s\n"), ua->cmd, result); + apply_bregexps(ua->cmd, regs, &result); + ua->send_msg(_("%s -> %s\n"), ua->cmd, result); } free_bregexps(regs); delete regs; @@ -925,8 +971,8 @@ try_again_reg: delete regs; } else { if (jcr->RegexWhere) { - bfree(jcr->RegexWhere); - jcr->RegexWhere = NULL; + bfree(jcr->RegexWhere); + jcr->RegexWhere = NULL; } ua->send_msg(_("Cannot use your regexp.\n")); } @@ -999,7 +1045,7 @@ static void select_job_level(UAContext *ua, JCR *jcr) } static bool display_job_parameters(UAContext *ua, JCR *jcr, JOB *job, char *verify_list, - char *jid, const char *replace) + char *jid, const char *replace, char *client_name) { Dmsg1(800, "JobType=%c\n", jcr->JobType); switch (jcr->JobType) { @@ -1101,27 +1147,29 @@ static bool display_job_parameters(UAContext *ua, JCR *jcr, JOB *job, char *veri ua->send_msg(_("Run Restore job\n" "JobName: %s\n" "Bootstrap: %s\n"), - job->name(), - NPRT(jcr->RestoreBootstrap)); - - /* RegexWhere is take before RestoreWhere */ - if (jcr->RegexWhere || (job->RegexWhere && !jcr->where)) { - ua->send_msg(_("RegexWhere: %s\n"), - jcr->RegexWhere?jcr->RegexWhere:job->RegexWhere); - } else { - ua->send_msg(_("Where: %s\n"), - jcr->where?jcr->where:NPRT(job->RestoreWhere)); - } - - ua->send_msg(_("Replace: %s\n" - "FileSet: %s\n" - "Client: %s\n" - "Storage: %s\n" - "When: %s\n" - "Catalog: %s\n" - "Priority: %d\n"), + job->name(), + NPRT(jcr->RestoreBootstrap)); + + /* RegexWhere is take before RestoreWhere */ + if (jcr->RegexWhere || (job->RegexWhere && !jcr->where)) { + ua->send_msg(_("RegexWhere: %s\n"), + jcr->RegexWhere?jcr->RegexWhere:job->RegexWhere); + } else { + ua->send_msg(_("Where: %s\n"), + jcr->where?jcr->where:NPRT(job->RestoreWhere)); + } + + ua->send_msg(_("Replace: %s\n" + "FileSet: %s\n" + "Backup Client: %s\n" + "Restore Client: %s\n" + "Storage: %s\n" + "When: %s\n" + "Catalog: %s\n" + "Priority: %d\n"), replace, jcr->fileset->name(), + client_name, jcr->client->name(), jcr->rstore->name(), bstrutime(dt, sizeof(dt), jcr->sched_time), @@ -1130,27 +1178,27 @@ static bool display_job_parameters(UAContext *ua, JCR *jcr, JOB *job, char *veri } else { if (ua->api) ua->signal(BNET_RUN_CMD); ua->send_msg(_("Run Restore job\n" - "JobName: %s\n" - "Bootstrap: %s\n"), - job->name(), - NPRT(jcr->RestoreBootstrap)); - - /* RegexWhere is take before RestoreWhere */ - if (jcr->RegexWhere || (job->RegexWhere && !jcr->where)) { - ua->send_msg(_("RegexWhere: %s\n"), - jcr->RegexWhere?jcr->RegexWhere:job->RegexWhere); - } else { - ua->send_msg(_("Where: %s\n"), - jcr->where?jcr->where:NPRT(job->RestoreWhere)); - } - - ua->send_msg(_("Replace: %s\n" - "Client: %s\n" - "Storage: %s\n" - "JobId: %s\n" - "When: %s\n" - "Catalog: %s\n" - "Priority: %d\n"), + "JobName: %s\n" + "Bootstrap: %s\n"), + job->name(), + NPRT(jcr->RestoreBootstrap)); + + /* RegexWhere is take before RestoreWhere */ + if (jcr->RegexWhere || (job->RegexWhere && !jcr->where)) { + ua->send_msg(_("RegexWhere: %s\n"), + jcr->RegexWhere?jcr->RegexWhere:job->RegexWhere); + } else { + ua->send_msg(_("Where: %s\n"), + jcr->where?jcr->where:NPRT(job->RestoreWhere)); + } + + ua->send_msg(_("Replace: %s\n" + "Client: %s\n" + "Storage: %s\n" + "JobId: %s\n" + "When: %s\n" + "Catalog: %s\n" + "Priority: %d\n"), replace, jcr->client->name(), jcr->rstore->name(), diff --git a/bacula/technotes-2.1 b/bacula/technotes-2.1 index 1c576e6b93..cf2e9ac79e 100644 --- a/bacula/technotes-2.1 +++ b/bacula/technotes-2.1 @@ -2,6 +2,7 @@ General: 25Apr07 +kes First cut implementing backup and restore client. kes Correct editing in Verify output that caused a seg fault. 25Apr07 kes Insure that bat.conf is not overwritten during installation. -- 2.39.5