From: Kern Sibbald Date: Sun, 15 Jun 2003 19:26:47 +0000 (+0000) Subject: LabelFormat X-Git-Tag: Release-1.31~75 X-Git-Url: https://git.sur5r.net/?a=commitdiff_plain;h=552a0e2db093379b0018434088c388e0aece05f8;p=bacula%2Fbacula LabelFormat git-svn-id: https://bacula.svn.sourceforge.net/svnroot/bacula/trunk@581 91ce42f0-d328-0410-95d8-f526ca767f89 --- diff --git a/bacula/examples/checkhost b/bacula/examples/checkhost new file mode 100755 index 0000000000..b201798a28 --- /dev/null +++ b/bacula/examples/checkhost @@ -0,0 +1,53 @@ +#!/usr/bin/perl + +use strict; +use Net::Ping; +use Net::Telnet (); +use Getopt::Long; +use IPC::Open2; + +# +# Check if a Bacula client is alive. By Phil Stracchino. +# +# Return values: +# -1 Program error or no host specified +# 0 Success, FD found and responding +# 1 Client alive but FD not listening +# 2 Client not found on network + +my $ret = -1; +my ($host, $p, $ret, $verbose); +GetOptions('verbose' => \$verbose, + 'v' => \$verbose); + +$host = shift || die "No host specified!\n"; + +$p = Net::Ping->new(); +if ($p->ping($host)) +{ + print "Host $host is alive\n" if ($verbose); + my $t = new Net::Telnet (Timeout => 10, + Port => 9102, + Prompt => '/bash\$ $/'); + if ($t->open($host)) + { + print "Bacula-FD listening on port 9102\n" if ($verbose); + $ret = 0; + } + else + { + print "Bacula-FD not found\n" if ($verbose); + $ret = 1; + } + $t->close; +} +else +{ + print "$host is unreachable\n" if ($verbose); + $ret = 2; +} +$p->close(); + +print "Returning value $ret\n" if ($verbose); + +exit ($ret); diff --git a/bacula/examples/is_client_alive b/bacula/examples/is_client_alive index e2f9315e63..3bd2504794 100755 --- a/bacula/examples/is_client_alive +++ b/bacula/examples/is_client_alive @@ -3,7 +3,7 @@ # Test if Bacula Client is alive # exit 0 if specified client (arg1) is alive # exit 1 if specified client (arg1) is NOT alive -# exit 2 if console could NOT connect with Director +# exit 2 if console could NOT connect to Director # OUTF=/tmp/client-${1}-alive rm -f ${OUTF} diff --git a/bacula/kernstodo b/bacula/kernstodo index dd01fda9e3..dfec9674b7 100644 --- a/bacula/kernstodo +++ b/bacula/kernstodo @@ -1,5 +1,5 @@ Kern's ToDo List - 10 June 2003 + 14 June 2003 Documentation to do: (any release a little bit at a time) - Document running a test version. @@ -34,6 +34,10 @@ Testing to do: (painful) - Figure out how to use ssh or stunnel to protect Bacula communications. For 1.31 release: +- Add client name to cram-md5 challenge so Director can immediately + verify if it is the correct client. +- Implement a record that suppresses errors if the Client is not + available. - Use runbeforejob to unload, then reload a volume previously used, then the next job run gets an error reading the drive. - Implement non-blocking writes and bsock->terminate in heartbeat thread, @@ -977,4 +981,3 @@ Done: (see kernsdone for more) Do lstat() to see if it is already properly linked. Same for symlinked file. Make sure ifnewer, ifolder, never, ... apply correctly. - diff --git a/bacula/src/cats/bdb_create.c b/bacula/src/cats/bdb_create.c index e86beab128..20468b33e4 100644 --- a/bacula/src/cats/bdb_create.c +++ b/bacula/src/cats/bdb_create.c @@ -293,4 +293,8 @@ int db_create_fileset_record(JCR *jcr, B_DB *mdb, FILESET_DBR *fsr) return 1; } +int db_create_counter_record(JCR *jcr, B_DB *mdb, COUNTER_DBR *cr) +{ return 0; } + + #endif /* HAVE_BACULA_DB */ diff --git a/bacula/src/cats/bdb_get.c b/bacula/src/cats/bdb_get.c index 8b4db4e82f..ca0003f421 100644 --- a/bacula/src/cats/bdb_get.c +++ b/bacula/src/cats/bdb_get.c @@ -498,4 +498,8 @@ int db_get_job_volume_parameters(JCR *jcr, B_DB *mdb, uint32_t JobId, VOL_PARAMS int db_get_client_ids(JCR *jcr, B_DB *mdb, int *num_ids, uint32_t *ids[]) { return 0; } +int db_get_counter_record(JCR *jcr, B_DB *mdb, COUNTER_DBR *cr) +{ return 0; } + + #endif /* HAVE_BACULA_DB */ diff --git a/bacula/src/cats/bdb_update.c b/bacula/src/cats/bdb_update.c index a4cc365585..cfba217730 100755 --- a/bacula/src/cats/bdb_update.c +++ b/bacula/src/cats/bdb_update.c @@ -212,4 +212,10 @@ int db_update_client_record(JCR *jcr, B_DB *mdb, CLIENT_DBR *cr) return 1; } +int db_update_counter_record(JCR *jcr, B_DB *mdb, COUNTER_DBR *cr) +{ + return 0; +} + + #endif /* HAVE_BACULA_DB */ diff --git a/bacula/src/cats/cats.h b/bacula/src/cats/cats.h index a3c1da5bcb..f4746db3c8 100644 --- a/bacula/src/cats/cats.h +++ b/bacula/src/cats/cats.h @@ -449,6 +449,16 @@ struct CLIENT_DBR { char Uname[256]; /* Uname for client */ }; +/* Counter record as in database */ +struct COUNTER_DBR { + char Counter[MAX_NAME_LENGTH]; + int32_t MinValue; + int32_t MaxValue; + int32_t CurrentValue; + char WrapCounter[MAX_NAME_LENGTH]; +}; + + /* FileSet record -- same as the database */ struct FILESET_DBR { uint32_t FileSetId; /* Unique FileSet id */ diff --git a/bacula/src/cats/make_mysql_tables.in b/bacula/src/cats/make_mysql_tables.in index e9b63202f0..1ce0d6aadc 100644 --- a/bacula/src/cats/make_mysql_tables.in +++ b/bacula/src/cats/make_mysql_tables.in @@ -177,11 +177,11 @@ INSERT INTO Version (VersionId) VALUES (6); CREATE TABLE Counters ( Counter TINYBLOB NOT NULL, - PoolId INTEGER UNSIGNED NOT NULL REFERENCES Pool, MinValue INTEGER, MaxValue INTEGER, CurrentValue INTEGER, - WrapCounter TINYBLOB NOT NULL + WrapCounter TINYBLOB NOT NULL, + PRIMARY KEY (Counter(128)) ); diff --git a/bacula/src/cats/make_sqlite_tables.in b/bacula/src/cats/make_sqlite_tables.in index 2275f4659c..56244601a6 100644 --- a/bacula/src/cats/make_sqlite_tables.in +++ b/bacula/src/cats/make_sqlite_tables.in @@ -188,7 +188,6 @@ INSERT INTO Version (VersionId) VALUES (6); CREATE TABLE Counters ( Counter TEXT NOT NULL, - PoolId INTEGER UNSIGNED REFERENCES Pool DEFAULT 0, MinValue INTEGER DEFAULT 0, MaxValue INTEGER DEFAULT 0, CurrentValue INTEGER DEFAULT 0, diff --git a/bacula/src/cats/protos.h b/bacula/src/cats/protos.h index 90822e2679..ff1ccede2c 100644 --- a/bacula/src/cats/protos.h +++ b/bacula/src/cats/protos.h @@ -31,7 +31,7 @@ /* sql.c */ B_DB *db_init_database(JCR *jcr, char *db_name, char *db_user, char *db_password, - char *db_address, int db_port, char *db_socket); + char *db_address, int db_port, char *db_socket); int db_open_database(JCR *jcr, B_DB *db); void db_close_database(JCR *jcr, B_DB *db); void db_escape_string(char *snew, char *old, int len); @@ -51,8 +51,9 @@ int db_create_job_record(JCR *jcr, B_DB *db, JOB_DBR *jr); int db_create_media_record(JCR *jcr, B_DB *db, MEDIA_DBR *media_dbr); int db_create_client_record(JCR *jcr, B_DB *db, CLIENT_DBR *cr); int db_create_fileset_record(JCR *jcr, B_DB *db, FILESET_DBR *fsr); -int db_create_pool_record(JCR *jcr, B_DB *db, POOL_DBR *pool_dbr); +int db_create_pool_record(JCR *jcr, B_DB *db, POOL_DBR *pool_dbr); int db_create_jobmedia_record(JCR *jcr, B_DB *mdb, JOBMEDIA_DBR *jr); +int db_create_counter_record(JCR *jcr, B_DB *mdb, COUNTER_DBR *cr); /* delete.c */ int db_delete_pool_record(JCR *jcr, B_DB *db, POOL_DBR *pool_dbr); @@ -78,6 +79,7 @@ int db_get_client_ids(JCR *jcr, B_DB *mdb, int *num_ids, uint32_t **ids); int db_get_media_ids(JCR *jcr, B_DB *mdb, int *num_ids, uint32_t **ids); int db_get_job_volume_parameters(JCR *jcr, B_DB *mdb, uint32_t JobId, VOL_PARAMS **VolParams); int db_get_client_record(JCR *jcr, B_DB *mdb, CLIENT_DBR *cdbr); +int db_get_counter_record(JCR *jcr, B_DB *mdb, COUNTER_DBR *cr); /* list.c */ @@ -100,6 +102,7 @@ int db_update_job_end_record(JCR *jcr, B_DB *db, JOB_DBR *jr); int db_update_client_record(JCR *jcr, B_DB *mdb, CLIENT_DBR *cr); int db_update_pool_record(JCR *jcr, B_DB *db, POOL_DBR *pr); int db_update_media_record(JCR *jcr, B_DB *db, MEDIA_DBR *mr); +int db_update_counter_record(JCR *jcr, B_DB *mdb, COUNTER_DBR *cr); int db_add_SIG_to_file_record(JCR *jcr, B_DB *mdb, FileId_t FileId, char *SIG, int type); int db_mark_file_record(JCR *jcr, B_DB *mdb, FileId_t FileId, JobId_t JobId); diff --git a/bacula/src/cats/sql_create.c b/bacula/src/cats/sql_create.c index e8edba50b6..9d8875e8f1 100644 --- a/bacula/src/cats/sql_create.c +++ b/bacula/src/cats/sql_create.c @@ -359,6 +359,44 @@ FileRetention, JobRetention) VALUES \ } +/* + * Create a Unique record for the counter -- no duplicates + * Returns: 0 on failure + * 1 on success with counter filled in + */ +int db_create_counter_record(JCR *jcr, B_DB *mdb, COUNTER_DBR *cr) +{ + COUNTER_DBR mcr; + int stat; + + db_lock(mdb); + memset(&mcr, 0, sizeof(mcr)); + bstrncpy(mcr.Counter, cr->Counter, sizeof(mcr.Counter)); + if (db_get_counter_record(jcr, mdb, &mcr)) { + memcpy(cr, &mcr, sizeof(COUNTER_DBR)); + db_unlock(mdb); + return 1; + } + + /* Must create it */ + Mmsg(&mdb->cmd, "INSERT INTO Counters (Counter,MinValue,MaxValue,CurrentValue," + "WrapCounter) VALUES ('%s','%d','%d','%d','%s')", + cr->Counter, cr->MinValue, cr->MaxValue, cr->CurrentValue, + cr->WrapCounter); + + if (!INSERT_DB(jcr, mdb, mdb->cmd)) { + Mmsg2(&mdb->errmsg, _("Create DB Counters record %s failed. ERR=%s\n"), + mdb->cmd, sql_strerror(mdb)); + Jmsg(jcr, M_ERROR, 0, "%s", mdb->errmsg); + stat = 0; + } else { + stat = 1; + } + db_unlock(mdb); + return stat; +} + + /* * Create a FileSet record. This record is unique in the * name and the MD5 signature of the include/exclude sets. diff --git a/bacula/src/cats/sql_get.c b/bacula/src/cats/sql_get.c index eb658aa278..0663905db8 100644 --- a/bacula/src/cats/sql_get.c +++ b/bacula/src/cats/sql_get.c @@ -607,6 +607,55 @@ int db_get_client_record(JCR *jcr, B_DB *mdb, CLIENT_DBR *cdbr) return stat; } +/* + * Get Counter Record + * + * Returns: 0 on failure + * 1 on success + */ +int db_get_counter_record(JCR *jcr, B_DB *mdb, COUNTER_DBR *cr) +{ + SQL_ROW row; + + db_lock(mdb); + Mmsg(&mdb->cmd, "SELECT MinValue,MaxValue,CurrentValue,WrapCounter " + "FROM Counters WHERE Counter='%s'", cr->Counter); + + if (QUERY_DB(jcr, mdb, mdb->cmd)) { + + mdb->num_rows = sql_num_rows(mdb); + + /* If more than one, report error, but return first row */ + if (mdb->num_rows > 1) { + Mmsg1(&mdb->errmsg, _("More than one Counter!: %d\n"), (int)(mdb->num_rows)); + Jmsg(jcr, M_ERROR, 0, "%s", mdb->errmsg); + } + if (mdb->num_rows >= 1) { + if ((row = sql_fetch_row(mdb)) == NULL) { + Mmsg1(&mdb->errmsg, _("error fetching Counter row: %s\n"), sql_strerror(mdb)); + Jmsg(jcr, M_ERROR, 0, "%s", mdb->errmsg); + sql_free_result(mdb); + db_unlock(mdb); + return 0; + } + cr->MinValue = atoi(row[0]); + cr->MaxValue = atoi(row[1]); + cr->CurrentValue = atoi(row[2]); + if (row[3]) { + bstrncpy(cr->WrapCounter, row[3], sizeof(cr->WrapCounter)); + } else { + cr->WrapCounter[0] = 0; + } + sql_free_result(mdb); + db_unlock(mdb); + return 1; + } + sql_free_result(mdb); + } + db_unlock(mdb); + return 0; +} + /* Get FileSet Record * If the FileSetId is non-zero, we get its record, diff --git a/bacula/src/cats/sql_update.c b/bacula/src/cats/sql_update.c index 5006b66880..d9b26ba770 100644 --- a/bacula/src/cats/sql_update.c +++ b/bacula/src/cats/sql_update.c @@ -150,6 +150,11 @@ VolSessionTime=%u, PoolId=%u, FileSetId=%u, JobTDate=%s WHERE JobId=%u", } +/* + * Update Client record + * Returns: 0 on failure + * 1 on success + */ int db_update_client_record(JCR *jcr, B_DB *mdb, CLIENT_DBR *cr) { @@ -178,6 +183,27 @@ db_update_client_record(JCR *jcr, B_DB *mdb, CLIENT_DBR *cr) } +/* + * Update Counters record + * Returns: 0 on failure + * 1 on success + */ +int db_update_counter_record(JCR *jcr, B_DB *mdb, COUNTER_DBR *cr) +{ + db_lock(mdb); + + Mmsg(&mdb->cmd, +"UPDATE Counters SET MinValue=%d,MaxValue=%d,CurrentValue=%d," +"WrapCounter='%s' WHERE Counter='%s'", + cr->MinValue, cr->MaxValue, cr->CurrentValue, + cr->WrapCounter, cr->Counter); + + int stat = UPDATE_DB(jcr, mdb, mdb->cmd); + db_unlock(mdb); + return stat; +} + + int db_update_pool_record(JCR *jcr, B_DB *mdb, POOL_DBR *pr) { diff --git a/bacula/src/dird/dird.c b/bacula/src/dird/dird.c index d197713855..029ca2b261 100644 --- a/bacula/src/dird/dird.c +++ b/bacula/src/dird/dird.c @@ -380,6 +380,25 @@ Without that I don't know who I am :-(\n"), configfile); if (job->pool) { create_pool(NULL, db, job->pool, POOL_OP_UPDATE); /* update request */ } + /* Set default value in all counters */ + for (COUNTER *counter=NULL; (counter = (COUNTER *)GetNextRes(R_COUNTER, (RES *)counter)); ) { + /* Write to catalog? */ + if (!counter->created && counter->Catalog == catalog) { + COUNTER_DBR cr; + bstrncpy(cr.Counter, counter->hdr.name, sizeof(cr.Counter)); + cr.MinValue = counter->MinValue; + cr.MaxValue = counter->MaxValue; + cr.CurrentValue = counter->MinValue; + bstrncpy(cr.WrapCounter, counter->WrapCounter->hdr.name, sizeof(cr.WrapCounter)); + if (db_create_counter_record(NULL, db, &cr)) { + counter->CurrentValue = cr.CurrentValue; + counter->created = true; +// Dmsg2(000, "Create counter %s val=%d\n", counter->hdr.name, counter->CurrentValue); + } + } else { + counter->CurrentValue = counter->MinValue; /* default value */ + } + } db_close_database(NULL, db); } diff --git a/bacula/src/dird/dird_conf.c b/bacula/src/dird/dird_conf.c index fcec481e25..d485ffb042 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}, @@ -215,7 +215,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}, @@ -224,13 +224,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}, @@ -241,7 +241,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}, @@ -251,7 +251,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}, @@ -277,15 +277,15 @@ 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}, {"description", store_str, ITEM(res_counter.hdr.desc), 0, 0, 0}, {"minimum", store_int, ITEM(res_counter.MinValue), 0, ITEM_DEFAULT, 0}, {"maximum", store_pint, ITEM(res_counter.MaxValue), 0, ITEM_DEFAULT, INT32_MAX}, - {"global", store_yesno, ITEM(res_counter.Global), 0, ITEM_DEFAULT, 0}, - {"wrapcounter", store_strname, ITEM(res_counter.WrapCounter), 0, 0, 0}, + {"wrapcounter", store_res, ITEM(res_counter.WrapCounter), R_COUNTER, 0, 0}, + {"catalog", store_res, ITEM(res_counter.Catalog), R_CATALOG, 0, 0}, {NULL, NULL, NULL, 0, 0, 0} }; @@ -297,7 +297,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}, @@ -312,13 +312,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}, @@ -330,19 +330,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} }; @@ -351,7 +351,7 @@ static struct s_kw BakVerFields[] = { {"client", 'C'}, {"fileset", 'F'}, {"level", 'L'}, - {NULL, 0} + {NULL, 0} }; /* Keywords (RHS) permitted in Restore records */ @@ -362,7 +362,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= */ @@ -371,7 +371,7 @@ struct s_kw ReplaceOptions[] = { {"ifnewer", REPLACE_IFNEWER}, {"ifolder", REPLACE_IFOLDER}, {"never", REPLACE_NEVER}, - {NULL, 0} + {NULL, 0} }; char *level_to_str(int level) @@ -383,8 +383,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; @@ -400,223 +400,239 @@ 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: - char ed1[30], ed2[30]; - 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)); - 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); - } - break; - case R_CONSOLE: - sendit(sock, "Console name=%s SSL=%d\n", - res->res_con.hdr.name, res->res_con.enable_ssl); - 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); - sendit(sock, " JobRetention=%" lld " FileRetention=%" lld " AutoPrune=%d\n", - 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); - } - 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); - 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)); - 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); - if (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); - } - if (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)); - } - if (res->res_job.RestoreBootstrap) { - sendit(sock, " --> Bootstrap=%s\n", NPRT(res->res_job.RestoreBootstrap)); - } - if (res->res_job.RunBeforeJob) { - sendit(sock, " --> RunBefore=%s\n", NPRT(res->res_job.RunBeforeJob)); - } - if (res->res_job.RunAfterJob) { - sendit(sock, " --> RunAfter=%s\n", NPRT(res->res_job.RunAfterJob)); - } - if (res->res_job.WriteBootstrap) { - sendit(sock, " --> WriteBootstrap=%s\n", NPRT(res->res_job.WriteBootstrap)); - } - if (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); - } 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); - } - 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++) { - 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++) { - 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]; - sendit(sock, "Schedule: name=%s\n", res->res_sch.hdr.name); - if (!run) { - break; - } + case R_DIRECTOR: + char ed1[30], ed2[30]; + 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)); + 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); + } + break; + case R_CONSOLE: + sendit(sock, "Console: name=%s SSL=%d\n", + 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); + if (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); + } + + + + 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); + sendit(sock, " JobRetention=%" lld " FileRetention=%" lld " AutoPrune=%d\n", + 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); + } + 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); + 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)); + 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); + if (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); + } + if (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)); + } + if (res->res_job.RestoreBootstrap) { + sendit(sock, " --> Bootstrap=%s\n", NPRT(res->res_job.RestoreBootstrap)); + } + if (res->res_job.RunBeforeJob) { + sendit(sock, " --> RunBefore=%s\n", NPRT(res->res_job.RunBeforeJob)); + } + if (res->res_job.RunAfterJob) { + sendit(sock, " --> RunAfter=%s\n", NPRT(res->res_job.RunAfterJob)); + } + if (res->res_job.WriteBootstrap) { + sendit(sock, " --> WriteBootstrap=%s\n", NPRT(res->res_job.WriteBootstrap)); + } + if (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); + } 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); + } + 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++) { + 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++) { + 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]; + sendit(sock, "Schedule: name=%s\n", res->res_sch.hdr.name); + 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)) { - sprintf(num, "%d ", i); - strcat(buf, num); - } - } - strcat(buf, "\n"); - sendit(sock, buf); - strcpy(buf, " mday="); - for (i=0; i<31; i++) { - if (bit_is_set(i, run->mday)) { - sprintf(num, "%d ", i+1); - strcat(buf, num); - } - } - strcat(buf, "\n"); - sendit(sock, buf); - strcpy(buf, " month="); - for (i=0; i<12; i++) { - if (bit_is_set(i, run->month)) { - sprintf(num, "%d ", i+1); - strcat(buf, num); - } - } - strcat(buf, "\n"); - sendit(sock, buf); - strcpy(buf, " wday="); - for (i=0; i<7; i++) { - if (bit_is_set(i, run->wday)) { - sprintf(num, "%d ", i+1); - strcat(buf, num); - } - } - strcat(buf, "\n"); - sendit(sock, buf); - strcpy(buf, " wpos="); - for (i=0; i<5; i++) { - if (bit_is_set(i, run->wpos)) { - sprintf(num, "%d ", i+1); - strcat(buf, num); - } - } - strcat(buf, "\n"); - sendit(sock, buf); - sendit(sock, " mins=%d\n", run->minute); - if (run->pool) { - sendit(sock, " --> "); - 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) { - 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; - } - } else { - sendit(sock, "Schedule: name=%s\n", res->res_sch.hdr.name); - } - break; - case R_GROUP: - sendit(sock, "Group: name=%s\n", res->res_group.hdr.name); - break; - case R_POOL: - sendit(sock, "Pool: name=%s PoolType=%s\n", res->res_pool.hdr.name, - 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); - sendit(sock, " max_vols=%d auto_prune=%d VolRetention=%" lld "\n", - 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)); - sendit(sock, " CleaningPrefix=%s\n", - 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); - break; - case R_MSGS: - sendit(sock, "Messages: name=%s\n", res->res_msgs.hdr.name); - if (res->res_msgs.mail_cmd) - sendit(sock, " mailcmd=%s\n", res->res_msgs.mail_cmd); - if (res->res_msgs.operator_cmd) - sendit(sock, " opcmd=%s\n", res->res_msgs.operator_cmd); - break; - default: - sendit(sock, "Unknown resource type %d in dump_resource.\n", type); - break; + 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)) { + sprintf(num, "%d ", i); + strcat(buf, num); + } + } + strcat(buf, "\n"); + sendit(sock, buf); + strcpy(buf, " mday="); + for (i=0; i<31; i++) { + if (bit_is_set(i, run->mday)) { + sprintf(num, "%d ", i+1); + strcat(buf, num); + } + } + strcat(buf, "\n"); + sendit(sock, buf); + strcpy(buf, " month="); + for (i=0; i<12; i++) { + if (bit_is_set(i, run->month)) { + sprintf(num, "%d ", i+1); + strcat(buf, num); + } + } + strcat(buf, "\n"); + sendit(sock, buf); + strcpy(buf, " wday="); + for (i=0; i<7; i++) { + if (bit_is_set(i, run->wday)) { + sprintf(num, "%d ", i+1); + strcat(buf, num); + } + } + strcat(buf, "\n"); + sendit(sock, buf); + strcpy(buf, " wpos="); + for (i=0; i<5; i++) { + if (bit_is_set(i, run->wpos)) { + sprintf(num, "%d ", i+1); + strcat(buf, num); + } + } + strcat(buf, "\n"); + sendit(sock, buf); + sendit(sock, " mins=%d\n", run->minute); + if (run->pool) { + sendit(sock, " --> "); + 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) { + 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; + } + } else { + sendit(sock, "Schedule: name=%s\n", res->res_sch.hdr.name); + } + break; + case R_GROUP: + sendit(sock, "Group: name=%s\n", res->res_group.hdr.name); + break; + case R_POOL: + sendit(sock, "Pool: name=%s PoolType=%s\n", res->res_pool.hdr.name, + 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); + sendit(sock, " max_vols=%d auto_prune=%d VolRetention=%" lld "\n", + 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)); + sendit(sock, " CleaningPrefix=%s\n", + 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); + break; + case R_MSGS: + sendit(sock, "Messages: name=%s\n", res->res_msgs.hdr.name); + if (res->res_msgs.mail_cmd) + sendit(sock, " mailcmd=%s\n", res->res_msgs.mail_cmd); + if (res->res_msgs.operator_cmd) + sendit(sock, " opcmd=%s\n", res->res_msgs.operator_cmd); + break; + default: + sendit(sock, "Unknown resource type %d in dump_resource.\n", type); + break; } if (recurse && res->res_dir.hdr.next) { dump_resource(type, res->res_dir.hdr.next, sendit, sock); @@ -637,13 +653,13 @@ 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); + free(fopt->match); } for (int j=0; jnum_base; j++) { - free(fopt->base_list[j]); + free(fopt->base_list[j]); } if (fopt->base_list) { - free(fopt->base_list); + free(fopt->base_list); } free(fopt); } @@ -682,137 +698,139 @@ void free_resource(int type) } switch (type) { - case R_DIRECTOR: - if (res->res_dir.working_directory) { - free(res->res_dir.working_directory); - } - if (res->res_dir.pid_directory) { - free(res->res_dir.pid_directory); - } - if (res->res_dir.subsys_directory) { - free(res->res_dir.subsys_directory); - } - if (res->res_dir.password) { - free(res->res_dir.password); - } - if (res->res_dir.query_file) { - free(res->res_dir.query_file); - } - if (res->res_dir.DIRaddr) { - free(res->res_dir.DIRaddr); - } - break; - case R_CONSOLE: - if (res->res_con.password) { - free(res->res_con.password); - } - break; - case R_CLIENT: - if (res->res_client.address) { - free(res->res_client.address); - } - if (res->res_client.password) { - free(res->res_client.password); - } - break; - case R_STORAGE: - if (res->res_store.address) { - free(res->res_store.address); - } - if (res->res_store.password) { - free(res->res_store.password); - } - if (res->res_store.media_type) { - free(res->res_store.media_type); - } - if (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); - } - if (res->res_cat.db_socket) { - free(res->res_cat.db_socket); - } - if (res->res_cat.db_user) { - free(res->res_cat.db_user); - } - if (res->res_cat.db_name) { - free(res->res_cat.db_name); - } - if (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); - } - 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); - } - res->res_fs.num_excludes = 0; - break; - case R_POOL: - if (res->res_pool.pool_type) { - free(res->res_pool.pool_type); - } - if (res->res_pool.label_format) { - free(res->res_pool.label_format); - } - if (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; - } - } - break; - case R_JOB: - if (res->res_job.RestoreWhere) { - free(res->res_job.RestoreWhere); - } - if (res->res_job.RestoreBootstrap) { - free(res->res_job.RestoreBootstrap); - } - if (res->res_job.WriteBootstrap) { - free(res->res_job.WriteBootstrap); - } - if (res->res_job.RunBeforeJob) { - free(res->res_job.RunBeforeJob); - } - if (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); - if (res->res_msgs.operator_cmd) - free(res->res_msgs.operator_cmd); - free_msgs_res((MSGS *)res); /* free message resource */ - res = NULL; - break; - case R_GROUP: - break; - default: - printf("Unknown resource type %d in free_resource.\n", type); + case R_DIRECTOR: + if (res->res_dir.working_directory) { + free(res->res_dir.working_directory); + } + if (res->res_dir.pid_directory) { + free(res->res_dir.pid_directory); + } + if (res->res_dir.subsys_directory) { + free(res->res_dir.subsys_directory); + } + if (res->res_dir.password) { + free(res->res_dir.password); + } + if (res->res_dir.query_file) { + free(res->res_dir.query_file); + } + if (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); + } + break; + case R_CLIENT: + if (res->res_client.address) { + free(res->res_client.address); + } + if (res->res_client.password) { + free(res->res_client.password); + } + break; + case R_STORAGE: + if (res->res_store.address) { + free(res->res_store.address); + } + if (res->res_store.password) { + free(res->res_store.password); + } + if (res->res_store.media_type) { + free(res->res_store.media_type); + } + if (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); + } + if (res->res_cat.db_socket) { + free(res->res_cat.db_socket); + } + if (res->res_cat.db_user) { + free(res->res_cat.db_user); + } + if (res->res_cat.db_name) { + free(res->res_cat.db_name); + } + if (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); + } + 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); + } + res->res_fs.num_excludes = 0; + break; + case R_POOL: + if (res->res_pool.pool_type) { + free(res->res_pool.pool_type); + } + if (res->res_pool.label_format) { + free(res->res_pool.label_format); + } + if (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; + } + } + break; + case R_JOB: + if (res->res_job.RestoreWhere) { + free(res->res_job.RestoreWhere); + } + if (res->res_job.RestoreBootstrap) { + free(res->res_job.RestoreBootstrap); + } + if (res->res_job.WriteBootstrap) { + free(res->res_job.WriteBootstrap); + } + if (res->res_job.RunBeforeJob) { + free(res->res_job.RunBeforeJob); + } + if (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); + if (res->res_msgs.operator_cmd) + free(res->res_msgs.operator_cmd); + free_msgs_res((MSGS *)res); /* free message resource */ + res = NULL; + break; + case R_GROUP: + break; + default: + printf("Unknown resource type %d in free_resource.\n", type); } /* Common stuff again -- free the resource, recurse to next one */ if (res) { @@ -842,10 +860,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) { @@ -860,147 +878,155 @@ void save_resource(int type, struct res_items *items, int pass) */ if (pass == 2) { switch (type) { - /* Resources not containing a resource */ - case R_CONSOLE: - case R_CATALOG: - case R_STORAGE: - case R_GROUP: - case R_POOL: - case R_MSGS: - case R_FILESET: - break; - - /* Resources containing another resource */ - case R_DIRECTOR: - 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; - case R_JOB: - 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) { - 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) { - Emsg1(M_ERROR_TERM, 0, "Inappropriate level specified in Job resource %s\n", - res_all.res_dir.hdr.name); - } - } - break; - case R_CLIENT: - 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; - case R_SCHEDULE: - /* 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) { - 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; - default: - Emsg1(M_ERROR, 0, "Unknown resource type %d in save_resource.\n", type); - error = 1; - break; + /* Resources not containing a resource */ + case R_CONSOLE: + case R_CATALOG: + case R_STORAGE: + case R_GROUP: + case R_POOL: + case R_MSGS: + case R_FILESET: + break; + + /* Resources containing another resource */ + case R_DIRECTOR: + 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; + case R_JOB: + 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) { + 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) { + Emsg1(M_ERROR_TERM, 0, "Inappropriate level specified in Job resource %s\n", + res_all.res_dir.hdr.name); + } + } + break; + case R_COUNTER: + 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; + + case R_CLIENT: + 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; + case R_SCHEDULE: + /* 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) { + 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; + default: + Emsg1(M_ERROR, 0, "Unknown resource type %d in save_resource.\n", type); + 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; } /* The following code is only executed for pass 1 */ switch (type) { - case R_DIRECTOR: - size = sizeof(DIRRES); - break; - case R_CONSOLE: - size = sizeof(CONRES); - break; - case R_CLIENT: - size =sizeof(CLIENT); - break; - case R_STORAGE: - size = sizeof(STORE); - break; - case R_CATALOG: - size = sizeof(CAT); - break; - case R_JOB: - size = sizeof(JOB); - break; - case R_FILESET: - size = sizeof(FILESET); - break; - case R_SCHEDULE: - size = sizeof(SCHED); - break; - case R_GROUP: - size = sizeof(GROUP); - break; - case R_POOL: - size = sizeof(POOL); - break; - case R_MSGS: - size = sizeof(MSGS); - break; - case R_COUNTER: - size = sizeof(COUNTER); - break; - default: - printf("Unknown resource type %d in save_resrouce.\n", type); - error = 1; - size = 1; - break; + case R_DIRECTOR: + size = sizeof(DIRRES); + break; + case R_CONSOLE: + size = sizeof(CONRES); + break; + case R_CLIENT: + size =sizeof(CLIENT); + break; + case R_STORAGE: + size = sizeof(STORE); + break; + case R_CATALOG: + size = sizeof(CAT); + break; + case R_JOB: + size = sizeof(JOB); + break; + case R_FILESET: + size = sizeof(FILESET); + break; + case R_SCHEDULE: + size = sizeof(SCHED); + break; + case R_GROUP: + size = sizeof(GROUP); + break; + case R_POOL: + size = sizeof(POOL); + break; + case R_MSGS: + size = sizeof(MSGS); + break; + case R_COUNTER: + size = sizeof(COUNTER); + break; + default: + printf("Unknown resource type %d in save_resrouce.\n", type); + error = 1; + size = 1; + break; } /* Common */ if (!error) { 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); } } } @@ -1017,9 +1043,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) { @@ -1041,9 +1067,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) { @@ -1060,9 +1086,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) { @@ -1100,59 +1126,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); } @@ -1182,91 +1208,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 f9f28dca6c..41dc341b6d 100644 --- a/bacula/src/dird/dird_conf.h +++ b/bacula/src/dird/dird_conf.h @@ -271,8 +271,10 @@ struct COUNTER { int32_t MinValue; /* Minimum value */ int32_t MaxValue; /* Maximum value */ - int Global; /* global/local */ - char *WrapCounter; /* Wrap counter name */ + int32_t CurrentValue; /* Current value */ + CAT *WrapCounter; /* Wrap counter name */ + CAT *Catalog; /* Where to store */ + bool created; /* Created in DB */ }; /* @@ -282,7 +284,6 @@ struct COUNTER { struct POOL { RES hdr; - COUNTER counter; /* Counter resources */ char *pool_type; /* Pool type */ char *label_format; /* Label format string */ char *cleaning_prefix; /* Cleaning label prefix */ diff --git a/bacula/src/dird/newvol.c b/bacula/src/dird/newvol.c index d24cacc0f0..1c5c162e2e 100644 --- a/bacula/src/dird/newvol.c +++ b/bacula/src/dird/newvol.c @@ -35,6 +35,11 @@ #include "bacula.h" #include "dird.h" +/* Forward referenced functions */ +static int create_simple_name(JCR *jcr, MEDIA_DBR *mr, POOL_DBR *pr); +static int perform_full_name_substitution(JCR *jcr, MEDIA_DBR *mr, POOL_DBR *pr); + + /* * Really crude automatic Volume name creation using * LabelFormat. We assume that if this routine is being @@ -43,8 +48,6 @@ int newVolume(JCR *jcr, MEDIA_DBR *mr) { POOL_DBR pr; - char name[MAXSTRING]; - char num[20]; memset(&pr, 0, sizeof(pr)); @@ -54,36 +57,26 @@ int newVolume(JCR *jcr, MEDIA_DBR *mr) if (db_get_pool_record(jcr, jcr->db, &pr) && pr.LabelFormat[0] && pr.LabelFormat[0] != '*') { if (pr.MaxVols == 0 || pr.NumVols < pr.MaxVols) { - memset(mr, 0, sizeof(mr)); + memset(mr, 0, sizeof(MEDIA_DBR)); set_pool_dbr_defaults_in_media_dbr(mr, &pr); mr->LabelDate = time(NULL); bstrncpy(mr->MediaType, jcr->store->media_type, sizeof(mr->MediaType)); - bstrncpy(name, pr.LabelFormat, sizeof(name)); - if (!is_volume_name_legal(NULL, name)) { - Jmsg(jcr, M_ERROR, 0, _("Illegal character in Label Format\n")); - goto bail_out; - } - /* See if volume already exists */ - mr->VolumeName[0] = 0; - for (int i=pr.NumVols+1; i<(int)pr.NumVols+11; i++) { - MEDIA_DBR tmr; - memset(&tmr, 0, sizeof(tmr)); - sprintf(num, "%04d", i); - bstrncpy(tmr.VolumeName, name, sizeof(tmr.VolumeName)); - bstrncat(tmr.VolumeName, num, sizeof(tmr.VolumeName)); - if (db_get_media_record(jcr, jcr->db, &tmr)) { - Jmsg(jcr, M_WARNING, 0, -_("Wanted to create Volume \"%s\", but it already exists. Trying again.\n"), - tmr.VolumeName); - continue; + /* Check for special characters */ + if (is_volume_name_legal(NULL, pr.LabelFormat)) { + /* No special characters, so apply simple algorithm */ + if (!create_simple_name(jcr, mr, &pr)) { + goto bail_out; + } + } else { /* try full substitution */ + /* Found special characters, so try substitution */ + if (!perform_full_name_substitution(jcr, mr, &pr)) { + goto bail_out; + } + if (!is_volume_name_legal(NULL, mr->VolumeName)) { + Jmsg(jcr, M_ERROR, 0, _("Illegal character in Volume name \"%s\"\n"), + mr->VolumeName); + goto bail_out; } - bstrncpy(mr->VolumeName, name, sizeof(mr->VolumeName)); - bstrncat(mr->VolumeName, num, sizeof(mr->VolumeName)); - break; /* Got good name */ - } - if (mr->VolumeName[0] == 0) { - Jmsg(jcr, M_ERROR, 0, _("Too many failures. Giving up creating Volume.\n")); - goto bail_out; } pr.NumVols++; if (db_create_media_record(jcr, jcr->db, mr) && @@ -101,3 +94,363 @@ bail_out: db_unlock(jcr->db); return 0; } + +static int create_simple_name(JCR *jcr, MEDIA_DBR *mr, POOL_DBR *pr) +{ + char name[MAXSTRING]; + char num[20]; + + /* See if volume already exists */ + mr->VolumeName[0] = 0; + bstrncpy(name, pr->LabelFormat, sizeof(name)); + for (int i=pr->NumVols+1; i<(int)pr->NumVols+11; i++) { + MEDIA_DBR tmr; + memset(&tmr, 0, sizeof(tmr)); + sprintf(num, "%04d", i); + bstrncpy(tmr.VolumeName, name, sizeof(tmr.VolumeName)); + bstrncat(tmr.VolumeName, num, sizeof(tmr.VolumeName)); + if (db_get_media_record(jcr, jcr->db, &tmr)) { + Jmsg(jcr, M_WARNING, 0, + _("Wanted to create Volume \"%s\", but it already exists. Trying again.\n"), + tmr.VolumeName); + continue; + } + bstrncpy(mr->VolumeName, name, sizeof(mr->VolumeName)); + bstrncat(mr->VolumeName, num, sizeof(mr->VolumeName)); + break; /* Got good name */ + } + if (mr->VolumeName[0] == 0) { + Jmsg(jcr, M_ERROR, 0, _("Too many failures. Giving up creating Volume name.\n")); + return 0; + } + return 1; +} + +static int date_item(JCR *jcr, int code, + const char **val_ptr, int *val_len, int *val_size) +{ + struct tm tm; + time_t now = time(NULL); + localtime_r(&now, &tm); + int val = 0; + char buf[10]; + + switch (code) { + case 1: /* year */ + val = tm.tm_year + 1900; + break; + case 2: /* month */ + val = tm.tm_mon + 1; + break; + case 3: /* day */ + val = tm.tm_mday; + break; + case 4: /* hour */ + val = tm.tm_hour; + break; + case 5: /* minute */ + val = tm.tm_min; + break; + case 6: /* second */ + val = tm.tm_sec; + break; + case 7: /* Week day */ + val = tm.tm_wday; + break; + } + bsnprintf(buf, sizeof(buf), "%d", val); + *val_ptr = bstrdup(buf); + *val_len = strlen(buf); + *val_size = *val_len; + return 1; +} + +static int job_item(JCR *jcr, int code, + const char **val_ptr, int *val_len, int *val_size) +{ + char *str = " "; + char buf[20]; + + switch (code) { + case 1: /* Job */ + str = jcr->Job; + break; + case 2: /* Director's name */ + str = my_name; + break; + case 3: /* level */ + str = job_level_to_str(jcr->JobLevel); + break; + case 4: /* type */ + str = job_type_to_str(jcr->JobType); + break; + case 5: /* JobId */ + bsnprintf(buf, sizeof(buf), "%d", jcr->JobId); + str = buf; + break; + case 6: /* Client */ + str = jcr->client_name; + if (!str) { + str = " "; + } + break; + case 7: /* NumVols */ + bsnprintf(buf, sizeof(buf), "%d", jcr->NumVols); + str = buf; + break; + case 8: /* Pool */ + str = jcr->client->hdr.name; + break; + } + *val_ptr = bstrdup(str); + *val_len = strlen(str); + *val_size = *val_len; + return 1; +} + + +struct s_built_in_vars {char *var_name; int code; int (*func)(JCR *jcr, int code, + const char **val_ptr, int *val_len, int *val_size);}; + +static struct s_built_in_vars built_in_vars[] = { + { N_("Year"), 1, date_item}, + { N_("Month"), 2, date_item}, + { N_("Day"), 3, date_item}, + { N_("Hour"), 4, date_item}, + { N_("Minute"), 5, date_item}, + { N_("Second"), 6, date_item}, + { N_("WeekDay"), 7, date_item}, + + { N_("Job"), 1, job_item}, + { N_("Dir"), 2, job_item}, + { N_("Level"), 3, job_item}, + { N_("Type"), 4, job_item}, + { N_("JobId"), 5, job_item}, + { N_("Client"), 6, job_item}, + { N_("NumVols"), 7, job_item}, + { N_("Pool"), 8, job_item}, + + { NULL, 0, NULL} +}; + + +static var_rc_t lookup_built_in_var(var_t *ctx, void *my_ctx, + const char *var_ptr, int var_len, int var_index, + const char **val_ptr, int *val_len, int *val_size) +{ + JCR *jcr = (JCR *)my_ctx; + int stat; + + for (int i=0; _(built_in_vars[i].var_name); i++) { + if (strncmp(_(built_in_vars[i].var_name), var_ptr, var_len) == 0) { + stat = (*built_in_vars[i].func)(jcr, built_in_vars[i].code, + val_ptr, val_len, val_size); + if (stat) { + return VAR_OK; + } + break; + } + } + return VAR_ERR_UNDEFINED_VARIABLE; +} + + +/* + * Search counter variables + */ +static var_rc_t lookup_counter_var(var_t *ctx, void *my_ctx, + const char *var_ptr, int var_len, int var_inc, int var_index, + const char **val_ptr, int *val_len, int *val_size) +{ + char buf[MAXSTRING]; + var_rc_t stat = VAR_ERR_UNDEFINED_VARIABLE; + + if (var_len > (int)sizeof(buf) - 1) { + return VAR_ERR_OUT_OF_MEMORY; + } + memcpy(buf, var_ptr, var_len); + buf[var_len] = 0; + LockRes(); + for (COUNTER *counter=NULL; (counter = (COUNTER *)GetNextRes(R_COUNTER, (RES *)counter)); ) { + if (strcmp(counter->hdr.name, buf) == 0) { + bsnprintf(buf, sizeof(buf), "%d", counter->CurrentValue); + *val_ptr = bstrdup(buf); + *val_len = strlen(buf); + *val_size = *val_len; + if (var_inc) { + COUNTER_DBR cr; + JCR *jcr = (JCR *)my_ctx; + memset(&cr, 0, sizeof(cr)); + bstrncpy(cr.Counter, counter->hdr.name, sizeof(cr.Counter)); + cr.MinValue = counter->MinValue; + cr.MaxValue = counter->MaxValue; + cr.CurrentValue = ++counter->CurrentValue; + bstrncpy(cr.WrapCounter, counter->WrapCounter->hdr.name, sizeof(cr.WrapCounter)); + if (!db_update_counter_record(jcr, jcr->db, &cr)) { + Jmsg(jcr, M_ERROR, 0, _("Count not update counter %s: ERR=%s\n"), + counter->hdr.name, db_strerror(jcr->db)); + } + } + stat = VAR_OK; + break; + } + } + UnlockRes(); + return stat; +} + + +/* + * Called here to look up a variable + */ +static var_rc_t lookup_var(var_t *ctx, void *my_ctx, + const char *var_ptr, int var_len, int var_inc, int var_index, + const char **val_ptr, int *val_len, int *val_size) +{ + char buf[MAXSTRING]; + var_rc_t stat; + + if ((stat = lookup_built_in_var(ctx, my_ctx, var_ptr, var_len, var_index, + val_ptr, val_len, val_size)) == VAR_OK) { + return VAR_OK; + } + + if ((stat = lookup_counter_var(ctx, my_ctx, var_ptr, var_len, var_inc, var_index, + val_ptr, val_len, val_size)) == VAR_OK) { + return VAR_OK; + } + + /* Look in environment */ + if (var_index != 0) { + return VAR_ERR_ARRAY_LOOKUPS_ARE_UNSUPPORTED; + } + if (var_len > (int)sizeof(buf) - 1) { + return VAR_ERR_OUT_OF_MEMORY; + } + memcpy(buf, var_ptr, var_len+1); + buf[var_len+1] = 0; + Dmsg1(000, "Var=%s\n", buf); + + if ((*val_ptr = getenv(buf)) == NULL) { + return VAR_ERR_UNDEFINED_VARIABLE; + } + *val_len = strlen(*val_ptr); + *val_size = 0; + return VAR_OK; +} + +/* + * Called here to do a special operation on a variable + * op_ptr points to the special operation code (not EOS terminated) + * arg_ptr points to argument to special op code + * val_ptr points to the value string + * out_ptr points to string to be returned + */ +static var_rc_t operate_var(var_t *var, void *my_ctx, + const char *op_ptr, int op_len, + const char *arg_ptr, int arg_len, + const char *val_ptr, int val_len, + char **out_ptr, int *out_len, int *out_size) +{ + var_rc_t stat = VAR_ERR_UNDEFINED_OPERATION; + Dmsg0(000, "Enter operate_var\n"); + if (!val_ptr) { + *out_size = 0; + return stat; + } + if (op_len == 3 && strncmp(op_ptr, "inc", 3) == 0) { + char buf[MAXSTRING]; + if (val_len > (int)sizeof(buf) - 1) { + return VAR_ERR_OUT_OF_MEMORY; + } + memcpy(buf, arg_ptr, arg_len); + buf[arg_len] = 0; + Dmsg1(000, "Arg=%s\n", buf); + memcpy(buf, val_ptr, val_len); + buf[val_len] = 0; + Dmsg1(000, "Val=%s\n", buf); + LockRes(); + for (COUNTER *counter=NULL; (counter = (COUNTER *)GetNextRes(R_COUNTER, (RES *)counter)); ) { + if (strcmp(counter->hdr.name, buf) == 0) { + Dmsg2(000, "counter=%s val=%s\n", counter->hdr.name, buf); + break; + } + } + UnlockRes(); + return stat; + } + *out_size = 0; + return stat; +} + +/* + * Perform full substitution on Label + */ +static int perform_full_name_substitution(JCR *jcr, MEDIA_DBR *mr, POOL_DBR *pr) +{ + var_t *var_ctx; + var_rc_t stat; + char *inp, *outp; + int in_len, out_len; + int rtn_stat = 0; + + inp = pr->LabelFormat; + in_len = strlen(inp); + + outp = NULL; + out_len = 0; + + jcr->NumVols = pr->NumVols; + /* create context */ + if ((stat = var_create(&var_ctx)) != VAR_OK) { + Jmsg(jcr, M_ERROR, 0, _("Cannot create var context: ERR=%s\n"), var_strerror(var_ctx, stat)); + goto bail_out; + } + /* define callback */ + if ((stat = var_config(var_ctx, VAR_CONFIG_CB_VALUE, lookup_var, (void *)jcr)) != VAR_OK) { + Jmsg(jcr, M_ERROR, 0, _("Cannot set var callback: ERR=%s\n"), var_strerror(var_ctx, stat)); + goto bail_out; + } + + + /* define special operations */ + if ((stat = var_config(var_ctx, VAR_CONFIG_CB_OPERATION, operate_var, (void *)jcr)) != VAR_OK) { + Jmsg(jcr, M_ERROR, 0, _("Cannot set var operate: ERR=%s\n"), var_strerror(var_ctx, stat)); + goto bail_out; + } + + /* unescape in place */ + if ((stat = var_unescape(var_ctx, inp, in_len, inp, in_len+1, 0)) != VAR_OK) { + Jmsg(jcr, M_ERROR, 0, _("Cannot unescape string: ERR=%s\n"), var_strerror(var_ctx, stat)); + goto bail_out; + } + + in_len = strlen(inp); + + /* expand variables */ + if ((stat = var_expand(var_ctx, inp, in_len, &outp, &out_len, 1)) != VAR_OK) { + Jmsg(jcr, M_ERROR, 0, _("Cannot expand LabelFormat \"%s\": ERR=%s\n"), + inp, var_strerror(var_ctx, stat)); + goto bail_out; + } + + /* unescape once more in place */ + if ((stat = var_unescape(var_ctx, outp, out_len, outp, out_len+1, 1)) != VAR_OK) { + Jmsg(jcr, M_ERROR, 0, _("Cannot unescape string: ERR=%s\n"), var_strerror(var_ctx, stat)); + goto bail_out; + } + + bstrncpy(mr->VolumeName, outp, sizeof(mr->VolumeName)); + + rtn_stat = 1; + +bail_out: + /* destroy expansion context */ + if ((stat = var_destroy(var_ctx)) != VAR_OK) { + Jmsg(jcr, M_ERROR, 0, _("Cannot destroy var context: ERR=%s\n"), var_strerror(var_ctx, stat)); + } + if (outp) { + free(outp); + } + return rtn_stat; +} diff --git a/bacula/src/dird/ua_cmds.c b/bacula/src/dird/ua_cmds.c index d5133b2361..118e91c1d0 100644 --- a/bacula/src/dird/ua_cmds.c +++ b/bacula/src/dird/ua_cmds.c @@ -48,7 +48,7 @@ extern char *list_pool; extern int statuscmd(UAContext *ua, char *cmd); extern int listcmd(UAContext *ua, char *cmd); extern int llistcmd(UAContext *ua, char *cmd); -extern int showcmd(UAContext *ua, char *cmd); +extern int show_cmd(UAContext *ua, char *cmd); extern int messagescmd(UAContext *ua, char *cmd); extern int autodisplaycmd(UAContext *ua, char *cmd); extern int sqlquerycmd(UAContext *ua, char *cmd); @@ -87,30 +87,30 @@ static struct cmdstruct commands[] = { { N_("add"), add_cmd, _("add media to a pool")}, { N_("autodisplay"), autodisplaycmd, _("autodisplay [on/off] -- console messages")}, { N_("automount"), automount_cmd, _("automount [on/off] -- after label")}, - { N_("cancel"), cancelcmd, _("cancel job=nnn -- cancel a job")}, - { N_("create"), createcmd, _("create DB Pool from resource")}, + { N_("cancel"), cancelcmd, _("cancel job=nnn -- cancel a job")}, + { N_("create"), createcmd, _("create DB Pool from resource")}, { N_("delete"), delete_cmd, _("delete [pool= | media volume=]")}, { N_("help"), help_cmd, _("print this command")}, - { N_("label"), labelcmd, _("label a tape")}, - { N_("relabel"), relabelcmd, _("relabel a tape")}, - { N_("list"), listcmd, _("list [pools | jobs | jobtotals | media | files job=]; from catalog")}, - { N_("llist"), llistcmd, _("full or long list like list command")}, - { N_("messages"), messagescmd, _("messages")}, + { N_("label"), labelcmd, _("label a tape")}, + { N_("relabel"), relabelcmd, _("relabel a tape")}, + { N_("list"), listcmd, _("list [pools | jobs | jobtotals | media | files job=]; from catalog")}, + { N_("llist"), llistcmd, _("full or long list like list command")}, + { N_("messages"), messagescmd, _("messages")}, { N_("mount"), mount_cmd, _("mount ")}, - { N_("restore"), restorecmd, _("restore files")}, - { N_("prune"), prunecmd, _("prune expired records from catalog")}, - { N_("purge"), purgecmd, _("purge records from catalog")}, - { N_("run"), runcmd, _("run ")}, + { N_("restore"), restorecmd, _("restore files")}, + { N_("prune"), prunecmd, _("prune expired records from catalog")}, + { N_("purge"), purgecmd, _("purge records from catalog")}, + { N_("run"), runcmd, _("run ")}, { N_("setdebug"), setdebug_cmd, _("sets debug level")}, - { N_("show"), showcmd, _("show (resource records) [jobs | pools | ... | all]")}, - { N_("sqlquery"), sqlquerycmd, _("use SQL to query catalog")}, - { N_("status"), statuscmd, _("status [storage | client]=")}, + { N_("show"), show_cmd, _("show (resource records) [jobs | pools | ... | all]")}, + { N_("sqlquery"), sqlquerycmd, _("use SQL to query catalog")}, + { N_("status"), statuscmd, _("status [storage | client]=")}, { N_("unmount"), unmount_cmd, _("unmount ")}, { N_("update"), update_cmd, _("update Volume or Pool")}, { N_("use"), use_cmd, _("use catalog xxx")}, { N_("version"), version_cmd, _("print Director version")}, { N_("quit"), quit_cmd, _("quit")}, - { N_("query"), querycmd, _("query catalog")}, + { N_("query"), querycmd, _("query catalog")}, { N_("release"), release_cmd, _("release ")}, { N_("time"), time_cmd, _("print current time")}, { N_("exit"), quit_cmd, _("exit = quit")}, diff --git a/bacula/src/dird/ua_output.c b/bacula/src/dird/ua_output.c index 76045c7038..479eb80087 100644 --- a/bacula/src/dird/ua_output.c +++ b/bacula/src/dird/ua_output.c @@ -78,6 +78,7 @@ struct showstruct {char *res_name; int type;}; static struct showstruct reses[] = { {N_("directors"), R_DIRECTOR}, {N_("clients"), R_CLIENT}, + {N_("counters"), R_COUNTER}, {N_("jobs"), R_JOB}, {N_("storages"), R_STORAGE}, {N_("catalogs"), R_CATALOG}, @@ -100,7 +101,7 @@ static struct showstruct reses[] = { * show = e.g. show director=HeadMan * */ -int showcmd(UAContext *ua, char *cmd) +int show_cmd(UAContext *ua, char *cmd) { int i, j, type, len; int recurse; diff --git a/bacula/src/jcr.h b/bacula/src/jcr.h index be78fcdae4..4b09ccfc07 100644 --- a/bacula/src/jcr.h +++ b/bacula/src/jcr.h @@ -139,7 +139,6 @@ struct JCR { MSGS *messages; /* Default message handler */ volatile int SDJobStatus; /* Storage Job Status */ volatile int FDJobStatus; /* File daemon Job Status */ - int mode; /* manual/auto run */ B_DB *db; /* database pointer */ uint32_t MediaId; /* DB record IDs associated with this job */ uint32_t PoolId; /* Pool record id */ @@ -153,6 +152,7 @@ struct JCR { POOLMEM *client_uname; /* client uname */ int replace; /* Replace option */ int acquired_resource_locks; /* set if resource locks acquired */ + int NumVols; /* Number of Volume used in pool */ #endif /* DIRECTOR_DAEMON */ diff --git a/bacula/src/lib/Makefile.in b/bacula/src/lib/Makefile.in index 8229502d37..5eda0b8eca 100644 --- a/bacula/src/lib/Makefile.in +++ b/bacula/src/lib/Makefile.in @@ -39,7 +39,7 @@ LIBSRCS = alloc.c attr.c base64.c bsys.c bget_msg.c \ md5.c message.c mem_pool.c parse_conf.c \ queue.c rwlock.c scan.c serial.c sha1.c \ semlock.c signal.c smartall.c tree.c \ - util.c watchdog.c workq.c + util.c var.c watchdog.c workq.c LIBOBJS = alloc.o attr.o base64.o bsys.o bget_msg.o \ @@ -50,7 +50,7 @@ LIBOBJS = alloc.o attr.o base64.o bsys.o bget_msg.o \ md5.o message.o mem_pool.o parse_conf.o \ queue.o rwlock.o scan.o serial.o sha1.o \ semlock.o signal.o smartall.o tree.o \ - util.o watchdog.o workq.o + util.o var.o watchdog.o workq.o EXTRAOBJS = @OBJLIST@ diff --git a/bacula/src/lib/lib.h b/bacula/src/lib/lib.h index bc2b74fdc7..0a4b7715b3 100644 --- a/bacula/src/lib/lib.h +++ b/bacula/src/lib/lib.h @@ -51,5 +51,6 @@ #include "watchdog.h" #include "bpipe.h" #include "attr.h" +#include "var.h" #include "protos.h" diff --git a/bacula/src/lib/util.c b/bacula/src/lib/util.c index fda802a52d..0ef5a59c29 100644 --- a/bacula/src/lib/util.c +++ b/bacula/src/lib/util.c @@ -527,7 +527,7 @@ POOLMEM *edit_job_codes(JCR *jcr, char *omsg, char *imsg, char *to) str = job_status_to_str(jcr->JobStatus); break; case 'i': - sprintf(add, "%d", jcr->JobId); + bsnprintf(add, sizeof(add), "%d", jcr->JobId); str = add; break; case 'j': /* Job name */ diff --git a/bacula/src/version.h b/bacula/src/version.h index 38d81bbbe0..3f069734af 100644 --- a/bacula/src/version.h +++ b/bacula/src/version.h @@ -1,8 +1,8 @@ /* */ #define VERSION "1.31" #define VSTRING "1" -#define BDATE "10 Jun 2003" -#define LSMDATE "10Jun03" +#define BDATE "14 Jun 2003" +#define LSMDATE "14Jun03" /* Debug flags */ #define DEBUG 1