1 /*
2 Bacula(R) - The Network Backup Solution
3
4 Copyright (C) 2000-2020 Kern Sibbald
5
6 The original author of Bacula is Kern Sibbald, with contributions
7 from many others, a complete list can be found in the file AUTHORS.
8
9 You may use this file and others of this release according to the
10 license defined in the LICENSE file, which includes the Affero General
11 Public License, v3.0 ("AGPLv3") and some additional permissions and
12 terms pursuant to its AGPLv3 Section 7.
13
14 This notice must be preserved when any source code is
15 conveyed and/or propagated.
16
17 Bacula(R) is a registered trademark of Kern Sibbald.
18 */
19 /*
20 * Master Configuration routines.
21 *
22 * This file contains the common parts of the Bacula
23 * configuration routines.
24 *
25 * Note, the configuration file parser consists of three parts
26 *
27 * 1. The generic lexical scanner in lib/lex.c and lib/lex.h
28 *
29 * 2. The generic config scanner in lib/parse_conf.c and
30 * lib/parse_conf.h.
31 * These files contain the parser code, some utility
32 * routines, and the common store routines (name, int,
33 * string, time, int64, size, ...).
34 *
35 * 3. The daemon specific file, which contains the Resource
36 * definitions as well as any specific store routines
37 * for the resource records.
38 *
39 * N.B. This is a two pass parser, so if you malloc() a string
40 * in a "store" routine, you must ensure to do it during
41 * only one of the two passes, or to free it between.
42 * Also, note that the resource record is malloced and
43 * saved in save_resource() during pass 1. Anything that
44 * you want saved after pass two (e.g. resource pointers)
45 * must explicitly be done in save_resource. Take a look
46 * at the Job resource in src/dird/dird_conf.c to see how
47 * it is done.
48 *
49 * Kern Sibbald, January MM
50 *
51 */
52
53
54 #include "bacula.h"
55
56 #if defined(HAVE_WIN32)
57 #include "shlobj.h"
58 #else
59 #define MAX_PATH 1024
60 #endif
61
62 /*
63 * Define the Union of all the common resource structure definitions.
64 */
65 union URES {
66 MSGS res_msgs;
67 RES hdr;
68 COLLECTOR res_collector;
69 };
70
71 #if defined(_MSC_VER)
72 // work around visual studio name mangling preventing external linkage since res_all
73 // is declared as a different type when instantiated.
74 extern "C" URES res_all;
75 #else
76 extern URES res_all;
77 #endif
78
79 extern brwlock_t res_lock; /* resource lock */
80
81
82 /* Forward referenced subroutines */
83 static void scan_types(LEX *lc, MSGS *msg, int dest, char *where, char *cmd);
84 static const char *get_default_configdir();
85
86 /* Common Resource definitions */
87
88 /*
89 * Message resource directives
90 * Note: keep all store_mesgs last in the list as they are all
91 * output in json as a list.
92 * Also, the list store_msgs item must have flags set to ITEM_LAST
93 * so that the list editor (bjson.c) knows when to stop.
94 *
95 * name handler value code flags default_value
96 */
97 RES_ITEM msgs_items[] = {
98 {"Name", store_name, ITEM(res_msgs.hdr.name), 0, ITEM_REQUIRED, 0},
99 {"Description", store_str, ITEM(res_msgs.hdr.desc), 0, 0, 0},
100 {"MailCommand", store_str, ITEM(res_msgs.mail_cmd), 0, ITEM_ALLOW_DUPS, 0},
101 {"OperatorCommand", store_str, ITEM(res_msgs.operator_cmd), 0, ITEM_ALLOW_DUPS, 0},
102 /* See comments above */
103 {"Syslog", store_msgs, ITEM(res_msgs), MD_SYSLOG, 0, 0},
104 {"Mail", store_msgs, ITEM(res_msgs), MD_MAIL, 0, 0},
105 {"MailOnError", store_msgs, ITEM(res_msgs), MD_MAIL_ON_ERROR, 0, 0},
106 {"MailOnSuccess", store_msgs, ITEM(res_msgs), MD_MAIL_ON_SUCCESS, 0, 0},
107 {"File", store_msgs, ITEM(res_msgs), MD_FILE, 0, 0},
108 {"Append", store_msgs, ITEM(res_msgs), MD_APPEND, 0, 0},
109 {"Stdout", store_msgs, ITEM(res_msgs), MD_STDOUT, 0, 0},
110 {"Stderr", store_msgs, ITEM(res_msgs), MD_STDERR, 0, 0},
111 {"Director", store_msgs, ITEM(res_msgs), MD_DIRECTOR, 0, 0},
112 {"Console", store_msgs, ITEM(res_msgs), MD_CONSOLE, 0, 0},
113 {"Operator", store_msgs, ITEM(res_msgs), MD_OPERATOR, 0, 0},
114 {"Catalog", store_msgs, ITEM(res_msgs), MD_CATALOG, ITEM_LAST, 0},
115 {NULL, NULL, {0}, 0, 0, 0}
116 };
117
118 /*
119 * Statistics resource directives
120 *
121 * name handler value code flags default_value
122 */
123 RES_ITEM collector_items[] = {
124 {"Name", store_name, ITEM(res_collector.hdr.name), 0, ITEM_REQUIRED, 0},
125 {"Description", store_str, ITEM(res_collector.hdr.desc), 0, 0, 0},
126 {"Prefix", store_str, ITEM(res_collector.prefix), 0, 0, 0},
127 {"Metrics", store_alist_str, ITEM(res_collector.metrics), 0, 0, 0}, /* default all */
128 {"Interval", store_time, ITEM(res_collector.interval), 0, ITEM_DEFAULT, 5*60}, /* default 5 min */
129 {"Port", store_pint32, ITEM(res_collector.port), 0, 0, 0},
130 {"Host", store_str, ITEM(res_collector.host), 0, 0, 0},
131 {"Type", store_coll_type, ITEM(res_collector.type), 0, ITEM_REQUIRED, 0},
132 {"File", store_str, ITEM(res_collector.file), 0, 0, 0},
133 {"MangleMetric", store_bool, ITEM(res_collector.mangle_name), 0, 0, 0},
134 {NULL, NULL, {0}, 0, 0, 0}
135 };
136
137 /* Various message types */
138 s_kw msg_types[] = {
139 {"Debug", M_DEBUG}, /* Keep 1st place */
140 {"Saved", M_SAVED}, /* Keep 2nd place */
141 {"Events", M_EVENTS}, /* Keep 3rd place */
142 {"Abort", M_ABORT},
143 {"Fatal", M_FATAL},
144 {"Error", M_ERROR},
145 {"Warning", M_WARNING},
146 {"Info", M_INFO},
147 {"NotSaved", M_NOTSAVED},
148 {"Skipped", M_SKIPPED},
149 {"Mount", M_MOUNT},
150 {"Terminate", M_TERM},
151 {"Restored", M_RESTORED},
152 {"Security", M_SECURITY},
153 {"Alert", M_ALERT},
154 {"VolMgmt", M_VOLMGMT},
155 {"ErrorTerm", M_ERROR_TERM},
156 {"All", M_MAX+1},
157 {NULL, 0}
158 };
159
160
161 /*
162 * Tape Label types permitted in Pool records
163 *
164 * tape label label code = token
165 */
166 s_kw tapelabels[] = {
167 {"Bacula", B_BACULA_LABEL},
168 {"ANSI", B_ANSI_LABEL},
169 {"IBM", B_IBM_LABEL},
170 {NULL, 0}
171 };
172
173 /*
174 * Keywords (RHS) permitted in Statistics type records
175 *
176 * type_name backend_type
177 */
178 s_collt collectortypes[] = {
179 {"CSV", COLLECTOR_BACKEND_CSV},
180 {"Graphite", COLLECTOR_BACKEND_Graphite},
181 {NULL, 0}
182 };
183
184
185 /* Simply print a message */
prtmsg(void * sock,const char * fmt,...)186 static void prtmsg(void *sock, const char *fmt, ...)
187 {
188 va_list arg_ptr;
189
190 va_start(arg_ptr, fmt);
191 vfprintf(stdout, fmt, arg_ptr);
192 va_end(arg_ptr);
193 }
194
res_to_str(int rcode)195 const char *res_to_str(int rcode)
196 {
197 if (rcode < r_first || rcode > r_last) {
198 return _("***UNKNOWN***");
199 } else {
200 return resources[rcode-r_first].name;
201 }
202 }
203
204 /*
205 * Create a new res_head pointer to a list of res_heads
206 */
init_res_head(RES_HEAD *** rhead,int32_t rfirst,int32_t rlast)207 void CONFIG::init_res_head(RES_HEAD ***rhead, int32_t rfirst, int32_t rlast)
208 {
209 int num = rlast - rfirst + 1;
210 RES *res = NULL;
211 RES_HEAD **rh;
212 rh = *rhead = (RES_HEAD **)malloc(num * sizeof(RES_HEAD));
213 for (int i=0; i<num; i++) {
214 rh[i] = (RES_HEAD *)malloc(sizeof(RES_HEAD));
215 rh[i]->res_list = New(rblist(res, &res->link));
216 rh[i]->first = NULL;
217 rh[i]->last = NULL;
218 }
219 }
220
221 /*
222 * Copy the resource in res_all into a new allocated resource
223 * an insert it into the resource list.
224 */
insert_res(int rindex,int size)225 bool CONFIG::insert_res(int rindex, int size)
226 {
227 RES *res = (RES *)malloc(size);
228 memcpy(res, m_res_all, size);
229 return insert_res(rindex, res);
230 }
231
232 /*
233 * Insert the resource res into the resource list.
234 */
insert_res(int rindex,RES * res)235 bool CONFIG::insert_res(int rindex, RES *res)
236 {
237 rblist *list = m_res_head[rindex]->res_list;
238 if (list->empty()) {
239 list->insert(res, res_compare);
240 m_res_head[rindex]->first = res;
241 m_res_head[rindex]->last = res;
242 } else {
243 RES *item, *prev;
244 prev = m_res_head[rindex]->last;
245 item = (RES *)list->insert(res, res_compare);
246 if (item != res) {
247 Mmsg(m_errmsg, _("Attempt to define second \"%s\" resource named \"%s\" is not permitted.\n"),
248 resources[rindex].name, ((URES *)res)->hdr.name);
249 return false;
250 }
251 prev->res_next = res;
252 m_res_head[rindex]->last = res;
253 }
254 Dmsg2(900, _("Inserted res: %s index=%d\n"), ((URES *)res)->hdr.name, rindex);
255 return true;
256 }
257
258 /*
259 * Initialize the static structure to zeros, then
260 * apply all the default values.
261 */
init_resource0(CONFIG * config,int type,RES_ITEM * items,int pass)262 void init_resource0(CONFIG *config, int type, RES_ITEM *items, int pass)
263 {
264 int i;
265 int rindex = type - r_first;
266
267 memset(config->m_res_all, 0, config->m_res_all_size);
268 res_all.hdr.rcode = type;
269 res_all.hdr.refcnt = 1;
270
271 /* Set defaults in each item */
272 for (i=0; items[i].name; i++) {
273 Dmsg3(900, "Item=%s def=%s defval=%d\n", items[i].name,
274 (items[i].flags & ITEM_DEFAULT) ? "yes" : "no",
275 items[i].default_value);
276 if (items[i].flags & ITEM_DEFAULT && items[i].default_value != 0) {
277 if (items[i].handler == store_bit) {
278 *(uint32_t *)(items[i].value) |= items[i].code;
279 } else if (items[i].handler == store_bool) {
280 *(bool *)(items[i].value) = items[i].default_value != 0;
281 } else if (items[i].handler == store_pint32 ||
282 items[i].handler == store_int32 ||
283 items[i].handler == store_size32) {
284 *(uint32_t *)(items[i].value) = items[i].default_value;
285 } else if (items[i].handler == store_int64) {
286 *(int64_t *)(items[i].value) = items[i].default_value;
287 } else if (items[i].handler == store_size64) {
288 *(uint64_t *)(items[i].value) = (uint64_t)items[i].default_value;
289 } else if (items[i].handler == store_speed) {
290 *(uint64_t *)(items[i].value) = (uint64_t)items[i].default_value;
291 } else if (items[i].handler == store_time) {
292 *(utime_t *)(items[i].value) = (utime_t)items[i].default_value;
293 } else if (pass == 1 && items[i].handler == store_addresses) {
294 init_default_addresses((dlist**)items[i].value, items[i].default_value);
295 }
296 }
297 /* If this triggers, take a look at lib/parse_conf.h */
298 if (i >= MAX_RES_ITEMS) {
299 Emsg1(M_ERROR_TERM, 0, _("Too many directives in \"%s\" resource\n"), resources[rindex].name);
300 }
301 }
302 }
303
304 /* Initialize a resouce with default values */
init_resource(CONFIG * config,uint32_t type,void * res,int size)305 bool init_resource(CONFIG *config, uint32_t type, void *res, int size)
306 {
307 RES_ITEM *items;
308 for (int i=0; resources[i].name; i++) {
309 if (resources[i].rcode == type) {
310 items = resources[i].items;
311 if (!items) {
312 return false;
313 }
314 init_resource0(config, type, items, 1);
315 memcpy(res, config->m_res_all, size);
316 return true;
317 }
318 }
319 return false;
320 }
321
322 /*
323 * Dump each resource of type
324 */
dump_each_resource(int type,void sendit (void * sock,const char * fmt,...),void * sock)325 void dump_each_resource(int type, void sendit(void *sock, const char *fmt, ...), void *sock)
326 {
327 RES *res = NULL;
328
329 if (type < 0) { /* no recursion */
330 type = -type;
331 }
332 foreach_res(res, type) {
333 dump_resource(-type, res, sendit, sock);
334 }
335 }
336
337
338 /* Store Messages Destination information */
store_msgs(LEX * lc,RES_ITEM * item,int index,int pass)339 void store_msgs(LEX *lc, RES_ITEM *item, int index, int pass)
340 {
341 int token;
342 char *cmd;
343 POOLMEM *dest;
344 int dest_len;
345
346 Dmsg2(900, "store_msgs pass=%d code=%d\n", pass, item->code);
347 if (pass == 1) {
348 switch (item->code) {
349 case MD_STDOUT:
350 case MD_STDERR:
351 case MD_SYSLOG: /* syslog */
352 case MD_CONSOLE:
353 case MD_CATALOG:
354 scan_types(lc, (MSGS *)(item->value), item->code, NULL, NULL);
355 break;
356 case MD_OPERATOR: /* send to operator */
357 case MD_DIRECTOR: /* send to Director */
358 case MD_MAIL: /* mail */
359 case MD_MAIL_ON_ERROR: /* mail if Job errors */
360 case MD_MAIL_ON_SUCCESS: /* mail if Job succeeds */
361 if (item->code == MD_OPERATOR) {
362 cmd = res_all.res_msgs.operator_cmd;
363 } else {
364 cmd = res_all.res_msgs.mail_cmd;
365 }
366 dest = get_pool_memory(PM_MESSAGE);
367 dest[0] = 0;
368 dest_len = 0;
369 /* Pick up comma separated list of destinations */
370 for ( ;; ) {
371 token = lex_get_token(lc, T_NAME); /* scan destination */
372 dest = check_pool_memory_size(dest, dest_len + lc->str_len + 2);
373 if (dest[0] != 0) {
374 pm_strcat(dest, " "); /* separate multiple destinations with space */
375 dest_len++;
376 }
377 pm_strcat(dest, lc->str);
378 dest_len += lc->str_len;
379 Dmsg2(900, "store_msgs newdest=%s: dest=%s:\n", lc->str, NPRT(dest));
380 token = lex_get_token(lc, T_SKIP_EOL);
381 if (token == T_COMMA) {
382 continue; /* get another destination */
383 }
384 if (token != T_EQUALS) {
385 scan_err1(lc, _("expected an =, got: %s"), lc->str);
386 return;
387 }
388 break;
389 }
390 Dmsg1(900, "mail_cmd=%s\n", NPRT(cmd));
391 scan_types(lc, (MSGS *)(item->value), item->code, dest, cmd);
392 free_pool_memory(dest);
393 Dmsg0(900, "done with dest codes\n");
394 break;
395
396 case MD_FILE: /* file */
397 case MD_APPEND: /* append */
398 dest = get_pool_memory(PM_MESSAGE);
399 /* Pick up a single destination */
400 token = lex_get_token(lc, T_NAME); /* scan destination */
401 pm_strcpy(dest, lc->str);
402 dest_len = lc->str_len;
403 token = lex_get_token(lc, T_SKIP_EOL);
404 Dmsg1(900, "store_msgs dest=%s:\n", NPRT(dest));
405 if (token != T_EQUALS) {
406 scan_err1(lc, _("expected an =, got: %s"), lc->str);
407 return;
408 }
409 scan_types(lc, (MSGS *)(item->value), item->code, dest, NULL);
410 free_pool_memory(dest);
411 Dmsg0(900, "done with dest codes\n");
412 break;
413
414 default:
415 scan_err1(lc, _("Unknown item code: %d\n"), item->code);
416 return;
417 }
418 }
419 scan_to_eol(lc);
420 set_bit(index, res_all.hdr.item_present);
421 Dmsg0(900, "Done store_msgs\n");
422 }
423
424 /*
425 * Scan for message types and add them to the message
426 * destination. The basic job here is to connect message types
427 * (WARNING, ERROR, FATAL, INFO, ...) with an appropriate
428 * destination (MAIL, FILE, OPERATOR, ...)
429 */
scan_types(LEX * lc,MSGS * msg,int dest_code,char * where,char * cmd)430 static void scan_types(LEX *lc, MSGS *msg, int dest_code, char *where, char *cmd)
431 {
432 int i;
433 bool found, is_not;
434 int msg_type = 0;
435 char *str;
436
437 for ( ;; ) {
438 lex_get_token(lc, T_NAME); /* expect at least one type */
439 found = false;
440 if (lc->str[0] == '!') {
441 is_not = true;
442 str = &lc->str[1];
443 } else {
444 is_not = false;
445 str = &lc->str[0];
446 }
447 for (i=0; msg_types[i].name; i++) {
448 if (strcasecmp(str, msg_types[i].name) == 0) {
449 msg_type = msg_types[i].token;
450 found = true;
451 break;
452 }
453 }
454 /* Custom event, we add it to the list for this Message */
455 if (!found && strncasecmp(str, "events.", 6) == 0) {
456 msg_type = msg->add_custom_type(is_not, str+7); /* We can ignore completely if we want */
457 Dmsg2(50, "Add events %s => %d\n", str, msg_type);
458 if (msg_type < 0) {
459 scan_err2(lc, _("message type: Unable to add %s message type. %s"), str,
460 (msg_type == -1) ? "Too much custom type" : "Invalid format");
461 return;
462 }
463 found = true;
464 }
465 if (!found) {
466 scan_err1(lc, _("message type: %s not found"), str);
467 return;
468 }
469
470 if (msg_type == M_MAX+1) { /* all? */
471 for (i=3; i<=M_MAX; i++) { /* yes set all types except Debug, Saved and Events */
472 add_msg_dest(msg, dest_code, msg_types[i].token, where, cmd);
473 }
474 } else if (is_not) {
475 rem_msg_dest(msg, dest_code, msg_type, where);
476 } else {
477 add_msg_dest(msg, dest_code, msg_type, where, cmd);
478 }
479 if (lc->ch != ',') {
480 break;
481 }
482 Dmsg0(900, "call lex_get_token() to eat comma\n");
483 lex_get_token(lc, T_ALL); /* eat comma */
484 }
485 Dmsg0(900, "Done scan_types()\n");
486 }
487
488
489 /*
490 * This routine is ONLY for resource names
491 * Store a name at specified address.
492 */
store_name(LEX * lc,RES_ITEM * item,int index,int pass)493 void store_name(LEX *lc, RES_ITEM *item, int index, int pass)
494 {
495 POOLMEM *msg = get_pool_memory(PM_EMSG);
496
497 lex_get_token(lc, T_NAME);
498 if (!is_name_valid(lc->str, &msg)) {
499 scan_err1(lc, "%s\n", msg);
500 return;
501 }
502 free_pool_memory(msg);
503 /* Store the name both pass 1 and pass 2 */
504 if (*(item->value)) {
505 scan_err5(lc, _("Attempt to redefine \"%s\" from \"%s\" to \"%s\" referenced on line %d : %s\n"),
506 item->name, *(item->value), lc->str, lc->line_no, lc->line);
507 return;
508 }
509 *(item->value) = bstrdup(lc->str);
510 scan_to_eol(lc);
511 set_bit(index, res_all.hdr.item_present);
512 }
513
514
515 /*
516 * Store a name string at specified address
517 * A name string is limited to MAX_RES_NAME_LENGTH
518 */
store_strname(LEX * lc,RES_ITEM * item,int index,int pass)519 void store_strname(LEX *lc, RES_ITEM *item, int index, int pass)
520 {
521 lex_get_token(lc, T_NAME);
522 /* Store the name */
523 if (pass == 1) {
524 if (*(item->value)) {
525 scan_err5(lc, _("Attempt to redefine \"%s\" from \"%s\" to \"%s\" referenced on line %d : %s\n"),
526 item->name, *(item->value), lc->str, lc->line_no, lc->line);
527 return;
528 }
529 *(item->value) = bstrdup(lc->str);
530 }
531 scan_to_eol(lc);
532 set_bit(index, res_all.hdr.item_present);
533 }
534
535 /* Store a string at specified address */
store_str(LEX * lc,RES_ITEM * item,int index,int pass)536 void store_str(LEX *lc, RES_ITEM *item, int index, int pass)
537 {
538 lex_get_token(lc, T_STRING);
539 if (pass == 1) {
540 if (*(item->value) && (item->flags & ITEM_ALLOW_DUPS)) {
541 free(*(item->value));
542 *(item->value) = NULL;
543 }
544 if (*(item->value)) {
545 scan_err5(lc, _("Attempt to redefine \"%s\" from \"%s\" to \"%s\" referenced on line %d : %s\n"),
546 item->name, *(item->value), lc->str, lc->line_no, lc->line);
547 return;
548 }
549 *(item->value) = bstrdup(lc->str);
550 }
551 scan_to_eol(lc);
552 set_bit(index, res_all.hdr.item_present);
553 }
554
555 /*
556 * Store a directory name at specified address. Note, we do
557 * shell expansion except if the string begins with a vertical
558 * bar (i.e. it will likely be passed to the shell later).
559 */
store_dir(LEX * lc,RES_ITEM * item,int index,int pass)560 void store_dir(LEX *lc, RES_ITEM *item, int index, int pass)
561 {
562 lex_get_token(lc, T_STRING);
563 if (pass == 1) {
564 if (lc->str[0] != '|') {
565 do_shell_expansion(lc->str, sizeof_pool_memory(lc->str));
566 }
567 #ifdef STANDARDIZED_DIRECTORY_USAGE
568 // TODO ASX we should store all directory without the ending slash to
569 // avoid the need of testing its presence
570 int len=strlen(lc->str);
571 if (len>0 && IsPathSeparator(lc->str[len-1])) {
572 lc->str[len-1]='\0';
573 }
574 #endif
575 if (*(item->value)) {
576 scan_err5(lc, _("Attempt to redefine \"%s\" from \"%s\" to \"%s\" referenced on line %d : %s\n"),
577 item->name, *(item->value), lc->str, lc->line_no, lc->line);
578 return;
579 }
580 *(item->value) = bstrdup(lc->str);
581 }
582 scan_to_eol(lc);
583 set_bit(index, res_all.hdr.item_present);
584 }
585
586
587 /* Store a password specified address in MD5 coding */
store_password(LEX * lc,RES_ITEM * item,int index,int pass)588 void store_password(LEX *lc, RES_ITEM *item, int index, int pass)
589 {
590 unsigned int i, j;
591 struct MD5Context md5c;
592 unsigned char digest[CRYPTO_DIGEST_MD5_SIZE];
593 char sig[100];
594
595 if (lc->options & LOPT_NO_MD5) {
596 store_str(lc, item, index, pass);
597
598 } else {
599 lex_get_token(lc, T_STRING);
600 if (pass == 1) {
601 MD5Init(&md5c);
602 MD5Update(&md5c, (unsigned char *) (lc->str), lc->str_len);
603 MD5Final(digest, &md5c);
604 for (i = j = 0; i < sizeof(digest); i++) {
605 sprintf(&sig[j], "%02x", digest[i]);
606 j += 2;
607 }
608 if (*(item->value)) {
609 scan_err5(lc, _("Attempt to redefine \"%s\" from \"%s\" to \"%s\" referenced on line %d : %s\n"),
610 item->name, *(item->value), lc->str, lc->line_no, lc->line);
611 return;
612 }
613 *(item->value) = bstrdup(sig);
614 }
615 scan_to_eol(lc);
616 set_bit(index, res_all.hdr.item_present);
617 }
618 }
619
620
621 /* Store a resource at specified address.
622 * If we are in pass 2, do a lookup of the
623 * resource.
624 */
store_res(LEX * lc,RES_ITEM * item,int index,int pass)625 void store_res(LEX *lc, RES_ITEM *item, int index, int pass)
626 {
627 RES *res;
628
629 lex_get_token(lc, T_NAME);
630 if (pass == 2) {
631 res = GetResWithName(item->code, lc->str);
632 if (res == NULL) {
633 scan_err3(lc, _("Could not find config Resource \"%s\" referenced on line %d : %s\n"),
634 lc->str, lc->line_no, lc->line);
635 return;
636 }
637 if (*(item->value)) {
638 scan_err3(lc, _("Attempt to redefine resource \"%s\" referenced on line %d : %s\n"),
639 item->name, lc->line_no, lc->line);
640 return;
641 }
642 *(item->value) = (char *)res;
643 }
644 scan_to_eol(lc);
645 set_bit(index, res_all.hdr.item_present);
646 }
647
648 /*
649 * Store a resource pointer in an alist. default_value indicates how many
650 * times this routine can be called -- i.e. how many alists
651 * there are.
652 * If we are in pass 2, do a lookup of the
653 * resource.
654 */
store_alist_res(LEX * lc,RES_ITEM * item,int index,int pass)655 void store_alist_res(LEX *lc, RES_ITEM *item, int index, int pass)
656 {
657 RES *res;
658 int count = item->default_value;
659 int i = 0;
660 alist *list;
661
662 if (pass == 2) {
663 if (count == 0) { /* always store in item->value */
664 i = 0;
665 if ((item->value)[i] == NULL) {
666 list = New(alist(10, not_owned_by_alist));
667 } else {
668 list = (alist *)(item->value)[i];
669 }
670 } else {
671 /* Find empty place to store this directive */
672 while ((item->value)[i] != NULL && i++ < count) { }
673 if (i >= count) {
674 scan_err4(lc, _("Too many %s directives. Max. is %d. line %d: %s\n"),
675 lc->str, count, lc->line_no, lc->line);
676 return;
677 }
678 list = New(alist(10, not_owned_by_alist));
679 }
680
681 for (;;) {
682 lex_get_token(lc, T_NAME); /* scan next item */
683 res = GetResWithName(item->code, lc->str);
684 if (res == NULL) {
685 scan_err3(lc, _("Could not find config Resource \"%s\" referenced on line %d : %s\n"),
686 lc->str, lc->line_no, lc->line);
687 return;
688 }
689 Dmsg5(900, "Append %p to alist %p size=%d i=%d %s\n",
690 res, list, list->size(), i, item->name);
691 list->append(res);
692 (item->value)[i] = (char *)list;
693 if (lc->ch != ',') { /* if no other item follows */
694 if (!lex_check_eol(lc)) {
695 /* found garbage at the end of the line */
696 scan_err3(lc, _("Found unexpected characters resource list in Directive \"%s\" at the end of line %d : %s\n"),
697 item->name, lc->line_no, lc->line);
698 }
699 break; /* get out */
700 }
701 lex_get_token(lc, T_ALL); /* eat comma */
702 }
703 }
704 scan_to_eol(lc);
705 set_bit(index, res_all.hdr.item_present);
706 }
707
708
709 /*
710 * Store a string in an alist.
711 */
store_alist_str(LEX * lc,RES_ITEM * item,int index,int pass)712 void store_alist_str(LEX *lc, RES_ITEM *item, int index, int pass)
713 {
714 alist *list;
715
716 if (pass == 2) {
717 if (*(item->value) == NULL) {
718 list = New(alist(10, owned_by_alist));
719 *(item->value) = (char *)list;
720 } else {
721 list = (alist *)(*(item->value));
722 }
723 for (;;) {
724 lex_get_token(lc, T_STRING); /* scan next item */
725 Dmsg4(900, "Append %s to alist 0x%p size=%d %s\n",
726 lc->str, list, list->size(), item->name);
727 list->append(bstrdup(lc->str));
728 if (lc->ch != ',') { /* if no other item follows */
729 if (!lex_check_eol(lc)) {
730 /* found garbage at the end of the line */
731 scan_err3(lc, _("Found unexpected characters in resource list in Directive \"%s\" at the end of line %d : %s\n"),
732 item->name, lc->line_no, lc->line);
733 }
734 break; /* get out */
735 }
736 lex_get_token(lc, T_ALL); /* eat comma */
737 }
738 }
739 scan_to_eol(lc);
740 set_bit(index, res_all.hdr.item_present);
741 }
742
743
744
745 /*
746 * Store default values for Resource from xxxDefs
747 * If we are in pass 2, do a lookup of the
748 * resource and store everything not explicitly set
749 * in main resource.
750 *
751 * Note, here item points to the main resource (e.g. Job, not
752 * the jobdefs, which we look up).
753 */
store_defs(LEX * lc,RES_ITEM * item,int index,int pass)754 void store_defs(LEX *lc, RES_ITEM *item, int index, int pass)
755 {
756 RES *res;
757
758 lex_get_token(lc, T_NAME);
759 if (pass == 2) {
760 Dmsg2(900, "Code=%d name=%s\n", item->code, lc->str);
761 res = GetResWithName(item->code, lc->str);
762 if (res == NULL) {
763 scan_err3(lc, _("Missing config Resource \"%s\" referenced on line %d : %s\n"),
764 lc->str, lc->line_no, lc->line);
765 return;
766 }
767 }
768 scan_to_eol(lc);
769 }
770
771
772
773 /* Store an integer at specified address */
store_int32(LEX * lc,RES_ITEM * item,int index,int pass)774 void store_int32(LEX *lc, RES_ITEM *item, int index, int pass)
775 {
776 lex_get_token(lc, T_INT32);
777 *(uint32_t *)(item->value) = lc->int32_val;
778 scan_to_eol(lc);
779 set_bit(index, res_all.hdr.item_present);
780 }
781
782 /* Store a positive integer at specified address */
store_pint32(LEX * lc,RES_ITEM * item,int index,int pass)783 void store_pint32(LEX *lc, RES_ITEM *item, int index, int pass)
784 {
785 lex_get_token(lc, T_PINT32);
786 *(uint32_t *)(item->value) = lc->pint32_val;
787 scan_to_eol(lc);
788 set_bit(index, res_all.hdr.item_present);
789 }
790
791
792 /* Store an 64 bit integer at specified address */
store_int64(LEX * lc,RES_ITEM * item,int index,int pass)793 void store_int64(LEX *lc, RES_ITEM *item, int index, int pass)
794 {
795 lex_get_token(lc, T_INT64);
796 *(int64_t *)(item->value) = lc->int64_val;
797 scan_to_eol(lc);
798 set_bit(index, res_all.hdr.item_present);
799 }
800
801 enum store_unit_type {
802 STORE_SIZE,
803 STORE_SPEED
804 } ;
805
806 /*
807 * This routine stores either a 32 or a 64 bit value (size32)
808 * and either a size (in bytes) or a speed (bytes per second).
809 */
store_int_unit(LEX * lc,RES_ITEM * item,int index,int pass,bool size32,enum store_unit_type type)810 static void store_int_unit(LEX *lc, RES_ITEM *item, int index, int pass,
811 bool size32, enum store_unit_type type)
812 {
813 int token;
814 uint64_t uvalue;
815 char bsize[500];
816
817 Dmsg0(900, "Enter store_unit\n");
818 token = lex_get_token(lc, T_SKIP_EOL);
819 errno = 0;
820 switch (token) {
821 case T_NUMBER:
822 case T_IDENTIFIER:
823 case T_UNQUOTED_STRING:
824 bstrncpy(bsize, lc->str, sizeof(bsize)); /* save first part */
825 /* if terminated by space, scan and get modifier */
826 while (lc->ch == ' ') {
827 token = lex_get_token(lc, T_ALL);
828 switch (token) {
829 case T_NUMBER:
830 case T_IDENTIFIER:
831 case T_UNQUOTED_STRING:
832 bstrncat(bsize, lc->str, sizeof(bsize));
833 break;
834 }
835 }
836 if (type == STORE_SIZE) {
837 if (!size_to_uint64(bsize, strlen(bsize), &uvalue)) {
838 scan_err1(lc, _("expected a size number, got: %s"), lc->str);
839 return;
840 }
841 } else {
842 if (!speed_to_uint64(bsize, strlen(bsize), &uvalue)) {
843 scan_err1(lc, _("expected a speed number, got: %s"), lc->str);
844 return;
845 }
846 }
847 if (size32) {
848 *(uint32_t *)(item->value) = (uint32_t)uvalue;
849 } else {
850 *(uint64_t *)(item->value) = uvalue;
851 }
852 break;
853 default:
854 scan_err2(lc, _("expected a %s, got: %s"),
855 (type == STORE_SIZE)?_("size"):_("speed"), lc->str);
856 return;
857 }
858 if (token != T_EOL) {
859 scan_to_eol(lc);
860 }
861 set_bit(index, res_all.hdr.item_present);
862 Dmsg0(900, "Leave store_unit\n");
863 }
864
865 /* Store a size in bytes */
store_size32(LEX * lc,RES_ITEM * item,int index,int pass)866 void store_size32(LEX *lc, RES_ITEM *item, int index, int pass)
867 {
868 store_int_unit(lc, item, index, pass, true /* 32 bit */, STORE_SIZE);
869 }
870
871 /* Store a size in bytes */
store_size64(LEX * lc,RES_ITEM * item,int index,int pass)872 void store_size64(LEX *lc, RES_ITEM *item, int index, int pass)
873 {
874 store_int_unit(lc, item, index, pass, false /* not 32 bit */, STORE_SIZE);
875 }
876
877 /* Store a speed in bytes/s */
store_speed(LEX * lc,RES_ITEM * item,int index,int pass)878 void store_speed(LEX *lc, RES_ITEM *item, int index, int pass)
879 {
880 store_int_unit(lc, item, index, pass, false /* 64 bit */, STORE_SPEED);
881 }
882
883 /* Store a time period in seconds */
store_time(LEX * lc,RES_ITEM * item,int index,int pass)884 void store_time(LEX *lc, RES_ITEM *item, int index, int pass)
885 {
886 int token;
887 utime_t utime;
888 char period[500];
889
890 token = lex_get_token(lc, T_SKIP_EOL);
891 errno = 0;
892 switch (token) {
893 case T_NUMBER:
894 case T_IDENTIFIER:
895 case T_UNQUOTED_STRING:
896 bstrncpy(period, lc->str, sizeof(period)); /* get first part */
897 /* if terminated by space, scan and get modifier */
898 while (lc->ch == ' ') {
899 token = lex_get_token(lc, T_ALL);
900 switch (token) {
901 case T_NUMBER:
902 case T_IDENTIFIER:
903 case T_UNQUOTED_STRING:
904 bstrncat(period, lc->str, sizeof(period));
905 break;
906 }
907 }
908 if (!duration_to_utime(period, &utime)) {
909 scan_err1(lc, _("expected a time period, got: %s"), period);
910 return;
911 }
912 *(utime_t *)(item->value) = utime;
913 break;
914 default:
915 scan_err1(lc, _("expected a time period, got: %s"), lc->str);
916 return;
917 }
918 if (token != T_EOL) {
919 scan_to_eol(lc);
920 }
921 set_bit(index, res_all.hdr.item_present);
922 }
923
924
925 /* Store a yes/no in a bit field */
store_bit(LEX * lc,RES_ITEM * item,int index,int pass)926 void store_bit(LEX *lc, RES_ITEM *item, int index, int pass)
927 {
928 lex_get_token(lc, T_NAME);
929 if (strcasecmp(lc->str, "yes") == 0 || strcasecmp(lc->str, "true") == 0) {
930 *(uint32_t *)(item->value) |= item->code;
931 } else if (strcasecmp(lc->str, "no") == 0 || strcasecmp(lc->str, "false") == 0) {
932 *(uint32_t *)(item->value) &= ~(item->code);
933 } else {
934 scan_err2(lc, _("Expect %s, got: %s"), "YES, NO, TRUE, or FALSE", lc->str); /* YES and NO must not be translated */
935 return;
936 }
937 scan_to_eol(lc);
938 set_bit(index, res_all.hdr.item_present);
939 }
940
941 /* Store a bool in a bit field */
store_bool(LEX * lc,RES_ITEM * item,int index,int pass)942 void store_bool(LEX *lc, RES_ITEM *item, int index, int pass)
943 {
944 lex_get_token(lc, T_NAME);
945 if (strcasecmp(lc->str, "yes") == 0 || strcasecmp(lc->str, "true") == 0) {
946 *(bool *)(item->value) = true;
947 } else if (strcasecmp(lc->str, "no") == 0 || strcasecmp(lc->str, "false") == 0) {
948 *(bool *)(item->value) = false;
949 } else {
950 scan_err2(lc, _("Expect %s, got: %s"), "YES, NO, TRUE, or FALSE", lc->str); /* YES and NO must not be translated */
951 return;
952 }
953 scan_to_eol(lc);
954 set_bit(index, res_all.hdr.item_present);
955 }
956
957
958 /*
959 * Store Tape Label Type (Bacula, ANSI, IBM)
960 *
961 */
store_label(LEX * lc,RES_ITEM * item,int index,int pass)962 void store_label(LEX *lc, RES_ITEM *item, int index, int pass)
963 {
964 int i;
965
966 lex_get_token(lc, T_NAME);
967 /* Store the label pass 2 so that type is defined */
968 for (i=0; tapelabels[i].name; i++) {
969 if (strcasecmp(lc->str, tapelabels[i].name) == 0) {
970 *(uint32_t *)(item->value) = tapelabels[i].token;
971 i = 0;
972 break;
973 }
974 }
975 if (i != 0) {
976 scan_err1(lc, _("Expected a Tape Label keyword, got: %s"), lc->str);
977 return;
978 }
979 scan_to_eol(lc);
980 set_bit(index, res_all.hdr.item_present);
981 }
982
983 /*
984 * Store Statistics Type (CSV, Graphite - only supported)
985 */
store_coll_type(LEX * lc,RES_ITEM * item,int index,int pass)986 void store_coll_type(LEX *lc, RES_ITEM *item, int index, int pass)
987 {
988 int i;
989
990 lex_get_token(lc, T_NAME);
991 /* Store the type both pass 1 and pass 2 */
992 for (i = 0; collectortypes[i].type_name; i++) {
993 if (strcasecmp(lc->str, collectortypes[i].type_name) == 0) {
994 *(int32_t *)(item->value) = collectortypes[i].coll_type;
995 i = 0;
996 break;
997 }
998 }
999 if (i != 0) {
1000 scan_err1(lc, _("Expected a Statistics backend type keyword, got: %s"), lc->str);
1001 }
1002 scan_to_eol(lc);
1003 set_bit(index, res_all.hdr.item_present);
1004 }
1005
1006
1007 /*
1008 *
1009 * Configuration parser for Director Run Configuration
1010 * directives, which are part of the Schedule Resource
1011 *
1012 * Kern Sibbald, May MM
1013 *
1014 */
1015
1016 enum e_state {
1017 s_none = 0,
1018 s_range,
1019 s_mday,
1020 s_month,
1021 s_time,
1022 s_at,
1023 s_wday,
1024 s_daily,
1025 s_weekly,
1026 s_monthly,
1027 s_hourly,
1028 s_wom, /* 1st, 2nd, ...*/
1029 s_woy, /* week of year w00 - w53 */
1030 s_ldom /* last day of month */
1031 };
1032
1033 struct s_keyw {
1034 const char *name; /* keyword */
1035 enum e_state state; /* parser state */
1036 int code; /* state value */
1037 };
1038
1039 /* Keywords understood by parser */
1040 static struct s_keyw keyw[] = {
1041 {NT_("on"), s_none, 0},
1042 {NT_("at"), s_at, 0},
1043 {NT_("lastday"), s_ldom, 0},
1044
1045 {NT_("sun"), s_wday, 0},
1046 {NT_("mon"), s_wday, 1},
1047 {NT_("tue"), s_wday, 2},
1048 {NT_("wed"), s_wday, 3},
1049 {NT_("thu"), s_wday, 4},
1050 {NT_("fri"), s_wday, 5},
1051 {NT_("sat"), s_wday, 6},
1052 {NT_("jan"), s_month, 0},
1053 {NT_("feb"), s_month, 1},
1054 {NT_("mar"), s_month, 2},
1055 {NT_("apr"), s_month, 3},
1056 {NT_("may"), s_month, 4},
1057 {NT_("jun"), s_month, 5},
1058 {NT_("jul"), s_month, 6},
1059 {NT_("aug"), s_month, 7},
1060 {NT_("sep"), s_month, 8},
1061 {NT_("oct"), s_month, 9},
1062 {NT_("nov"), s_month, 10},
1063 {NT_("dec"), s_month, 11},
1064
1065 {NT_("sunday"), s_wday, 0},
1066 {NT_("monday"), s_wday, 1},
1067 {NT_("tuesday"), s_wday, 2},
1068 {NT_("wednesday"), s_wday, 3},
1069 {NT_("thursday"), s_wday, 4},
1070 {NT_("friday"), s_wday, 5},
1071 {NT_("saturday"), s_wday, 6},
1072 {NT_("january"), s_month, 0},
1073 {NT_("february"), s_month, 1},
1074 {NT_("march"), s_month, 2},
1075 {NT_("april"), s_month, 3},
1076 {NT_("june"), s_month, 5},
1077 {NT_("july"), s_month, 6},
1078 {NT_("august"), s_month, 7},
1079 {NT_("september"), s_month, 8},
1080 {NT_("october"), s_month, 9},
1081 {NT_("november"), s_month, 10},
1082 {NT_("december"), s_month, 11},
1083
1084 {NT_("daily"), s_daily, 0},
1085 {NT_("weekly"), s_weekly, 0},
1086 {NT_("monthly"), s_monthly, 0},
1087 {NT_("hourly"), s_hourly, 0},
1088
1089 {NT_("1st"), s_wom, 0},
1090 {NT_("2nd"), s_wom, 1},
1091 {NT_("3rd"), s_wom, 2},
1092 {NT_("4th"), s_wom, 3},
1093 {NT_("5th"), s_wom, 4},
1094 {NT_("6th"), s_wom, 5},
1095
1096 {NT_("first"), s_wom, 0},
1097 {NT_("second"), s_wom, 1},
1098 {NT_("third"), s_wom, 2},
1099 {NT_("fourth"), s_wom, 3},
1100 {NT_("fifth"), s_wom, 4},
1101 {NT_("sixth"), s_wom, 5},
1102 {NULL, s_none, 0}
1103 };
1104
1105 static bool have_hour, have_mday, have_wday, have_month, have_wom;
1106 static bool have_at, have_woy;
1107
set_defaults(RUNBASE * lrun)1108 static void set_defaults(RUNBASE *lrun) {
1109 have_hour = have_mday = have_wday = have_month = have_wom = have_woy = false;
1110 have_at = false;
1111 set_bits(0, 23, lrun->hour);
1112 set_bits(0, 30, lrun->mday);
1113 set_bits(0, 6, lrun->wday);
1114 set_bits(0, 11, lrun->month);
1115 set_bits(0, 5, lrun->wom);
1116 set_bits(0, 53, lrun->woy);
1117 }
1118
copy(RUNBASE * src)1119 void RUNBASE::copy(RUNBASE *src)
1120 {
1121 minute = src->minute;
1122 last_run = src->last_run;
1123 next_run = src->next_run;
1124 last_day_set = src->last_day_set;
1125 memcpy(hour, src->hour, sizeof(hour));
1126 memcpy(mday, src->mday, sizeof(mday));
1127 memcpy(month,src->month,sizeof(month));
1128 memcpy(wday, src->wday, sizeof(wday));
1129 memcpy(wom, src->wom, sizeof(wom));
1130 memcpy(woy, src->woy, sizeof(woy));
1131 }
1132
1133 /*
1134 * Store Schedule Run information
1135 *
1136 * Parse Run statement:
1137 *
1138 * Run <keyword=value ...> [on] 2 january at 23:45
1139 *
1140 * Default Run time is daily at 0:0
1141 *
1142 * There can be multiple run statements, they are simply chained
1143 * together at the upper level.
1144 *
1145 * Look src/dird/run_conf.c to see how to use this function
1146 *
1147 */
store_runbase(LEX * lc,int token)1148 void RUNBASE::store_runbase(LEX *lc, int token)
1149 {
1150 int i;
1151 int state, state2 = 0, code = 0, code2 = 0;
1152 int options = lc->options;
1153 char *p;
1154 RUNBASE *lrun = this;
1155
1156
1157 lc->options |= LOPT_NO_IDENT; /* want only "strings" */
1158
1159 /* clear local copy of run record */
1160 clear();
1161
1162 if (token == T_ERROR) {
1163 return;
1164 }
1165
1166 /*
1167 * Scan schedule times.
1168 * Default is: daily at 0:0
1169 */
1170 state = s_none;
1171 set_defaults(lrun);
1172
1173 for ( ; token != T_EOL; (token = lex_get_token(lc, T_ALL))) {
1174 int len;
1175 bool pm = false;
1176 bool am = false;
1177 switch (token) {
1178 case T_NUMBER:
1179 state = s_mday;
1180 code = atoi(lc->str) - 1;
1181 if (code < 0 || code > 30) {
1182 scan_err0(lc, _("Day number out of range (1-31)"));
1183 }
1184 break;
1185 case T_NAME: /* this handles drop through from keyword */
1186 case T_UNQUOTED_STRING:
1187 if (strchr(lc->str, (int)'-')) {
1188 state = s_range;
1189 break;
1190 }
1191 if (strchr(lc->str, (int)':')) {
1192 state = s_time;
1193 break;
1194 }
1195 if (lc->str_len == 3 && (lc->str[0] == 'w' || lc->str[0] == 'W') &&
1196 is_an_integer(lc->str+1)) {
1197 code = atoi(lc->str+1);
1198 if (code < 0 || code > 53) {
1199 scan_err0(lc, _("Week number out of range (0-53)"));
1200 /* NOT REACHED */
1201 }
1202 state = s_woy; /* week of year */
1203 break;
1204 }
1205 /* everything else must be a keyword */
1206 for (i=0; keyw[i].name; i++) {
1207 if (strcasecmp(lc->str, keyw[i].name) == 0) {
1208 state = keyw[i].state;
1209 code = keyw[i].code;
1210 i = 0;
1211 break;
1212 }
1213 }
1214 if (i != 0) {
1215 scan_err1(lc, _("Job type field: %s in run record not found"), lc->str);
1216 /* NOT REACHED */
1217 }
1218 break;
1219 case T_COMMA:
1220 continue;
1221 default:
1222 scan_err2(lc, _("Unexpected token: %d:%s"), token, lc->str);
1223 /* NOT REACHED */
1224 break;
1225 }
1226 switch (state) {
1227 case s_none:
1228 continue;
1229 case s_mday: /* day of month */
1230 if (!have_mday) {
1231 clear_bits(0, 30, lrun->mday);
1232 have_mday = true;
1233 }
1234 set_bit(code, lrun->mday);
1235 break;
1236 case s_month: /* month of year */
1237 if (!have_month) {
1238 clear_bits(0, 11, lrun->month);
1239 have_month = true;
1240 }
1241 set_bit(code, lrun->month);
1242 break;
1243 case s_wday: /* week day */
1244 if (!have_wday) {
1245 clear_bits(0, 6, lrun->wday);
1246 have_wday = true;
1247 }
1248 set_bit(code, lrun->wday);
1249 break;
1250 case s_wom: /* Week of month 1st, ... */
1251 if (!have_wom) {
1252 clear_bits(0, 5, lrun->wom);
1253 have_wom = true;
1254 }
1255 set_bit(code, lrun->wom);
1256 break;
1257 case s_woy:
1258 if (!have_woy) {
1259 clear_bits(0, 53, lrun->woy);
1260 have_woy = true;
1261 }
1262 set_bit(code, lrun->woy);
1263 break;
1264 case s_time: /* time */
1265 if (!have_at) {
1266 scan_err0(lc, _("Time must be preceded by keyword AT."));
1267 /* NOT REACHED */
1268 }
1269 if (!have_hour) {
1270 clear_bits(0, 23, lrun->hour);
1271 }
1272 // Dmsg1(000, "s_time=%s\n", lc->str);
1273 p = strchr(lc->str, ':');
1274 if (!p) {
1275 scan_err0(lc, _("Time logic error.\n"));
1276 /* NOT REACHED */
1277 }
1278 *p++ = 0; /* separate two halves */
1279 code = atoi(lc->str); /* pick up hour */
1280 code2 = atoi(p); /* pick up minutes */
1281 len = strlen(p);
1282 if (len >= 2) {
1283 p += 2;
1284 }
1285 if (strcasecmp(p, "pm") == 0) {
1286 pm = true;
1287 } else if (strcasecmp(p, "am") == 0) {
1288 am = true;
1289 } else if (len != 2) {
1290 scan_err0(lc, _("Bad time specification."));
1291 /* NOT REACHED */
1292 }
1293 /*
1294 * Note, according to NIST, 12am and 12pm are ambiguous and
1295 * can be defined to anything. However, 12:01am is the same
1296 * as 00:01 and 12:01pm is the same as 12:01, so we define
1297 * 12am as 00:00 and 12pm as 12:00.
1298 */
1299 if (pm) {
1300 /* Convert to 24 hour time */
1301 if (code != 12) {
1302 code += 12;
1303 }
1304 /* am */
1305 } else if (am && code == 12) {
1306 code -= 12;
1307 }
1308 if (code < 0 || code > 23 || code2 < 0 || code2 > 59) {
1309 scan_err0(lc, _("Bad time specification."));
1310 /* NOT REACHED */
1311 }
1312 // Dmsg2(000, "hour=%d min=%d\n", code, code2);
1313 set_bit(code, lrun->hour);
1314 lrun->minute = code2;
1315 have_hour = true;
1316 break;
1317 case s_at:
1318 have_at = true;
1319 break;
1320 case s_ldom:
1321 if (!have_mday) {
1322 clear_bits(0, 30, lrun->mday);
1323 have_mday = true;
1324 }
1325 lrun->last_day_set = true;
1326 set_bit(31, lrun->mday); /* day 32 => last day of month */
1327 break;
1328 case s_range:
1329 p = strchr(lc->str, '-');
1330 if (!p) {
1331 scan_err0(lc, _("Range logic error.\n"));
1332 }
1333 *p++ = 0; /* separate two halves */
1334
1335 /* Check for day range */
1336 if (is_an_integer(lc->str) && is_an_integer(p)) {
1337 code = atoi(lc->str) - 1;
1338 code2 = atoi(p) - 1;
1339 if (code < 0 || code > 30 || code2 < 0 || code2 > 30) {
1340 scan_err0(lc, _("Bad day range specification."));
1341 }
1342 if (!have_mday) {
1343 clear_bits(0, 30, lrun->mday);
1344 have_mday = true;
1345 }
1346 if (code < code2) {
1347 set_bits(code, code2, lrun->mday);
1348 } else {
1349 set_bits(code, 30, lrun->mday);
1350 set_bits(0, code2, lrun->mday);
1351 }
1352 break;
1353 }
1354 /* Check for week of year range */
1355 if (strlen(lc->str) == 3 && strlen(p) == 3 &&
1356 (lc->str[0] == 'w' || lc->str[0] == 'W') &&
1357 (p[0] == 'w' || p[0] == 'W') &&
1358 is_an_integer(lc->str+1) && is_an_integer(p+1)) {
1359 code = atoi(lc->str+1);
1360 code2 = atoi(p+1);
1361 if (code < 0 || code > 53 || code2 < 0 || code2 > 53) {
1362 scan_err0(lc, _("Week number out of range (0-53)"));
1363 }
1364 if (!have_woy) {
1365 clear_bits(0, 53, lrun->woy);
1366 have_woy = true;
1367 }
1368 if (code < code2) {
1369 set_bits(code, code2, lrun->woy);
1370 } else {
1371 set_bits(code, 53, lrun->woy);
1372 set_bits(0, code2, lrun->woy);
1373 }
1374 break;
1375 }
1376 /* lookup first half of keyword range (week days or months) */
1377 lcase(lc->str);
1378 for (i=0; keyw[i].name; i++) {
1379 if (strcasecmp(lc->str, keyw[i].name) == 0) {
1380 state = keyw[i].state;
1381 code = keyw[i].code;
1382 i = 0;
1383 break;
1384 }
1385 }
1386 if (i != 0 || (state != s_month && state != s_wday && state != s_wom)) {
1387 scan_err0(lc, _("Invalid month, week or position day range"));
1388 /* NOT REACHED */
1389 }
1390
1391 /* Lookup end of range */
1392 lcase(p);
1393 for (i=0; keyw[i].name; i++) {
1394 if (strcasecmp(p, keyw[i].name) == 0) {
1395 state2 = keyw[i].state;
1396 code2 = keyw[i].code;
1397 i = 0;
1398 break;
1399 }
1400 }
1401 if (i != 0 || state != state2 || code == code2) {
1402 scan_err0(lc, _("Invalid month, weekday or position range"));
1403 /* NOT REACHED */
1404 }
1405 if (state == s_wday) {
1406 if (!have_wday) {
1407 clear_bits(0, 6, lrun->wday);
1408 have_wday = true;
1409 }
1410 if (code < code2) {
1411 set_bits(code, code2, lrun->wday);
1412 } else {
1413 set_bits(code, 6, lrun->wday);
1414 set_bits(0, code2, lrun->wday);
1415 }
1416 } else if (state == s_month) {
1417 if (!have_month) {
1418 clear_bits(0, 11, lrun->month);
1419 have_month = true;
1420 }
1421 if (code < code2) {
1422 set_bits(code, code2, lrun->month);
1423 } else {
1424 /* this is a bit odd, but we accept it anyway */
1425 set_bits(code, 11, lrun->month);
1426 set_bits(0, code2, lrun->month);
1427 }
1428 } else {
1429 /* Must be position */
1430 if (!have_wom) {
1431 clear_bits(0, 5, lrun->wom);
1432 have_wom = true;
1433 }
1434 if (code < code2) {
1435 set_bits(code, code2, lrun->wom);
1436 } else {
1437 set_bits(code, 5, lrun->wom);
1438 set_bits(0, code2, lrun->wom);
1439 }
1440 }
1441 break;
1442 case s_hourly:
1443 have_hour = true;
1444 set_bits(0, 23, lrun->hour);
1445 break;
1446 case s_weekly:
1447 have_mday = have_wom = have_woy = true;
1448 set_bits(0, 30, lrun->mday);
1449 set_bits(0, 5, lrun->wom);
1450 set_bits(0, 53, lrun->woy);
1451 break;
1452 case s_daily:
1453 have_mday = true;
1454 set_bits(0, 6, lrun->wday);
1455 break;
1456 case s_monthly:
1457 have_month = true;
1458 set_bits(0, 11, lrun->month);
1459 break;
1460 default:
1461 scan_err0(lc, _("Unexpected run state\n"));
1462 /* NOT REACHED */
1463 break;
1464 }
1465 }
1466
1467 lc->options = options; /* restore scanner options */
1468 }
1469
1470
1471 /* Parser state */
1472 enum parse_state {
1473 p_none,
1474 p_resource
1475 };
1476
init(const char * cf,LEX_ERROR_HANDLER * scan_error,int32_t err_type,void * vres_all,int32_t res_all_size,int32_t r_first,int32_t r_last,RES_TABLE * resources,RES_HEAD *** res_head)1477 void CONFIG::init(
1478 const char *cf,
1479 LEX_ERROR_HANDLER *scan_error,
1480 int32_t err_type,
1481 void *vres_all,
1482 int32_t res_all_size,
1483 int32_t r_first,
1484 int32_t r_last,
1485 RES_TABLE *resources,
1486 RES_HEAD ***res_head)
1487 {
1488 m_cf = cf;
1489 m_scan_error = scan_error;
1490 m_err_type = err_type;
1491 m_res_all = vres_all;
1492 m_res_all_size = res_all_size;
1493 m_r_first = r_first;
1494 m_r_last = r_last;
1495 m_resources = resources;
1496 init_res_head(res_head, r_first, r_last);
1497 m_res_head = *res_head;
1498 }
1499
1500 /*********************************************************************
1501 *
1502 * Parse configuration file
1503 *
1504 * Return 0 if reading failed, 1 otherwise
1505 * Note, the default behavior unless you have set an alternate
1506 * scan_error handler is to die on an error.
1507 */
parse_config()1508 bool CONFIG::parse_config()
1509 {
1510 LEX *lc = NULL;
1511 int token, i, pass;
1512 int res_type = 0;
1513 enum parse_state state = p_none;
1514 RES_ITEM *items = NULL;
1515 int level = 0;
1516 static bool first = true;
1517 int errstat;
1518 const char *cf = m_cf;
1519 LEX_ERROR_HANDLER *scan_error = m_scan_error;
1520 int err_type = m_err_type;
1521 //HPKT hpkt;
1522
1523 if (first && (errstat=rwl_init(&res_lock)) != 0) {
1524 berrno be;
1525 Jmsg1(NULL, M_ABORT, 0, _("Unable to initialize resource lock. ERR=%s\n"),
1526 be.bstrerror(errstat));
1527 }
1528 first = false;
1529
1530 char *full_path = (char *)alloca(MAX_PATH + 1);
1531
1532 if (!find_config_file(cf, full_path, MAX_PATH +1)) {
1533 Jmsg0(NULL, M_ABORT, 0, _("Config filename too long.\n"));
1534 }
1535 cf = full_path;
1536
1537 /* Make two passes. The first builds the name symbol table,
1538 * and the second picks up the items.
1539 */
1540 Dmsg0(900, "Enter parse_config()\n");
1541 for (pass=1; pass <= 2; pass++) {
1542 Dmsg1(900, "parse_config pass %d\n", pass);
1543 if ((lc = lex_open_file(lc, cf, scan_error)) == NULL) {
1544 berrno be;
1545 /* We must create a lex packet to print the error */
1546 lc = (LEX *)malloc(sizeof(LEX));
1547 memset(lc, 0, sizeof(LEX));
1548 lc->str = get_memory(5000);
1549 if (scan_error) {
1550 lc->scan_error = scan_error;
1551 } else {
1552 lex_set_default_error_handler(lc);
1553 }
1554 lex_set_error_handler_error_type(lc, err_type) ;
1555 pm_strcpy(lc->str, cf);
1556 lc->fname = lc->str;
1557 scan_err2(lc, _("Cannot open config file \"%s\": %s\n"),
1558 lc->str, be.bstrerror());
1559 free_pool_memory(lc->str);
1560 free(lc);
1561 return 0;
1562 }
1563 if (!m_encode_pass) {
1564 lex_store_clear_passwords(lc);
1565 }
1566 lex_set_error_handler_error_type(lc, err_type) ;
1567 while ((token=lex_get_token(lc, T_ALL)) != T_EOF) {
1568 Dmsg3(900, "parse state=%d pass=%d got token=%s\n", state, pass,
1569 lex_tok_to_str(token));
1570 switch (state) {
1571 case p_none:
1572 if (token == T_EOL) {
1573 break;
1574 } else if (token == T_UTF8_BOM) {
1575 /* We can assume the file is UTF-8 as we have seen a UTF-8 BOM */
1576 break;
1577 } else if (token == T_UTF16_BOM) {
1578 scan_err0(lc, _("Currently we cannot handle UTF-16 source files. "
1579 "Please convert the conf file to UTF-8\n"));
1580 goto bail_out;
1581 } else if (token != T_IDENTIFIER) {
1582 scan_err1(lc, _("Expected a Resource name identifier, got: %s"), lc->str);
1583 goto bail_out;
1584 }
1585 for (i=0; resources[i].name; i++) {
1586 if (strcasecmp(resources[i].name, lc->str) == 0) {
1587 items = resources[i].items;
1588 if (!items) {
1589 break;
1590 }
1591 state = p_resource;
1592 res_type = resources[i].rcode;
1593 init_resource0(this, res_type, items, pass);
1594 break;
1595 }
1596 }
1597 if (state == p_none) {
1598 scan_err1(lc, _("expected resource name, got: %s"), lc->str);
1599 goto bail_out;
1600 }
1601 break;
1602 case p_resource:
1603 switch (token) {
1604 case T_BOB:
1605 level++;
1606 break;
1607 case T_IDENTIFIER:
1608 if (level != 1) {
1609 scan_err1(lc, _("not in resource definition: %s"), lc->str);
1610 goto bail_out;
1611 }
1612 for (i=0; items[i].name; i++) {
1613 //hpkt.pass = pass;
1614 //hpkt.ritem = &items[i];
1615 //hpkt.edbuf = NULL;
1616 //hpkt.index = i;
1617 //hpkt.lc = lc;
1618 //hpkt.hfunc = HF_STORE;
1619 if (strcasecmp(items[i].name, lc->str) == 0) {
1620 /* If the ITEM_NO_EQUALS flag is set we do NOT
1621 * scan for = after the keyword */
1622 if (!(items[i].flags & ITEM_NO_EQUALS)) {
1623 token = lex_get_token(lc, T_SKIP_EOL);
1624 Dmsg1 (900, "in T_IDENT got token=%s\n", lex_tok_to_str(token));
1625 if (token != T_EQUALS) {
1626 scan_err1(lc, _("expected an equals, got: %s"), lc->str);
1627 goto bail_out;
1628 }
1629 }
1630 Dmsg1(800, "calling handler for %s\n", items[i].name);
1631 /* Call item handler */
1632 items[i].handler(lc, &items[i], i, pass);
1633 i = -1;
1634 break;
1635 }
1636 }
1637 if (i >= 0) {
1638 Dmsg2(900, "level=%d id=%s\n", level, lc->str);
1639 Dmsg1(900, "Keyword = %s\n", lc->str);
1640 scan_err1(lc, _("Keyword \"%s\" not permitted in this resource.\n"
1641 "Perhaps you left the trailing brace off of the previous resource."), lc->str);
1642 goto bail_out;
1643 }
1644 break;
1645
1646 case T_EOB:
1647 level--;
1648 state = p_none;
1649 Dmsg0(900, "T_EOB => define new resource\n");
1650 if (res_all.hdr.name == NULL) {
1651 scan_err0(lc, _("Name not specified for resource"));
1652 goto bail_out;
1653 }
1654 if (!save_resource(this, res_type, items, pass)) { /* save resource */
1655 scan_err1(lc, "%s", m_errmsg);
1656 goto bail_out;
1657 }
1658 break;
1659
1660 case T_EOL:
1661 break;
1662
1663 default:
1664 scan_err2(lc, _("unexpected token %d %s in resource definition"),
1665 token, lex_tok_to_str(token));
1666 goto bail_out;
1667 }
1668 break;
1669 default:
1670 scan_err1(lc, _("Unknown parser state %d\n"), state);
1671 goto bail_out;
1672 }
1673 }
1674 if (state != p_none) {
1675 scan_err0(lc, _("End of conf file reached with unclosed resource."));
1676 goto bail_out;
1677 }
1678 if (chk_dbglvl(900) && pass == 2) {
1679 int i;
1680 for (i=m_r_first; i<=m_r_last; i++) {
1681 dump_each_resource(i, prtmsg, NULL);
1682 }
1683 }
1684 lc = lex_close_file(lc);
1685 }
1686 Dmsg0(900, "Leave parse_config()\n");
1687 return 1;
1688 bail_out:
1689 if (lc) {
1690 lc = lex_close_file(lc);
1691 }
1692 return 0;
1693 }
1694
get_default_configdir()1695 const char *get_default_configdir()
1696 {
1697 return SYSCONFDIR;
1698 }
1699
1700 #ifdef xxx_not_used
1701 HRESULT hr;
1702 static char szConfigDir[MAX_PATH + 1] = { 0 };
1703 if (!p_SHGetFolderPath) {
1704 bstrncpy(szConfigDir, DEFAULT_CONFIGDIR, sizeof(szConfigDir));
1705 return szConfigDir;
1706 }
1707 if (szConfigDir[0] == '\0') {
1708 hr = p_SHGetFolderPath(NULL, CSIDL_COMMON_APPDATA, NULL, 0, szConfigDir);
1709 if (SUCCEEDED(hr)) {
1710 bstrncat(szConfigDir, "\\Bacula", sizeof(szConfigDir));
1711 } else {
1712 bstrncpy(szConfigDir, DEFAULT_CONFIGDIR, sizeof(szConfigDir));
1713 }
1714 }
1715 return szConfigDir;
1716 #endif
1717
1718
1719 /*
1720 * Returns false on error
1721 * true on OK, with full_path set to where config file should be
1722 */
1723 bool
find_config_file(const char * config_file,char * full_path,int max_path)1724 find_config_file(const char *config_file, char *full_path, int max_path)
1725 {
1726 int file_length = strlen(config_file) + 1;
1727
1728 /* If a full path specified, use it */
1729 if (first_path_separator(config_file) != NULL) {
1730 if (file_length > max_path) {
1731 return false;
1732 }
1733 bstrncpy(full_path, config_file, file_length);
1734 return true;
1735 }
1736
1737 /* config_file is default file name, now find default dir */
1738 const char *config_dir = get_default_configdir();
1739 int dir_length = strlen(config_dir);
1740
1741 if ((dir_length + 1 + file_length) > max_path) {
1742 return false;
1743 }
1744
1745 memcpy(full_path, config_dir, dir_length + 1);
1746
1747 if (!IsPathSeparator(full_path[dir_length - 1])) {
1748 full_path[dir_length++] = '/';
1749 }
1750
1751 memcpy(&full_path[dir_length], config_file, file_length);
1752
1753 return true;
1754 }
1755
1756 /*********************************************************************
1757 *
1758 * Free configuration resources
1759 *
1760 */
free_all_resources()1761 void CONFIG::free_all_resources()
1762 {
1763 RES *next, *res;
1764 if (m_res_head == NULL) {
1765 return;
1766 }
1767 /* Walk down chain of res_heads */
1768 for (int i=m_r_first; i<=m_r_last; i++) {
1769 if (m_res_head[i-m_r_first]) {
1770 next = m_res_head[i-m_r_first]->first;
1771 Dmsg2(500, "i=%d, next=%p\n", i, next);
1772 /* Walk down resource chain freeing them */
1773 for ( ; next; ) {
1774 res = next;
1775 next = res->res_next;
1776 free_resource(res, i);
1777 }
1778 free(m_res_head[i-m_r_first]->res_list);
1779 free(m_res_head[i-m_r_first]);
1780 m_res_head[i-m_r_first] = NULL;
1781 }
1782 }
1783 }
1784
CONFIG()1785 CONFIG::CONFIG()
1786 : m_cf(NULL),
1787 m_scan_error(NULL),
1788 m_err_type(0),
1789 m_res_all(NULL),
1790 m_res_all_size(0),
1791 m_encode_pass(true),
1792 m_r_first(0),
1793 m_r_last(0),
1794 m_resources(NULL),
1795 m_res_head(NULL)
1796 {
1797 m_errmsg = get_pool_memory(PM_EMSG);
1798 *m_errmsg = 0;
1799 }
1800
~CONFIG()1801 CONFIG::~CONFIG() {
1802 free_all_resources();
1803 free_pool_memory(m_errmsg);
1804 }
1805
encode_password(bool a)1806 void CONFIG::encode_password(bool a)
1807 {
1808 m_encode_pass = a;
1809 }
1810