From 87700e77146cd5624f5375adeadb5073fa7170cd Mon Sep 17 00:00:00 2001 From: Kern Sibbald Date: Sat, 20 Sep 2003 11:45:44 +0000 Subject: [PATCH] Add full lenght time modifiers + require resource names to be unique git-svn-id: https://bacula.svn.sourceforge.net/svnroot/bacula/trunk@708 91ce42f0-d328-0410-95d8-f526ca767f89 --- bacula/ChangeLog | 32 ++- bacula/ReleaseNotes | 5 + bacula/kernstodo | 15 +- bacula/src/console/console_conf.c | 10 +- bacula/src/dird/authenticate.c | 4 +- bacula/src/dird/dird_conf.c | 41 ++-- bacula/src/dird/fd_cmds.c | 12 +- bacula/src/dird/ua_tree.c | 4 +- bacula/src/filed/filed_conf.c | 9 +- bacula/src/lib/edit.c | 104 ++++++++-- bacula/src/lib/lex.c | 330 +++++++++++++++--------------- bacula/src/lib/parse_conf.c | 19 +- bacula/src/stored/bscan.c | 14 +- bacula/src/stored/stored_conf.c | 9 +- bacula/src/version.h | 4 +- 15 files changed, 380 insertions(+), 232 deletions(-) diff --git a/bacula/ChangeLog b/bacula/ChangeLog index 960937403c..31b70f765e 100644 --- a/bacula/ChangeLog +++ b/bacula/ChangeLog @@ -1,5 +1,35 @@ -2003-09-12 Version 1.32 12Sep03 Beta +2003-09-20 Version 1.32 20Sep03 Beta +- Replace a number strcpy() calls with bstrncpy(). +- Added code to ensure that the names for each resource + type are unique. Two resources of different types can + have the same name. +- More documentation +- Added new full length modifiers for time intervals. + Compatible with previous method EXCEPT a modifier is now + manditory. +- Completely restructured recycling. It should work now, but + in any case, the logic is much cleaner. A lot of new + code in next_vol.c +- Added a few pthread_xx_destroy() for items inited. +- Nic Bellamy pointed out that it wasn't necessary to do + destroy() of static initialized pthread variables -- fixed + watchdog. +- update VolStatus asked for the media and volume twice. +- Changed a few more strcpy() to bstrncpy(). +- Made VolBytes=1 as indicator that the Volume is labeled. +- Modified creation of Media record to include VolBytes, + same for sql_update - also set LabelDate if VolBytes = 1. +- Copy any statically linked programs to install directory. +- Change relabel flag to label in Update_media protocol Dir<->SD. +- Change a few strcpy to bstrncpy ... +- Update Media record after an automatic tape label. +- Added more debug code to bnet_server and bnet.c to attempt to + track down Alex's SD segfault (BSOCK==0) +- Add additional debug cod for authentication errors in cram-md5. +- Implement "list nextvol job=xx" and add Volume to Dir status. +- Retry waitpid if interrupted -- needed for FreeBSD! +- Move lex.c debug level to 900 - Add new aliases SDAddress, ... - Final changes for variable expansion - Possible fix to Alex's SD crashes diff --git a/bacula/ReleaseNotes b/bacula/ReleaseNotes index 30b351987b..ede070c3e2 100644 --- a/bacula/ReleaseNotes +++ b/bacula/ReleaseNotes @@ -17,6 +17,8 @@ Major Changes this Release: - Lots of fixes with variable expansion and counter variables - Automatic labeling of tape Volumes is fixed. - Recycling has been completely restructured and should work. +- Implemented full length time interval qualifiers (e.g + "5n is now "5 min" or "5 minutes". A modifier is now required! Other Changes this Release: @@ -46,3 +48,6 @@ Other Changes this Release: Items to note: !!!!! +- Modifiers (sec, min, hour, day, ...) are now required on conf file + time interval specifications. +- Duplicate names within the same conf resource are prohibited. diff --git a/bacula/kernstodo b/bacula/kernstodo index fdc8f9fd6b..c056395a5b 100644 --- a/bacula/kernstodo +++ b/bacula/kernstodo @@ -23,18 +23,14 @@ Testing to do: (painful) - Figure out how to use ssh or stunnel to protect Bacula communications. For 1.32 Testing/Documentation: -- Document list nextvol and new format status dir. - Document new records in Director. SDAddress SDDeviceName, SDPassword. FDPassword, FDAddress, DBAddress, DBPort, DBPassword. - Document that it is safe to use the drive when the lights stop flashing. - Document new Include/Exclude ... - Document all the status codes JobLevel, JobType, JobStatus. - Add test of exclusion, test multiple Include {} statements. -- Client files in Win32 with Unix eol conventions doesn't work. For 1.32: -- Add multiple character duration qualifiers. -- Require some modifer. - Enhance "update slots" to include a "scan" feature scan 1; scan 1-5; scan 1,2,4 ... to update the catalog - Allow a slot or range of slots on the label barcodes command. @@ -42,6 +38,8 @@ For 1.32: For 1.33 +- Get MySQL 3.23.58 +- Get and test MySQL 4.0 - Do a complete audit of all pthreads_mutex, cond, ... to ensure that any that are dynamically initialized are destroyed when no longer used. - Write a mini-readline with history and editing. @@ -923,3 +921,12 @@ Done: (see kernsdone for more) - LabelFormat on tape volume apparently creates the db record but never actually labels the volume. - Recycling a volume when two jobs are using it is going to break. Fixed. +- Document list nextvol and new format status dir. +- Client files in Win32 with Unix eol conventions doesn't work. +- Either fix or document that fill command in btape can be + compressed enormously by the hardware - a 36GB tape wrote 750GB! +- Add multiple character duration qualifiers. +- Require some modifer. +- Restrict characters permitted in a Resource name, and don't permit + duplicate names. + diff --git a/bacula/src/console/console_conf.c b/bacula/src/console/console_conf.c index 573bff15f8..f69975c2d2 100644 --- a/bacula/src/console/console_conf.c +++ b/bacula/src/console/console_conf.c @@ -254,9 +254,13 @@ void save_resource(int type, struct res_items *items, int pass) resources[rindex].res_head = (RES *)res; /* store first entry */ } else { RES *next; - /* Add new res to end of chain */ - for (next=resources[rindex].res_head; next->next; next=next->next) - { } + for (next=resources[rindex].res_head; next->next; next=next->next) { + if (strcmp(next->name, res->res_dir.hdr.name) == 0) { + Emsg2(M_ERROR_TERM, 0, + _("Attempt to define second %s resource named \"%s\" is not permitted.\n"), + resources[rindex].name, res->res_dir.hdr.name); + } + } next->next = (RES *)res; Dmsg2(90, "Inserting %s res: %s\n", res_to_str(type), res->res_dir.hdr.name); diff --git a/bacula/src/dird/authenticate.c b/bacula/src/dird/authenticate.c index 81c638c97c..b41ca667c6 100644 --- a/bacula/src/dird/authenticate.c +++ b/bacula/src/dird/authenticate.c @@ -61,7 +61,7 @@ int authenticate_storage_daemon(JCR *jcr) /* * Send my name to the Storage daemon then do authentication */ - strcpy(dirname, director->hdr.name); + bstrncpy(dirname, director->hdr.name, sizeof(dirname)); bash_spaces(dirname); if (!bnet_fsend(sd, hello, dirname)) { Jmsg(jcr, M_FATAL, 0, _("Error sending Hello to Storage daemon. ERR=%s\n"), bnet_strerror(sd)); @@ -98,7 +98,7 @@ int authenticate_file_daemon(JCR *jcr) /* * Send my name to the File daemon then do authentication */ - strcpy(dirname, director->hdr.name); + bstrncpy(dirname, director->hdr.name, sizeof(dirname)); bash_spaces(dirname); if (!bnet_fsend(fd, hello, dirname)) { Jmsg(jcr, M_FATAL, 0, _("Error sending Hello to File daemon. ERR=%s\n"), bnet_strerror(fd)); diff --git a/bacula/src/dird/dird_conf.c b/bacula/src/dird/dird_conf.c index 526504166f..47c9f98581 100644 --- a/bacula/src/dird/dird_conf.c +++ b/bacula/src/dird/dird_conf.c @@ -310,11 +310,13 @@ extern struct res_items msgs_items[]; * This is the master resource definition. * It must have one item for each of the resources. * + * NOTE!!! keep it in the same order as the R_codes + * or eliminate all resources[rindex].name + * * name items rcode res_head */ struct s_res resources[] = { {"director", dir_items, R_DIRECTOR, NULL}, - {"console", con_items, R_CONSOLE, NULL}, {"client", cli_items, R_CLIENT, NULL}, {"job", job_items, R_JOB, NULL}, {"storage", store_items, R_STORAGE, NULL}, @@ -325,6 +327,7 @@ struct s_res resources[] = { {"pool", pool_items, R_POOL, NULL}, {"messages", msgs_items, R_MSGS, NULL}, {"counter", counter_items, R_COUNTER, NULL}, + {"console", con_items, R_CONSOLE, NULL}, {NULL, NULL, 0, NULL} }; @@ -408,7 +411,7 @@ void dump_resource(int type, RES *reshdr, void sendit(void *sock, char *fmt, ... { URES *res = (URES *)reshdr; int recurse = 1; - char ed1[30], ed2[30]; + char ed1[100], ed2[100]; if (res == NULL) { sendit(sock, "No %s resource defined\n", res_to_str(type)); @@ -457,8 +460,9 @@ void dump_resource(int type, RES *reshdr, void sendit(void *sock, char *fmt, ... 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, + sendit(sock, " JobRetention=%s FileRetention=%s AutoPrune=%d\n", + edit_utime(res->res_client.JobRetention, ed1), + edit_utime(res->res_client.FileRetention, ed2), res->res_client.AutoPrune); if (res->res_client.catalog) { sendit(sock, " --> "); @@ -554,11 +558,11 @@ void dump_resource(int type, RES *reshdr, void sendit(void *sock, char *fmt, ... } next_run: sendit(sock, " --> Run Level=%s\n", level_to_str(run->level)); - strcpy(buf, " hour="); + bstrncpy(buf, " hour=", sizeof(buf)); for (i=0; i<24; i++) { if (bit_is_set(i, run->hour)) { sprintf(num, "%d ", i); - strcat(buf, num); + bstrncat(buf, num, sizeof(buf)); } } strcat(buf, "\n"); @@ -630,10 +634,12 @@ next_run: 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", + sendit(sock, " max_vols=%d auto_prune=%d VolRetention=%s\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, + edit_utime(res->res_pool.VolRetention, ed1)); + sendit(sock, " VolUse=%s recycle=%d LabelFormat=%s\n", + edit_utime(res->res_pool.VolUseDuration, ed1), + res->res_pool.Recycle, NPRT(res->res_pool.label_format)); sendit(sock, " CleaningPrefix=%s\n", NPRT(res->res_pool.cleaning_prefix)); @@ -981,7 +987,9 @@ void save_resource(int type, struct res_items *items, int pass) return; } - /* The following code is only executed for pass 1 */ + /* + * The following code is only executed during pass 1 + */ switch (type) { case R_DIRECTOR: size = sizeof(DIRRES); @@ -1036,11 +1044,16 @@ void save_resource(int type, struct res_items *items, int pass) } else { RES *next; /* Add new res to end of chain */ - for (next=resources[rindex].res_head; next->next; next=next->next) - { } + for (next=resources[rindex].res_head; next->next; next=next->next) { + if (strcmp(next->name, res->res_dir.hdr.name) == 0) { + Emsg2(M_ERROR_TERM, 0, + _("Attempt to define second %s resource named \"%s\" is not permitted.\n"), + resources[rindex].name, res->res_dir.hdr.name); + } + } next->next = (RES *)res; - Dmsg3(200, "Inserting %s res: %s index=%d\n", res_to_str(type), - res->res_dir.hdr.name, rindex); + Dmsg4(200, "Inserting %s res: %s index=%d pass=%d\n", res_to_str(type), + res->res_dir.hdr.name, rindex, pass); } } } diff --git a/bacula/src/dird/fd_cmds.c b/bacula/src/dird/fd_cmds.c index 0c53376ca6..4d7f1e25b9 100644 --- a/bacula/src/dird/fd_cmds.c +++ b/bacula/src/dird/fd_cmds.c @@ -245,10 +245,10 @@ static int send_list(JCR *jcr, int list) } /* Copy File options */ if (ie->num_opts) { - strcpy(buf, ie->opts_list[0]->opts); - strcat(buf, " "); + bstrncpy(buf, ie->opts_list[0]->opts, sizeof(buf)); + bstrncat(buf, " ", sizeof(buf)); } else { - strcpy(buf, "0 "); + bstrncpy(buf, "0 ", sizeof(buf)); } optlen = strlen(buf); while (fgets(buf+optlen, sizeof(buf)-optlen, bpipe->rfd)) { @@ -274,10 +274,10 @@ static int send_list(JCR *jcr, int list) } /* Copy File options */ if (ie->num_opts) { - strcpy(buf, ie->opts_list[0]->opts); - strcat(buf, " "); + bstrncpy(buf, ie->opts_list[0]->opts, sizeof(buf)); + bstrncat(buf, " ", sizeof(buf)); } else { - strcpy(buf, "0 "); + bstrncpy(buf, "0 ", sizeof(buf)); } optlen = strlen(buf); while (fgets(buf+optlen, sizeof(buf)-optlen, ffd)) { diff --git a/bacula/src/dird/ua_tree.c b/bacula/src/dird/ua_tree.c index 9713505283..29db4a832d 100644 --- a/bacula/src/dird/ua_tree.c +++ b/bacula/src/dird/ua_tree.c @@ -384,8 +384,8 @@ static int cdcmd(UAContext *ua, TREE_CTX *tree) if (!node) { /* Try once more if Win32 drive -- make absolute */ if (ua->argk[1][1] == ':') { /* win32 drive */ - strcpy(cwd, "/"); - strcat(cwd, ua->argk[1]); + bstrncpy(cwd, "/", sizeof(cwd)); + bstrncat(cwd, ua->argk[1], sizeof(cwd)); node = tree_cwd(cwd, tree->root, tree->node); } if (!node) { diff --git a/bacula/src/filed/filed_conf.c b/bacula/src/filed/filed_conf.c index dd4db8c282..fcc3e53ca7 100644 --- a/bacula/src/filed/filed_conf.c +++ b/bacula/src/filed/filed_conf.c @@ -308,8 +308,13 @@ void save_resource(int type, struct res_items *items, int pass) } else { RES *next; /* Add new res to end of chain */ - for (next=resources[rindex].res_head; next->next; next=next->next) - { } + for (next=resources[rindex].res_head; next->next; next=next->next) { + if (strcmp(next->name, res->res_dir.hdr.name) == 0) { + Emsg2(M_ERROR_TERM, 0, + _("Attempt to define second %s resource named \"%s\" is not permitted.\n"), + resources[rindex].name, res->res_dir.hdr.name); + } + } next->next = (RES *)res; Dmsg2(90, "Inserting %s res: %s\n", res_to_str(type), res->res_dir.hdr.name); diff --git a/bacula/src/lib/edit.c b/bacula/src/lib/edit.c index 153e73c9b2..7d490c0457 100644 --- a/bacula/src/lib/edit.c +++ b/bacula/src/lib/edit.c @@ -102,38 +102,82 @@ char *edit_uint64(uint64_t val, char *buf) */ int duration_to_utime(char *str, utime_t *value) { - int i, ch, len; + int i, len; double val; - /* Default to 1 day if no modifier given */ - static int mod[] = {'*', 's', 'n', 'h', 'd', 'w', 'm', 'q', 'y', 0}; - static int mult[] = {60*60*24, 1, 60, 60*60, 60*60*24, 60*60*24*7, 60*60*24*30, - 60*60*24*91, 60*60*24*365}; + /* + * The "n" = mins and months appears before minutes so that m maps + * to months. These "kludges" make it compatible with pre 1.31 + * Baculas. + */ + static char *mod[] = {"n", "seconds", "months", "minutes", + "hours", "days", "weeks", "quarters", "years", NULL}; + static int32_t mult[] = {60, 1, 60*60*24*30, 60, + 60*60, 60*60*24, 60*60*24*7, 60*60*24*91, 60*60*24*365}; + char mod_str[20]; + int mod_len; - /* Look for modifier */ + /* + * Look for modifier by walking back looking for the first + * space or digit. + */ + strip_trailing_junk(str); len = strlen(str); - ch = str[len - 1]; - i = 0; - if (B_ISALPHA(ch)) { - if (B_ISUPPER(ch)) { - ch = tolower(ch); + /* Strip trailing spaces */ + for (i=len; i>0; i--) { + if (!B_ISSPACE(str[i-1])) { + break; } - while (mod[++i] != 0) { - if (ch == mod[i]) { - len--; - str[len] = 0; /* strip modifier */ - break; - } + str[i-1] = 0; + } + /* Find beginning of the modifier */ + for ( ; i>0; i--) { + if (!B_ISALPHA(str[i-1])) { + break; } } - if (mod[i] == 0 || !is_a_number(str)) { + /* If not found, error */ + if (i == 0 || i == len) { + Dmsg2(200, "error i=%d len=%d\n", i, len); return 0; } + /* Move modifier to mod_str */ + bstrncpy(mod_str, &str[i], sizeof(mod_str)); + mod_len = strlen(mod_str); + if (mod_len == 0) { /* Make sure we have a modifier */ + Dmsg0(200, "No modifier found\n"); + return 0; + } + Dmsg2(200, "in=%s mod=%s:\n", str, mod_str); + /* Backup over any spaces in front of modifier */ + for ( ; i>0; i--) { + if (B_ISSPACE(str[i-1])) { + continue; + } + str[i] = 0; + break; + } + /* The remainder (beginning) should be our number */ + if (!is_a_number(str)) { + Dmsg0(200, "input not a number\n"); + return 0; + } + /* Now find the multiplier corresponding to the modifier */ + for (i=0; mod[i]; i++) { + if (strncasecmp(mod_str, mod[i], mod_len) == 0) { + break; + } + } + if (mod[i] == NULL) { + Dmsg0(200, "Modifier not found\n"); + return 0; /* modifer not found */ + } + Dmsg2(200, "str=%s: mult=%d\n", str, mult[i]); errno = 0; val = strtod(str, NULL); if (errno != 0 || val < 0) { return 0; } - *value = (utime_t)(val * mult[i]); + *value = (utime_t)(val * mult[i]); return 1; } @@ -293,3 +337,25 @@ char *add_commas(char *val, char *buf) } return buf; } + +#ifdef TEST_PROGRAM +void d_msg(char*, int, int, char*, ...) +{} +int main(int argc, char *argv[]) +{ + char *str[] = {"3", "3n", "3 hours", "3.5 day", "3 week", "3 m", "3 q", "3 years"}; + utime_t val; + char buf[100]; + char outval[100]; + + for (int i=0; i<8; i++) { + strcpy(buf, str[i]); + if (!duration_to_utime(buf, &val)) { + printf("Error return from duration_to_utime for in=%s\n", str[i]); + continue; + } + edit_utime(val, outval); + printf("in=%s val=%lld outval=%s\n", str[i], val, outval); + } +} +#endif diff --git a/bacula/src/lib/lex.c b/bacula/src/lib/lex.c index 04131d7171..64b611d11b 100644 --- a/bacula/src/lib/lex.c +++ b/bacula/src/lib/lex.c @@ -284,183 +284,183 @@ lex_get_token(LEX *lf, int expect) while (token == T_NONE) { ch = lex_get_char(lf); switch (lf->state) { - case lex_none: - Dmsg2(900, "Lex state lex_none ch=%d,%x\n", ch, ch); - if (B_ISSPACE(ch)) - break; - if (B_ISALPHA(ch)) { - if (lf->options & LOPT_NO_IDENT) - lf->state = lex_string; - else - lf->state = lex_identifier; - begin_str(lf, ch); - break; - } - if (B_ISDIGIT(ch)) { - lf->state = lex_number; - begin_str(lf, ch); - break; - } - Dmsg0(900, "Enter lex_none switch\n"); - switch (ch) { - case L_EOF: - token = T_EOF; - Dmsg0(900, "got L_EOF set token=T_EOF\n"); - break; - case '#': - lf->state = lex_comment; - break; - case '{': - token = T_BOB; - begin_str(lf, ch); - break; - case '}': - token = T_EOB; - begin_str(lf, ch); - break; - case '"': - lf->state = lex_quoted_string; - begin_str(lf, 0); - break; - case '=': - token = T_EQUALS; - begin_str(lf, ch); - break; - case ',': - token = T_COMMA; - begin_str(lf, ch); - break; - case ';': - token = T_EOL; /* treat ; like EOL */ - break; - case L_EOL: - Dmsg0(900, "got L_EOL set token=T_EOL\n"); - token = T_EOL; - break; - case '@': - lf->state = lex_include; - begin_str(lf, 0); - break; - default: - lf->state = lex_string; - begin_str(lf, ch); - break; - } + case lex_none: + Dmsg2(900, "Lex state lex_none ch=%d,%x\n", ch, ch); + if (B_ISSPACE(ch)) break; - case lex_comment: - Dmsg1(900, "Lex state lex_comment ch=%x\n", ch); - if (ch == L_EOL) { - lf->state = lex_none; - token = T_EOL; - } else if (ch == L_EOF) { - token = T_ERROR; - } - break; - case lex_number: - Dmsg2(900, "Lex state lex_number ch=%x %c\n", ch, ch); - if (ch == L_EOF) { - token = T_ERROR; - break; - } - /* Might want to allow trailing specifications here */ - if (B_ISDIGIT(ch)) { - add_str(lf, ch); - break; - } - - /* A valid number can be terminated by the following */ - if (B_ISSPACE(ch) || ch == L_EOL || ch == ',' || ch == ';') { - token = T_NUMBER; - lf->state = lex_none; - } else { + if (B_ISALPHA(ch)) { + if (lf->options & LOPT_NO_IDENT) lf->state = lex_string; - } - lex_unget_char(lf); + else + lf->state = lex_identifier; + begin_str(lf, ch); break; - case lex_ip_addr: - if (ch == L_EOF) { - token = T_ERROR; - break; - } - Dmsg1(900, "Lex state lex_ip_addr ch=%x\n", ch); + } + if (B_ISDIGIT(ch)) { + lf->state = lex_number; + begin_str(lf, ch); break; - case lex_string: - Dmsg1(900, "Lex state lex_string ch=%x\n", ch); - if (ch == L_EOF) { - token = T_ERROR; - break; - } - if (ch == '\n' || ch == L_EOL || ch == '=' || ch == '}' || ch == '{' || - ch == ';' || ch == ',' || ch == '#' || (B_ISSPACE(ch)) ) { - lex_unget_char(lf); - token = T_UNQUOTED_STRING; - lf->state = lex_none; - break; - } - add_str(lf, ch); + } + Dmsg0(900, "Enter lex_none switch\n"); + switch (ch) { + case L_EOF: + token = T_EOF; + Dmsg0(900, "got L_EOF set token=T_EOF\n"); + break; + case '#': + lf->state = lex_comment; + break; + case '{': + token = T_BOB; + begin_str(lf, ch); + break; + case '}': + token = T_EOB; + begin_str(lf, ch); + break; + case '"': + lf->state = lex_quoted_string; + begin_str(lf, 0); break; - case lex_identifier: - Dmsg2(900, "Lex state lex_identifier ch=%x %c\n", ch, ch); - if (B_ISALPHA(ch)) { - add_str(lf, ch); - break; - } else if (B_ISSPACE(ch)) { - break; - } else if (ch == '\n' || ch == L_EOL || ch == '=' || ch == '}' || ch == '{' || - ch == ';' || ch == ',' || ch == '"' || ch == '#') { - lex_unget_char(lf); - token = T_IDENTIFIER; - lf->state = lex_none; - break; - } else if (ch == L_EOF) { - token = T_ERROR; - lf->state = lex_none; - begin_str(lf, ch); - break; - } - /* Some non-alpha character => string */ + case '=': + token = T_EQUALS; + begin_str(lf, ch); + break; + case ',': + token = T_COMMA; + begin_str(lf, ch); + break; + case ';': + token = T_EOL; /* treat ; like EOL */ + break; + case L_EOL: + Dmsg0(900, "got L_EOL set token=T_EOL\n"); + token = T_EOL; + break; + case '@': + lf->state = lex_include; + begin_str(lf, 0); + break; + default: lf->state = lex_string; + begin_str(lf, ch); + break; + } + break; + case lex_comment: + Dmsg1(900, "Lex state lex_comment ch=%x\n", ch); + if (ch == L_EOL) { + lf->state = lex_none; + token = T_EOL; + } else if (ch == L_EOF) { + token = T_ERROR; + } + break; + case lex_number: + Dmsg2(900, "Lex state lex_number ch=%x %c\n", ch, ch); + if (ch == L_EOF) { + token = T_ERROR; + break; + } + /* Might want to allow trailing specifications here */ + if (B_ISDIGIT(ch)) { add_str(lf, ch); break; - case lex_quoted_string: - Dmsg2(900, "Lex state lex_quoted_string ch=%x %c\n", ch, ch); - if (ch == L_EOF) { - token = T_ERROR; - break; - } - if (ch == L_EOL) { - esc_next = FALSE; - break; - } - if (esc_next) { - add_str(lf, ch); - esc_next = FALSE; - break; - } - if (ch == '\\') { - esc_next = TRUE; - break; - } - if (ch == '"') { - token = T_QUOTED_STRING; - lf->state = lex_none; - break; - } + } + + /* A valid number can be terminated by the following */ + if (B_ISSPACE(ch) || ch == L_EOL || ch == ',' || ch == ';') { + token = T_NUMBER; + lf->state = lex_none; + } else { + lf->state = lex_string; + } + lex_unget_char(lf); + break; + case lex_ip_addr: + if (ch == L_EOF) { + token = T_ERROR; + break; + } + Dmsg1(900, "Lex state lex_ip_addr ch=%x\n", ch); + break; + case lex_string: + Dmsg1(900, "Lex state lex_string ch=%x\n", ch); + if (ch == L_EOF) { + token = T_ERROR; + break; + } + if (ch == '\n' || ch == L_EOL || ch == '=' || ch == '}' || ch == '{' || + ch == ';' || ch == ',' || ch == '#' || (B_ISSPACE(ch)) ) { + lex_unget_char(lf); + token = T_UNQUOTED_STRING; + lf->state = lex_none; + break; + } + add_str(lf, ch); + break; + case lex_identifier: + Dmsg2(900, "Lex state lex_identifier ch=%x %c\n", ch, ch); + if (B_ISALPHA(ch)) { add_str(lf, ch); break; - case lex_include: /* scanning a filename */ - if (ch == L_EOF) { - token = T_ERROR; - break; - } - if (B_ISSPACE(ch) || ch == '\n' || ch == L_EOL || ch == '}' || ch == '{' || - ch == ';' || ch == ',' || ch == '"' || ch == '#') { - lf->state = lex_none; - lf = lex_open_file(lf, lf->str, NULL); - break; - } + } else if (B_ISSPACE(ch)) { + break; + } else if (ch == '\n' || ch == L_EOL || ch == '=' || ch == '}' || ch == '{' || + ch == ';' || ch == ',' || ch == '"' || ch == '#') { + lex_unget_char(lf); + token = T_IDENTIFIER; + lf->state = lex_none; + break; + } else if (ch == L_EOF) { + token = T_ERROR; + lf->state = lex_none; + begin_str(lf, ch); + break; + } + /* Some non-alpha character => string */ + lf->state = lex_string; + add_str(lf, ch); + break; + case lex_quoted_string: + Dmsg2(900, "Lex state lex_quoted_string ch=%x %c\n", ch, ch); + if (ch == L_EOF) { + token = T_ERROR; + break; + } + if (ch == L_EOL) { + esc_next = FALSE; + break; + } + if (esc_next) { add_str(lf, ch); + esc_next = FALSE; + break; + } + if (ch == '\\') { + esc_next = TRUE; + break; + } + if (ch == '"') { + token = T_QUOTED_STRING; + lf->state = lex_none; + break; + } + add_str(lf, ch); + break; + case lex_include: /* scanning a filename */ + if (ch == L_EOF) { + token = T_ERROR; break; + } + if (B_ISSPACE(ch) || ch == '\n' || ch == L_EOL || ch == '}' || ch == '{' || + ch == ';' || ch == ',' || ch == '"' || ch == '#') { + lf->state = lex_none; + lf = lex_open_file(lf, lf->str, NULL); + break; + } + add_str(lf, ch); + break; } Dmsg4(900, "ch=%d state=%s token=%s %c\n", ch, lex_state_to_str(lf->state), lex_tok_to_str(token), ch); diff --git a/bacula/src/lib/parse_conf.c b/bacula/src/lib/parse_conf.c index 217a4d50e6..6b612deb0a 100755 --- a/bacula/src/lib/parse_conf.c +++ b/bacula/src/lib/parse_conf.c @@ -485,6 +485,7 @@ void store_time(LEX *lc, struct res_items *item, int index, int pass) { int token; utime_t utime; + char period[500]; token = lex_get_token(lc, T_ALL); errno = 0; @@ -492,8 +493,18 @@ void store_time(LEX *lc, struct res_items *item, int index, int pass) case T_NUMBER: case T_IDENTIFIER: case T_UNQUOTED_STRING: - if (!duration_to_utime(lc->str, &utime)) { - scan_err1(lc, "expected a time period, got: %s", lc->str); + bstrncpy(period, lc->str, sizeof(period)); + if (lc->ch == ' ') { + token = lex_get_token(lc, T_ALL); + switch (token) { + case T_IDENTIFIER: + case T_UNQUOTED_STRING: + bstrncat(period, lc->str, sizeof(period)); + break; + } + } + if (!duration_to_utime(period, &utime)) { + scan_err1(lc, "expected a time period, got: %s", period); } *(utime_t *)(item->value) = utime; break; @@ -501,7 +512,9 @@ void store_time(LEX *lc, struct res_items *item, int index, int pass) scan_err1(lc, "expected a time period, got: %s", lc->str); break; } - scan_to_eol(lc); + if (token != T_EOL) { + scan_to_eol(lc); + } set_bit(index, res_all.hdr.item_present); } diff --git a/bacula/src/stored/bscan.c b/bacula/src/stored/bscan.c index 53dc6b5c6f..adad6a0c36 100644 --- a/bacula/src/stored/bscan.c +++ b/bacula/src/stored/bscan.c @@ -418,7 +418,7 @@ static int record_cb(JCR *bjcr, DEVICE *dev, DEV_BLOCK *block, DEV_RECORD *rec) } } /* Create Client record if not already there */ - strcpy(cr.Name, label.ClientName); + bstrncpy(cr.Name, label.ClientName, sizeof(cr.Name)); create_client_record(db, &cr); jr.ClientId = cr.ClientId; @@ -471,8 +471,8 @@ static int record_cb(JCR *bjcr, DEVICE *dev, DEV_BLOCK *block, DEV_RECORD *rec) unser_session_label(&elabel, rec); /* Create FileSet record */ - strcpy(fsr.FileSet, label.FileSetName); - strcpy(fsr.MD5, label.FileSetMD5); + bstrncpy(fsr.FileSet, label.FileSetName, sizeof(fsr.FileSet)); + bstrncpy(fsr.MD5, label.FileSetMD5, sizeof(fsr.MD5)); create_fileset_record(db, &fsr); jr.FileSetId = fsr.FileSetId; @@ -714,7 +714,7 @@ static int create_media_record(B_DB *db, MEDIA_DBR *mr, VOLUME_LABEL *vl) struct date_time dt; struct tm tm; - strcpy(mr->VolStatus, "Full"); + bstrncpy(mr->VolStatus, "Full", sizeof(mr->VolStatus)); mr->VolRetention = 365 * 3600 * 24; /* 1 year */ if (vl->VerNum >= 11) { mr->FirstWritten = btime_to_utime(vl->write_btime); @@ -855,8 +855,8 @@ static JCR *create_job_record(B_DB *db, JOB_DBR *jr, SESSION_LABEL *label, jr->Type = label->JobType; jr->Level = label->JobLevel; jr->JobStatus = JS_Created; - strcpy(jr->Name, label->JobName); - strcpy(jr->Job, label->Job); + bstrncpy(jr->Name, label->JobName, sizeof(jr->Name)); + bstrncpy(jr->Job, label->Job, sizeof(jr->Job)); if (label->VerNum >= 11) { jr->SchedTime = btime_to_unix(label->write_btime); } else { @@ -1091,7 +1091,7 @@ static JCR *create_jcr(JOB_DBR *jr, DEV_RECORD *rec, uint32_t JobId) jobjcr->JobType = jr->Type; jobjcr->JobLevel = jr->Level; jobjcr->JobStatus = jr->JobStatus; - strcpy(jobjcr->Job, jr->Job); + bstrncpy(jobjcr->Job, jr->Job, sizeof(jobjcr->Job)); jobjcr->JobId = JobId; /* this is JobId on tape */ jobjcr->sched_time = jr->SchedTime; jobjcr->start_time = jr->StartTime; diff --git a/bacula/src/stored/stored_conf.c b/bacula/src/stored/stored_conf.c index 841f2b2728..28c1d57872 100644 --- a/bacula/src/stored/stored_conf.c +++ b/bacula/src/stored/stored_conf.c @@ -408,8 +408,13 @@ void save_resource(int type, struct res_items *items, int pass) } else { RES *next; /* Add new res to end of chain */ - for (next=resources[rindex].res_head; next->next; next=next->next) - { } + for (next=resources[rindex].res_head; next->next; next=next->next) { + if (strcmp(next->name, res->res_dir.hdr.name) == 0) { + Emsg2(M_ERROR_TERM, 0, + _("Attempt to define second %s resource named \"%s\" is not permitted.\n"), + resources[rindex].name, res->res_dir.hdr.name); + } + } next->next = (RES *)res; Dmsg2(90, "Inserting %s res: %s\n", res_to_str(type), res->res_dir.hdr.name); diff --git a/bacula/src/version.h b/bacula/src/version.h index 4c1c968022..377540ca05 100644 --- a/bacula/src/version.h +++ b/bacula/src/version.h @@ -2,8 +2,8 @@ #undef VERSION #define VERSION "1.32" #define VSTRING "1" -#define BDATE "18 Sep 2003" -#define LSMDATE "18Sep03" +#define BDATE "20 Sep 2003" +#define LSMDATE "20Sep03" /* Debug flags */ #undef DEBUG -- 2.39.5