-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
- 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:
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.
- 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.
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.
- 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.
+
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);
/*
* 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));
/*
* 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));
* 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},
{"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}
};
{
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));
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, " --> ");
}
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");
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));
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);
} 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);
}
}
}
}
/* 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)) {
}
/* 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)) {
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) {
} 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);
*/
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;
}
}
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
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);
{
int token;
utime_t utime;
+ char period[500];
token = lex_get_token(lc, T_ALL);
errno = 0;
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;
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);
}
}
}
/* 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;
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;
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);
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 {
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;
} 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);
#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