From d88ee65bc32791bd9079e4403fe8cba32b4e4a01 Mon Sep 17 00:00:00 2001 From: Kern Sibbald Date: Sat, 5 Jul 2003 12:07:08 +0000 Subject: [PATCH] Constrain BSR indexes, fix bscan, add some new alist code git-svn-id: https://bacula.svn.sourceforge.net/svnroot/bacula/trunk@617 91ce42f0-d328-0410-95d8-f526ca767f89 --- bacula/ReleaseNotes | 2 + bacula/kernstodo | 5 +- bacula/src/baconfig.h | 5 +- bacula/src/bc_types.h | 7 +- bacula/src/console/console.c | 2 +- bacula/src/dird/bsr.c | 65 ++-- bacula/src/dird/catreq.c | 8 +- bacula/src/dird/dird_conf.c | 701 +++++++++++++++++------------------ bacula/src/dird/dird_conf.h | 14 +- bacula/src/dird/fd_cmds.c | 36 +- bacula/src/dird/inc_conf.c | 30 +- bacula/src/dird/restore.c | 4 +- bacula/src/dird/ua_cmds.c | 360 ++++++++++-------- bacula/src/dird/ua_input.c | 2 +- bacula/src/dird/ua_restore.c | 81 +++- bacula/src/dird/ua_run.c | 10 + bacula/src/dird/ua_select.c | 18 +- bacula/src/dird/ua_server.c | 3 +- bacula/src/filed/job.c | 10 +- bacula/src/findlib/find.h | 11 +- bacula/src/findlib/match.c | 94 ++--- bacula/src/lib/mem_pool.h | 6 + bacula/src/lib/protos.h | 226 +++++------ bacula/src/lib/scan.c | 15 +- bacula/src/stored/append.c | 6 +- bacula/src/stored/bextract.c | 1 - bacula/src/stored/block.c | 27 +- bacula/src/stored/block.h | 2 + bacula/src/stored/bscan.c | 71 +--- bacula/src/stored/label.c | 60 ++- bacula/src/stored/mount.c | 1 - bacula/src/stored/record.c | 36 +- bacula/src/version.h | 4 +- 33 files changed, 1022 insertions(+), 901 deletions(-) diff --git a/bacula/ReleaseNotes b/bacula/ReleaseNotes index 135c204260..7abe9651f8 100644 --- a/bacula/ReleaseNotes +++ b/bacula/ReleaseNotes @@ -63,6 +63,8 @@ Other Changes this Release: Items to note: !!!!! +- Recycle Oldest Volume has changed to be Purge Oldest Volume + Please change your Director's .conf file. - The default time interval is now days instead of seconds. Please check your .conf files! - For MySQL users, you must have the thread safe client libraries diff --git a/bacula/kernstodo b/bacula/kernstodo index 532387eaaf..4b560ba98b 100644 --- a/bacula/kernstodo +++ b/bacula/kernstodo @@ -18,6 +18,9 @@ Documentation to do: (any release a little bit at a time) (./create_mys... ./make_my...). - Document c:/working directory better than /working directory. - Document all the status codes JobLevel, JobType, JobStatus. +- Document update volume: jobid, current, before, all +- Document run "yes". +- Document that bscan does not work with multiple simultaneous jobs. Testing to do: (painful) @@ -33,7 +36,6 @@ Testing to do: (painful) - Figure out how to use ssh or stunnel to protect Bacula communications. For 1.31 release: -- Non-fatal errors are not correct counting attribs.c:277 - In Win portable restore the directory is not create 27-Jun-2003 16:52 tibs-fd: kernsrestore.2003-06-27_16.52.20 Error: create_file.c:175 Could not create @@ -1013,4 +1015,5 @@ Done: (see kernsdone for more) - Make Restore report an error if FD or SD term codes are not OK. - To link with mysqlclient_r may require -lssl -lcrypto - Document Heart beat code +- Non-fatal errors are not correct counting attribs.c:277 diff --git a/bacula/src/baconfig.h b/bacula/src/baconfig.h index f334453666..2ffaa3c8ec 100644 --- a/bacula/src/baconfig.h +++ b/bacula/src/baconfig.h @@ -60,10 +60,13 @@ #define _(s) gettext((s)) #define N_(s) (s) #else +#undef _ #define _(s) (s) +#undef N_ #define N_(s) (s) +#undef textdomain #define textdomain(d) -#define bindtextdomain(p, d) +/* #define bindtextdomain(p, d) */ #endif diff --git a/bacula/src/bc_types.h b/bacula/src/bc_types.h index e0916b2ece..e55b377bb2 100644 --- a/bacula/src/bc_types.h +++ b/bacula/src/bc_types.h @@ -8,7 +8,6 @@ int8_t, int16_t, int32_t, int64_t uint8_t, uint16_t, uint32_t, uint64_t - float32_t, float64_t Also, we define types such as file address lengths. @@ -43,9 +42,13 @@ typedef char POOLMEM; #define mp_chr(x) x #ifdef xxxxx #define mp_chr(x) ((char*)(x)) -struct POOLMEM { }; +struct POOLMEM { + POOLMEM() {} + operator const char*() const { return (char *)this; } +}; #endif + /* Types */ /* If sys/types.h does not supply intXX_t, supply them ourselves */ diff --git a/bacula/src/console/console.c b/bacula/src/console/console.c index a05ee37f0f..b036edc30d 100644 --- a/bacula/src/console/console.c +++ b/bacula/src/console/console.c @@ -196,7 +196,7 @@ static void read_and_process_input(FILE *input, BSOCK *UA_sock) at_prompt = FALSE; /* @ => internal command for us */ if (UA_sock->msg[0] == '@') { - parse_args(UA_sock->msg, args, &argc, argk, argv, MAX_CMD_ARGS); + parse_args(UA_sock->msg, &args, &argc, argk, argv, MAX_CMD_ARGS); if (!do_a_command(input, UA_sock)) { break; } diff --git a/bacula/src/dird/bsr.c b/bacula/src/dird/bsr.c index e8e3508be5..e2bc4e0115 100644 --- a/bacula/src/dird/bsr.c +++ b/bacula/src/dird/bsr.c @@ -34,7 +34,6 @@ #include "dird.h" /* Forward referenced functions */ -static RBSR *sort_bsr(RBSR *bsr); static void write_bsr(UAContext *ua, RBSR *bsr, FILE *fd); @@ -57,18 +56,43 @@ static void free_findex(RBSR_FINDEX *fi) } } -static void write_findex(UAContext *ua, RBSR_FINDEX *fi, FILE *fd) +/* + * Our data structures were not designed completely + * correctly, so the file indexes cover the full + * range regardless of volume. The FirstIndex and LastIndex + * passed in here are for the current volume, so when + * writing out the fi, constrain them to those values. + */ +static void write_findex(UAContext *ua, RBSR_FINDEX *fi, + int32_t FirstIndex, int32_t LastIndex, FILE *fd) { if (fi) { - if (fi->findex == fi->findex2) { - fprintf(fd, "FileIndex=%d\n", fi->findex); + int32_t findex, findex2; + findex = fi->findex < FirstIndex ? FirstIndex : fi->findex; + findex2 = fi->findex2 > LastIndex ? LastIndex : fi->findex2; + if (findex == findex2) { + fprintf(fd, "FileIndex=%d\n", findex); } else { - fprintf(fd, "FileIndex=%d-%d\n", fi->findex, fi->findex2); + fprintf(fd, "FileIndex=%d-%d\n", findex, findex2); } - write_findex(ua, fi->next, fd); + write_findex(ua, fi->next, FirstIndex, LastIndex, fd); } } +static bool is_volume_selected(RBSR_FINDEX *fi, + int32_t FirstIndex, int32_t LastIndex) +{ + if (fi) { + if ((fi->findex >= FirstIndex && fi->findex <= LastIndex) || + (fi->findex2 >= FirstIndex && fi->findex2 <= LastIndex)) { + return true; + } + return is_volume_selected(fi->next, FirstIndex, LastIndex); + } + return false; +} + + static void print_findex(UAContext *ua, RBSR_FINDEX *fi) { @@ -109,9 +133,8 @@ void free_bsr(RBSR *bsr) */ int complete_bsr(UAContext *ua, RBSR *bsr) { - JOB_DBR jr; - if (bsr) { + JOB_DBR jr; memset(&jr, 0, sizeof(jr)); jr.JobId = bsr->JobId; if (!db_get_job_record(ua->jcr, ua->db, &jr)) { @@ -151,8 +174,6 @@ int write_bsr_file(UAContext *ua, RBSR *bsr) free_pool_memory(fname); return 0; } - /* Sort the bsr chain */ - bsr = sort_bsr(bsr); /* Write them to file */ write_bsr(ua, bsr, fd); stat = !ferror(fd); @@ -179,24 +200,14 @@ int write_bsr_file(UAContext *ua, RBSR *bsr) return stat; } -/* - * First sort the bsr chain, then sort the VolParams - */ -static RBSR *sort_bsr(RBSR *bsr) -{ - if (!bsr) { - return bsr; - } - /* ****FIXME**** sort the bsr chain */ - for (RBSR *nbsr=bsr; nbsr; nbsr=nbsr->next) { - } - return bsr; -} - static void write_bsr(UAContext *ua, RBSR *bsr, FILE *fd) { if (bsr) { for (int i=0; i < bsr->VolCount; i++) { + if (!is_volume_selected(bsr->fi, bsr->VolParams[i].FirstIndex, + bsr->VolParams[i].LastIndex)) { + continue; + } fprintf(fd, "Volume=\"%s\"\n", bsr->VolParams[i].VolumeName); fprintf(fd, "VolSessionId=%u\n", bsr->VolSessionId); fprintf(fd, "VolSessionTime=%u\n", bsr->VolSessionTime); @@ -204,7 +215,11 @@ static void write_bsr(UAContext *ua, RBSR *bsr, FILE *fd) bsr->VolParams[i].EndFile); fprintf(fd, "VolBlock=%u-%u\n", bsr->VolParams[i].StartBlock, bsr->VolParams[i].EndBlock); - write_findex(ua, bsr->fi, fd); + +// Dmsg2(000, "bsr VolParam FI=%u LI=%u\n", +// bsr->VolParams[i].FirstIndex, bsr->VolParams[i].LastIndex); + write_findex(ua, bsr->fi, bsr->VolParams[i].FirstIndex, + bsr->VolParams[i].LastIndex, fd); } write_bsr(ua, bsr->next, fd); } diff --git a/bacula/src/dird/catreq.c b/bacula/src/dird/catreq.c index e2083a30ae..2ffc82b5f7 100644 --- a/bacula/src/dird/catreq.c +++ b/bacula/src/dird/catreq.c @@ -107,9 +107,9 @@ next_volume: } } - if (!ok && jcr->pool->recycle_oldest_volume) { - Dmsg1(200, "No next volume found. RecycleOldest=%d\n", - jcr->pool->recycle_oldest_volume); + if (!ok && jcr->pool->purge_oldest_volume) { + Dmsg1(200, "No next volume found. PurgeOldest=%d\n", + jcr->pool->purge_oldest_volume); /* Find oldest volume to recycle */ ok = db_find_next_volume(jcr, jcr->db, -1, &mr); Dmsg1(400, "Find oldest=%d\n", ok); @@ -118,7 +118,7 @@ next_volume: Dmsg0(400, "Try purge.\n"); /* Try to purge oldest volume */ ua = new_ua_context(jcr); - Jmsg(jcr, M_INFO, 0, _("Recycling oldest volume \"%s\"\n"), mr.VolumeName); + Jmsg(jcr, M_INFO, 0, _("Purging oldest volume \"%s\"\n"), mr.VolumeName); ok = purge_jobs_from_volume(ua, &mr); free_ua_context(ua); if (ok) { diff --git a/bacula/src/dird/dird_conf.c b/bacula/src/dird/dird_conf.c index fd34100dbb..7b8b14aece 100644 --- a/bacula/src/dird/dird_conf.c +++ b/bacula/src/dird/dird_conf.c @@ -8,14 +8,14 @@ * 1. The generic lexical scanner in lib/lex.c and lib/lex.h * * 2. The generic config scanner in lib/parse_config.c and - * lib/parse_config.h. - * These files contain the parser code, some utility - * routines, and the common store routines (name, int, - * string). + * lib/parse_config.h. + * These files contain the parser code, some utility + * routines, and the common store routines (name, int, + * string). * * 3. The daemon specific file, which contains the Resource - * definitions as well as any specific store routines - * for the resource records. + * definitions as well as any specific store routines + * for the resource records. * * Kern Sibbald, January MM * @@ -83,7 +83,7 @@ int res_all_size = sizeof(res_all); /* * Director Resource * - * name handler value code flags default_value + * name handler value code flags default_value */ static struct res_items dir_items[] = { {"name", store_name, ITEM(res_dir.hdr.name), 0, ITEM_REQUIRED, 0}, @@ -107,7 +107,7 @@ static struct res_items dir_items[] = { /* * Console Resource * - * name handler value code flags default_value + * name handler value code flags default_value */ static struct res_items con_items[] = { {"name", store_name, ITEM(res_con.hdr.name), 0, ITEM_REQUIRED, 0}, @@ -121,7 +121,7 @@ static struct res_items con_items[] = { /* * Client or File daemon resource * - * name handler value code flags default_value + * name handler value code flags default_value */ static struct res_items cli_items[] = { @@ -141,7 +141,7 @@ static struct res_items cli_items[] = { /* Storage daemon resource * - * name handler value code flags default_value + * name handler value code flags default_value */ static struct res_items store_items[] = { {"name", store_name, ITEM(res_store.hdr.name), 0, ITEM_REQUIRED, 0}, @@ -161,7 +161,7 @@ static struct res_items store_items[] = { /* * Catalog Resource Directives * - * name handler value code flags default_value + * name handler value code flags default_value */ static struct res_items cat_items[] = { {"name", store_name, ITEM(res_cat.hdr.name), 0, ITEM_REQUIRED, 0}, @@ -180,7 +180,7 @@ static struct res_items cat_items[] = { /* * Job Resource Directives * - * name handler value code flags default_value + * name handler value code flags default_value */ static struct res_items job_items[] = { {"name", store_name, ITEM(res_job.hdr.name), 0, ITEM_REQUIRED, 0}, @@ -218,7 +218,7 @@ static struct res_items job_items[] = { /* FileSet resource * - * name handler value code flags default_value + * name handler value code flags default_value */ static struct res_items fs_items[] = { {"name", store_name, ITEM(res_fs.hdr.name), 0, ITEM_REQUIRED, 0}, @@ -227,13 +227,13 @@ static struct res_items fs_items[] = { {"finclude", store_finc, NULL, 0, ITEM_NO_EQUALS, 0}, {"exclude", store_inc, NULL, 1, 0, 0}, {"fexclude", store_finc, NULL, 1, ITEM_NO_EQUALS, 0}, - {NULL, NULL, NULL, 0, 0, 0} + {NULL, NULL, NULL, 0, 0, 0} }; /* Schedule -- see run_conf.c */ /* Schedule * - * name handler value code flags default_value + * name handler value code flags default_value */ static struct res_items sch_items[] = { {"name", store_name, ITEM(res_sch.hdr.name), 0, ITEM_REQUIRED, 0}, @@ -244,7 +244,7 @@ static struct res_items sch_items[] = { /* Group resource -- not implemented * - * name handler value code flags default_value + * name handler value code flags default_value */ static struct res_items group_items[] = { {"name", store_name, ITEM(res_group.hdr.name), 0, ITEM_REQUIRED, 0}, @@ -254,7 +254,7 @@ static struct res_items group_items[] = { /* Pool resource * - * name handler value code flags default_value + * name handler value code flags default_value */ static struct res_items pool_items[] = { {"name", store_name, ITEM(res_pool.hdr.name), 0, ITEM_REQUIRED, 0}, @@ -264,7 +264,7 @@ static struct res_items pool_items[] = { {"cleaningprefix", store_strname, ITEM(res_pool.cleaning_prefix), 0, 0, 0}, {"usecatalog", store_yesno, ITEM(res_pool.use_catalog), 1, ITEM_DEFAULT, 1}, {"usevolumeonce", store_yesno, ITEM(res_pool.use_volume_once), 1, 0, 0}, - {"recycleoldestvolume", store_yesno, ITEM(res_pool.recycle_oldest_volume), 1, 0, 0}, + {"purgeoldestvolume", store_yesno, ITEM(res_pool.purge_oldest_volume), 1, 0, 0}, {"maximumvolumes", store_pint, ITEM(res_pool.max_volumes), 0, 0, 0}, {"maximumvolumejobs", store_pint, ITEM(res_pool.MaxVolJobs), 0, 0, 0}, {"maximumvolumefiles", store_pint, ITEM(res_pool.MaxVolFiles), 0, 0, 0}, @@ -280,7 +280,7 @@ static struct res_items pool_items[] = { /* * Counter Resource - * name handler value code flags default_value + * name handler value code flags default_value */ static struct res_items counter_items[] = { {"name", store_name, ITEM(res_counter.hdr.name), 0, ITEM_REQUIRED, 0}, @@ -300,7 +300,7 @@ extern struct res_items msgs_items[]; * This is the master resource definition. * It must have one item for each of the resources. * - * name items rcode res_head + * name items rcode res_head */ struct s_res resources[] = { {"director", dir_items, R_DIRECTOR, NULL}, @@ -315,13 +315,13 @@ struct s_res resources[] = { {"pool", pool_items, R_POOL, NULL}, {"messages", msgs_items, R_MSGS, NULL}, {"counter", counter_items, R_COUNTER, NULL}, - {NULL, NULL, 0, NULL} + {NULL, NULL, 0, NULL} }; /* Keywords (RHS) permitted in Job Level records * - * level_name level job_type + * level_name level job_type */ struct s_jl joblevels[] = { {"Full", L_FULL, JT_BACKUP}, @@ -333,19 +333,19 @@ struct s_jl joblevels[] = { {"Initcatalog", L_VERIFY_INIT, JT_VERIFY}, {"VolumeToCatalog", L_VERIFY_VOLUME_TO_CATALOG, JT_VERIFY}, {"Data", L_VERIFY_DATA, JT_VERIFY}, - {NULL, 0} + {NULL, 0} }; /* Keywords (RHS) permitted in Job type records * - * type_name job_type + * type_name job_type */ struct s_jt jobtypes[] = { {"backup", JT_BACKUP}, {"admin", JT_ADMIN}, {"verify", JT_VERIFY}, {"restore", JT_RESTORE}, - {NULL, 0} + {NULL, 0} }; @@ -354,7 +354,7 @@ static struct s_kw BakVerFields[] = { {"client", 'C'}, {"fileset", 'F'}, {"level", 'L'}, - {NULL, 0} + {NULL, 0} }; /* Keywords (RHS) permitted in Restore records */ @@ -365,7 +365,7 @@ static struct s_kw RestoreFields[] = { {"where", 'W'}, /* root of restore */ {"replace", 'R'}, /* replacement options */ {"bootstrap", 'B'}, /* bootstrap file */ - {NULL, 0} + {NULL, 0} }; /* Options permitted in Restore replace= */ @@ -374,7 +374,7 @@ struct s_kw ReplaceOptions[] = { {"ifnewer", REPLACE_IFNEWER}, {"ifolder", REPLACE_IFOLDER}, {"never", REPLACE_NEVER}, - {NULL, 0} + {NULL, 0} }; char *level_to_str(int level) @@ -386,8 +386,8 @@ char *level_to_str(int level) sprintf(level_no, "%d", level); /* default if not found */ for (i=0; joblevels[i].level_name; i++) { if (level == joblevels[i].level) { - str = joblevels[i].level_name; - break; + str = joblevels[i].level_name; + break; } } return str; @@ -404,87 +404,87 @@ void dump_resource(int type, RES *reshdr, void sendit(void *sock, char *fmt, ... sendit(sock, "No %s resource defined\n", res_to_str(type)); return; } - if (type < 0) { /* no recursion */ + if (type < 0) { /* no recursion */ type = - type; recurse = 0; } switch (type) { case R_DIRECTOR: sendit(sock, "Director: name=%s MaxJobs=%d FDtimeout=%s SDtimeout=%s\n", - reshdr->name, res->res_dir.MaxConcurrentJobs, - edit_uint64(res->res_dir.FDConnectTimeout, ed1), - edit_uint64(res->res_dir.SDConnectTimeout, ed2)); + reshdr->name, res->res_dir.MaxConcurrentJobs, + edit_uint64(res->res_dir.FDConnectTimeout, ed1), + edit_uint64(res->res_dir.SDConnectTimeout, ed2)); if (res->res_dir.query_file) { sendit(sock, " query_file=%s\n", res->res_dir.query_file); } if (res->res_dir.messages) { sendit(sock, " --> "); - dump_resource(-R_MSGS, (RES *)res->res_dir.messages, sendit, sock); + dump_resource(-R_MSGS, (RES *)res->res_dir.messages, sendit, sock); } break; case R_CONSOLE: sendit(sock, "Console: name=%s SSL=%d\n", - res->res_con.hdr.name, res->res_con.enable_ssl); + res->res_con.hdr.name, res->res_con.enable_ssl); break; case R_COUNTER: sendit(sock, "Counter: name=%s min=%d max=%d\n", - res->res_counter.hdr.name, res->res_counter.MinValue, - res->res_counter.MaxValue); + res->res_counter.hdr.name, res->res_counter.MinValue, + res->res_counter.MaxValue); if (res->res_counter.Catalog) { sendit(sock, " --> "); - dump_resource(-R_CATALOG, (RES *)res->res_counter.Catalog, sendit, sock); + dump_resource(-R_CATALOG, (RES *)res->res_counter.Catalog, sendit, sock); } if (res->res_counter.WrapCounter) { sendit(sock, " --> "); - dump_resource(-R_COUNTER, (RES *)res->res_counter.WrapCounter, sendit, sock); + dump_resource(-R_COUNTER, (RES *)res->res_counter.WrapCounter, sendit, sock); } - break; + break; case R_CLIENT: sendit(sock, "Client: name=%s address=%s FDport=%d MaxJobs=%u\n", - res->res_client.hdr.name, res->res_client.address, res->res_client.FDport, - res->res_client.MaxConcurrentJobs); + res->res_client.hdr.name, res->res_client.address, res->res_client.FDport, + res->res_client.MaxConcurrentJobs); sendit(sock, " JobRetention=%" lld " FileRetention=%" lld " AutoPrune=%d\n", - res->res_client.JobRetention, res->res_client.FileRetention, - res->res_client.AutoPrune); + res->res_client.JobRetention, res->res_client.FileRetention, + res->res_client.AutoPrune); if (res->res_client.catalog) { sendit(sock, " --> "); - dump_resource(-R_CATALOG, (RES *)res->res_client.catalog, sendit, sock); + dump_resource(-R_CATALOG, (RES *)res->res_client.catalog, sendit, sock); } break; case R_STORAGE: sendit(sock, "Storage: name=%s address=%s SDport=%d MaxJobs=%u\n\ DeviceName=%s MediaType=%s\n", - res->res_store.hdr.name, res->res_store.address, res->res_store.SDport, - res->res_store.MaxConcurrentJobs, - res->res_store.dev_name, res->res_store.media_type); + res->res_store.hdr.name, res->res_store.address, res->res_store.SDport, + res->res_store.MaxConcurrentJobs, + res->res_store.dev_name, res->res_store.media_type); break; case R_CATALOG: sendit(sock, "Catalog: name=%s address=%s DBport=%d db_name=%s\n\ db_user=%s\n", - res->res_cat.hdr.name, NPRT(res->res_cat.db_address), - res->res_cat.db_port, res->res_cat.db_name, NPRT(res->res_cat.db_user)); + res->res_cat.hdr.name, NPRT(res->res_cat.db_address), + res->res_cat.db_port, res->res_cat.db_name, NPRT(res->res_cat.db_user)); break; case R_JOB: sendit(sock, "Job: name=%s JobType=%d level=%s MaxJobs=%u\n", - res->res_job.hdr.name, res->res_job.JobType, - level_to_str(res->res_job.level), res->res_job.MaxConcurrentJobs); + res->res_job.hdr.name, res->res_job.JobType, + level_to_str(res->res_job.level), res->res_job.MaxConcurrentJobs); sendit(sock, " Resched=%d Times=%d Interval=%s\n", - res->res_job.RescheduleOnError, res->res_job.RescheduleTimes, - edit_uint64_with_commas(res->res_job.RescheduleInterval, ed1)); + res->res_job.RescheduleOnError, res->res_job.RescheduleTimes, + edit_uint64_with_commas(res->res_job.RescheduleInterval, ed1)); if (res->res_job.client) { sendit(sock, " --> "); - dump_resource(-R_CLIENT, (RES *)res->res_job.client, sendit, sock); + dump_resource(-R_CLIENT, (RES *)res->res_job.client, sendit, sock); } if (res->res_job.fileset) { sendit(sock, " --> "); - dump_resource(-R_FILESET, (RES *)res->res_job.fileset, sendit, sock); + dump_resource(-R_FILESET, (RES *)res->res_job.fileset, sendit, sock); } if (res->res_job.schedule) { sendit(sock, " --> "); - dump_resource(-R_SCHEDULE, (RES *)res->res_job.schedule, sendit, sock); + dump_resource(-R_SCHEDULE, (RES *)res->res_job.schedule, sendit, sock); } if (res->res_job.RestoreWhere) { sendit(sock, " --> Where=%s\n", NPRT(res->res_job.RestoreWhere)); @@ -503,108 +503,108 @@ void dump_resource(int type, RES *reshdr, void sendit(void *sock, char *fmt, ... } if (res->res_job.storage) { sendit(sock, " --> "); - dump_resource(-R_STORAGE, (RES *)res->res_job.storage, sendit, sock); + dump_resource(-R_STORAGE, (RES *)res->res_job.storage, sendit, sock); } if (res->res_job.pool) { sendit(sock, " --> "); - dump_resource(-R_POOL, (RES *)res->res_job.pool, sendit, sock); + dump_resource(-R_POOL, (RES *)res->res_job.pool, sendit, sock); } else { sendit(sock, "!!! No Pool resource\n"); } if (res->res_job.messages) { sendit(sock, " --> "); - dump_resource(-R_MSGS, (RES *)res->res_job.messages, sendit, sock); + dump_resource(-R_MSGS, (RES *)res->res_job.messages, sendit, sock); } break; case R_FILESET: sendit(sock, "FileSet: name=%s\n", res->res_fs.hdr.name); for (int i=0; ires_fs.num_includes; i++) { - INCEXE *incexe = res->res_fs.include_items[i]; - for (int j=0; jnum_names; j++) { + INCEXE *incexe = res->res_fs.include_items[i]; + for (int j=0; jnum_names; j++) { sendit(sock, " Inc: %s\n", incexe->name_list[j]); - } + } } for (int i=0; ires_fs.num_excludes; i++) { - INCEXE *incexe = res->res_fs.exclude_items[i]; - for (int j=0; jnum_names; j++) { + INCEXE *incexe = res->res_fs.exclude_items[i]; + for (int j=0; jnum_names; j++) { sendit(sock, " Exc: %s\n", incexe->name_list[j]); - } + } } break; case R_SCHEDULE: if (res->res_sch.run) { - int i; - RUN *run = res->res_sch.run; - char buf[1000], num[10]; + int i; + RUN *run = res->res_sch.run; + char buf[1000], num[10]; sendit(sock, "Schedule: name=%s\n", res->res_sch.hdr.name); - if (!run) { - break; - } + if (!run) { + break; + } next_run: sendit(sock, " --> Run Level=%s\n", level_to_str(run->level)); strcpy(buf, " hour="); - for (i=0; i<24; i++) { - if (bit_is_set(i, run->hour)) { + for (i=0; i<24; i++) { + if (bit_is_set(i, run->hour)) { sprintf(num, "%d ", i); - strcat(buf, num); - } - } + strcat(buf, num); + } + } strcat(buf, "\n"); - sendit(sock, buf); + sendit(sock, buf); strcpy(buf, " mday="); - for (i=0; i<31; i++) { - if (bit_is_set(i, run->mday)) { + for (i=0; i<31; i++) { + if (bit_is_set(i, run->mday)) { sprintf(num, "%d ", i+1); - strcat(buf, num); - } - } + strcat(buf, num); + } + } strcat(buf, "\n"); - sendit(sock, buf); + sendit(sock, buf); strcpy(buf, " month="); - for (i=0; i<12; i++) { - if (bit_is_set(i, run->month)) { + for (i=0; i<12; i++) { + if (bit_is_set(i, run->month)) { sprintf(num, "%d ", i+1); - strcat(buf, num); - } - } + strcat(buf, num); + } + } strcat(buf, "\n"); - sendit(sock, buf); + sendit(sock, buf); strcpy(buf, " wday="); - for (i=0; i<7; i++) { - if (bit_is_set(i, run->wday)) { + for (i=0; i<7; i++) { + if (bit_is_set(i, run->wday)) { sprintf(num, "%d ", i+1); - strcat(buf, num); - } - } + strcat(buf, num); + } + } strcat(buf, "\n"); - sendit(sock, buf); + sendit(sock, buf); strcpy(buf, " wpos="); - for (i=0; i<5; i++) { - if (bit_is_set(i, run->wpos)) { + for (i=0; i<5; i++) { + if (bit_is_set(i, run->wpos)) { sprintf(num, "%d ", i+1); - strcat(buf, num); - } - } + strcat(buf, num); + } + } strcat(buf, "\n"); - sendit(sock, buf); + sendit(sock, buf); sendit(sock, " mins=%d\n", run->minute); - if (run->pool) { + if (run->pool) { sendit(sock, " --> "); - dump_resource(-R_POOL, (RES *)run->pool, sendit, sock); - } - if (run->storage) { + dump_resource(-R_POOL, (RES *)run->pool, sendit, sock); + } + if (run->storage) { sendit(sock, " --> "); - dump_resource(-R_STORAGE, (RES *)run->storage, sendit, sock); - } - if (run->msgs) { + dump_resource(-R_STORAGE, (RES *)run->storage, sendit, sock); + } + if (run->msgs) { sendit(sock, " --> "); - dump_resource(-R_MSGS, (RES *)run->msgs, sendit, sock); - } - /* If another Run record is chained in, go print it */ - if (run->next) { - run = run->next; - goto next_run; - } + dump_resource(-R_MSGS, (RES *)run->msgs, sendit, sock); + } + /* If another Run record is chained in, go print it */ + if (run->next) { + run = run->next; + goto next_run; + } } else { sendit(sock, "Schedule: name=%s\n", res->res_sch.hdr.name); } @@ -614,20 +614,20 @@ next_run: break; case R_POOL: sendit(sock, "Pool: name=%s PoolType=%s\n", res->res_pool.hdr.name, - res->res_pool.pool_type); + res->res_pool.pool_type); sendit(sock, " use_cat=%d use_once=%d acpt_any=%d cat_files=%d\n", - res->res_pool.use_catalog, res->res_pool.use_volume_once, - res->res_pool.accept_any_volume, res->res_pool.catalog_files); + res->res_pool.use_catalog, res->res_pool.use_volume_once, + res->res_pool.accept_any_volume, res->res_pool.catalog_files); sendit(sock, " max_vols=%d auto_prune=%d VolRetention=%" lld "\n", - res->res_pool.max_volumes, res->res_pool.AutoPrune, - res->res_pool.VolRetention); + res->res_pool.max_volumes, res->res_pool.AutoPrune, + res->res_pool.VolRetention); sendit(sock, " recycle=%d LabelFormat=%s\n", res->res_pool.Recycle, - NPRT(res->res_pool.label_format)); + NPRT(res->res_pool.label_format)); sendit(sock, " CleaningPrefix=%s\n", - NPRT(res->res_pool.cleaning_prefix)); + NPRT(res->res_pool.cleaning_prefix)); sendit(sock, " recyleOldest=%d MaxVolJobs=%d MaxVolFiles=%d\n", - res->res_pool.recycle_oldest_volume, - res->res_pool.MaxVolJobs, res->res_pool.MaxVolFiles); + res->res_pool.purge_oldest_volume, + res->res_pool.MaxVolJobs, res->res_pool.MaxVolFiles); break; case R_MSGS: sendit(sock, "Messages: name=%s\n", res->res_msgs.hdr.name); @@ -658,15 +658,8 @@ static void free_incexe(INCEXE *incexe) } for (int i=0; inum_opts; i++) { FOPTS *fopt = incexe->opts_list[i]; - if (fopt->match) { - free(fopt->match); - } - for (int j=0; jnum_base; j++) { - free(fopt->base_list[j]); - } - if (fopt->base_list) { - free(fopt->base_list); - } + fopt->match.destroy(); + fopt->base_list.destroy(); free(fopt); } if (incexe->opts_list) { @@ -706,130 +699,130 @@ void free_resource(int type) switch (type) { case R_DIRECTOR: if (res->res_dir.working_directory) { - free(res->res_dir.working_directory); + free(res->res_dir.working_directory); } if (res->res_dir.pid_directory) { - free(res->res_dir.pid_directory); + free(res->res_dir.pid_directory); } if (res->res_dir.subsys_directory) { - free(res->res_dir.subsys_directory); + free(res->res_dir.subsys_directory); } if (res->res_dir.password) { - free(res->res_dir.password); + free(res->res_dir.password); } if (res->res_dir.query_file) { - free(res->res_dir.query_file); + free(res->res_dir.query_file); } if (res->res_dir.DIRaddr) { - free(res->res_dir.DIRaddr); + free(res->res_dir.DIRaddr); } break; case R_COUNTER: break; case R_CONSOLE: if (res->res_con.password) { - free(res->res_con.password); + free(res->res_con.password); } break; case R_CLIENT: if (res->res_client.address) { - free(res->res_client.address); + free(res->res_client.address); } if (res->res_client.password) { - free(res->res_client.password); + free(res->res_client.password); } break; case R_STORAGE: if (res->res_store.address) { - free(res->res_store.address); + free(res->res_store.address); } if (res->res_store.password) { - free(res->res_store.password); + free(res->res_store.password); } if (res->res_store.media_type) { - free(res->res_store.media_type); + free(res->res_store.media_type); } if (res->res_store.dev_name) { - free(res->res_store.dev_name); + free(res->res_store.dev_name); } break; case R_CATALOG: if (res->res_cat.db_address) { - free(res->res_cat.db_address); + free(res->res_cat.db_address); } if (res->res_cat.db_socket) { - free(res->res_cat.db_socket); + free(res->res_cat.db_socket); } if (res->res_cat.db_user) { - free(res->res_cat.db_user); + free(res->res_cat.db_user); } if (res->res_cat.db_name) { - free(res->res_cat.db_name); + free(res->res_cat.db_name); } if (res->res_cat.db_password) { - free(res->res_cat.db_password); + free(res->res_cat.db_password); } break; case R_FILESET: if ((num=res->res_fs.num_includes)) { - while (--num >= 0) { - free_incexe(res->res_fs.include_items[num]); - } - free(res->res_fs.include_items); + while (--num >= 0) { + free_incexe(res->res_fs.include_items[num]); + } + free(res->res_fs.include_items); } res->res_fs.num_includes = 0; if ((num=res->res_fs.num_excludes)) { - while (--num >= 0) { - free_incexe(res->res_fs.exclude_items[num]); - } - free(res->res_fs.exclude_items); + while (--num >= 0) { + free_incexe(res->res_fs.exclude_items[num]); + } + free(res->res_fs.exclude_items); } res->res_fs.num_excludes = 0; break; case R_POOL: if (res->res_pool.pool_type) { - free(res->res_pool.pool_type); + free(res->res_pool.pool_type); } if (res->res_pool.label_format) { - free(res->res_pool.label_format); + free(res->res_pool.label_format); } if (res->res_pool.cleaning_prefix) { - free(res->res_pool.cleaning_prefix); + free(res->res_pool.cleaning_prefix); } break; case R_SCHEDULE: if (res->res_sch.run) { - RUN *nrun, *next; - nrun = res->res_sch.run; - while (nrun) { - next = nrun->next; - free(nrun); - nrun = next; - } + RUN *nrun, *next; + nrun = res->res_sch.run; + while (nrun) { + next = nrun->next; + free(nrun); + nrun = next; + } } break; case R_JOB: if (res->res_job.RestoreWhere) { - free(res->res_job.RestoreWhere); + free(res->res_job.RestoreWhere); } if (res->res_job.RestoreBootstrap) { - free(res->res_job.RestoreBootstrap); + free(res->res_job.RestoreBootstrap); } if (res->res_job.WriteBootstrap) { - free(res->res_job.WriteBootstrap); + free(res->res_job.WriteBootstrap); } if (res->res_job.RunBeforeJob) { - free(res->res_job.RunBeforeJob); + free(res->res_job.RunBeforeJob); } if (res->res_job.RunAfterJob) { - free(res->res_job.RunAfterJob); + free(res->res_job.RunAfterJob); } break; case R_MSGS: if (res->res_msgs.mail_cmd) - free(res->res_msgs.mail_cmd); + free(res->res_msgs.mail_cmd); if (res->res_msgs.operator_cmd) - free(res->res_msgs.operator_cmd); + free(res->res_msgs.operator_cmd); free_msgs_res((MSGS *)res); /* free message resource */ res = NULL; break; @@ -866,10 +859,10 @@ void save_resource(int type, struct res_items *items, int pass) */ for (i=0; items[i].name; i++) { if (items[i].flags & ITEM_REQUIRED) { - if (!bit_is_set(i, res_all.res_dir.hdr.item_present)) { + if (!bit_is_set(i, res_all.res_dir.hdr.item_present)) { Emsg2(M_ERROR_TERM, 0, "%s item is required in %s resource, but not found.\n", - items[i].name, resources[rindex]); - } + items[i].name, resources[rindex]); + } } /* If this triggers, take a look at lib/parse_conf.h */ if (i >= MAX_RES_ITEMS) { @@ -892,83 +885,83 @@ void save_resource(int type, struct res_items *items, int pass) case R_POOL: case R_MSGS: case R_FILESET: - break; + break; /* Resources containing another resource */ case R_DIRECTOR: - if ((res = (URES *)GetResWithName(R_DIRECTOR, res_all.res_dir.hdr.name)) == NULL) { + if ((res = (URES *)GetResWithName(R_DIRECTOR, res_all.res_dir.hdr.name)) == NULL) { Emsg1(M_ERROR_TERM, 0, "Cannot find Director resource %s\n", res_all.res_dir.hdr.name); - } - res->res_dir.messages = res_all.res_dir.messages; - break; + } + res->res_dir.messages = res_all.res_dir.messages; + break; case R_JOB: - if ((res = (URES *)GetResWithName(R_JOB, res_all.res_dir.hdr.name)) == NULL) { + if ((res = (URES *)GetResWithName(R_JOB, res_all.res_dir.hdr.name)) == NULL) { Emsg1(M_ERROR_TERM, 0, "Cannot find Job resource %s\n", res_all.res_dir.hdr.name); - } - res->res_job.messages = res_all.res_job.messages; - res->res_job.schedule = res_all.res_job.schedule; - res->res_job.client = res_all.res_job.client; - res->res_job.fileset = res_all.res_job.fileset; - res->res_job.storage = res_all.res_job.storage; - res->res_job.pool = res_all.res_job.pool; - if (res->res_job.JobType == 0) { + } + res->res_job.messages = res_all.res_job.messages; + res->res_job.schedule = res_all.res_job.schedule; + res->res_job.client = res_all.res_job.client; + res->res_job.fileset = res_all.res_job.fileset; + res->res_job.storage = res_all.res_job.storage; + res->res_job.pool = res_all.res_job.pool; + if (res->res_job.JobType == 0) { Emsg1(M_ERROR_TERM, 0, "Job Type not defined for Job resource %s\n", res_all.res_dir.hdr.name); - } - if (res->res_job.level != 0) { - int i; - for (i=0; joblevels[i].level_name; i++) { - if (joblevels[i].level == res->res_job.level && - joblevels[i].job_type == res->res_job.JobType) { - i = 0; - break; - } - } - if (i != 0) { + } + if (res->res_job.level != 0) { + int i; + for (i=0; joblevels[i].level_name; i++) { + if (joblevels[i].level == res->res_job.level && + joblevels[i].job_type == res->res_job.JobType) { + i = 0; + break; + } + } + if (i != 0) { Emsg1(M_ERROR_TERM, 0, "Inappropriate level specified in Job resource %s\n", - res_all.res_dir.hdr.name); - } - } - break; + res_all.res_dir.hdr.name); + } + } + break; case R_COUNTER: - if ((res = (URES *)GetResWithName(R_COUNTER, res_all.res_counter.hdr.name)) == NULL) { + if ((res = (URES *)GetResWithName(R_COUNTER, res_all.res_counter.hdr.name)) == NULL) { Emsg1(M_ERROR_TERM, 0, "Cannot find Counter resource %s\n", res_all.res_counter.hdr.name); - } - res->res_counter.Catalog = res_all.res_counter.Catalog; - res->res_counter.WrapCounter = res_all.res_counter.WrapCounter; - break; + } + res->res_counter.Catalog = res_all.res_counter.Catalog; + res->res_counter.WrapCounter = res_all.res_counter.WrapCounter; + break; case R_CLIENT: - if ((res = (URES *)GetResWithName(R_CLIENT, res_all.res_client.hdr.name)) == NULL) { + if ((res = (URES *)GetResWithName(R_CLIENT, res_all.res_client.hdr.name)) == NULL) { Emsg1(M_ERROR_TERM, 0, "Cannot find Client resource %s\n", res_all.res_client.hdr.name); - } - res->res_client.catalog = res_all.res_client.catalog; - break; + } + res->res_client.catalog = res_all.res_client.catalog; + break; case R_SCHEDULE: - /* Schedule is a bit different in that it contains a RUN record + /* Schedule is a bit different in that it contains a RUN record * chain which isn't a "named" resource. This chain was linked - * in by run_conf.c during pass 2, so here we jam the pointer - * into the Schedule resource. - */ - if ((res = (URES *)GetResWithName(R_SCHEDULE, res_all.res_client.hdr.name)) == NULL) { + * in by run_conf.c during pass 2, so here we jam the pointer + * into the Schedule resource. + */ + if ((res = (URES *)GetResWithName(R_SCHEDULE, res_all.res_client.hdr.name)) == NULL) { Emsg1(M_ERROR_TERM, 0, "Cannot find Schedule resource %s\n", res_all.res_client.hdr.name); - } - res->res_sch.run = res_all.res_sch.run; - break; + } + res->res_sch.run = res_all.res_sch.run; + break; default: Emsg1(M_ERROR, 0, "Unknown resource type %d in save_resource.\n", type); - error = 1; - break; + error = 1; + break; } /* Note, the resource name was already saved during pass 1, * so here, we can just release it. */ if (res_all.res_dir.hdr.name) { - free(res_all.res_dir.hdr.name); - res_all.res_dir.hdr.name = NULL; + free(res_all.res_dir.hdr.name); + res_all.res_dir.hdr.name = NULL; } if (res_all.res_dir.hdr.desc) { - free(res_all.res_dir.hdr.desc); - res_all.res_dir.hdr.desc = NULL; + free(res_all.res_dir.hdr.desc); + res_all.res_dir.hdr.desc = NULL; } return; } @@ -1022,17 +1015,17 @@ void save_resource(int type, struct res_items *items, int pass) res = (URES *)malloc(size); memcpy(res, &res_all, size); if (!resources[rindex].res_head) { - resources[rindex].res_head = (RES *)res; /* store first entry */ + resources[rindex].res_head = (RES *)res; /* store first entry */ Dmsg3(200, "Inserting first %s res: %s index=%d\n", res_to_str(type), - res->res_dir.hdr.name, rindex); + res->res_dir.hdr.name, rindex); } else { - RES *next; - /* Add new res to end of chain */ - for (next=resources[rindex].res_head; next->next; next=next->next) - { } - next->next = (RES *)res; + RES *next; + /* Add new res to end of chain */ + for (next=resources[rindex].res_head; next->next; next=next->next) + { } + next->next = (RES *)res; Dmsg3(200, "Inserting %s res: %s index=%d\n", res_to_str(type), - res->res_dir.hdr.name, rindex); + res->res_dir.hdr.name, rindex); } } } @@ -1049,9 +1042,9 @@ static void store_jobtype(LEX *lc, struct res_items *item, int index, int pass) /* Store the type both pass 1 and pass 2 */ for (i=0; jobtypes[i].type_name; i++) { if (strcasecmp(lc->str, jobtypes[i].type_name) == 0) { - ((JOB *)(item->value))->JobType = jobtypes[i].job_type; - i = 0; - break; + ((JOB *)(item->value))->JobType = jobtypes[i].job_type; + i = 0; + break; } } if (i != 0) { @@ -1073,9 +1066,9 @@ static void store_level(LEX *lc, struct res_items *item, int index, int pass) /* Store the level pass 2 so that type is defined */ for (i=0; joblevels[i].level_name; i++) { if (strcasecmp(lc->str, joblevels[i].level_name) == 0) { - ((JOB *)(item->value))->level = joblevels[i].level; - i = 0; - break; + ((JOB *)(item->value))->level = joblevels[i].level; + i = 0; + break; } } if (i != 0) { @@ -1092,9 +1085,9 @@ static void store_replace(LEX *lc, struct res_items *item, int index, int pass) /* Scan Replacement options */ for (i=0; ReplaceOptions[i].name; i++) { if (strcasecmp(lc->str, ReplaceOptions[i].name) == 0) { - *(int *)(item->value) = ReplaceOptions[i].token; - i = 0; - break; + *(int *)(item->value) = ReplaceOptions[i].token; + i = 0; + break; } } if (i != 0) { @@ -1132,59 +1125,59 @@ static void store_backup(LEX *lc, struct res_items *item, int index, int pass) Dmsg1(190, "Got keyword: %s\n", lc->str); found = FALSE; for (i=0; BakVerFields[i].name; i++) { - if (strcasecmp(lc->str, BakVerFields[i].name) == 0) { - found = TRUE; - if (lex_get_token(lc, T_ALL) != T_EQUALS) { + if (strcasecmp(lc->str, BakVerFields[i].name) == 0) { + found = TRUE; + if (lex_get_token(lc, T_ALL) != T_EQUALS) { scan_err1(lc, "Expected an equals, got: %s", lc->str); - } - token = lex_get_token(lc, T_NAME); + } + token = lex_get_token(lc, T_NAME); Dmsg1(190, "Got value: %s\n", lc->str); - switch (BakVerFields[i].token) { + switch (BakVerFields[i].token) { case 'C': - /* Find Client Resource */ - if (pass == 2) { - res = GetResWithName(R_CLIENT, lc->str); - if (res == NULL) { + /* Find Client Resource */ + if (pass == 2) { + res = GetResWithName(R_CLIENT, lc->str); + if (res == NULL) { scan_err1(lc, "Could not find specified Client Resource: %s", - lc->str); - } - res_all.res_job.client = (CLIENT *)res; - } - break; + lc->str); + } + res_all.res_job.client = (CLIENT *)res; + } + break; case 'F': - /* Find FileSet Resource */ - if (pass == 2) { - res = GetResWithName(R_FILESET, lc->str); - if (res == NULL) { + /* Find FileSet Resource */ + if (pass == 2) { + res = GetResWithName(R_FILESET, lc->str); + if (res == NULL) { scan_err1(lc, "Could not find specified FileSet Resource: %s\n", - lc->str); - } - res_all.res_job.fileset = (FILESET *)res; - } - break; + lc->str); + } + res_all.res_job.fileset = (FILESET *)res; + } + break; case 'L': - /* Get level */ - for (i=0; joblevels[i].level_name; i++) { - if (joblevels[i].job_type == item->code && - strcasecmp(lc->str, joblevels[i].level_name) == 0) { - ((JOB *)(item->value))->level = joblevels[i].level; - i = 0; - break; - } - } - if (i != 0) { + /* Get level */ + for (i=0; joblevels[i].level_name; i++) { + if (joblevels[i].job_type == item->code && + strcasecmp(lc->str, joblevels[i].level_name) == 0) { + ((JOB *)(item->value))->level = joblevels[i].level; + i = 0; + break; + } + } + if (i != 0) { scan_err1(lc, "Expected a Job Level keyword, got: %s", lc->str); - } - break; - } /* end switch */ - break; - } /* end if strcmp() */ + } + break; + } /* end switch */ + break; + } /* end if strcmp() */ } /* end for */ if (!found) { scan_err1(lc, "%s not a valid Backup/verify keyword", lc->str); } } /* end while */ - lc->options = options; /* reset original options */ + lc->options = options; /* reset original options */ set_bit(index, res_all.hdr.item_present); } @@ -1214,91 +1207,91 @@ static void store_restore(LEX *lc, struct res_items *item, int index, int pass) found = FALSE; for (i=0; RestoreFields[i].name; i++) { Dmsg1(190, "Restore kw=%s\n", lc->str); - if (strcasecmp(lc->str, RestoreFields[i].name) == 0) { - found = TRUE; - if (lex_get_token(lc, T_ALL) != T_EQUALS) { + if (strcasecmp(lc->str, RestoreFields[i].name) == 0) { + found = TRUE; + if (lex_get_token(lc, T_ALL) != T_EQUALS) { scan_err1(lc, "Expected an equals, got: %s", lc->str); - } - token = lex_get_token(lc, T_ALL); + } + token = lex_get_token(lc, T_ALL); Dmsg1(190, "Restore value=%s\n", lc->str); - switch (RestoreFields[i].token) { + switch (RestoreFields[i].token) { case 'B': - /* Bootstrap */ - if (token != T_IDENTIFIER && token != T_UNQUOTED_STRING && token != T_QUOTED_STRING) { + /* Bootstrap */ + if (token != T_IDENTIFIER && token != T_UNQUOTED_STRING && token != T_QUOTED_STRING) { scan_err1(lc, "Expected a Restore bootstrap file, got: %s", lc->str); - } - if (pass == 1) { - res_all.res_job.RestoreBootstrap = bstrdup(lc->str); - } - break; + } + if (pass == 1) { + res_all.res_job.RestoreBootstrap = bstrdup(lc->str); + } + break; case 'C': - /* Find Client Resource */ - if (pass == 2) { - res = GetResWithName(R_CLIENT, lc->str); - if (res == NULL) { + /* Find Client Resource */ + if (pass == 2) { + res = GetResWithName(R_CLIENT, lc->str); + if (res == NULL) { scan_err1(lc, "Could not find specified Client Resource: %s", - lc->str); - } - res_all.res_job.client = (CLIENT *)res; - } - break; + lc->str); + } + res_all.res_job.client = (CLIENT *)res; + } + break; case 'F': - /* Find FileSet Resource */ - if (pass == 2) { - res = GetResWithName(R_FILESET, lc->str); - if (res == NULL) { + /* Find FileSet Resource */ + if (pass == 2) { + res = GetResWithName(R_FILESET, lc->str); + if (res == NULL) { scan_err1(lc, "Could not find specified FileSet Resource: %s\n", - lc->str); - } - res_all.res_job.fileset = (FILESET *)res; - } - break; + lc->str); + } + res_all.res_job.fileset = (FILESET *)res; + } + break; case 'J': - /* JobId */ - if (token != T_NUMBER) { + /* JobId */ + if (token != T_NUMBER) { scan_err1(lc, "expected an integer number, got: %s", lc->str); - } - errno = 0; - res_all.res_job.RestoreJobId = strtol(lc->str, NULL, 0); + } + errno = 0; + res_all.res_job.RestoreJobId = strtol(lc->str, NULL, 0); Dmsg1(190, "RestorJobId=%d\n", res_all.res_job.RestoreJobId); - if (errno != 0) { + if (errno != 0) { scan_err1(lc, "expected an integer number, got: %s", lc->str); - } - break; + } + break; case 'W': - /* Where */ - if (token != T_IDENTIFIER && token != T_UNQUOTED_STRING && token != T_QUOTED_STRING) { + /* Where */ + if (token != T_IDENTIFIER && token != T_UNQUOTED_STRING && token != T_QUOTED_STRING) { scan_err1(lc, "Expected a Restore root directory, got: %s", lc->str); - } - if (pass == 1) { - res_all.res_job.RestoreWhere = bstrdup(lc->str); - } - break; + } + if (pass == 1) { + res_all.res_job.RestoreWhere = bstrdup(lc->str); + } + break; case 'R': - /* Replacement options */ - if (token != T_IDENTIFIER && token != T_UNQUOTED_STRING && token != T_QUOTED_STRING) { + /* Replacement options */ + if (token != T_IDENTIFIER && token != T_UNQUOTED_STRING && token != T_QUOTED_STRING) { scan_err1(lc, "Expected a keyword name, got: %s", lc->str); - } - /* Fix to scan Replacement options */ - for (i=0; ReplaceOptions[i].name; i++) { - if (strcasecmp(lc->str, ReplaceOptions[i].name) == 0) { - ((JOB *)(item->value))->replace = ReplaceOptions[i].token; - i = 0; - break; - } - } - if (i != 0) { + } + /* Fix to scan Replacement options */ + for (i=0; ReplaceOptions[i].name; i++) { + if (strcasecmp(lc->str, ReplaceOptions[i].name) == 0) { + ((JOB *)(item->value))->replace = ReplaceOptions[i].token; + i = 0; + break; + } + } + if (i != 0) { scan_err1(lc, "Expected a Restore replacement option, got: %s", lc->str); - } - break; - } /* end switch */ - break; - } /* end if strcmp() */ + } + break; + } /* end switch */ + break; + } /* end if strcmp() */ } /* end for */ if (!found) { scan_err1(lc, "%s not a valid Restore keyword", lc->str); } } /* end while */ - lc->options = options; /* reset original options */ + lc->options = options; /* reset original options */ set_bit(index, res_all.hdr.item_present); } diff --git a/bacula/src/dird/dird_conf.h b/bacula/src/dird/dird_conf.h index 817183b1b3..146fb29a0d 100644 --- a/bacula/src/dird/dird_conf.h +++ b/bacula/src/dird/dird_conf.h @@ -210,17 +210,16 @@ struct JOB { #define MAX_FOPTS 30 -struct s_fopts_item { +/* File options structure */ +struct FOPTS { char opts[MAX_FOPTS]; /* options string */ - char *match; /* match string */ - char **base_list; /* list of base job names */ - int num_base; /* number of bases in list */ + alist match; /* match string(s) */ + alist base_list; /* list of base names */ }; -typedef struct s_fopts_item FOPTS; /* This is either an include item or an exclude item */ -struct s_incexc_item { +struct INCEXE { FOPTS *current_opts; /* points to current options structure */ FOPTS **opts_list; /* options list */ int num_opts; /* number of options items */ @@ -228,7 +227,6 @@ struct s_incexc_item { int max_names; /* malloc'ed size of name list */ int num_names; /* number of names in the list */ }; -typedef struct s_incexc_item INCEXE; /* * FileSet Resource @@ -294,7 +292,7 @@ struct POOL { int catalog_files; /* maintain file entries in catalog */ int use_volume_once; /* write on volume only once */ int accept_any_volume; /* accept any volume */ - int recycle_oldest_volume; /* recycle oldest volume */ + int purge_oldest_volume; /* purge oldest 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 */ diff --git a/bacula/src/dird/fd_cmds.c b/bacula/src/dird/fd_cmds.c index 8323a21a88..450e005d80 100644 --- a/bacula/src/dird/fd_cmds.c +++ b/bacula/src/dird/fd_cmds.c @@ -167,21 +167,21 @@ int send_level_command(JCR *jcr) * Send Level command to File daemon */ switch (jcr->JobLevel) { - case L_BASE: - bnet_fsend(fd, levelcmd, "base", " ", 0); - break; - case L_FULL: - bnet_fsend(fd, levelcmd, "full", " ", 0); - break; - case L_DIFFERENTIAL: - case L_INCREMENTAL: - bnet_fsend(fd, levelcmd, "since ", jcr->stime, 0); - break; - case L_SINCE: - default: - Jmsg2(jcr, M_FATAL, 0, _("Unimplemented backup level %d %c\n"), - jcr->JobLevel, jcr->JobLevel); - return 0; + case L_BASE: + bnet_fsend(fd, levelcmd, "base", " ", 0); + break; + case L_FULL: + bnet_fsend(fd, levelcmd, "full", " ", 0); + break; + case L_DIFFERENTIAL: + case L_INCREMENTAL: + bnet_fsend(fd, levelcmd, "since ", jcr->stime, 0); + break; + case L_SINCE: + default: + Jmsg2(jcr, M_FATAL, 0, _("Unimplemented backup level %d %c\n"), + jcr->JobLevel, jcr->JobLevel); + return 0; } Dmsg1(120, ">filed: %s", fd->msg); if (!response(jcr, fd, OKlevel, "Level", DISPLAY_ERROR)) { @@ -216,12 +216,18 @@ static int send_list(JCR *jcr, int list) char *p; int optlen, stat; INCEXE *ie; + FOPTS *fo; + if (list == INC_LIST) { ie = fileset->include_items[i]; } else { ie = fileset->exclude_items[i]; } + fo = ie->opts_list[0]; + for (int j=0; jmatch.size(); j++) { + Dmsg1(000, "Match=%s\n", fo->match.get(j)); + } for (int j=0; jnum_names; j++) { p = ie->name_list[j]; switch (*p) { diff --git a/bacula/src/dird/inc_conf.c b/bacula/src/dird/inc_conf.c index c5caf6235e..2b2629090f 100644 --- a/bacula/src/dird/inc_conf.c +++ b/bacula/src/dird/inc_conf.c @@ -398,17 +398,14 @@ static void store_match(LEX *lc, struct res_items *item, int index, int pass) */ token = lex_get_token(lc, T_ALL); switch (token) { - case T_IDENTIFIER: - case T_UNQUOTED_STRING: - case T_QUOTED_STRING: - setup_current_opts(); - if (res_incexe.current_opts->match) { - scan_err0(lc, _("More than one match specified.\n")); - } - res_incexe.current_opts->match = bstrdup(lc->str); - break; - default: - scan_err1(lc, _("Expected a filename, got: %s\n"), lc->str); + case T_IDENTIFIER: + case T_UNQUOTED_STRING: + case T_QUOTED_STRING: + setup_current_opts(); + res_incexe.current_opts->match.append(bstrdup(lc->str)); + break; + default: + scan_err1(lc, _("Expected a filename, got: %s\n"), lc->str); } } else { /* pass 2 */ lex_get_token(lc, T_ALL); @@ -420,7 +417,6 @@ static void store_match(LEX *lc, struct res_items *item, int index, int pass) static void store_base(LEX *lc, struct res_items *item, int index, int pass) { int token; - FOPTS *copt; if (pass == 1) { setup_current_opts(); @@ -428,14 +424,7 @@ static void store_base(LEX *lc, struct res_items *item, int index, int pass) * Pickup Base Job Name */ token = lex_get_token(lc, T_NAME); - copt = res_incexe.current_opts; - if (copt->base_list == NULL) { - copt->base_list = (char **)malloc(sizeof(char *)); - } else { - copt->base_list = (char **)realloc(copt->base_list, - sizeof(char *) * (copt->num_base+1)); - } - copt->base_list[copt->num_base++] = bstrdup(lc->str); + res_incexe.current_opts->base_list.append(bstrdup(lc->str)); } else { /* pass 2 */ lex_get_token(lc, T_ALL); } @@ -507,7 +496,6 @@ static void store_opts(LEX *lc, struct res_items *item, int index, int pass) if (pass == 1) { setup_current_opts(); - bstrncat(res_incexe.current_opts->opts, inc_opts, MAX_FOPTS); } diff --git a/bacula/src/dird/restore.c b/bacula/src/dird/restore.c index 52c1b66f88..d8b1b72088 100644 --- a/bacula/src/dird/restore.c +++ b/bacula/src/dird/restore.c @@ -42,7 +42,7 @@ #include "dird.h" /* Commands sent to File daemon */ -static char restorecmd[] = "restore replace=%c where=%s\n"; +static char restorecmd[] = "restore replace=%c prelinks=%d where=%s\n"; static char storaddr[] = "storage address=%s port=%d ssl=0\n"; static char sessioncmd[] = "session %s %ld %ld %ld %ld %ld %ld\n"; @@ -237,7 +237,7 @@ int do_restore(JCR *jcr) where = ""; /* None */ } bash_spaces(where); - bnet_fsend(fd, restorecmd, replace, where); + bnet_fsend(fd, restorecmd, replace, jcr->prefix_links, where); unbash_spaces(where); if (!response(jcr, fd, OKrestore, "Restore", DISPLAY_ERROR)) { diff --git a/bacula/src/dird/ua_cmds.c b/bacula/src/dird/ua_cmds.c index 2e05678084..ccf346e862 100644 --- a/bacula/src/dird/ua_cmds.c +++ b/bacula/src/dird/ua_cmds.c @@ -617,18 +617,18 @@ static int update_cmd(UAContext *ua, char *cmd) } switch (find_arg_keyword(ua, kw)) { - case 0: - case 1: - update_volume(ua); - return 1; - case 2: - update_pool(ua); - return 1; - case 3: - update_slots(ua); - return 1; - default: - break; + case 0: + case 1: + update_volume(ua); + return 1; + case 2: + update_pool(ua); + return 1; + case 3: + update_slots(ua); + return 1; + default: + break; } start_prompt(ua, _("Update choice:\n")); @@ -636,21 +636,142 @@ static int update_cmd(UAContext *ua, char *cmd) add_prompt(ua, _("Pool from resource")); add_prompt(ua, _("Slots from autochanger")); switch (do_prompt(ua, _("item"), _("Choose catalog item to update"), NULL, 0)) { - case 0: - update_volume(ua); - break; - case 1: - update_pool(ua); - break; - case 2: - update_slots(ua); - break; - default: - break; + case 0: + update_volume(ua); + break; + case 1: + update_pool(ua); + break; + case 2: + update_slots(ua); + break; + default: + break; } return 1; } +static void update_volstatus(UAContext *ua, char *val, MEDIA_DBR *mr) +{ + POOLMEM *query = get_pool_memory(PM_MESSAGE); + bstrncpy(mr->VolStatus, val, sizeof(mr->VolStatus)); + Mmsg(&query, "UPDATE Media SET VolStatus='%s' WHERE MediaId=%u", + mr->VolStatus, mr->MediaId); + if (!db_sql_query(ua->db, query, NULL, NULL)) { + bsendmsg(ua, "%s", db_strerror(ua->db)); + } else { + bsendmsg(ua, _("New Volume status is: %s\n"), mr->VolStatus); + } + free_pool_memory(query); +} + +static void update_volretention(UAContext *ua, char *val, MEDIA_DBR *mr) +{ + char ed1[50]; + POOLMEM *query = get_pool_memory(PM_MESSAGE); + if (!duration_to_utime(val, &mr->VolRetention)) { + bsendmsg(ua, _("Invalid retention period specified.\n")); + return; + } + Mmsg(&query, "UPDATE Media SET VolRetention=%s WHERE MediaId=%u", + edit_uint64(mr->VolRetention, ed1), mr->MediaId); + if (!db_sql_query(ua->db, query, NULL, NULL)) { + bsendmsg(ua, "%s", db_strerror(ua->db)); + } else { + bsendmsg(ua, _("New retention seconds is: %s\n"), + edit_utime(mr->VolRetention, ed1)); + } + free_pool_memory(query); +} + +static void update_voluseduration(UAContext *ua, char *val, MEDIA_DBR *mr) +{ + char ed1[50]; + POOLMEM *query = get_pool_memory(PM_MESSAGE); + if (!duration_to_utime(val, &mr->VolUseDuration)) { + bsendmsg(ua, _("Invalid use duration specified.\n")); + return; + } + query = get_pool_memory(PM_MESSAGE); + Mmsg(&query, "UPDATE Media SET VolUseDuration=%s WHERE MediaId=%u", + edit_uint64(mr->VolUseDuration, ed1), mr->MediaId); + if (!db_sql_query(ua->db, query, NULL, NULL)) { + bsendmsg(ua, "%s", db_strerror(ua->db)); + } else { + bsendmsg(ua, _("New use duration is: %s\n"), + edit_utime(mr->VolUseDuration, ed1)); + } + free_pool_memory(query); +} + +static void update_volmaxjobs(UAContext *ua, char *val, MEDIA_DBR *mr) +{ + POOLMEM *query = get_pool_memory(PM_MESSAGE); + Mmsg(&query, "UPDATE Media SET MaxVolJobs=%s WHERE MediaId=%u", + val, mr->MediaId); + if (!db_sql_query(ua->db, query, NULL, NULL)) { + bsendmsg(ua, "%s", db_strerror(ua->db)); + } else { + bsendmsg(ua, _("New max jobs is: %s\n"), val); + } + free_pool_memory(query); +} + +static void update_volmaxfiles(UAContext *ua, char *val, MEDIA_DBR *mr) +{ + POOLMEM *query = get_pool_memory(PM_MESSAGE); + Mmsg(&query, "UPDATE Media SET MaxVolFiles=%s WHERE MediaId=%u", + val, mr->MediaId); + if (!db_sql_query(ua->db, query, NULL, NULL)) { + bsendmsg(ua, "%s", db_strerror(ua->db)); + } else { + bsendmsg(ua, _("New max files is: %s\n"), val); + } + free_pool_memory(query); +} + +static void update_volmaxbytes(UAContext *ua, char *val, MEDIA_DBR *mr) +{ + uint64_t maxbytes; + char ed1[50]; + POOLMEM *query = get_pool_memory(PM_MESSAGE); + if (!size_to_uint64(val, strlen(val), &maxbytes)) { + bsendmsg(ua, _("Invalid byte size specification.\n")); + return; + } + Mmsg(&query, "UPDATE Media SET MaxVolBytes=%s WHERE MediaId=%u", + edit_uint64(maxbytes, ed1), mr->MediaId); + if (!db_sql_query(ua->db, query, NULL, NULL)) { + bsendmsg(ua, "%s", db_strerror(ua->db)); + } else { + bsendmsg(ua, _("New Max bytes is: %s\n"), edit_uint64(maxbytes, ed1)); + } + free_pool_memory(query); +} + +static void update_volrecycle(UAContext *ua, char *val, MEDIA_DBR *mr) +{ + int recycle; + POOLMEM *query = get_pool_memory(PM_MESSAGE); + if (strcasecmp(val, _("yes")) == 0) { + recycle = 1; + } else if (strcasecmp(val, _("no")) == 0) { + recycle = 0; + } else { + bsendmsg(ua, _("Invalid value. It must by yes or no.\n")); + return; + } + Mmsg(&query, "UPDATE Media SET Recycle=%d WHERE MediaId=%u", + recycle, mr->MediaId); + if (!db_sql_query(ua->db, query, NULL, NULL)) { + bsendmsg(ua, "%s", db_strerror(ua->db)); + } else { + bsendmsg(ua, _("New recycle flag is: %s\n"), + mr->Recycle==1?_("yes"):_("no")); + } + free_pool_memory(query); +} + /* * Update a media record -- allows you to change the * Volume status. E.g. if you want Bacula to stop @@ -662,9 +783,31 @@ static int update_volume(UAContext *ua) MEDIA_DBR mr; POOLMEM *query; char ed1[30]; + bool done = false; + char *kw[] = { + N_("VolStatus"), + N_("VolRetention"), + N_("VolUse"), + N_("MaxVolJobs"), + N_("MaxVolFiles"), + N_("Recycle"), + NULL }; + if (!select_media_dbr(ua, &mr)) { + return 0; + } + for (int i=0; kw[i]; i++) { + if (find_arg_with_value(ua, kw[i]) > 0) { + switch (i) { + case 0: + update_volstatus(ua, ua->argv[i], &mr); + break; + } + done = true; + } + } - for (int done=0; !done; ) { + for ( ; !done; ) { if (!select_media_dbr(ua, &mr)) { return 0; } @@ -698,16 +841,7 @@ static int update_volume(UAContext *ua) if (do_prompt(ua, "", _("Choose new Volume Status"), ua->cmd, sizeof(mr.VolStatus)) < 0) { return 1; } - bstrncpy(mr.VolStatus, ua->cmd, sizeof(mr.VolStatus)); - query = get_pool_memory(PM_MESSAGE); - Mmsg(&query, "UPDATE Media SET VolStatus='%s' WHERE MediaId=%u", - mr.VolStatus, mr.MediaId); - if (!db_sql_query(ua->db, query, NULL, NULL)) { - bsendmsg(ua, "%s", db_strerror(ua->db)); - } else { - bsendmsg(ua, _("New Volume status is: %s\n"), mr.VolStatus); - } - free_pool_memory(query); + update_volstatus(ua, ua->cmd, &mr); break; case 1: /* Retention */ bsendmsg(ua, _("Current retention seconds is: %s\n"), @@ -715,20 +849,7 @@ static int update_volume(UAContext *ua) if (!get_cmd(ua, _("Enter Volume Retention period: "))) { return 0; } - if (!duration_to_utime(ua->cmd, &mr.VolRetention)) { - bsendmsg(ua, _("Invalid retention period specified.\n")); - break; - } - query = get_pool_memory(PM_MESSAGE); - Mmsg(&query, "UPDATE Media SET VolRetention=%s WHERE MediaId=%u", - edit_uint64(mr.VolRetention, ed1), mr.MediaId); - if (!db_sql_query(ua->db, query, NULL, NULL)) { - bsendmsg(ua, "%s", db_strerror(ua->db)); - } else { - bsendmsg(ua, _("New retention seconds is: %s\n"), - edit_utime(mr.VolRetention, ed1)); - } - free_pool_memory(query); + update_volretention(ua, ua->cmd, &mr); break; case 2: /* Use Duration */ @@ -737,98 +858,41 @@ static int update_volume(UAContext *ua) if (!get_cmd(ua, _("Enter Volume Use Duration: "))) { return 0; } - if (!duration_to_utime(ua->cmd, &mr.VolUseDuration)) { - bsendmsg(ua, _("Invalid use duration specified.\n")); - break; - } - query = get_pool_memory(PM_MESSAGE); - Mmsg(&query, "UPDATE Media SET VolUseDuration=%s WHERE MediaId=%u", - edit_uint64(mr.VolUseDuration, ed1), mr.MediaId); - if (!db_sql_query(ua->db, query, NULL, NULL)) { - bsendmsg(ua, "%s", db_strerror(ua->db)); - } else { - bsendmsg(ua, _("New use duration is: %s\n"), - edit_utime(mr.VolUseDuration, ed1)); - } - free_pool_memory(query); + update_voluseduration(ua, ua->cmd, &mr); break; case 3: /* Max Jobs */ - int32_t maxjobs; bsendmsg(ua, _("Current max jobs is: %u\n"), mr.MaxVolJobs); if (!get_pint(ua, _("Enter new Maximum Jobs: "))) { return 0; } - maxjobs = ua->pint32_val; - query = get_pool_memory(PM_MESSAGE); - Mmsg(&query, "UPDATE Media SET MaxVolJobs=%u WHERE MediaId=%u", - maxjobs, mr.MediaId); - if (!db_sql_query(ua->db, query, NULL, NULL)) { - bsendmsg(ua, "%s", db_strerror(ua->db)); - } else { - bsendmsg(ua, _("New max jobs is: %u\n"), maxjobs); - } - free_pool_memory(query); + update_volmaxjobs(ua, ua->cmd, &mr); break; case 4: /* Max Files */ - int32_t maxfiles; bsendmsg(ua, _("Current max files is: %u\n"), mr.MaxVolFiles); if (!get_pint(ua, _("Enter new Maximum Files: "))) { return 0; } - maxfiles = ua->pint32_val; - query = get_pool_memory(PM_MESSAGE); - Mmsg(&query, "UPDATE Media SET MaxVolFiles=%u WHERE MediaId=%u", - maxfiles, mr.MediaId); - if (!db_sql_query(ua->db, query, NULL, NULL)) { - bsendmsg(ua, "%s", db_strerror(ua->db)); - } else { - bsendmsg(ua, _("New max files is: %u\n"), maxfiles); - } - free_pool_memory(query); + update_volmaxfiles(ua, ua->cmd, &mr); break; case 5: /* Max Bytes */ - uint64_t maxbytes; bsendmsg(ua, _("Current value is: %s\n"), edit_uint64(mr.MaxVolBytes, ed1)); if (!get_cmd(ua, _("Enter new Maximum Bytes: "))) { return 0; } - if (!size_to_uint64(ua->cmd, strlen(ua->cmd), &maxbytes)) { - bsendmsg(ua, _("Invalid byte size specification.\n")); - break; - } - query = get_pool_memory(PM_MESSAGE); - Mmsg(&query, "UPDATE Media SET MaxVolBytes=%s WHERE MediaId=%u", - edit_uint64(maxbytes, ed1), mr.MediaId); - if (!db_sql_query(ua->db, query, NULL, NULL)) { - bsendmsg(ua, "%s", db_strerror(ua->db)); - } else { - bsendmsg(ua, _("New Max bytes is: %s\n"), edit_uint64(maxbytes, ed1)); - } - free_pool_memory(query); + update_volmaxbytes(ua, ua->cmd, &mr); break; case 6: /* Recycle */ - int recycle; bsendmsg(ua, _("Current recycle flag is: %s\n"), mr.Recycle==1?_("yes"):_("no")); if (!get_yesno(ua, _("Enter new Recycle status: "))) { return 0; } - recycle = ua->pint32_val; - query = get_pool_memory(PM_MESSAGE); - Mmsg(&query, "UPDATE Media SET Recycle=%d WHERE MediaId=%u", - recycle, mr.MediaId); - if (!db_sql_query(ua->db, query, NULL, NULL)) { - bsendmsg(ua, "%s", db_strerror(ua->db)); - } else { - bsendmsg(ua, _("New recycle flag is: %s\n"), - mr.Recycle==1?_("yes"):_("no")); - } - free_pool_memory(query); + update_volrecycle(ua, ua->cmd, &mr); break; case 7: /* Slot */ @@ -906,7 +970,6 @@ static int update_pool(UAContext *ua) POOL *pool; POOLMEM *query; - pool = get_pool_resource(ua); if (!pool) { return 0; @@ -981,7 +1044,6 @@ static void do_client_setdebug(UAContext *ua, CLIENT *client, int level) bnet_sig(fd, BNET_TERMINATE); bnet_close(fd); ua->jcr->file_bsock = NULL; - return; } @@ -1141,26 +1203,26 @@ static int setdebug_cmd(UAContext *ua, char *cmd) add_prompt(ua, _("Client")); add_prompt(ua, _("All")); switch(do_prompt(ua, "", _("Select daemon type to set debug level"), NULL, 0)) { - case 0: /* Director */ - debug_level = level; - break; - case 1: - store = get_storage_resource(ua, 0); - if (store) { - do_storage_setdebug(ua, store, level); - } - break; - case 2: - client = select_client_resource(ua); - if (client) { - do_client_setdebug(ua, client, level); - } - break; - case 3: - do_all_setdebug(ua, level); - break; - default: - break; + case 0: /* Director */ + debug_level = level; + break; + case 1: + store = get_storage_resource(ua, 0); + if (store) { + do_storage_setdebug(ua, store, level); + } + break; + case 2: + client = select_client_resource(ua); + if (client) { + do_client_setdebug(ua, client, level); + } + break; + case 3: + do_all_setdebug(ua, level); + break; + default: + break; } return 1; } @@ -1307,25 +1369,25 @@ static int delete_cmd(UAContext *ua, char *cmd) "Pool or a Volume since they may contain data.\n\n")); switch (find_arg_keyword(ua, keywords)) { - case 0: - delete_volume(ua); - return 1; - case 1: - delete_pool(ua); - return 1; - default: - break; + case 0: + delete_volume(ua); + return 1; + case 1: + delete_pool(ua); + return 1; + default: + break; } switch (do_keyword_prompt(ua, _("Choose catalog item to delete"), keywords)) { - case 0: - delete_volume(ua); - break; - case 1: - delete_pool(ua); - break; - default: - bsendmsg(ua, _("Nothing done.\n")); - break; + case 0: + delete_volume(ua); + break; + case 1: + delete_pool(ua); + break; + default: + bsendmsg(ua, _("Nothing done.\n")); + break; } return 1; } diff --git a/bacula/src/dird/ua_input.c b/bacula/src/dird/ua_input.c index 65505a716c..c0f3ea74ed 100644 --- a/bacula/src/dird/ua_input.c +++ b/bacula/src/dird/ua_input.c @@ -131,5 +131,5 @@ int get_yesno(UAContext *ua, char *prompt) void parse_ua_args(UAContext *ua) { - parse_args(ua->cmd, ua->args, &ua->argc, ua->argk, ua->argv, MAX_CMD_ARGS); + parse_args(ua->cmd, &ua->args, &ua->argc, ua->argk, ua->argv, MAX_CMD_ARGS); } diff --git a/bacula/src/dird/ua_restore.c b/bacula/src/dird/ua_restore.c index e169cfdf3b..02853da6f0 100644 --- a/bacula/src/dird/ua_restore.c +++ b/bacula/src/dird/ua_restore.c @@ -80,7 +80,6 @@ static void free_name_list(NAME_LIST *name_list); static void get_storage_from_mediatype(UAContext *ua, NAME_LIST *name_list, JOBIDS *ji); static int select_backups_before_date(UAContext *ua, JOBIDS *ji, char *date); - /* * Restore files * @@ -176,7 +175,6 @@ int restorecmd(UAContext *ua, char *cmd) if (!db_sql_query(ua->db, query, unique_name_list_handler, (void *)&name_list)) { bsendmsg(ua, "%s", db_strerror(ua->db)); } - } bsendmsg(ua, "%d item%s inserted into the tree and marked for extraction.\n", items, items==1?"":"s"); @@ -186,8 +184,10 @@ int restorecmd(UAContext *ua, char *cmd) get_storage_from_mediatype(ua, &name_list, &ji); free_name_list(&name_list); - /* Let the user select which files to restore */ - user_select_files_from_tree(&tree); + if (find_arg(ua, _("all")) < 0) { + /* Let the user select which files to restore */ + user_select_files_from_tree(&tree); + } /* * Walk down through the tree finding all files marked to be @@ -273,7 +273,8 @@ static int user_select_jobids(UAContext *ua, JOBIDS *ji) JobId_t JobId; JOB_DBR jr; POOLMEM *query; - int done = 0; + bool done = false; + int i; char *list[] = { "List last 20 Jobs run", "List Jobs where a given File is saved", @@ -284,23 +285,68 @@ static int user_select_jobids(UAContext *ua, JOBIDS *ji) "Cancel", NULL }; - bsendmsg(ua, _("\nFirst you select one or more JobIds that contain files\n" + char *kw[] = { + "jobid", /* 0 */ + "current", /* 1 */ + "before", /* 2 */ + NULL + }; + + switch (find_arg_keyword(ua, kw)) { + case 0: /* jobid */ + i = find_arg_with_value(ua, _("jobid")); + if (i < 0) { + return 0; + } + bstrncpy(ji->JobIds, ua->argv[i], sizeof(ji->JobIds)); + done = true; + break; + case 1: /* current */ + bstrutime(date, sizeof(date), time(NULL)); + if (!select_backups_before_date(ua, ji, date)) { + return 0; + } + done = true; + break; + case 2: /* before */ + i = find_arg_with_value(ua, _("before")); + if (i < 0) { + return 0; + } + if (str_to_utime(ua->argv[i]) == 0) { + bsendmsg(ua, _("Improper date format: %s\n"), ua->argv[i]); + return 0; + } + bstrncpy(date, ua->argv[i], sizeof(date)); + if (!select_backups_before_date(ua, ji, date)) { + return 0; + } + done = true; + break; + default: + break; + } + + if (!done) { + bsendmsg(ua, _("\nFirst you select one or more JobIds that contain files\n" "to be restored. You will be presented several methods\n" "of specifying the JobIds. Then you will be allowed to\n" "select which files from those JobIds are to be restored.\n\n")); + } + /* If choice not already made above, prompt */ for ( ; !done; ) { start_prompt(ua, _("To select the JobIds, you have the following choices:\n")); for (int i=0; list[i]; i++) { add_prompt(ua, list[i]); } - done = 1; + done = true; switch (do_prompt(ua, "", _("Select item: "), NULL, 0)) { case -1: /* error */ return 0; case 0: /* list last 20 Jobs run */ db_list_sql_query(ua->jcr, ua->db, uar_list_jobs, prtit, ua, 1, HORZ_LIST); - done = 0; + done = false; break; case 1: /* list where a file is saved */ char *fname; @@ -316,7 +362,7 @@ static int user_select_jobids(UAContext *ua, JOBIDS *ji) free(fname); db_list_sql_query(ua->jcr, ua->db, query, prtit, ua, 1, HORZ_LIST); free_pool_memory(query); - done = 0; + done = false; break; case 2: /* enter a list of JobIds */ if (!get_cmd(ua, _("Enter JobId(s), comma separated, to restore: "))) { @@ -329,7 +375,7 @@ static int user_select_jobids(UAContext *ua, JOBIDS *ji) return 0; } db_list_sql_query(ua->jcr, ua->db, ua->cmd, prtit, ua, 1, HORZ_LIST); - done = 0; + done = false; break; case 4: /* Select the most recent backups */ bstrutime(date, sizeof(date), time(NULL)); @@ -493,15 +539,14 @@ bail_out: return stat; } - +/* Return next JobId from comma separated list */ static int next_jobid_from_list(char **p, uint32_t *JobId) { char jobid[30]; - int i; char *q = *p; jobid[0] = 0; - for (i=0; i<(int)sizeof(jobid); i++) { + for (int i=0; i<(int)sizeof(jobid); i++) { if (*q == ',' || *q == 0) { q++; break; @@ -524,13 +569,13 @@ static int jobid_handler(void *ctx, int num_fields, char **row) { JOBIDS *ji = (JOBIDS *)ctx; + /* Concatenate a JobId if it does not exceed array size */ if (strlen(ji->JobIds)+strlen(row[0])+2 < sizeof(ji->JobIds)) { if (ji->JobIds[0] != 0) { strcat(ji->JobIds, ","); } strcat(ji->JobIds, row[0]); } - return 0; } @@ -597,9 +642,7 @@ static int unique_name_list_handler(void *ctx, int num_fields, char **row) */ static void print_name_list(UAContext *ua, NAME_LIST *name_list) { - int i; - - for (i=0; i < name_list->num_ids; i++) { + for (int i=0; i < name_list->num_ids; i++) { bsendmsg(ua, "%s\n", name_list->name[i]); } } @@ -610,9 +653,7 @@ static void print_name_list(UAContext *ua, NAME_LIST *name_list) */ static void free_name_list(NAME_LIST *name_list) { - int i; - - for (i=0; i < name_list->num_ids; i++) { + for (int i=0; i < name_list->num_ids; i++) { free(name_list->name[i]); } if (name_list->name) { diff --git a/bacula/src/dird/ua_run.c b/bacula/src/dird/ua_run.c index 8275e19834..6dadd3dfff 100644 --- a/bacula/src/dird/ua_run.c +++ b/bacula/src/dird/ua_run.c @@ -447,6 +447,15 @@ When: %s\n"), free_jcr(jcr); return 0; } + + /* Run without prompting? */ + if (find_arg(ua, _("yes")) > 0) { + Dmsg1(200, "Calling run_job job=%x\n", jcr->job); + run_job(jcr); + bsendmsg(ua, _("Run command submitted.\n")); + return 1; + } + if (!get_cmd(ua, _("OK to run? (yes/mod/no): "))) { free_jcr(jcr); return 0; /* do not run */ @@ -655,6 +664,7 @@ When: %s\n"), free_jcr(jcr); return 0; /* error do no run Job */ } + if (strncasecmp(ua->cmd, _("yes"), strlen(ua->cmd)) == 0) { Dmsg1(200, "Calling run_job job=%x\n", jcr->job); run_job(jcr); diff --git a/bacula/src/dird/ua_select.c b/bacula/src/dird/ua_select.c index 39cf261c8c..f3afec0d05 100644 --- a/bacula/src/dird/ua_select.c +++ b/bacula/src/dird/ua_select.c @@ -74,9 +74,8 @@ int confirm_retention(UAContext *ua, utime_t *ret, char *msg) */ int find_arg_keyword(UAContext *ua, char **list) { - int i, j; - for (i=1; iargc; i++) { - for(j=0; list[j]; j++) { + for (int i=1; iargc; i++) { + for(int j=0; list[j]; j++) { if (strcasecmp(_(list[j]), ua->argk[i]) == 0) { return j; } @@ -85,11 +84,6 @@ int find_arg_keyword(UAContext *ua, char **list) return -1; } -/* - * Given a single keyword, find it in the argument list. - * Returns: -1 if not found - * list index (base 0) on success - */ int find_arg(UAContext *ua, char *keyword) { for (int i=1; iargc; i++) { @@ -100,6 +94,12 @@ int find_arg(UAContext *ua, char *keyword) return -1; } +/* + * Given a single keyword, find it in the argument list, but + * it must have a value + * Returns: -1 if not found or no value + * list index (base 0) on success + */ int find_arg_with_value(UAContext *ua, char *keyword) { for (int i=1; iargc; i++) { @@ -114,8 +114,6 @@ int find_arg_with_value(UAContext *ua, char *keyword) return -1; } - - /* * Given a list of keywords, prompt the user * to choose one. diff --git a/bacula/src/dird/ua_server.c b/bacula/src/dird/ua_server.c index eb5470c0f1..ef0832930d 100644 --- a/bacula/src/dird/ua_server.c +++ b/bacula/src/dird/ua_server.c @@ -147,8 +147,7 @@ static void *handle_UA_client_request(void *arg) while (!ua->quit) { stat = bnet_recv(ua->UA_sock); if (stat >= 0) { - ua->cmd = check_pool_memory_size(ua->cmd, ua->UA_sock->msglen+1); - bstrncpy(ua->cmd, ua->UA_sock->msg, ua->UA_sock->msglen+1); + pm_strcpy(&ua->cmd, ua->UA_sock->msg); parse_ua_args(ua); if (ua->argc > 0 && ua->argk[0][0] == '.') { do_a_dot_command(ua, ua->cmd); diff --git a/bacula/src/filed/job.c b/bacula/src/filed/job.c index da51fed3b9..8c6652c441 100644 --- a/bacula/src/filed/job.c +++ b/bacula/src/filed/job.c @@ -90,8 +90,8 @@ static struct s_cmds cmds[] = { static char jobcmd[] = "JobId=%d Job=%127s SDid=%d SDtime=%d Authorization=%100s"; static char storaddr[] = "storage address=%s port=%d ssl=%d\n"; static char sessioncmd[] = "session %127s %ld %ld %ld %ld %ld %ld\n"; -static char restorecmd[] = "restore replace=%c where=%s\n"; -static char restorecmd1[] = "restore replace=%c where=\n"; +static char restorecmd[] = "restore replace=%c prelinks=%d where=%s\n"; +static char restorecmd1[] = "restore replace=%c prelinks=%d where=\n"; static char verifycmd[] = "verify level=%30s\n"; static char estimatecmd[] = "estimate listing=%d\n"; @@ -741,6 +741,7 @@ static int restore_cmd(JCR *jcr) BSOCK *dir = jcr->dir_bsock; BSOCK *sd = jcr->store_bsock; POOLMEM *where; + int prefix_links; char replace; char ed1[50], ed2[50]; @@ -752,8 +753,8 @@ static int restore_cmd(JCR *jcr) where = get_memory(dir->msglen+1); *where = 0; - if (sscanf(dir->msg, restorecmd, &replace, where) != 2) { - if (sscanf(dir->msg, restorecmd1, &replace) != 1) { + if (sscanf(dir->msg, restorecmd, &replace, &prefix_links, where) != 3) { + if (sscanf(dir->msg, restorecmd1, &replace, &prefix_links) != 2) { pm_strcpy(&jcr->errmsg, dir->msg); Jmsg(jcr, M_FATAL, 0, _("Bad replace command. CMD=%s\n"), jcr->errmsg); return 0; @@ -770,6 +771,7 @@ static int restore_cmd(JCR *jcr) jcr->where = bstrdup(where); free_pool_memory(where); jcr->replace = replace; + jcr->prefix_links = prefix_links; bnet_fsend(dir, OKrestore); Dmsg1(110, "bfiled>dird: %s", dir->msg); diff --git a/bacula/src/findlib/find.h b/bacula/src/findlib/find.h index 0cca05390e..7251b7f03e 100755 --- a/bacula/src/findlib/find.h +++ b/bacula/src/findlib/find.h @@ -105,14 +105,14 @@ struct s_excluded_file { * Definition of the find_files packet passed as the * first argument to the find_files callback subroutine. */ -typedef struct s_ff { +struct FF_PKT { char *fname; /* filename */ char *link; /* link if file linked */ POOLMEM *sys_fname; /* system filename */ struct stat statp; /* stat packet */ - uint32_t FileIndex; /* FileIndex of this file */ - uint32_t LinkFI; /* FileIndex of main hard linked file */ - struct f_link *linked; /* Set if we are hard linked */ + int32_t FileIndex; /* FileIndex of this file */ + int32_t LinkFI; /* FileIndex of main hard linked file */ + struct f_link *linked; /* Set if this file is hard linked */ int type; /* FT_ type from above */ uint32_t flags; /* control flags */ int ff_errno; /* errno */ @@ -129,8 +129,9 @@ typedef struct s_ff { struct s_excluded_file *excluded_files_list; struct s_excluded_file *excluded_paths_list; + /* List of all hard linked files found */ struct f_link *linklist; /* hard linked files */ -} FF_PKT; +}; #include "protos.h" diff --git a/bacula/src/findlib/match.c b/bacula/src/findlib/match.c index 4a66dab5c2..823e3b5a10 100644 --- a/bacula/src/findlib/match.c +++ b/bacula/src/findlib/match.c @@ -103,54 +103,54 @@ void add_fname_to_include_list(FF_PKT *ff, int prefixed, char *fname) if (prefixed) { for (p=fname; *p && *p != ' '; p++) { switch (*p) { - case 'a': /* alway replace */ - case '0': /* no option */ - break; - case 'f': - inc->options |= FO_MULTIFS; - break; - case 'h': /* no recursion */ - inc->options |= FO_NO_RECURSION; - break; - case 'M': /* MD5 */ - inc->options |= FO_MD5; - break; - case 'n': - inc->options |= FO_NOREPLACE; - break; - case 'p': /* use portable data format */ - inc->options |= FO_PORTABLE; - break; - case 'r': /* read fifo */ - inc->options |= FO_READFIFO; - break; - case 'S': - inc->options |= FO_SHA1; - break; - case 's': - inc->options |= FO_SPARSE; - break; - case 'V': /* verify options */ - /* Copy Verify Options */ - for (j=0; *p && *p != ':'; p++) { - inc->VerifyOpts[j] = *p; - if (j < (int)sizeof(inc->VerifyOpts) - 1) { - j++; - } + case 'a': /* alway replace */ + case '0': /* no option */ + break; + case 'f': + inc->options |= FO_MULTIFS; + break; + case 'h': /* no recursion */ + inc->options |= FO_NO_RECURSION; + break; + case 'M': /* MD5 */ + inc->options |= FO_MD5; + break; + case 'n': + inc->options |= FO_NOREPLACE; + break; + case 'p': /* use portable data format */ + inc->options |= FO_PORTABLE; + break; + case 'r': /* read fifo */ + inc->options |= FO_READFIFO; + break; + case 'S': + inc->options |= FO_SHA1; + break; + case 's': + inc->options |= FO_SPARSE; + break; + case 'V': /* verify options */ + /* Copy Verify Options */ + for (j=0; *p && *p != ':'; p++) { + inc->VerifyOpts[j] = *p; + if (j < (int)sizeof(inc->VerifyOpts) - 1) { + j++; } - inc->VerifyOpts[j] = 0; - break; - case 'w': - inc->options |= FO_IF_NEWER; - break; - case 'Z': /* gzip compression */ - inc->options |= FO_GZIP; - inc->level = *++p - '0'; - Dmsg1(200, "Compression level=%d\n", inc->level); - break; - default: - Emsg1(M_ERROR, 0, "Unknown include/exclude option: %c\n", *p); - break; + } + inc->VerifyOpts[j] = 0; + break; + case 'w': + inc->options |= FO_IF_NEWER; + break; + case 'Z': /* gzip compression */ + inc->options |= FO_GZIP; + inc->level = *++p - '0'; + Dmsg1(200, "Compression level=%d\n", inc->level); + break; + default: + Emsg1(M_ERROR, 0, "Unknown include/exclude option: %c\n", *p); + break; } } /* Skip past space(s) */ diff --git a/bacula/src/lib/mem_pool.h b/bacula/src/lib/mem_pool.h index 6c7c928bda..96fa5a7de8 100644 --- a/bacula/src/lib/mem_pool.h +++ b/bacula/src/lib/mem_pool.h @@ -25,6 +25,10 @@ */ +#ifndef __MEM_POOL_H_ +#define __MEM_POOL_H_ + + #ifdef SMARTALLOC #define get_pool_memory(pool) sm_get_pool_memory(__FILE__, __LINE__, pool) @@ -68,3 +72,5 @@ extern void print_memory_pool_stats(); #define PM_MESSAGE 3 /* daemon message */ #define PM_EMSG 4 /* error message */ #define PM_MAX PM_EMSG /* Number of types */ + +#endif diff --git a/bacula/src/lib/protos.h b/bacula/src/lib/protos.h index 9b3516831e..130656d3d1 100644 --- a/bacula/src/lib/protos.h +++ b/bacula/src/lib/protos.h @@ -26,159 +26,159 @@ struct JCR; /* attr.c */ -ATTR *new_attr(); -void free_attr(ATTR *attr); -int unpack_attributes_record(JCR *jcr, int32_t stream, char *rec, ATTR *attr); -void build_attr_output_fnames(JCR *jcr, ATTR *attr); -void print_ls_output(JCR *jcr, ATTR *attr); +ATTR *new_attr(); +void free_attr(ATTR *attr); +int unpack_attributes_record(JCR *jcr, int32_t stream, char *rec, ATTR *attr); +void build_attr_output_fnames(JCR *jcr, ATTR *attr); +void print_ls_output(JCR *jcr, ATTR *attr); /* base64.c */ -void base64_init (void); -int to_base64 (intmax_t value, char *where); -int from_base64 (intmax_t *value, char *where); -int bin_to_base64 (char *buf, char *bin, int len); +void base64_init (void); +int to_base64 (intmax_t value, char *where); +int from_base64 (intmax_t *value, char *where); +int bin_to_base64 (char *buf, char *bin, int len); /* bsys.c */ -char *bstrncpy (char *dest, const char *src, int maxlen); -char *bstrncat (char *dest, const char *src, int maxlen); -void *b_malloc (char *file, int line, size_t size); +char *bstrncpy (char *dest, const char *src, int maxlen); +char *bstrncat (char *dest, const char *src, int maxlen); +void *b_malloc (char *file, int line, size_t size); #ifndef DEBUG -void *bmalloc (size_t size); +void *bmalloc (size_t size); #endif -void *brealloc (void *buf, size_t size); -void *bcalloc (size_t size1, size_t size2); -int bsnprintf (char *str, size_t size, const char *format, ...); -int bvsnprintf (char *str, size_t size, const char *format, va_list ap); -int pool_sprintf (char *pool_buf, char *fmt, ...); -void create_pid_file (char *dir, char *progname, int port); -int delete_pid_file (char *dir, char *progname, int port); -void drop (char *uid, char *gid); -int bmicrosleep (time_t sec, long msec); -char *bfgets (char *s, int size, FILE *fd); +void *brealloc (void *buf, size_t size); +void *bcalloc (size_t size1, size_t size2); +int bsnprintf (char *str, size_t size, const char *format, ...); +int bvsnprintf (char *str, size_t size, const char *format, va_list ap); +int pool_sprintf (char *pool_buf, char *fmt, ...); +void create_pid_file (char *dir, char *progname, int port); +int delete_pid_file (char *dir, char *progname, int port); +void drop (char *uid, char *gid); +int bmicrosleep (time_t sec, long msec); +char *bfgets (char *s, int size, FILE *fd); #ifndef HAVE_STRTOLL -long long int strtoll (const char *ptr, char **endptr, int base); +long long int strtoll (const char *ptr, char **endptr, int base); #endif /* bnet.c */ -int32_t bnet_recv (BSOCK *bsock); -int bnet_send (BSOCK *bsock); -int bnet_fsend (BSOCK *bs, char *fmt, ...); -int bnet_set_buffer_size (BSOCK *bs, uint32_t size, int rw); -int bnet_sig (BSOCK *bs, int sig); -int bnet_ssl_server (BSOCK *bsock, char *password, int ssl_need, int ssl_has); -int bnet_ssl_client (BSOCK *bsock, char *password, int ssl_need); -BSOCK * bnet_connect (JCR *jcr, int retry_interval, - int max_retry_time, char *name, char *host, char *service, - int port, int verbose); -void bnet_close (BSOCK *bsock); -BSOCK * init_bsock (JCR *jcr, int sockfd, char *who, char *ip, int port); -BSOCK * dup_bsock (BSOCK *bsock); -void term_bsock (BSOCK *bsock); -char * bnet_strerror (BSOCK *bsock); -char * bnet_sig_to_ascii (BSOCK *bsock); -int bnet_wait_data (BSOCK *bsock, int sec); -int bnet_wait_data_intr (BSOCK *bsock, int sec); -int bnet_despool (BSOCK *bsock); -int is_bnet_stop (BSOCK *bsock); -int is_bnet_error (BSOCK *bsock); -void bnet_suppress_error_messages(BSOCK *bsock, int flag); +int32_t bnet_recv (BSOCK *bsock); +int bnet_send (BSOCK *bsock); +int bnet_fsend (BSOCK *bs, char *fmt, ...); +int bnet_set_buffer_size (BSOCK *bs, uint32_t size, int rw); +int bnet_sig (BSOCK *bs, int sig); +int bnet_ssl_server (BSOCK *bsock, char *password, int ssl_need, int ssl_has); +int bnet_ssl_client (BSOCK *bsock, char *password, int ssl_need); +BSOCK * bnet_connect (JCR *jcr, int retry_interval, + int max_retry_time, char *name, char *host, char *service, + int port, int verbose); +void bnet_close (BSOCK *bsock); +BSOCK * init_bsock (JCR *jcr, int sockfd, char *who, char *ip, int port); +BSOCK * dup_bsock (BSOCK *bsock); +void term_bsock (BSOCK *bsock); +char * bnet_strerror (BSOCK *bsock); +char * bnet_sig_to_ascii (BSOCK *bsock); +int bnet_wait_data (BSOCK *bsock, int sec); +int bnet_wait_data_intr (BSOCK *bsock, int sec); +int bnet_despool (BSOCK *bsock); +int is_bnet_stop (BSOCK *bsock); +int is_bnet_error (BSOCK *bsock); +void bnet_suppress_error_messages(BSOCK *bsock, int flag); /* bget_msg.c */ -int bget_msg(BSOCK *sock); +int bget_msg(BSOCK *sock); /* bpipe.c */ -BPIPE * open_bpipe(char *prog, int wait, char *mode); -int close_wpipe(BPIPE *bpipe); -int close_bpipe(BPIPE *bpipe); +BPIPE * open_bpipe(char *prog, int wait, char *mode); +int close_wpipe(BPIPE *bpipe); +int close_bpipe(BPIPE *bpipe); /* cram-md5.c */ int cram_md5_get_auth(BSOCK *bs, char *password, int ssl_need); int cram_md5_auth(BSOCK *bs, char *password, int ssl_need); void hmac_md5(uint8_t* text, int text_len, uint8_t* key, - int key_len, uint8_t *hmac); + int key_len, uint8_t *hmac); /* crc32.c */ uint32_t bcrc32(uint8_t *buf, int len); /* daemon.c */ -void daemon_start (); +void daemon_start (); /* edit.c */ -uint64_t str_to_uint64(char *str); -int64_t str_to_int64(char *str); -char * edit_uint64_with_commas (uint64_t val, char *buf); -char * add_commas (char *val, char *buf); -char * edit_uint64 (uint64_t val, char *buf); -int duration_to_utime (char *str, utime_t *value); -int size_to_uint64(char *str, int str_len, uint64_t *rtn_value); -char *edit_utime (utime_t val, char *buf); -int is_a_number (const char *num); -int is_an_integer (const char *n); +uint64_t str_to_uint64(char *str); +int64_t str_to_int64(char *str); +char * edit_uint64_with_commas (uint64_t val, char *buf); +char * add_commas (char *val, char *buf); +char * edit_uint64 (uint64_t val, char *buf); +int duration_to_utime (char *str, utime_t *value); +int size_to_uint64(char *str, int str_len, uint64_t *rtn_value); +char *edit_utime (utime_t val, char *buf); +int is_a_number (const char *num); +int is_an_integer (const char *n); /* lex.c */ -LEX * lex_close_file (LEX *lf); -LEX * lex_open_file (LEX *lf, char *fname, LEX_ERROR_HANDLER *scan_error); -int lex_get_char (LEX *lf); -void lex_unget_char (LEX *lf); -char * lex_tok_to_str (int token); -int lex_get_token (LEX *lf, int expect); +LEX * lex_close_file (LEX *lf); +LEX * lex_open_file (LEX *lf, char *fname, LEX_ERROR_HANDLER *scan_error); +int lex_get_char (LEX *lf); +void lex_unget_char (LEX *lf); +char * lex_tok_to_str (int token); +int lex_get_token (LEX *lf, int expect); /* message.c */ -void my_name_is (int argc, char *argv[], char *name); -void init_msg (JCR *jcr, MSGS *msg); -void term_msg (void); -void close_msg (JCR *jcr); -void add_msg_dest (MSGS *msg, int dest, int type, char *where, char *dest_code); -void rem_msg_dest (MSGS *msg, int dest, int type, char *where); -void Jmsg (JCR *jcr, int type, int level, char *fmt, ...); -void dispatch_message (JCR *jcr, int type, int level, char *buf); -void init_console_msg (char *wd); -void free_msgs_res (MSGS *msgs); -int open_spool_file (JCR *jcr, BSOCK *bs); -int close_spool_file (JCR *jcr, BSOCK *bs); +void my_name_is (int argc, char *argv[], char *name); +void init_msg (JCR *jcr, MSGS *msg); +void term_msg (void); +void close_msg (JCR *jcr); +void add_msg_dest (MSGS *msg, int dest, int type, char *where, char *dest_code); +void rem_msg_dest (MSGS *msg, int dest, int type, char *where); +void Jmsg (JCR *jcr, int type, int level, char *fmt, ...); +void dispatch_message (JCR *jcr, int type, int level, char *buf); +void init_console_msg (char *wd); +void free_msgs_res (MSGS *msgs); +int open_spool_file (JCR *jcr, BSOCK *bs); +int close_spool_file (JCR *jcr, BSOCK *bs); /* bnet_server.c */ -void bnet_thread_server(char *bind_addr, int port, int max_clients, workq_t *client_wq, - void *handle_client_request(void *bsock)); -void bnet_server (int port, void handle_client_request(BSOCK *bsock)); -int net_connect (int port); -BSOCK * bnet_bind (int port); -BSOCK * bnet_accept (BSOCK *bsock, char *who); +void bnet_thread_server(char *bind_addr, int port, int max_clients, workq_t *client_wq, + void *handle_client_request(void *bsock)); +void bnet_server (int port, void handle_client_request(BSOCK *bsock)); +int net_connect (int port); +BSOCK * bnet_bind (int port); +BSOCK * bnet_accept (BSOCK *bsock, char *who); /* signal.c */ -void init_signals (void terminate(int sig)); -void init_stack_dump (void); +void init_signals (void terminate(int sig)); +void init_stack_dump (void); /* scan.c */ -void strip_trailing_junk (char *str); -void strip_trailing_slashes (char *dir); -int skip_spaces (char **msg); -int skip_nonspaces (char **msg); -int fstrsch (char *a, char *b); -int parse_args(POOLMEM *cmd, POOLMEM *args, int *argc, - char **argk, char **argv, int max_args); -char *next_arg(char **s); +void strip_trailing_junk (char *str); +void strip_trailing_slashes (char *dir); +int skip_spaces (char **msg); +int skip_nonspaces (char **msg); +int fstrsch (char *a, char *b); +int parse_args(POOLMEM *cmd, POOLMEM **args, int *argc, + char **argk, char **argv, int max_args); +char *next_arg(char **s); /* util.c */ -int is_buf_zero (char *buf, int len); -void lcase (char *str); -void bash_spaces (char *str); -void unbash_spaces (char *str); -char * encode_time (time_t time, char *buf); -char * encode_mode (mode_t mode, char *buf); -int do_shell_expansion (char *name, int name_len); -void jobstatus_to_ascii (int JobStatus, char *msg, int maxlen); -void pm_strcat (POOLMEM **pm, char *str); -void pm_strcpy (POOLMEM **pm, char *str); -int run_program (char *prog, int wait, POOLMEM *results); -char * job_type_to_str (int type); -char * job_status_to_str (int stat); -char * job_level_to_str (int level); -void make_session_key (char *key, char *seed, int mode); -POOLMEM *edit_job_codes(JCR *jcr, char *omsg, char *imsg, char *to); -void set_working_directory(char *wd); +int is_buf_zero (char *buf, int len); +void lcase (char *str); +void bash_spaces (char *str); +void unbash_spaces (char *str); +char * encode_time (time_t time, char *buf); +char * encode_mode (mode_t mode, char *buf); +int do_shell_expansion (char *name, int name_len); +void jobstatus_to_ascii (int JobStatus, char *msg, int maxlen); +void pm_strcat (POOLMEM **pm, char *str); +void pm_strcpy (POOLMEM **pm, char *str); +int run_program (char *prog, int wait, POOLMEM *results); +char * job_type_to_str (int type); +char * job_status_to_str (int stat); +char * job_level_to_str (int level); +void make_session_key (char *key, char *seed, int mode); +POOLMEM *edit_job_codes(JCR *jcr, char *omsg, char *imsg, char *to); +void set_working_directory(char *wd); /* watchdog.c */ diff --git a/bacula/src/lib/scan.c b/bacula/src/lib/scan.c index 376e3fd393..2a80ad2b18 100644 --- a/bacula/src/lib/scan.c +++ b/bacula/src/lib/scan.c @@ -188,18 +188,15 @@ char *next_arg(char **s) * argv[2] = */ -int parse_args(POOLMEM *cmd, POOLMEM *args, int *argc, +int parse_args(POOLMEM *cmd, POOLMEM **args, int *argc, char **argk, char **argv, int max_args) { char *p, *q, *n; - int len; - len = strlen(cmd) + 1; - args = check_pool_memory_size(args, len); - bstrncpy(args, cmd, len); - strip_trailing_junk(args); + pm_strcpy(args, cmd); + strip_trailing_junk(*args); + p = *args; *argc = 0; - p = args; /* Pick up all arguments */ while (*argc < max_args) { n = next_arg(&p); @@ -232,10 +229,10 @@ int parse_args(POOLMEM *cmd, POOLMEM *args, int *argc, } argv[i] = p; /* save ptr to value or NULL */ } - return 1; #ifdef xxxx - for (i=0; iVolFirstIndex = 0; + jcr->VolFirstIndex = jcr->VolLastIndex = 0; jcr->run_time = time(NULL); /* start counting time for rates */ for (last_file_index = 0; ok && !job_canceled(jcr); ) { @@ -161,10 +161,6 @@ int do_append_data(JCR *jcr) } if (file_index != last_file_index) { jcr->JobFiles = file_index; - if (jcr->VolFirstIndex == 0) { - jcr->VolFirstIndex = file_index; - } - jcr->VolLastIndex = file_index; last_file_index = file_index; } diff --git a/bacula/src/stored/bextract.c b/bacula/src/stored/bextract.c index 8d063902ea..f8d5175a32 100644 --- a/bacula/src/stored/bextract.c +++ b/bacula/src/stored/bextract.c @@ -49,7 +49,6 @@ static FF_PKT *ff = &my_ff; static BSR *bsr = NULL; static int extract = FALSE; static int non_support_data = 0; -static int non_support_attr = 0; static long total = 0; static ATTR *attr; static char *where; diff --git a/bacula/src/stored/block.c b/bacula/src/stored/block.c index acbb5d5e60..9cf920f0c7 100644 --- a/bacula/src/stored/block.c +++ b/bacula/src/stored/block.c @@ -146,6 +146,7 @@ void empty_block(DEV_BLOCK *block) block->read_len = 0; block->write_failed = false; block->block_read = false; + block->FirstIndex = block->LastIndex = 0; } /* @@ -475,7 +476,7 @@ int write_block_to_dev(JCR *jcr, DEVICE *dev, DEV_BLOCK *block) return 0; } - /* Do housekeeping */ + /* We successfully wrote the block, now do housekeeping */ dev->VolCatInfo.VolCatBytes += block->binbuf; dev->VolCatInfo.VolCatBlocks++; @@ -493,6 +494,12 @@ int write_block_to_dev(JCR *jcr, DEVICE *dev, DEV_BLOCK *block) jcr->EndBlock = (uint32_t)dev->file_addr; jcr->EndFile = (uint32_t)(dev->file_addr >> 32); } + if (jcr->VolFirstIndex == 0 && block->FirstIndex > 0) { + jcr->VolFirstIndex = block->FirstIndex; + } + if (block->LastIndex > 0) { + jcr->VolLastIndex = block->LastIndex; + } jcr->WroteVol = true; Dmsg2(190, "write_block: wrote block %d bytes=%d\n", dev->block_num, @@ -635,10 +642,26 @@ reread: } dev->state &= ~(ST_EOF|ST_SHORT); /* clear EOF and short block */ - dev->block_num++; dev->VolCatInfo.VolCatReads++; dev->VolCatInfo.VolCatRBytes += block->read_len; + dev->VolCatInfo.VolCatBytes += block->block_len; + dev->VolCatInfo.VolCatBlocks++; + dev->file_addr += block->block_len; + dev->EndBlock = dev->block_num; + dev->EndFile = dev->file; + dev->block_num++; + block->BlockNumber++; + + /* Update jcr values */ + if (dev->state & ST_TAPE) { + jcr->EndBlock = dev->EndBlock; + jcr->EndFile = dev->EndFile; + } else { + jcr->EndBlock = (uint32_t)dev->file_addr; + jcr->EndFile = (uint32_t)(dev->file_addr >> 32); + } + /* * If we read a short block on disk, * seek to beginning of next block. This saves us diff --git a/bacula/src/stored/block.h b/bacula/src/stored/block.h index 1f76241524..2972bded93 100644 --- a/bacula/src/stored/block.h +++ b/bacula/src/stored/block.h @@ -99,6 +99,8 @@ struct DEV_BLOCK { int BlockVer; /* block version 1 or 2 */ bool write_failed; /* set if write failed */ bool block_read; /* set when block read */ + int32_t FirstIndex; /* first index this block */ + int32_t LastIndex; /* last index this block */ char *bufp; /* pointer into buffer */ POOLMEM *buf; /* actual data buffer */ }; diff --git a/bacula/src/stored/bscan.c b/bacula/src/stored/bscan.c index 5197c4538c..fac6ec0920 100644 --- a/bacula/src/stored/bscan.c +++ b/bacula/src/stored/bscan.c @@ -337,8 +337,8 @@ static void record_cb(JCR *bjcr, DEVICE *dev, DEV_BLOCK *block, DEV_RECORD *rec) case VOL_LABEL: unser_volume_label(dev, rec); /* Check Pool info */ - strcpy(pr.Name, dev->VolHdr.PoolName); - strcpy(pr.PoolType, dev->VolHdr.PoolType); + bstrncpy(pr.Name, dev->VolHdr.PoolName, sizeof(pr.Name)); + bstrncpy(pr.PoolType, dev->VolHdr.PoolType, sizeof(pr.PoolType)); if (db_get_pool_record(bjcr, db, &pr)) { if (verbose) { Pmsg1(000, _("Pool record for %s found in DB.\n"), pr.Name); @@ -360,7 +360,7 @@ static void record_cb(JCR *bjcr, DEVICE *dev, DEV_BLOCK *block, DEV_RECORD *rec) /* Check Media Info */ memset(&mr, 0, sizeof(mr)); - strcpy(mr.VolumeName, dev->VolHdr.VolName); + bstrncpy(mr.VolumeName, dev->VolHdr.VolName, sizeof(mr.VolumeName)); mr.PoolId = pr.PoolId; if (db_get_media_record(bjcr, db, &mr)) { if (verbose) { @@ -374,7 +374,7 @@ static void record_cb(JCR *bjcr, DEVICE *dev, DEV_BLOCK *block, DEV_RECORD *rec) Pmsg1(000, _("VOL_LABEL: Media record not found for Volume: %s\n"), mr.VolumeName); } - strcpy(mr.MediaType, dev->VolHdr.MediaType); + bstrncpy(mr.MediaType, dev->VolHdr.MediaType, sizeof(mr.MediaType)); create_media_record(db, &mr, &dev->VolHdr); } if (strcmp(mr.MediaType, dev->VolHdr.MediaType) != 0) { @@ -534,6 +534,19 @@ static void record_cb(JCR *bjcr, DEVICE *dev, DEV_BLOCK *block, DEV_RECORD *rec) return; } + mjcr = get_jcr_by_session(rec->VolSessionId, rec->VolSessionTime); + if (!mjcr) { + if (mr.VolJobs > 0) { + Pmsg2(000, _("Could not find Job for SessId=%d SessTime=%d record.\n"), + rec->VolSessionId, rec->VolSessionTime); + } else { + ignored_msgs++; + } + return; + } + if (mjcr->VolFirstIndex == 0) { + mjcr->VolFirstIndex = block->FirstIndex; + } /* File Attributes stream */ switch (rec->Stream) { @@ -554,16 +567,6 @@ static void record_cb(JCR *bjcr, DEVICE *dev, DEV_BLOCK *block, DEV_RECORD *rec) build_attr_output_fnames(bjcr, attr); print_ls_output(bjcr, attr); } - mjcr = get_jcr_by_session(rec->VolSessionId, rec->VolSessionTime); - if (!mjcr) { - if (mr.VolJobs > 0) { - Pmsg2(000, _("Could not find Job SessId=%d SessTime=%d for Attributes record.\n"), - rec->VolSessionId, rec->VolSessionTime); - } else { - ignored_msgs++; - } - return; - } fr.JobId = mjcr->JobId; fr.FileId = 0; if (db_get_file_attributes_record(bjcr, db, attr->fname, &fr)) { @@ -581,16 +584,6 @@ static void record_cb(JCR *bjcr, DEVICE *dev, DEV_BLOCK *block, DEV_RECORD *rec) case STREAM_WIN32_DATA: case STREAM_FILE_DATA: case STREAM_SPARSE_DATA: - mjcr = get_jcr_by_session(rec->VolSessionId, rec->VolSessionTime); - if (!mjcr) { - if (mr.VolJobs > 0) { - Pmsg2(000, _("Could not find Job SessId=%d SessTime=%d for File Data record.\n"), - rec->VolSessionId, rec->VolSessionTime); - } else { - ignored_msgs++; - } - return; - } mjcr->JobBytes += rec->data_len; if (rec->Stream == STREAM_SPARSE_DATA) { mjcr->JobBytes -= sizeof(uint64_t); @@ -600,47 +593,17 @@ static void record_cb(JCR *bjcr, DEVICE *dev, DEV_BLOCK *block, DEV_RECORD *rec) break; case STREAM_GZIP_DATA: - mjcr = get_jcr_by_session(rec->VolSessionId, rec->VolSessionTime); - if (!mjcr) { - if (mr.VolJobs > 0) { - Pmsg2(000, _("Could not find Job SessId=%d SessTime=%d for GZIP Data record.\n"), - rec->VolSessionId, rec->VolSessionTime); - } else { - ignored_msgs++; - } - return; - } mjcr->JobBytes += rec->data_len; /* No correct, we should expand it */ free_jcr(mjcr); /* done using JCR */ break; case STREAM_SPARSE_GZIP_DATA: - mjcr = get_jcr_by_session(rec->VolSessionId, rec->VolSessionTime); - if (!mjcr) { - if (mr.VolJobs > 0) { - Pmsg2(000, _("Could not find Job SessId=%d SessTime=%d for Sparse GZIP Data record.\n"), - rec->VolSessionId, rec->VolSessionTime); - } else { - ignored_msgs++; - } - return; - } mjcr->JobBytes += rec->data_len - sizeof(uint64_t); /* No correct, we should expand it */ free_jcr(mjcr); /* done using JCR */ break; /* Win32 GZIP stream */ case STREAM_WIN32_GZIP_DATA: - mjcr = get_jcr_by_session(rec->VolSessionId, rec->VolSessionTime); - if (!mjcr) { - if (mr.VolJobs > 0) { - Pmsg2(000, _("Could not find Job SessId=%d SessTime=%d for Win32 GZIP Data record.\n"), - rec->VolSessionId, rec->VolSessionTime); - } else { - ignored_msgs++; - } - return; - } mjcr->JobBytes += rec->data_len; free_jcr(mjcr); /* done using JCR */ break; diff --git a/bacula/src/stored/label.c b/bacula/src/stored/label.c index 739e8d8447..1912d1571e 100644 --- a/bacula/src/stored/label.c +++ b/bacula/src/stored/label.c @@ -441,7 +441,6 @@ int write_volume_label_to_dev(JCR *jcr, DEVRES *device, char *VolName, char *Poo void create_session_label(JCR *jcr, DEV_RECORD *rec, int label) { ser_declare; - struct date_time dt; rec->sync = 1; /* wait for completion */ rec->VolSessionId = jcr->VolSessionId; @@ -455,15 +454,9 @@ void create_session_label(JCR *jcr, DEV_RECORD *rec, int label) ser_uint32(jcr->JobId); - if (BaculaTapeVersion >= 11) { - ser_btime(get_current_btime()); - ser_float64(0); - } else { - /* OLD WAY DEPRECATED */ - get_current_time(&dt); - ser_float64(dt.julian_day_number); - ser_float64(dt.julian_day_fraction); - } + /* Changed in VerNum 11 */ + ser_btime(get_current_btime()); + ser_float64(0); ser_string(jcr->pool_name); ser_string(jcr->pool_type); @@ -475,9 +468,8 @@ void create_session_label(JCR *jcr, DEV_RECORD *rec, int label) ser_string(jcr->fileset_name); ser_uint32(jcr->JobType); ser_uint32(jcr->JobLevel); - if (BaculaTapeVersion >= 11) { - ser_string(jcr->fileset_md5); - } + /* Added in VerNum 11 */ + ser_string(jcr->fileset_md5); if (label == EOS_LABEL) { ser_uint32(jcr->JobFiles); @@ -507,27 +499,27 @@ int write_session_label(JCR *jcr, DEV_BLOCK *block, int label) rec = new_record(); Dmsg1(90, "session_label record=%x\n", rec); switch (label) { - case SOS_LABEL: - if (dev->state & ST_TAPE) { - jcr->StartBlock = dev->block_num; - jcr->StartFile = dev->file; - } else { - jcr->StartBlock = (uint32_t)dev->file_addr; - jcr->StartFile = (uint32_t)(dev->file_addr >> 32); - } - break; - case EOS_LABEL: - if (dev->state & ST_TAPE) { - jcr->EndBlock = dev->EndBlock; - jcr->EndFile = dev->EndFile; - } else { - jcr->EndBlock = (uint32_t)dev->file_addr; - jcr->EndFile = (uint32_t)(dev->file_addr >> 32); - } - break; - default: - Jmsg1(jcr, M_ABORT, 0, _("Bad session label = %d\n"), label); - break; + case SOS_LABEL: + if (dev->state & ST_TAPE) { + jcr->StartBlock = dev->block_num; + jcr->StartFile = dev->file; + } else { + jcr->StartBlock = (uint32_t)dev->file_addr; + jcr->StartFile = (uint32_t)(dev->file_addr >> 32); + } + break; + case EOS_LABEL: + if (dev->state & ST_TAPE) { + jcr->EndBlock = dev->EndBlock; + jcr->EndFile = dev->EndFile; + } else { + jcr->EndBlock = (uint32_t)dev->file_addr; + jcr->EndFile = (uint32_t)(dev->file_addr >> 32); + } + break; + default: + Jmsg1(jcr, M_ABORT, 0, _("Bad session label = %d\n"), label); + break; } create_session_label(jcr, rec, label); rec->FileIndex = label; diff --git a/bacula/src/stored/mount.c b/bacula/src/stored/mount.c index c747ef5fc5..816c830e45 100644 --- a/bacula/src/stored/mount.c +++ b/bacula/src/stored/mount.c @@ -95,7 +95,6 @@ mount_next_vol: dev->state &= ~(ST_APPEND|ST_READ|ST_EOT|ST_WEOT|ST_EOF); - jcr->VolFirstIndex = jcr->JobFiles; /* first update of Vol FileIndex */ for ( ;; ) { int vol_label_status; autochanger = autoload_device(jcr, dev, 1, NULL); diff --git a/bacula/src/stored/record.c b/bacula/src/stored/record.c index e560ad0385..efe66fa51a 100644 --- a/bacula/src/stored/record.c +++ b/bacula/src/stored/record.c @@ -211,8 +211,8 @@ rem=%d remainder=%d\n", if (remlen >= WRITE_RECHDR_LENGTH) { ser_begin(block->bufp, WRITE_RECHDR_LENGTH); if (BLOCK_VER == 1) { - ser_uint32(rec->VolSessionId); - ser_uint32(rec->VolSessionTime); + ser_uint32(rec->VolSessionId); + ser_uint32(rec->VolSessionTime); } else { block->VolSessionId = rec->VolSessionId; block->VolSessionTime = rec->VolSessionTime; @@ -225,6 +225,13 @@ rem=%d remainder=%d\n", block->binbuf += WRITE_RECHDR_LENGTH; remlen -= WRITE_RECHDR_LENGTH; rec->remainder = rec->data_len; + if (rec->FileIndex > 0) { + /* If data record, update what we have in this block */ + if (block->FirstIndex == 0) { + block->FirstIndex = rec->FileIndex; + } + block->LastIndex = rec->FileIndex; + } } else { rec->remainder = rec->data_len + WRITE_RECHDR_LENGTH; return 0; @@ -247,8 +254,8 @@ rem=%d remainder=%d\n", */ ser_begin(block->bufp, WRITE_RECHDR_LENGTH); if (BLOCK_VER == 1) { - ser_uint32(rec->VolSessionId); - ser_uint32(rec->VolSessionTime); + ser_uint32(rec->VolSessionId); + ser_uint32(rec->VolSessionTime); } else { block->VolSessionId = rec->VolSessionId; block->VolSessionTime = rec->VolSessionTime; @@ -269,6 +276,13 @@ rem=%d remainder=%d\n", block->bufp += WRITE_RECHDR_LENGTH; block->binbuf += WRITE_RECHDR_LENGTH; remlen -= WRITE_RECHDR_LENGTH; + if (rec->FileIndex > 0) { + /* If data record, update what we have in this block */ + if (block->FirstIndex == 0) { + block->FirstIndex = rec->FileIndex; + } + block->LastIndex = rec->FileIndex; + } } if (remlen == 0) { return 0; /* partial transfer */ @@ -393,8 +407,8 @@ int read_record_from_block(DEV_BLOCK *block, DEV_RECORD *rec) unser_begin(block->bufp, WRITE_RECHDR_LENGTH); if (block->BlockVer == 1) { - unser_uint32(VolSessionId); - unser_uint32(VolSessionTime); + unser_uint32(VolSessionId); + unser_uint32(VolSessionTime); } else { VolSessionId = block->VolSessionId; VolSessionTime = block->VolSessionTime; @@ -437,9 +451,15 @@ int read_record_from_block(DEV_BLOCK *block, DEV_RECORD *rec) rec->VolSessionId = VolSessionId; rec->VolSessionTime = VolSessionTime; rec->FileIndex = FileIndex; + if (FileIndex > 0) { + if (block->FirstIndex == 0) { + block->FirstIndex = FileIndex; + } + block->LastIndex = FileIndex; + } - Dmsg6(100, "rd_rec_blk() got FI=%s SessId=%d Strm=%s len=%u\n\ -remlen=%d data_len=%d\n", + Dmsg6(100, "rd_rec_blk() got FI=%s SessId=%d Strm=%s len=%u\n" + "remlen=%d data_len=%d\n", FI_to_ascii(rec->FileIndex), rec->VolSessionId, stream_to_ascii(rec->Stream, rec->FileIndex), data_bytes, remlen, rec->data_len); diff --git a/bacula/src/version.h b/bacula/src/version.h index 5022f86d85..d0a1f839ff 100644 --- a/bacula/src/version.h +++ b/bacula/src/version.h @@ -1,8 +1,8 @@ /* */ #define VERSION "1.31" #define VSTRING "1" -#define BDATE "26 Jun 2003" -#define LSMDATE "26Jun03" +#define BDATE "02 Jul 2003" +#define LSMDATE "02Jul03" /* Debug flags */ #define DEBUG 1 -- 2.39.5