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 * Main configuration file parser for Bacula Directors,
21 * some parts may be split into separate files such as
22 * the schedule configuration (run_config.c).
23 *
24 * Note, the configuration file parser consists of three parts
25 *
26 * 1. The generic lexical scanner in lib/lex.c and lib/lex.h
27 *
28 * 2. The generic config scanner in lib/parse_config.c and
29 * lib/parse_config.h.
30 * These files contain the parser code, some utility
31 * routines, and the common store routines (name, int,
32 * string).
33 *
34 * 3. The daemon specific file, which contains the Resource
35 * definitions as well as any specific store routines
36 * for the resource records.
37 *
38 * Kern Sibbald, January MM
39 *
40 */
41
42
43 #include "bacula.h"
44 #include "dird.h"
45
46 /* Define the first and last resource ID record
47 * types. Note, these should be unique for each
48 * daemon though not a requirement.
49 */
50 int32_t r_first = R_FIRST;
51 int32_t r_last = R_LAST;
52 RES_HEAD **res_head;
53
54 static pthread_mutex_t globals_mutex = PTHREAD_MUTEX_INITIALIZER;
55 dlist client_globals;
56 dlist job_globals;
57 dlist store_globals;
58 dlist sched_globals;
59
60
61 /* Imported subroutines */
62 extern void store_run(LEX *lc, RES_ITEM *item, int index, int pass);
63 extern void store_finc(LEX *lc, RES_ITEM *item, int index, int pass);
64 extern void store_inc(LEX *lc, RES_ITEM *item, int index, int pass);
65
66
67 /* Forward referenced subroutines */
68
69 void store_jobtype(LEX *lc, RES_ITEM *item, int index, int pass);
70 void store_level(LEX *lc, RES_ITEM *item, int index, int pass);
71 void store_replace(LEX *lc, RES_ITEM *item, int index, int pass);
72 void store_acl(LEX *lc, RES_ITEM *item, int index, int pass);
73 void store_migtype(LEX *lc, RES_ITEM *item, int index, int pass);
74 void store_ac_res(LEX *lc, RES_ITEM *item, int index, int pass);
75 void store_device(LEX *lc, RES_ITEM *item, int index, int pass);
76 void store_actiononpurge(LEX *lc, RES_ITEM *item, int index, int pass);
77 static void store_runscript_when(LEX *lc, RES_ITEM *item, int index, int pass);
78 static void store_runscript_cmd(LEX *lc, RES_ITEM *item, int index, int pass);
79 static void store_short_runscript(LEX *lc, RES_ITEM *item, int index, int pass);
80
81 /* We build the current resource here as we are
82 * scanning the resource configuration definition,
83 * then move it to allocated memory when the resource
84 * scan is complete.
85 */
86 #if defined(_MSC_VER)
87 extern "C" { // work around visual compiler mangling variables
88 URES res_all;
89 }
90 #else
91 URES res_all;
92 #endif
93 int32_t res_all_size = sizeof(res_all);
94
95 /* Implementation of certain classes */
96
create_client_globals()97 void CLIENT::create_client_globals()
98 {
99 globals = (CLIENT_GLOBALS *)malloc(sizeof(CLIENT_GLOBALS));
100 memset(globals, 0, sizeof(CLIENT_GLOBALS));
101 globals->name = bstrdup(name());
102 globals->enabled = -1; /* Not set */
103 client_globals.append(globals);
104 }
105
getNumConcurrentJobs()106 int32_t CLIENT::getNumConcurrentJobs()
107 {
108 LOCK_GUARD(globals_mutex);
109 if (globals == NULL) {
110 /* globals can be NULL when called from dump_each_resource() in parse_config() */
111 return 0;
112 }
113 return globals->NumConcurrentJobs;
114 }
115
incNumConcurrentJobs(int32_t inc)116 int32_t CLIENT::incNumConcurrentJobs(int32_t inc)
117 {
118 P(globals_mutex); // be sure globals is initialized
119 int32_t num = globals->NumConcurrentJobs += inc;
120 V(globals_mutex);
121 ASSERT(num >= 0);
122 Dmsg2(200, "Set NumConcurrentJobs=%ld for Client %s\n",
123 num, globals->name);
124 return num;
125 }
126
getBSOCK(int timeout)127 BSOCK *CLIENT::getBSOCK(int timeout)
128 {
129 P(globals_mutex);
130 if (!globals->socket) {
131 globals->socket = New(BsockMeeting());
132 }
133 V(globals_mutex);
134 return globals->socket->get(timeout);
135 }
136
getBSOCK_state(POOLMEM * & buf)137 bool CLIENT::getBSOCK_state(POOLMEM *&buf)
138 {
139 P(globals_mutex);
140 if (!globals->socket) {
141 globals->socket = New(BsockMeeting());
142 }
143 V(globals_mutex);
144 return globals->socket->is_set(buf);
145 }
146
setBSOCK(BSOCK * sock)147 void CLIENT::setBSOCK(BSOCK *sock)
148 {
149 P(globals_mutex);
150 if (!globals->socket) {
151 globals->socket = New(BsockMeeting());
152 }
153 V(globals_mutex);
154 globals->socket->set(sock);
155 }
156
address(POOLMEM * & buf)157 char *CLIENT::address(POOLMEM *&buf)
158 {
159 P(globals_mutex);
160 if (!globals || !globals->SetIPaddress) {
161 pm_strcpy(buf, NPRTB(client_address));
162
163 } else {
164 pm_strcpy(buf, globals->SetIPaddress);
165 }
166 V(globals_mutex);
167 return buf;
168 }
169
setAddress(char * addr)170 void CLIENT::setAddress(char *addr)
171 {
172 P(globals_mutex);
173 if (globals->SetIPaddress) {
174 free(globals->SetIPaddress);
175 }
176 globals->SetIPaddress = bstrdup(addr);
177 V(globals_mutex);
178 }
179
is_enabled()180 bool CLIENT::is_enabled()
181 {
182 LOCK_GUARD(globals_mutex);
183 if (globals == NULL || globals->enabled < 0) {
184 /* not yet modified, use default from resource */
185 /* globals can be NULL when called from dump_each_resource() in parse_config() */
186 return Enabled;
187 }
188 return globals->enabled;
189 }
190
setEnabled(bool val)191 void CLIENT::setEnabled(bool val)
192 {
193 P(globals_mutex);
194 /* TODO: We probably need to set -1 (not set) when we are back to the default value */
195 globals->enabled = val? 1 : 0;
196 V(globals_mutex);
197 Dmsg2(200, "Set Enabled=%d for Client %s\n",
198 val, globals->name);
199 }
200
create_job_globals()201 void JOB::create_job_globals()
202 {
203 globals = (JOB_GLOBALS *)malloc(sizeof(JOB_GLOBALS));
204 memset(globals, 0, sizeof(JOB_GLOBALS));
205 globals->name = bstrdup(name());
206 globals->enabled = -1; /* Not set */
207 job_globals.append(globals);
208 }
209
getNumConcurrentJobs()210 int32_t JOB::getNumConcurrentJobs()
211 {
212 LOCK_GUARD(globals_mutex);
213 if (globals == NULL) {
214 /* globals can be NULL when called from dump_each_resource() in parse_config() */
215 return 0;
216 }
217 return globals->NumConcurrentJobs;
218 }
219
incNumConcurrentJobs(int32_t inc)220 int32_t JOB::incNumConcurrentJobs(int32_t inc)
221 {
222 P(globals_mutex);
223 int32_t num = globals->NumConcurrentJobs += inc;
224 V(globals_mutex);
225 ASSERT(num >= 0);
226 Dmsg2(200, "Set NumConcurrentJobs=%ld for Job %s\n",
227 num, globals->name);
228 return num;
229 }
230
is_enabled()231 bool JOB::is_enabled()
232 {
233 LOCK_GUARD(globals_mutex);
234 if (globals == NULL || globals->enabled < 0) {
235 /* not yet modified, use default from resource */
236 /* globals can be NULL when called from dump_each_resource() in parse_config() */
237 return Enabled;
238 }
239 return globals->enabled;
240 }
241
setEnabled(bool val)242 void JOB::setEnabled(bool val)
243 {
244 P(globals_mutex);
245 globals->enabled = val ? 1 : 0;
246 V(globals_mutex);
247 Dmsg2(200, "Set Enabled=%d for Job %s\n",
248 val, globals->name);
249 }
250
create_store_globals()251 void STORE::create_store_globals()
252 {
253 globals = (STORE_GLOBALS *)malloc(sizeof(STORE_GLOBALS));
254 memset(globals, 0, sizeof(STORE_GLOBALS));
255 globals->name = bstrdup(name());
256 globals->enabled = -1; /* Not set */
257 store_globals.append(globals);
258 }
259
getNumConcurrentReadJobs()260 int32_t STORE::getNumConcurrentReadJobs()
261 {
262 LOCK_GUARD(globals_mutex);
263 if (globals == NULL) {
264 /* globals can be NULL when called from dump_each_resource() in parse_config() */
265 return 0;
266 }
267 return globals->NumConcurrentReadJobs;
268 }
269
incNumConcurrentReadJobs(int32_t inc)270 int32_t STORE::incNumConcurrentReadJobs(int32_t inc)
271 {
272 P(globals_mutex);
273 int32_t num = globals->NumConcurrentReadJobs += inc;
274 V(globals_mutex);
275 Dmsg2(200, "Set NumConcurrentReadJobs=%ld for Store %s\n",
276 num, globals->name);
277 ASSERT(num >= 0);
278 return num;
279 }
280
getNumConcurrentJobs()281 int32_t STORE::getNumConcurrentJobs()
282 {
283 LOCK_GUARD(globals_mutex);
284 if (globals == NULL) {
285 /* globals can be NULL when called from dump_each_resource() in parse_config() */
286 return 0;
287 }
288 return globals->NumConcurrentJobs;
289 }
290
incNumConcurrentJobs(int32_t inc)291 int32_t STORE::incNumConcurrentJobs(int32_t inc)
292 {
293 P(globals_mutex);
294 int32_t num = globals->NumConcurrentJobs += inc;
295 V(globals_mutex);
296 Dmsg2(200, "Set numconcurrentJobs=%ld for Store %s\n",
297 num, globals->name);
298 ASSERT(num >= 0);
299 return num;
300 }
301
is_enabled()302 bool STORE::is_enabled()
303 {
304 LOCK_GUARD(globals_mutex);
305 if (globals == NULL || globals->enabled < 0) {
306 /* not yet modified, use default from resource */
307 /* globals can be NULL when called from dump_each_resource() in parse_config() */
308 return Enabled;
309 }
310 return globals->enabled;
311 }
312
setEnabled(bool val)313 void STORE::setEnabled(bool val)
314 {
315 P(globals_mutex);
316 globals->enabled = val ? 1 : 0;
317 V(globals_mutex);
318 Dmsg2(200, "Set Enabled=%d for Storage %s\n",
319 val, globals->name);
320 }
321
create_sched_globals()322 void SCHED::create_sched_globals()
323 {
324 globals = (SCHED_GLOBALS *)malloc(sizeof(CLIENT_GLOBALS));
325 memset(globals, 0, sizeof(SCHED_GLOBALS));
326 globals->name = bstrdup(name());
327 globals->enabled = -1; /* Not set */
328 sched_globals.append(globals);
329 }
330
is_enabled()331 bool SCHED::is_enabled()
332 {
333 LOCK_GUARD(globals_mutex);
334 if (globals == NULL || globals->enabled < 0) {
335 /* not yet modified, use default from resource */
336 /* globals can be NULL when called from dump_each_resource() in parse_config() */
337 return Enabled;
338 }
339 return globals->enabled;
340 }
341
setEnabled(bool val)342 void SCHED::setEnabled(bool val)
343 {
344 P(globals_mutex);
345 globals->enabled = val ? 1 : 0;
346 V(globals_mutex);
347 Dmsg2(200, "Set Enabled=%d for Schedule %s\n",
348 val, globals->name);
349 }
350
351 /*
352 * Definition of records permitted within each
353 * resource with the routine to process the record
354 * information. NOTE! quoted names must be in lower case.
355 */
356 /*
357 * Director Resource
358 *
359 * name handler value code flags default_value
360 */
361 static RES_ITEM dir_items[] = {
362 {"Name", store_name, ITEM(res_dir.hdr.name), 0, ITEM_REQUIRED, 0},
363 {"Description", store_str, ITEM(res_dir.hdr.desc), 0, 0, 0},
364 {"EventsRetention", store_time, ITEM(res_dir.events_retention), 0, ITEM_DEFAULT, 30*24*60*60},
365 {"Messages", store_res, ITEM(res_dir.messages), R_MSGS, 0, 0},
366 {"Catalog", store_res, ITEM(res_dir.catalog), R_CATALOG, 0, 0},
367 {"DirPort", store_addresses_port, ITEM(res_dir.DIRaddrs), 0, ITEM_DEFAULT, 9101},
368 {"DirAddress", store_addresses_address, ITEM(res_dir.DIRaddrs), 0, ITEM_DEFAULT, 9101},
369 {"DirAddresses",store_addresses, ITEM(res_dir.DIRaddrs), 0, ITEM_DEFAULT, 9101},
370 {"DirSourceAddress",store_addresses_address, ITEM(res_dir.DIRsrc_addr), 0, ITEM_DEFAULT, 0},
371 {"QueryFile", store_dir, ITEM(res_dir.query_file), 0, ITEM_REQUIRED, 0},
372 {"WorkingDirectory", store_dir, ITEM(res_dir.working_directory), 0, ITEM_REQUIRED, 0},
373 {"PluginDirectory", store_dir, ITEM(res_dir.plugin_directory), 0, 0, 0},
374 {"ScriptsDirectory", store_dir, ITEM(res_dir.scripts_directory), 0, 0, 0},
375 {"PidDirectory", store_dir, ITEM(res_dir.pid_directory), 0, ITEM_REQUIRED, 0},
376 {"SubsysDirectory", store_dir, ITEM(res_dir.subsys_directory), 0, 0, 0},
377 {"MaximumConcurrentJobs", store_pint32, ITEM(res_dir.MaxConcurrentJobs), 0, ITEM_DEFAULT, 20},
378 {"MaximumReloadRequests", store_pint32, ITEM(res_dir.MaxReload), 0, ITEM_DEFAULT, 32},
379 {"MaximumConsoleConnections", store_pint32, ITEM(res_dir.MaxConsoleConnect), 0, ITEM_DEFAULT, 20},
380 {"Password", store_password, ITEM(res_dir.password), 0, ITEM_REQUIRED, 0},
381 {"FdConnectTimeout", store_time,ITEM(res_dir.FDConnectTimeout), 0, ITEM_DEFAULT, 3 * 60},
382 {"SdConnectTimeout", store_time,ITEM(res_dir.SDConnectTimeout), 0, ITEM_DEFAULT, 30 * 60},
383 {"HeartbeatInterval", store_time, ITEM(res_dir.heartbeat_interval), 0, ITEM_DEFAULT, 5 * 60},
384 {"AutoPrune", store_bool, ITEM(res_dir.AutoPrune), 0, ITEM_DEFAULT, true},
385 #if BEEF
386 {"FipsRequire", store_bool, ITEM(res_dir.require_fips), 0, 0, 0},
387 #endif
388 {"TlsAuthenticate", store_bool, ITEM(res_dir.tls_authenticate), 0, 0, 0},
389 {"TlsEnable", store_bool, ITEM(res_dir.tls_enable), 0, 0, 0},
390 {"TlsPskEnable", store_bool, ITEM(res_dir.tls_psk_enable), 0, ITEM_DEFAULT, tls_psk_default},
391 {"TlsRequire", store_bool, ITEM(res_dir.tls_require), 0, 0, 0},
392 {"TlsVerifyPeer", store_bool, ITEM(res_dir.tls_verify_peer), 0, ITEM_DEFAULT, true},
393 {"TlsCaCertificateFile", store_dir, ITEM(res_dir.tls_ca_certfile), 0, 0, 0},
394 {"TlsCaCertificateDir", store_dir, ITEM(res_dir.tls_ca_certdir), 0, 0, 0},
395 {"TlsCertificate", store_dir, ITEM(res_dir.tls_certfile), 0, 0, 0},
396 {"TlsKey", store_dir, ITEM(res_dir.tls_keyfile), 0, 0, 0},
397 {"TlsDhFile", store_dir, ITEM(res_dir.tls_dhfile), 0, 0, 0},
398 {"TlsAllowedCn", store_alist_str, ITEM(res_dir.tls_allowed_cns), 0, 0, 0},
399 {"StatisticsRetention", store_time, ITEM(res_dir.stats_retention), 0, ITEM_DEFAULT, 60*60*24*31*12*5},
400 {"VerId", store_str, ITEM(res_dir.verid), 0, 0, 0},
401 {"CommCompression", store_bool, ITEM(res_dir.comm_compression), 0, ITEM_DEFAULT, true},
402 {NULL, NULL, {0}, 0, 0, 0}
403 };
404
405 /*
406 * Console Resource
407 *
408 * name handler value code flags default_value
409 */
410 static RES_ITEM con_items[] = {
411 {"Name", store_name, ITEM(res_con.hdr.name), 0, ITEM_REQUIRED, 0},
412 {"Description", store_str, ITEM(res_con.hdr.desc), 0, 0, 0},
413 {"Password", store_password, ITEM(res_con.password), 0, ITEM_REQUIRED, 0},
414 {"JobAcl", store_acl, ITEM(res_con.ACL_lists), Job_ACL, 0, 0},
415 {"ClientAcl", store_acl, ITEM(res_con.ACL_lists), Client_ACL, 0, 0},
416 {"StorageAcl", store_acl, ITEM(res_con.ACL_lists), Storage_ACL, 0, 0},
417 {"ScheduleAcl", store_acl, ITEM(res_con.ACL_lists), Schedule_ACL, 0, 0},
418 {"RunAcl", store_acl, ITEM(res_con.ACL_lists), Run_ACL, 0, 0},
419 {"PoolAcl", store_acl, ITEM(res_con.ACL_lists), Pool_ACL, 0, 0},
420 {"CommandAcl", store_acl, ITEM(res_con.ACL_lists), Command_ACL, 0, 0},
421 {"FilesetAcl", store_acl, ITEM(res_con.ACL_lists), FileSet_ACL, 0, 0},
422 {"CatalogAcl", store_acl, ITEM(res_con.ACL_lists), Catalog_ACL, 0, 0},
423 {"WhereAcl", store_acl, ITEM(res_con.ACL_lists), Where_ACL, 0, 0},
424 {"RestoreClientAcl", store_acl, ITEM(res_con.ACL_lists), RestoreClient_ACL, 0, 0},
425 {"BackupClientAcl", store_acl, ITEM(res_con.ACL_lists), BackupClient_ACL, 0, 0},
426 {"PluginOptionsAcl", store_acl, ITEM(res_con.ACL_lists), PluginOptions_ACL, 0, 0},
427 // Not implemented
428 {"UserIdAcl", store_acl, ITEM(res_con.ACL_lists), UserId_ACL, 0, 0},
429 {"DirectoryAcl",store_acl, ITEM(res_con.ACL_lists), Directory_ACL, 0, 0},
430 {"TlsAuthenticate", store_bool, ITEM(res_con.tls_authenticate), 0, 0, 0},
431 {"TlsEnable", store_bool, ITEM(res_con.tls_enable), 0, 0, 0},
432 {"TlsPskEnable", store_bool, ITEM(res_con.tls_psk_enable), 0, ITEM_DEFAULT, tls_psk_default},
433 {"TlsRequire", store_bool, ITEM(res_con.tls_require), 0, 0, 0},
434 {"TlsVerifyPeer", store_bool, ITEM(res_con.tls_verify_peer), 0, ITEM_DEFAULT, true},
435 {"TlsCaCertificateFile", store_dir, ITEM(res_con.tls_ca_certfile), 0, 0, 0},
436 {"TlsCaCertificateDir", store_dir, ITEM(res_con.tls_ca_certdir), 0, 0, 0},
437 {"TlsCertificate", store_dir, ITEM(res_con.tls_certfile), 0, 0, 0},
438 {"TlsKey", store_dir, ITEM(res_con.tls_keyfile), 0, 0, 0},
439 {"TlsDhFile", store_dir, ITEM(res_con.tls_dhfile), 0, 0, 0},
440 {"TlsAllowedCn", store_alist_str, ITEM(res_con.tls_allowed_cns), 0, 0, 0},
441 {NULL, NULL, {0}, 0, 0, 0}
442 };
443
444
445 /*
446 * Client or File daemon resource
447 *
448 * name handler value code flags default_value
449 */
450
451 static RES_ITEM cli_items[] = {
452 {"Name", store_name, ITEM(res_client.hdr.name), 0, ITEM_REQUIRED, 0},
453 {"Description", store_str, ITEM(res_client.hdr.desc), 0, 0, 0},
454 /* ***BEE*** In BWeb/BConfig, the store_str is replaced by
455 store_addresses_address to check more carefully user inputs */
456 {"fdaddress", store_str, ITEM(res_client.client_address), 0, 0, 0},
457 /* ***BEE*** In BWeb/BConfig, the store_str is replaced by
458 store_addresses_address to check more carefully user inputs */
459 {"Address", store_str, ITEM(res_client.client_address), 0, 0, 0},
460 {"FdPort", store_pint32, ITEM(res_client.FDport), 0, ITEM_DEFAULT, 9102},
461 {"fdpassword", store_password, ITEM(res_client.password), 0, 0, 0},
462 {"Password", store_password, ITEM(res_client.password), 0, ITEM_REQUIRED, 0},
463 /* ***BEE*** In BWeb/BConfig, the store_str is replaced by
464 store_addresses_address to check more carefully user inputs */
465 {"FdStorageAddress", store_str, ITEM(res_client.fd_storage_address), 0, 0, 0},
466 {"Catalog", store_res, ITEM(res_client.catalog), R_CATALOG, ITEM_REQUIRED, 0},
467 {"FileRetention", store_time, ITEM(res_client.FileRetention), 0, ITEM_DEFAULT, 60*60*24*60},
468 {"JobRetention", store_time, ITEM(res_client.JobRetention), 0, ITEM_DEFAULT, 60*60*24*180},
469 {"HeartbeatInterval", store_time, ITEM(res_client.heartbeat_interval), 0, ITEM_DEFAULT, 5 * 60},
470 {"AutoPrune", store_bool, ITEM(res_client.AutoPrune), 0, ITEM_DEFAULT, true},
471 {"SDCallsClient", store_bool, ITEM(res_client.sd_calls_client), 0, ITEM_DEFAULT, false},
472 {"AllowFDConnections", store_bool, ITEM(res_client.allow_fd_connections), 0, ITEM_DEFAULT, false},
473 {"SnapshotRetention", store_time, ITEM(res_client.SnapRetention), 0, ITEM_DEFAULT, 0},
474 {"MaximumConcurrentJobs", store_pint32, ITEM(res_client.MaxConcurrentJobs), 0, ITEM_DEFAULT, 1},
475 {"TlsAuthenticate", store_bool, ITEM(res_client.tls_authenticate), 0, 0, 0},
476 {"TlsEnable", store_bool, ITEM(res_client.tls_enable), 0, 0, 0},
477 {"TlsPskEnable", store_bool, ITEM(res_client.tls_psk_enable), 0, ITEM_DEFAULT, tls_psk_default},
478 {"TlsRequire", store_bool, ITEM(res_client.tls_require), 0, 0, 0},
479 {"TlsCaCertificateFile", store_dir, ITEM(res_client.tls_ca_certfile), 0, 0, 0},
480 {"TlsCaCertificateDir", store_dir, ITEM(res_client.tls_ca_certdir), 0, 0, 0},
481 {"TlsCertificate", store_dir, ITEM(res_client.tls_certfile), 0, 0, 0},
482 {"TlsKey", store_dir, ITEM(res_client.tls_keyfile), 0, 0, 0},
483 {"TlsAllowedCn", store_alist_str, ITEM(res_client.tls_allowed_cns), 0, 0, 0},
484 {"TlsVerifyPeer", store_bool, ITEM(res_client.tls_verify_peer), 0, ITEM_DEFAULT, true},
485 {"MaximumBandwidthPerJob", store_speed, ITEM(res_client.max_bandwidth), 0, 0, 0},
486 {"Enabled", store_bool, ITEM(res_client.Enabled), 0, ITEM_DEFAULT, true},
487 {NULL, NULL, {0}, 0, 0, 0}
488 };
489
490 /* Storage daemon resource
491 *
492 * name handler value code flags default_value
493 */
494 static RES_ITEM store_items[] = {
495 {"Name", store_name, ITEM(res_store.hdr.name), 0, ITEM_REQUIRED, 0},
496 {"Description", store_str, ITEM(res_store.hdr.desc), 0, 0, 0},
497 {"SdPort", store_pint32, ITEM(res_store.SDport), 0, ITEM_DEFAULT, 9103},
498 /* ***BEE*** In BWeb/BConfig, the store_str is replaced by
499 store_addresses_address to check more carefully user inputs */
500 {"sdaddress", store_str, ITEM(res_store.address), 0, 0, 0},
501 /* ***BEE*** In BWeb/BConfig, the store_str is replaced by
502 store_addresses_address to check more carefully user inputs */
503 {"Address", store_str, ITEM(res_store.address), 0, ITEM_REQUIRED, 0},
504 /* ***BEE*** In BWeb/BConfig, the store_str is replaced by
505 store_addresses_address to check more carefully user inputs */
506 {"FdStorageAddress", store_str, ITEM(res_store.fd_storage_address), 0, 0, 0},
507 {"sdpassword", store_password, ITEM(res_store.password), 0, 0, 0},
508 {"Password", store_password, ITEM(res_store.password), 0, ITEM_REQUIRED, 0},
509 {"Device", store_device, ITEM(res_store.device), R_DEVICE, ITEM_REQUIRED, 0},
510 {"MediaType", store_strname, ITEM(res_store.media_type), 0, ITEM_REQUIRED, 0},
511 /* _bool,
512 * Big kludge, these two autochanger definitions must be in
513 * this order and together.
514 */
515 {"autochanger", store_ac_res, ITEM(res_store.changer), 0, ITEM_DEFAULT, 0},
516 {"autochanger", store_bool, ITEM(res_store.autochanger), 0, ITEM_DEFAULT, false},
517 {"SharedStorage", store_ac_res, ITEM(res_store.shared_storage), 1, ITEM_DEFAULT, 0},
518 {"Enabled", store_bool, ITEM(res_store.Enabled), 0, ITEM_DEFAULT, true},
519 {"AllowCompression", store_bool, ITEM(res_store.AllowCompress), 0, ITEM_DEFAULT, true},
520 {"HeartbeatInterval", store_time, ITEM(res_store.heartbeat_interval), 0, ITEM_DEFAULT, 5 * 60},
521 {"MaximumConcurrentJobs", store_pint32, ITEM(res_store.MaxConcurrentJobs), 0, ITEM_DEFAULT, 1},
522 {"MaximumConcurrentReadjobs", store_pint32, ITEM(res_store.MaxConcurrentReadJobs), 0, ITEM_DEFAULT, 0},
523 {"sddport", store_pint32, ITEM(res_store.SDDport), 0, 0, 0}, /* deprecated */
524 {"TlsAuthenticate", store_bool, ITEM(res_store.tls_authenticate), 0, 0, 0},
525 {"TlsEnable", store_bool, ITEM(res_store.tls_enable), 0, 0, 0},
526 {"TlsPskEnable", store_bool, ITEM(res_store.tls_psk_enable), 0, ITEM_DEFAULT, tls_psk_default},
527 {"TlsRequire", store_bool, ITEM(res_store.tls_require), 0, 0, 0},
528 {"TlsCaCertificateFile", store_dir, ITEM(res_store.tls_ca_certfile), 0, 0, 0},
529 {"TlsCaCertificateDir", store_dir, ITEM(res_store.tls_ca_certdir), 0, 0, 0},
530 {"TlsCertificate", store_dir, ITEM(res_store.tls_certfile), 0, 0, 0},
531 {"TlsKey", store_dir, ITEM(res_store.tls_keyfile), 0, 0, 0},
532 {NULL, NULL, {0}, 0, 0, 0}
533 };
534
535 /*
536 * Catalog Resource Directives
537 *
538 * name handler value code flags default_value
539 */
540 static RES_ITEM cat_items[] = {
541 {"Name", store_name, ITEM(res_cat.hdr.name), 0, ITEM_REQUIRED, 0},
542 {"Description", store_str, ITEM(res_cat.hdr.desc), 0, 0, 0},
543 {"dbaddress", store_str, ITEM(res_cat.db_address), 0, 0, 0},
544 /* ***BEE*** In BWeb/BConfig, the store_str is replaced by
545 store_addresses_address to check more carefully user inputs */
546 {"Address", store_str, ITEM(res_cat.db_address), 0, 0, 0},
547 {"DbPort", store_pint32, ITEM(res_cat.db_port), 0, 0, 0},
548 /* keep this password as store_str for the moment */
549 {"dbpassword", store_str, ITEM(res_cat.db_password), 0, 0, 0},
550 {"Password", store_str, ITEM(res_cat.db_password), 0, 0, 0},
551 {"dbuser", store_str, ITEM(res_cat.db_user), 0, 0, 0},
552 {"User", store_str, ITEM(res_cat.db_user), 0, 0, 0},
553 {"DbName", store_str, ITEM(res_cat.db_name), 0, ITEM_REQUIRED, 0},
554 {"dbdriver", store_str, ITEM(res_cat.db_driver), 0, 0, 0},
555 {"DbSocket", store_str, ITEM(res_cat.db_socket), 0, 0, 0},
556 {"dbsslmode", store_str, ITEM(res_cat.db_ssl_mode), 0, 0, 0},
557 {"dbsslkey", store_str, ITEM(res_cat.db_ssl_key), 0, 0, 0},
558 {"dbsslcert", store_str, ITEM(res_cat.db_ssl_cert), 0, 0, 0},
559 {"dbsslca", store_str, ITEM(res_cat.db_ssl_ca), 0, 0, 0},
560 {"dbsslcapath", store_str, ITEM(res_cat.db_ssl_capath), 0, 0, 0},
561 {"dbsocket", store_str, ITEM(res_cat.db_socket), 0, 0, 0},
562
563 /* Turned off for the moment */
564 {"MultipleConnections", store_bit, ITEM(res_cat.mult_db_connections), 0, 0, 0},
565 {"DisableBatchInsert", store_bool, ITEM(res_cat.disable_batch_insert), 0, ITEM_DEFAULT, false},
566 {NULL, NULL, {0}, 0, 0, 0}
567 };
568
569 /*
570 * Job Resource Directives
571 *
572 * name handler value code flags default_value
573 */
574 RES_ITEM job_items[] = {
575 {"Name", store_name, ITEM(res_job.hdr.name), 0, ITEM_REQUIRED, 0},
576 {"Description", store_str, ITEM(res_job.hdr.desc), 0, 0, 0},
577 {"Type", store_jobtype, ITEM(res_job.JobType), 0, ITEM_REQUIRED, 0},
578 {"Level", store_level, ITEM(res_job.JobLevel), 0, 0, 0},
579 {"Messages", store_res, ITEM(res_job.messages), R_MSGS, ITEM_REQUIRED, 0},
580 {"Storage", store_alist_res, ITEM(res_job.storage), R_STORAGE, 0, 0},
581 {"Pool", store_res, ITEM(res_job.pool), R_POOL, ITEM_REQUIRED, 0},
582 {"NextPool", store_res, ITEM(res_job.next_pool), R_POOL, 0, 0},
583 {"FullBackupPool", store_res, ITEM(res_job.full_pool), R_POOL, 0, 0},
584 #ifdef COMMUNITY
585 {"VirtualFullBackupPool", store_res, ITEM(res_job.vfull_pool), R_POOL, 0, 0},
586 #endif
587 {"IncrementalBackupPool", store_res, ITEM(res_job.inc_pool), R_POOL, 0, 0},
588 {"DifferentialBackupPool", store_res, ITEM(res_job.diff_pool), R_POOL, 0, 0},
589 {"Client", store_res, ITEM(res_job.client), R_CLIENT, ITEM_REQUIRED, 0},
590 {"Fileset", store_res, ITEM(res_job.fileset), R_FILESET, ITEM_REQUIRED, 0},
591 {"Schedule", store_res, ITEM(res_job.schedule), R_SCHEDULE, 0, 0},
592 {"VerifyJob", store_res, ITEM(res_job.verify_job), R_JOB, 0, 0},
593 {"JobToVerify", store_res, ITEM(res_job.verify_job), R_JOB, 0, 0},
594 {"JobDefs", store_res, ITEM(res_job.jobdefs), R_JOBDEFS, 0, 0},
595 {"Run", store_alist_str, ITEM(res_job.run_cmds), 0, 0, 0},
596 /* Root of where to restore files */
597 {"Where", store_dir, ITEM(res_job.RestoreWhere), 0, 0, 0},
598 {"RegexWhere", store_str, ITEM(res_job.RegexWhere), 0, 0, 0},
599 {"StripPrefix", store_str, ITEM(res_job.strip_prefix), 0, 0, 0},
600 {"AddPrefix", store_str, ITEM(res_job.add_prefix), 0, 0, 0},
601 {"AddSuffix", store_str, ITEM(res_job.add_suffix), 0, 0, 0},
602 /* Where to find bootstrap during restore */
603 {"Bootstrap",store_dir, ITEM(res_job.RestoreBootstrap), 0, 0, 0},
604 {"RestoreClient", store_str, ITEM(res_job.RestoreClient), 0, 0, 0},
605 /* Where to write bootstrap file during backup */
606 {"WriteBootstrap",store_dir, ITEM(res_job.WriteBootstrap), 0, 0, 0},
607 {"WriteVerifyList",store_dir,ITEM(res_job.WriteVerifyList), 0, 0, 0},
608 {"Replace", store_replace, ITEM(res_job.replace), 0, ITEM_DEFAULT, REPLACE_ALWAYS},
609 {"MaximumBandwidth", store_speed, ITEM(res_job.max_bandwidth), 0, 0, 0},
610 {"MaxRunSchedTime", store_time, ITEM(res_job.MaxRunSchedTime), 0, 0, 0},
611 {"MaxRunTime", store_time, ITEM(res_job.MaxRunTime), 0, 0, 0},
612 /* xxxMaxWaitTime are deprecated */
613 {"fullmaxwaittime", store_time, ITEM(res_job.FullMaxRunTime), 0, 0, 0},
614 {"incrementalmaxwaittime", store_time, ITEM(res_job.IncMaxRunTime), 0, 0, 0},
615 {"differentialmaxwaittime", store_time, ITEM(res_job.DiffMaxRunTime), 0, 0, 0},
616 {"FullMaxRunTime", store_time, ITEM(res_job.FullMaxRunTime), 0, 0, 0},
617 {"IncrementalMaxRunTime", store_time, ITEM(res_job.IncMaxRunTime), 0, 0, 0},
618 {"DifferentialMaxRunTime", store_time, ITEM(res_job.DiffMaxRunTime), 0, 0, 0},
619 {"MaxWaitTime", store_time, ITEM(res_job.MaxWaitTime), 0, 0, 0},
620 {"MaxStartDelay",store_time, ITEM(res_job.MaxStartDelay), 0, 0, 0},
621 {"MaxFullInterval", store_time, ITEM(res_job.MaxFullInterval), 0, 0, 0},
622 #ifdef COMMUNITY
623 {"MaxVirtualFullInterval", store_time, ITEM(res_job.MaxVirtualFullInterval), 0, 0, 0},
624 #endif
625 {"MaxDiffInterval", store_time, ITEM(res_job.MaxDiffInterval), 0, 0, 0},
626 {"PrefixLinks", store_bool, ITEM(res_job.PrefixLinks), 0, ITEM_DEFAULT, false},
627 {"PruneJobs", store_bool, ITEM(res_job.PruneJobs), 0, ITEM_DEFAULT, false},
628 {"PruneFiles", store_bool, ITEM(res_job.PruneFiles), 0, ITEM_DEFAULT, false},
629 {"PruneVolumes",store_bool, ITEM(res_job.PruneVolumes), 0, ITEM_DEFAULT, false},
630 {"PurgeMigrationJob", store_bool, ITEM(res_job.PurgeMigrateJob), 0, ITEM_DEFAULT, false},
631 {"Enabled", store_bool, ITEM(res_job.Enabled), 0, ITEM_DEFAULT, true},
632 {"SnapshotRetention", store_time, ITEM(res_job.SnapRetention), 0, ITEM_DEFAULT, 0},
633 {"SpoolAttributes",store_bool, ITEM(res_job.SpoolAttributes), 0, ITEM_DEFAULT, true},
634 {"SpoolData", store_bool, ITEM(res_job.spool_data), 0, ITEM_DEFAULT, false},
635 {"SpoolSize", store_size64, ITEM(res_job.spool_size), 0, 0, 0},
636 {"ReRunFailedLevels", store_bool, ITEM(res_job.rerun_failed_levels), 0, ITEM_DEFAULT, false},
637 {"PreferMountedVolumes", store_bool, ITEM(res_job.PreferMountedVolumes), 0, ITEM_DEFAULT, true},
638 /*
639 * JSON tools skip Directive in lowercase. They are deprecated or
640 * are synonym with an other one that follows. Like User and dbuser.
641 */
642 {"runbeforejob", store_short_runscript, ITEM(res_job.RunScripts), 0, 0, 0},
643 {"runafterjob", store_short_runscript, ITEM(res_job.RunScripts), 0, 0, 0},
644 {"runafterfailedjob", store_short_runscript, ITEM(res_job.RunScripts), 0, 0, 0},
645 {"clientrunbeforejob", store_short_runscript, ITEM(res_job.RunScripts), 0, 0, 0},
646 {"clientrunafterjob", store_short_runscript, ITEM(res_job.RunScripts), 0, 0, 0},
647 {"consolerunbeforejob", store_short_runscript, ITEM(res_job.RunScripts), 0, 0, 0},
648 {"consolerunafterjob", store_short_runscript, ITEM(res_job.RunScripts), 0, 0, 0},
649 {"Runscript", store_runscript, ITEM(res_job.RunScripts), 0, ITEM_NO_EQUALS, 0},
650 {"MaximumConcurrentJobs", store_pint32, ITEM(res_job.MaxConcurrentJobs), 0, ITEM_DEFAULT, 1},
651 {"MaximumSpawnedJobs", store_pint32, ITEM(res_job.MaxSpawnedJobs), 0, ITEM_DEFAULT, 600},
652 {"RescheduleOnError", store_bool, ITEM(res_job.RescheduleOnError), 0, ITEM_DEFAULT, false},
653 {"RescheduleIncompleteJobs", store_bool, ITEM(res_job.RescheduleIncompleteJobs), 0, ITEM_DEFAULT, true},
654 {"RescheduleInterval", store_time, ITEM(res_job.RescheduleInterval), 0, ITEM_DEFAULT, 60 * 30},
655 {"RescheduleTimes", store_pint32, ITEM(res_job.RescheduleTimes), 0, 0, 0},
656 {"Priority", store_pint32, ITEM(res_job.Priority), 0, ITEM_DEFAULT, 10},
657 {"BackupsToKeep", store_pint32, ITEM(res_job.BackupsToKeep), 0, ITEM_DEFAULT, 0},
658 {"AllowMixedPriority", store_bool, ITEM(res_job.allow_mixed_priority), 0, ITEM_DEFAULT, false},
659 {"AllowIncompleteJobs", store_bool, ITEM(res_job.allow_incomplete_jobs), 0, ITEM_DEFAULT, true},
660 {"WritePartAfterJob", store_bool, ITEM(res_job.write_part_after_job), 0, ITEM_DEFAULT, true},
661 {"SelectionPattern", store_str, ITEM(res_job.selection_pattern), 0, 0, 0},
662 {"SelectionType", store_migtype, ITEM(res_job.selection_type), 0, 0, 0},
663 {"Accurate", store_bool, ITEM(res_job.accurate), 0,0,0},
664 {"AllowDuplicateJobs", store_bool, ITEM(res_job.AllowDuplicateJobs), 0, ITEM_DEFAULT, true},
665 {"allowhigherduplicates", store_bool, ITEM(res_job.AllowHigherDuplicates), 0, ITEM_DEFAULT, true},
666 {"CancelLowerLevelDuplicates", store_bool, ITEM(res_job.CancelLowerLevelDuplicates), 0, ITEM_DEFAULT, false},
667 {"CancelQueuedDuplicates", store_bool, ITEM(res_job.CancelQueuedDuplicates), 0, ITEM_DEFAULT, false},
668 {"CancelRunningDuplicates", store_bool, ITEM(res_job.CancelRunningDuplicates), 0, ITEM_DEFAULT, false},
669 {"DeleteConsolidatedJobs", store_bool, ITEM(res_job.DeleteConsolidatedJobs), 0, ITEM_DEFAULT, false},
670 {"PluginOptions", store_str, ITEM(res_job.PluginOptions), 0, 0, 0},
671 {"Base", store_alist_res, ITEM(res_job.base), R_JOB, 0, 0},
672 {NULL, NULL, {0}, 0, 0, 0}
673 };
674
675 /* Fileset resource
676 *
677 * Name handler value code flags default_value
678 */
679 static RES_ITEM fs_items[] = {
680 {"Name", store_name, ITEM(res_fs.hdr.name), 0, ITEM_REQUIRED, 0},
681 {"Description", store_str, ITEM(res_fs.hdr.desc), 0, 0, 0},
682 {"IgnoreFilesetChanges", store_bool, ITEM(res_fs.ignore_fs_changes), 0, ITEM_DEFAULT, false},
683 {"EnableVss", store_bool, ITEM(res_fs.enable_vss), 0, ITEM_DEFAULT, true},
684 {"EnableSnapshot",store_bool, ITEM(res_fs.enable_snapshot), 0, ITEM_DEFAULT, false},
685 {"Include", store_inc, {0}, 0, ITEM_NO_EQUALS, 0},
686 {"Exclude", store_inc, {0}, 1, ITEM_NO_EQUALS, 0},
687 {NULL, NULL, {0}, 0, 0, 0}
688 };
689
690 /* Schedule -- see run_conf.c */
691 /* Schedule
692 *
693 * name handler value code flags default_value
694 */
695 static RES_ITEM sch_items[] = {
696 {"Name", store_name, ITEM(res_sch.hdr.name), 0, ITEM_REQUIRED, 0},
697 {"Description", store_str, ITEM(res_sch.hdr.desc), 0, 0, 0},
698 {"Run", store_run, ITEM(res_sch.run), 0, 0, 0},
699 {"Enabled", store_bool, ITEM(res_sch.Enabled), 0, ITEM_DEFAULT, true},
700 {NULL, NULL, {0}, 0, 0, 0}
701 };
702
703 /* Pool resource
704 *
705 * name handler value code flags default_value
706 */
707 static RES_ITEM pool_items[] = {
708 {"Name", store_name, ITEM(res_pool.hdr.name), 0, ITEM_REQUIRED, 0},
709 {"Description", store_str, ITEM(res_pool.hdr.desc), 0, 0, 0},
710 {"PoolType", store_strname, ITEM(res_pool.pool_type), 0, ITEM_REQUIRED, 0},
711 {"LabelFormat", store_strname, ITEM(res_pool.label_format), 0, 0, 0},
712 {"LabelType", store_label, ITEM(res_pool.LabelType), 0, 0, 0},
713 {"CleaningPrefix", store_strname, ITEM(res_pool.cleaning_prefix), 0, 0, 0},
714 {"UseCatalog", store_bool, ITEM(res_pool.use_catalog), 0, ITEM_DEFAULT, true},
715 {"UseVolumeOnce", store_bool, ITEM(res_pool.use_volume_once), 0, 0, 0},
716 {"PurgeOldestVolume", store_bool, ITEM(res_pool.purge_oldest_volume), 0, 0, 0},
717 {"ActionOnPurge", store_actiononpurge, ITEM(res_pool.action_on_purge), 0, 0, 0},
718 {"RecycleOldestVolume", store_bool, ITEM(res_pool.recycle_oldest_volume), 0, 0, 0},
719 {"RecycleCurrentVolume", store_bool, ITEM(res_pool.recycle_current_volume), 0, 0, 0},
720 {"MaximumVolumes", store_pint32, ITEM(res_pool.max_volumes), 0, 0, 0},
721 {"MaximumVolumeJobs", store_pint32, ITEM(res_pool.MaxVolJobs), 0, 0, 0},
722 {"MaximumVolumeFiles", store_pint32, ITEM(res_pool.MaxVolFiles), 0, 0, 0},
723 {"MaximumVolumeBytes", store_size64, ITEM(res_pool.MaxVolBytes), 0, 0, 0},
724 #if BEEF
725 {"MaximumPoolBytes", store_size64, ITEM(res_pool.MaxPoolBytes), 0, 0, 0},
726 #endif
727 {"CatalogFiles", store_bool, ITEM(res_pool.catalog_files), 0, ITEM_DEFAULT, true},
728 {"CacheRetention", store_time, ITEM(res_pool.CacheRetention), 0, 0, 0},
729 {"VolumeRetention", store_time, ITEM(res_pool.VolRetention), 0, ITEM_DEFAULT, 60*60*24*365},
730 {"VolumeUseDuration", store_time, ITEM(res_pool.VolUseDuration), 0, 0, 0},
731 {"MigrationTime", store_time, ITEM(res_pool.MigrationTime), 0, 0, 0},
732 {"MigrationHighBytes", store_size64, ITEM(res_pool.MigrationHighBytes), 0, 0, 0},
733 {"MigrationLowBytes", store_size64, ITEM(res_pool.MigrationLowBytes), 0, 0, 0},
734 {"NextPool", store_res, ITEM(res_pool.NextPool), R_POOL, 0, 0},
735 {"Storage", store_alist_res, ITEM(res_pool.storage), R_STORAGE, 0, 0},
736 {"AutoPrune", store_bool, ITEM(res_pool.AutoPrune), 0, ITEM_DEFAULT, true},
737 {"Recycle", store_bool, ITEM(res_pool.Recycle), 0, ITEM_DEFAULT, true},
738 {"RecyclePool", store_res, ITEM(res_pool.RecyclePool), R_POOL, 0, 0},
739 {"ScratchPool", store_res, ITEM(res_pool.ScratchPool), R_POOL, 0, 0},
740 {"CopyPool", store_alist_res, ITEM(res_pool.CopyPool), R_POOL, 0, 0},
741 {"Catalog", store_res, ITEM(res_pool.catalog), R_CATALOG, 0, 0},
742 {"FileRetention", store_time, ITEM(res_pool.FileRetention), 0, 0, 0},
743 {"JobRetention", store_time, ITEM(res_pool.JobRetention), 0, 0, 0},
744
745 {NULL, NULL, {0}, 0, 0, 0}
746 };
747
748 /*
749 * Counter Resource
750 * name handler value code flags default_value
751 */
752 static RES_ITEM counter_items[] = {
753 {"Name", store_name, ITEM(res_counter.hdr.name), 0, ITEM_REQUIRED, 0},
754 {"Description", store_str, ITEM(res_counter.hdr.desc), 0, 0, 0},
755 {"Minimum", store_int32, ITEM(res_counter.MinValue), 0, ITEM_DEFAULT, 0},
756 {"Maximum", store_pint32, ITEM(res_counter.MaxValue), 0, ITEM_DEFAULT, INT32_MAX},
757 {"WrapCounter", store_res, ITEM(res_counter.WrapCounter), R_COUNTER, 0, 0},
758 {"Catalog", store_res, ITEM(res_counter.Catalog), R_CATALOG, 0, 0},
759 {NULL, NULL, {0}, 0, 0, 0}
760 };
761
762
763 /* Message resource */
764 extern RES_ITEM msgs_items[];
765
766 /* Statistics resource */
767 extern RES_ITEM collector_items[];
768
769 /*
770 * This is the master resource definition.
771 * It must have one item for each of the resources.
772 *
773 * NOTE!!! keep it in the same order as the R_codes
774 * or eliminate all resources[rindex].name
775 *
776 * name items rcode
777 */
778 RES_TABLE resources[] = {
779 {"Director", dir_items, R_DIRECTOR},
780 {"Client", cli_items, R_CLIENT},
781 {"Job", job_items, R_JOB},
782 {"Storage", store_items, R_STORAGE},
783 {"Catalog", cat_items, R_CATALOG},
784 {"Schedule", sch_items, R_SCHEDULE},
785 {"Fileset", fs_items, R_FILESET},
786 {"Pool", pool_items, R_POOL},
787 {"Messages", msgs_items, R_MSGS},
788 {"Counter", counter_items, R_COUNTER},
789 {"Console", con_items, R_CONSOLE},
790 {"JobDefs", job_items, R_JOBDEFS},
791 {"Statistics", collector_items, R_COLLECTOR},
792 {"Device", NULL, R_DEVICE}, /* info obtained from SD */
793 {"Autochanger", store_items, R_AUTOCHANGER}, /* alias for R_STORAGE */
794 {NULL, NULL, 0}
795 };
796
797
798 /* Keywords (RHS) permitted in Job Level records
799 *
800 * level_name level job_type
801 */
802 struct s_jl joblevels[] = {
803 {"Full", L_FULL, JT_BACKUP},
804 {"Base", L_BASE, JT_BACKUP},
805 {"Incremental", L_INCREMENTAL, JT_BACKUP},
806 {"Differential", L_DIFFERENTIAL, JT_BACKUP},
807 {"Since", L_SINCE, JT_BACKUP},
808 {"VirtualFull", L_VIRTUAL_FULL, JT_BACKUP},
809 {"Catalog", L_VERIFY_CATALOG, JT_VERIFY},
810 {"InitCatalog", L_VERIFY_INIT, JT_VERIFY},
811 {"VolumeToCatalog", L_VERIFY_VOLUME_TO_CATALOG, JT_VERIFY},
812 {"DiskToCatalog", L_VERIFY_DISK_TO_CATALOG, JT_VERIFY},
813 {"Data", L_VERIFY_DATA, JT_VERIFY},
814 {"Full", L_FULL, JT_COPY},
815 {"Incremental", L_INCREMENTAL, JT_COPY},
816 {"Differential", L_DIFFERENTIAL, JT_COPY},
817 {"Full", L_FULL, JT_MIGRATE},
818 {"Incremental", L_INCREMENTAL, JT_MIGRATE},
819 {"Differential", L_DIFFERENTIAL, JT_MIGRATE},
820 {" ", L_NONE, JT_ADMIN},
821 {" ", L_NONE, JT_RESTORE},
822 {NULL, 0, 0}
823 };
824
825
826 /* Keywords (RHS) permitted in Job type records
827 *
828 * type_name job_type
829 */
830 s_jt jobtypes[] = {
831 {"Backup", JT_BACKUP},
832 {"Admin", JT_ADMIN},
833 {"Verify", JT_VERIFY},
834 {"Restore", JT_RESTORE},
835 {"Migrate", JT_MIGRATE},
836 {"Copy", JT_COPY},
837 {NULL, 0}
838 };
839
840
841 /* Keywords (RHS) permitted in Selection type records
842 *
843 * type_name job_type
844 */
845 s_jt migtypes[] = {
846 {"SmallestVolume", MT_SMALLEST_VOL},
847 {"OldestVolume", MT_OLDEST_VOL},
848 {"PoolOccupancy", MT_POOL_OCCUPANCY},
849 {"PoolTime", MT_POOL_TIME},
850 {"PoolUncopiedJobs", MT_POOL_UNCOPIED_JOBS},
851 {"Client", MT_CLIENT},
852 {"Volume", MT_VOLUME},
853 {"Job", MT_JOB},
854 {"SqlQuery", MT_SQLQUERY},
855 {NULL, 0}
856 };
857
858
859
860 /* Options permitted in Restore replace= */
861 s_kw ReplaceOptions[] = {
862 {"Always", REPLACE_ALWAYS},
863 {"IfNewer", REPLACE_IFNEWER},
864 {"IfOlder", REPLACE_IFOLDER},
865 {"Never", REPLACE_NEVER},
866 {NULL, 0}
867 };
868
display(POOLMEM * dst)869 char *CAT::display(POOLMEM *dst) {
870 Mmsg(dst,"catalog=%s\ndb_name=%s\ndb_driver=%s\ndb_user=%s\n"
871 "db_password=%s\ndb_address=%s\ndb_port=%i\n"
872 "db_socket=%s\n",
873 name(), NPRTB(db_name),
874 NPRTB(db_driver), NPRTB(db_user), NPRTB(db_password),
875 NPRTB(db_address), db_port, NPRTB(db_socket));
876 return dst;
877 }
878
level_to_static_str(int level)879 const char *level_to_static_str(int level)
880 {
881 char *ret = NULL; /* If not found... */
882 for (int i=0; joblevels[i].level_name; i++) {
883 if (level == (int)joblevels[i].level) {
884 return joblevels[i].level_name;
885 }
886 }
887 return ret;
888 }
889
level_to_str(char * buf,int len,int level)890 char *level_to_str(char *buf, int len, int level)
891 {
892 int i;
893 bsnprintf(buf, len, "%c (%d)", level, level); /* default if not found */
894 for (i=0; joblevels[i].level_name; i++) {
895 if (level == (int)joblevels[i].level) {
896 bstrncpy(buf, joblevels[i].level_name, len);
897 break;
898 }
899 }
900 return buf;
901 }
902
903 /* Dump contents of resource */
dump_resource(int type,RES * ares,void sendit (void * sock,const char * fmt,...),void * sock)904 void dump_resource(int type, RES *ares, void sendit(void *sock, const char *fmt, ...), void *sock)
905 {
906 RES *next;
907 URES *res = (URES *)ares;
908 bool recurse = true;
909 char ed1[100], ed2[100], ed3[100], edl[50];
910 DEVICE *dev;
911 UAContext *ua = (UAContext *)sock;
912 POOLMEM *buf;
913
914 if (res == NULL) {
915 sendit(sock, _("No %s resource defined\n"), res_to_str(type));
916 return;
917 }
918 if (type < 0) { /* no recursion */
919 type = -type;
920 recurse = false;
921 }
922 switch (type) {
923 case R_DIRECTOR:
924 sendit(sock, _("Director: name=%s MaxJobs=%d FDtimeout=%s SDtimeout=%s AutoPrune=%d\n"),
925 ares->name, res->res_dir.MaxConcurrentJobs,
926 edit_uint64(res->res_dir.FDConnectTimeout, ed1),
927 edit_uint64(res->res_dir.SDConnectTimeout, ed2),
928 res->res_dir.AutoPrune);
929 if (res->res_dir.query_file) {
930 sendit(sock, _(" query_file=%s\n"), res->res_dir.query_file);
931 }
932 if (res->res_dir.messages) {
933 sendit(sock, _(" --> "));
934 dump_resource(-R_MSGS, (RES *)res->res_dir.messages, sendit, sock);
935 }
936 break;
937 case R_CONSOLE:
938 if (!acl_access_console_ok(ua, res->res_con.name())) {
939 break;
940 }
941 sendit(sock, _("Console: name=%s SSL=%d PSK=%d\n"),
942 res->res_con.hdr.name, res->res_con.tls_enable, res->res_con.tls_psk_enable);
943 for (int acl=0; acl<Num_ACL; acl++) {
944 if (res->res_con.ACL_lists[acl]==NULL) {
945 continue;
946 }
947 // get the name of the ACL from con_items
948 for (RES_ITEM *item=con_items; item->name!=NULL; item++) {
949 if (item->handler==store_acl && item->code==acl) {
950 sendit(sock, _(" %s="), item->name);
951 char *acl_item;
952 bool first=true;
953 foreach_alist(acl_item, res->res_con.ACL_lists[acl]) {
954 if (!first) {
955 sendit(sock, _(", "));
956 } else {
957 first=false;
958 }
959 sendit(sock, _("%s"), acl_item);
960 }
961 sendit(sock, _("\n"));
962 break;
963 }
964 }
965 }
966 break;
967 case R_COUNTER:
968 if (res->res_counter.WrapCounter) {
969 sendit(sock, _("Counter: name=%s min=%d max=%d cur=%d wrapcntr=%s\n"),
970 res->res_counter.hdr.name, res->res_counter.MinValue,
971 res->res_counter.MaxValue, res->res_counter.CurrentValue,
972 res->res_counter.WrapCounter->hdr.name);
973 } else {
974 sendit(sock, _("Counter: name=%s min=%d max=%d\n"),
975 res->res_counter.hdr.name, res->res_counter.MinValue,
976 res->res_counter.MaxValue);
977 }
978 if (res->res_counter.Catalog) {
979 sendit(sock, _(" --> "));
980 dump_resource(-R_CATALOG, (RES *)res->res_counter.Catalog, sendit, sock);
981 }
982 break;
983
984 case R_CLIENT:
985 if (!acl_access_ok(ua, Client_ACL, res->res_client.name())) {
986 break;
987 }
988 buf = get_pool_memory(PM_FNAME);
989 sendit(sock, _("Client: Name=%s Enabled=%d Address=%s FDport=%d MaxJobs=%u NumJobs=%u\n"),
990 res->res_client.name(), res->res_client.is_enabled(),
991 res->res_client.address(buf), res->res_client.FDport,
992 res->res_client.MaxConcurrentJobs, res->res_client.getNumConcurrentJobs());
993 sendit(sock, _(" JobRetention=%s FileRetention=%s AutoPrune=%d\n"),
994 edit_utime(res->res_client.JobRetention, ed1, sizeof(ed1)),
995 edit_utime(res->res_client.FileRetention, ed2, sizeof(ed2)),
996 res->res_client.AutoPrune);
997 if (res->res_client.fd_storage_address) {
998 sendit(sock, " FDStorageAddress=%s\n", res->res_client.fd_storage_address);
999 }
1000 if (res->res_client.max_bandwidth) {
1001 sendit(sock, _(" MaximumBandwidth=%lld\n"),
1002 res->res_client.max_bandwidth);
1003 }
1004 if (res->res_client.allow_fd_connections) {
1005 res->res_client.getBSOCK_state(buf);
1006 if (*buf == 0) {
1007 pm_strcpy(buf, "*None*");
1008 }
1009 sendit(sock, _(" AllowFDConnections=%s\n"), buf);
1010 }
1011 if (res->res_client.catalog) {
1012 sendit(sock, _(" --> "));
1013 dump_resource(-R_CATALOG, (RES *)res->res_client.catalog, sendit, sock);
1014 }
1015 free_pool_memory(buf);
1016 break;
1017
1018 case R_DEVICE:
1019 dev = &res->res_dev;
1020 char ed1[50];
1021 sendit(sock, _("Device: name=%s ok=%d num_writers=%d max_writers=%d\n"
1022 " reserved=%d open=%d append=%d read=%d labeled=%d offline=%d autochgr=%d\n"
1023 " poolid=%s volname=%s MediaType=%s\n"),
1024 dev->hdr.name, dev->found, dev->num_writers, dev->max_writers,
1025 dev->reserved, dev->open, dev->append, dev->read, dev->labeled,
1026 dev->offline, dev->autochanger,
1027 edit_uint64(dev->PoolId, ed1),
1028 dev->VolumeName, dev->MediaType);
1029 break;
1030
1031 case R_AUTOCHANGER:
1032 case R_STORAGE:
1033 if (!acl_access_ok(ua, Storage_ACL, res->res_store.hdr.name)) {
1034 break;
1035 }
1036 sendit(sock, _("%s: name=%s address=%s SDport=%d MaxJobs=%u NumJobs=%u\n"
1037 " DeviceName=%s MediaType=%s StorageId=%s Autochanger=%d\n"),
1038 res->res_store.changer == &res->res_store ? "Autochanger" : "Storage",
1039 res->res_store.hdr.name, NPRTB(res->res_store.address), res->res_store.SDport,
1040 res->res_store.MaxConcurrentJobs,
1041 res->res_store.getNumConcurrentJobs(),
1042 res->res_store.dev_name(),
1043 res->res_store.media_type,
1044 edit_int64(res->res_store.StorageId, ed1),
1045 res->res_store.autochanger);
1046 if (res->res_store.fd_storage_address) {
1047 sendit(sock, " FDStorageAddress=%s\n", res->res_store.fd_storage_address);
1048 }
1049 if (res->res_store.ac_group) {
1050 STORE *shstore = res->res_store.shared_storage;
1051 sendit(sock, " AC group=%s ShareStore=%s\n", res->res_store.ac_group,
1052 shstore?shstore->name():"*none*");
1053 }
1054 if (res->res_store.changer && res->res_store.changer != &res->res_store) {
1055 sendit(sock, _(" Parent --> "));
1056 dump_resource(-R_STORAGE, (RES *)res->res_store.changer, sendit, sock);
1057 }
1058 if (recurse && res->res_store.shared_storage &&
1059 res->res_store.shared_storage != &res->res_store) {
1060 sendit(sock, _(" Shared --> "));
1061 dump_resource(-R_STORAGE, (RES *)res->res_store.shared_storage, sendit, sock);
1062 }
1063 break;
1064
1065 case R_CATALOG:
1066 if (!acl_access_ok(ua, Catalog_ACL, res->res_cat.hdr.name)) {
1067 break;
1068 }
1069 sendit(sock, _("Catalog: name=%s address=%s DBport=%d db_name=%s\n"
1070 " db_driver=%s db_user=%s MutliDBConn=%d\n"),
1071 res->res_cat.hdr.name, NPRT(res->res_cat.db_address),
1072 res->res_cat.db_port, res->res_cat.db_name,
1073 NPRT(res->res_cat.db_driver), NPRT(res->res_cat.db_user),
1074 res->res_cat.mult_db_connections);
1075 break;
1076
1077 case R_JOB:
1078 case R_JOBDEFS:
1079 if (!acl_access_ok(ua, Job_ACL, res->res_job.hdr.name)) {
1080 break;
1081 }
1082 sendit(sock, _("%s: name=%s JobType=%d level=%s Priority=%d Enabled=%d\n"),
1083 type == R_JOB ? _("Job") : _("JobDefs"),
1084 res->res_job.hdr.name, res->res_job.JobType,
1085 level_to_str(edl, sizeof(edl), res->res_job.JobLevel),
1086 res->res_job.Priority,
1087 res->res_job.is_enabled());
1088 sendit(sock, _(" MaxJobs=%u NumJobs=%u Resched=%d Times=%d Interval=%s Spool=%d WritePartAfterJob=%d\n"),
1089 res->res_job.MaxConcurrentJobs,
1090 res->res_job.getNumConcurrentJobs(),
1091 res->res_job.RescheduleOnError, res->res_job.RescheduleTimes,
1092 edit_uint64_with_commas(res->res_job.RescheduleInterval, ed1),
1093 res->res_job.spool_data, res->res_job.write_part_after_job);
1094 if (res->res_job.spool_size) {
1095 sendit(sock, _(" SpoolSize=%s\n"), edit_uint64(res->res_job.spool_size, ed1));
1096 }
1097 if (res->res_job.JobType == JT_BACKUP) {
1098 sendit(sock, _(" Accurate=%d\n"), res->res_job.accurate);
1099 }
1100 if (res->res_job.max_bandwidth) {
1101 sendit(sock, _(" MaximumBandwidth=%lld\n"),
1102 res->res_job.max_bandwidth);
1103 }
1104 if (res->res_job.JobType == JT_MIGRATE || res->res_job.JobType == JT_COPY) {
1105 sendit(sock, _(" SelectionType=%d\n"), res->res_job.selection_type);
1106 }
1107 if (res->res_job.JobType == JT_RESTORE) {
1108 sendit(sock, _(" PrefixLinks=%d\n"), res->res_job.PrefixLinks);
1109 }
1110 if (res->res_job.client) {
1111 sendit(sock, _(" --> "));
1112 dump_resource(-R_CLIENT, (RES *)res->res_job.client, sendit, sock);
1113 }
1114 if (res->res_job.fileset) {
1115 sendit(sock, _(" --> "));
1116 dump_resource(-R_FILESET, (RES *)res->res_job.fileset, sendit, sock);
1117 }
1118 if (res->res_job.schedule) {
1119 sendit(sock, _(" --> "));
1120 dump_resource(-R_SCHEDULE, (RES *)res->res_job.schedule, sendit, sock);
1121 }
1122 if (res->res_job.RestoreClient) {
1123 sendit(sock, _(" --> RestoreClient=%s\n"), NPRT(res->res_job.RestoreClient));
1124 }
1125 if (res->res_job.RestoreWhere && !res->res_job.RegexWhere) {
1126 sendit(sock, _(" --> Where=%s\n"), NPRT(res->res_job.RestoreWhere));
1127 }
1128 if (res->res_job.RegexWhere) {
1129 sendit(sock, _(" --> RegexWhere=%s\n"), NPRT(res->res_job.RegexWhere));
1130 }
1131 if (res->res_job.RestoreBootstrap) {
1132 sendit(sock, _(" --> Bootstrap=%s\n"), NPRT(res->res_job.RestoreBootstrap));
1133 }
1134 if (res->res_job.WriteBootstrap) {
1135 sendit(sock, _(" --> WriteBootstrap=%s\n"), NPRT(res->res_job.WriteBootstrap));
1136 }
1137 if (res->res_job.PluginOptions) {
1138 sendit(sock, _(" --> PluginOptions=%s\n"), NPRT(res->res_job.PluginOptions));
1139 }
1140 if (res->res_job.MaxRunTime) {
1141 sendit(sock, _(" --> MaxRunTime=%u\n"), res->res_job.MaxRunTime);
1142 }
1143 if (res->res_job.MaxWaitTime) {
1144 sendit(sock, _(" --> MaxWaitTime=%u\n"), res->res_job.MaxWaitTime);
1145 }
1146 if (res->res_job.MaxStartDelay) {
1147 sendit(sock, _(" --> MaxStartDelay=%u\n"), res->res_job.MaxStartDelay);
1148 }
1149 if (res->res_job.MaxRunSchedTime) {
1150 sendit(sock, _(" --> MaxRunSchedTime=%u\n"), res->res_job.MaxRunSchedTime);
1151 }
1152 if (res->res_job.storage) {
1153 STORE *store;
1154 foreach_alist(store, res->res_job.storage) {
1155 sendit(sock, _(" --> "));
1156 dump_resource(-R_STORAGE, (RES *)store, sendit, sock);
1157 }
1158 }
1159 if (res->res_job.base) {
1160 JOB *job;
1161 foreach_alist(job, res->res_job.base) {
1162 sendit(sock, _(" --> Base %s\n"), job->name());
1163 }
1164 }
1165 if (res->res_job.RunScripts) {
1166 RUNSCRIPT *script;
1167 foreach_alist(script, res->res_job.RunScripts) {
1168 sendit(sock, _(" --> RunScript\n"));
1169 sendit(sock, _(" --> Command=%s\n"), NPRT(script->command));
1170 sendit(sock, _(" --> Target=%s\n"), NPRT(script->target));
1171 sendit(sock, _(" --> RunOnSuccess=%u\n"), script->on_success);
1172 sendit(sock, _(" --> RunOnFailure=%u\n"), script->on_failure);
1173 sendit(sock, _(" --> FailJobOnError=%u\n"), script->fail_on_error);
1174 sendit(sock, _(" --> RunWhen=%u\n"), script->when);
1175 }
1176 }
1177 if (res->res_job.pool) {
1178 sendit(sock, _(" --> "));
1179 dump_resource(-R_POOL, (RES *)res->res_job.pool, sendit, sock);
1180 }
1181 if (res->res_job.vfull_pool) {
1182 sendit(sock, _(" --> VFullBackup"));
1183 dump_resource(-R_POOL, (RES *)res->res_job.vfull_pool, sendit, sock);
1184 }
1185 if (res->res_job.full_pool) {
1186 sendit(sock, _(" --> FullBackup"));
1187 dump_resource(-R_POOL, (RES *)res->res_job.full_pool, sendit, sock);
1188 }
1189 if (res->res_job.inc_pool) {
1190 sendit(sock, _(" --> IncrementalBackup"));
1191 dump_resource(-R_POOL, (RES *)res->res_job.inc_pool, sendit, sock);
1192 }
1193 if (res->res_job.diff_pool) {
1194 sendit(sock, _(" --> DifferentialBackup"));
1195 dump_resource(-R_POOL, (RES *)res->res_job.diff_pool, sendit, sock);
1196 }
1197 if (res->res_job.next_pool) {
1198 sendit(sock, _(" --> Next")); /* Pool will be added by dump_resource */
1199 dump_resource(-R_POOL, (RES *)res->res_job.next_pool, sendit, sock);
1200 }
1201 if (res->res_job.JobType == JT_VERIFY && res->res_job.verify_job) {
1202 sendit(sock, _(" --> JobToVerify %s"), (RES *)res->res_job.verify_job->name());
1203 }
1204 if (res->res_job.run_cmds) {
1205 char *runcmd;
1206 foreach_alist(runcmd, res->res_job.run_cmds) {
1207 sendit(sock, _(" --> Run=%s\n"), runcmd);
1208 }
1209 }
1210 if (res->res_job.selection_pattern) {
1211 sendit(sock, _(" --> SelectionPattern=%s\n"), NPRT(res->res_job.selection_pattern));
1212 }
1213 if (res->res_job.messages) {
1214 sendit(sock, _(" --> "));
1215 dump_resource(-R_MSGS, (RES *)res->res_job.messages, sendit, sock);
1216 }
1217 break;
1218
1219 case R_FILESET:
1220 {
1221 int i, j, k;
1222 if (!acl_access_ok(ua, FileSet_ACL, res->res_fs.hdr.name)) {
1223 break;
1224 }
1225 sendit(sock, _("FileSet: name=%s IgnoreFileSetChanges=%d\n"), res->res_fs.hdr.name, res->res_fs.ignore_fs_changes);
1226 for (i=0; i<res->res_fs.num_includes; i++) {
1227 INCEXE *incexe = res->res_fs.include_items[i];
1228 for (j=0; j<incexe->num_opts; j++) {
1229 FOPTS *fo = incexe->opts_list[j];
1230 sendit(sock, " O %s\n", fo->opts);
1231
1232 bool enhanced_wild = false;
1233 for (k=0; fo->opts[k]!='\0'; k++) {
1234 if (fo->opts[k]=='W') {
1235 enhanced_wild = true;
1236 break;
1237 }
1238 }
1239
1240 for (k=0; k<fo->regex.size(); k++) {
1241 sendit(sock, " R %s\n", fo->regex.get(k));
1242 }
1243 for (k=0; k<fo->regexdir.size(); k++) {
1244 sendit(sock, " RD %s\n", fo->regexdir.get(k));
1245 }
1246 for (k=0; k<fo->regexfile.size(); k++) {
1247 sendit(sock, " RF %s\n", fo->regexfile.get(k));
1248 }
1249 for (k=0; k<fo->wild.size(); k++) {
1250 sendit(sock, " W %s\n", fo->wild.get(k));
1251 }
1252 for (k=0; k<fo->wilddir.size(); k++) {
1253 sendit(sock, " WD %s\n", fo->wilddir.get(k));
1254 }
1255 for (k=0; k<fo->wildfile.size(); k++) {
1256 sendit(sock, " WF %s\n", fo->wildfile.get(k));
1257 }
1258 for (k=0; k<fo->wildbase.size(); k++) {
1259 sendit(sock, " W%c %s\n", enhanced_wild ? 'B' : 'F', fo->wildbase.get(k));
1260 }
1261 for (k=0; k<fo->base.size(); k++) {
1262 sendit(sock, " B %s\n", fo->base.get(k));
1263 }
1264 for (k=0; k<fo->fstype.size(); k++) {
1265 sendit(sock, " X %s\n", fo->fstype.get(k));
1266 }
1267 for (k=0; k<fo->drivetype.size(); k++) {
1268 sendit(sock, " XD %s\n", fo->drivetype.get(k));
1269 }
1270 if (fo->plugin) {
1271 sendit(sock, " G %s\n", fo->plugin);
1272 }
1273 if (fo->reader) {
1274 sendit(sock, " D %s\n", fo->reader);
1275 }
1276 if (fo->writer) {
1277 sendit(sock, " T %s\n", fo->writer);
1278 }
1279 sendit(sock, " N\n");
1280 }
1281 if (incexe->ignoredir) {
1282 sendit(sock, " Z %s\n", incexe->ignoredir);
1283 }
1284 for (j=0; j<incexe->name_list.size(); j++) {
1285 sendit(sock, " I %s\n", incexe->name_list.get(j));
1286 }
1287 if (incexe->name_list.size()) {
1288 sendit(sock, " N\n");
1289 }
1290 for (j=0; j<incexe->plugin_list.size(); j++) {
1291 sendit(sock, " P %s\n", incexe->plugin_list.get(j));
1292 }
1293 if (incexe->plugin_list.size()) {
1294 sendit(sock, " N\n");
1295 }
1296 } /* end for over includes */
1297
1298 for (i=0; i<res->res_fs.num_excludes; i++) {
1299 INCEXE *incexe = res->res_fs.exclude_items[i];
1300 for (j=0; j<incexe->name_list.size(); j++) {
1301 sendit(sock, " E %s\n", incexe->name_list.get(j));
1302 }
1303 if (incexe->name_list.size()) {
1304 sendit(sock, " N\n");
1305 }
1306 }
1307 break;
1308 } /* end case R_FILESET */
1309
1310 case R_SCHEDULE:
1311 if (!acl_access_ok(ua, Schedule_ACL, res->res_sch.hdr.name)) {
1312 break;
1313 }
1314
1315 if (res->res_sch.run) {
1316 int i;
1317 RUN *run = res->res_sch.run;
1318 char buf[1000], num[30];
1319 sendit(sock, _("Schedule: Name=%s Enabled=%d\n"),
1320 res->res_sch.hdr.name, res->res_sch.is_enabled());
1321 if (!run) {
1322 break;
1323 }
1324 next_run:
1325 sendit(sock, _(" --> Run Level=%s\n"),
1326 level_to_str(edl, sizeof(edl), run->level));
1327 if (run->MaxRunSchedTime) {
1328 sendit(sock, _(" MaxRunSchedTime=%u\n"), run->MaxRunSchedTime);
1329 }
1330 if (run->Priority) {
1331 sendit(sock, _(" Priority=%u\n"), run->Priority);
1332 }
1333 bstrncpy(buf, _(" hour="), sizeof(buf));
1334 for (i=0; i<24; i++) {
1335 if (bit_is_set(i, run->hour)) {
1336 bsnprintf(num, sizeof(num), "%d ", i);
1337 bstrncat(buf, num, sizeof(buf));
1338 }
1339 }
1340 bstrncat(buf, "\n", sizeof(buf));
1341 sendit(sock, buf);
1342 bstrncpy(buf, _(" mday="), sizeof(buf));
1343 for (i=0; i<32; i++) {
1344 if (bit_is_set(i, run->mday)) {
1345 bsnprintf(num, sizeof(num), "%d ", i);
1346 bstrncat(buf, num, sizeof(buf));
1347 }
1348 }
1349 bstrncat(buf, "\n", sizeof(buf));
1350 sendit(sock, buf);
1351 bstrncpy(buf, _(" month="), sizeof(buf));
1352 for (i=0; i<12; i++) {
1353 if (bit_is_set(i, run->month)) {
1354 bsnprintf(num, sizeof(num), "%d ", i);
1355 bstrncat(buf, num, sizeof(buf));
1356 }
1357 }
1358 bstrncat(buf, "\n", sizeof(buf));
1359 sendit(sock, buf);
1360 bstrncpy(buf, _(" wday="), sizeof(buf));
1361 for (i=0; i<7; i++) {
1362 if (bit_is_set(i, run->wday)) {
1363 bsnprintf(num, sizeof(num), "%d ", i);
1364 bstrncat(buf, num, sizeof(buf));
1365 }
1366 }
1367 bstrncat(buf, "\n", sizeof(buf));
1368 sendit(sock, buf);
1369 bstrncpy(buf, _(" wom="), sizeof(buf));
1370 for (i=0; i<6; i++) {
1371 if (bit_is_set(i, run->wom)) {
1372 bsnprintf(num, sizeof(num), "%d ", i);
1373 bstrncat(buf, num, sizeof(buf));
1374 }
1375 }
1376 bstrncat(buf, "\n", sizeof(buf));
1377 sendit(sock, buf);
1378 bstrncpy(buf, _(" woy="), sizeof(buf));
1379 for (i=0; i<54; i++) {
1380 if (bit_is_set(i, run->woy)) {
1381 bsnprintf(num, sizeof(num), "%d ", i);
1382 bstrncat(buf, num, sizeof(buf));
1383 }
1384 }
1385 bstrncat(buf, "\n", sizeof(buf));
1386 sendit(sock, buf);
1387 sendit(sock, _(" mins=%d\n"), run->minute);
1388 if (run->pool) {
1389 sendit(sock, _(" --> "));
1390 dump_resource(-R_POOL, (RES *)run->pool, sendit, sock);
1391 }
1392 if (run->next_pool) {
1393 sendit(sock, _(" --> Next")); /* Pool will be added by dump_resource */
1394 dump_resource(-R_POOL, (RES *)run->next_pool, sendit, sock);
1395 }
1396 if (run->storage) {
1397 sendit(sock, _(" --> "));
1398 dump_resource(-R_STORAGE, (RES *)run->storage, sendit, sock);
1399 }
1400 if (run->msgs) {
1401 sendit(sock, _(" --> "));
1402 dump_resource(-R_MSGS, (RES *)run->msgs, sendit, sock);
1403 }
1404 /* If another Run record is chained in, go print it */
1405 if (run->next) {
1406 run = run->next;
1407 goto next_run;
1408 }
1409 } else {
1410 sendit(sock, _("Schedule: name=%s\n"), res->res_sch.hdr.name);
1411 }
1412 break;
1413
1414 case R_POOL:
1415 if (!acl_access_ok(ua, Pool_ACL, res->res_pool.hdr.name)) {
1416 break;
1417 }
1418 sendit(sock, _("Pool: name=%s PoolType=%s\n"), res->res_pool.hdr.name,
1419 res->res_pool.pool_type);
1420 sendit(sock, _(" use_cat=%d use_once=%d cat_files=%d\n"),
1421 res->res_pool.use_catalog, res->res_pool.use_volume_once,
1422 res->res_pool.catalog_files);
1423 sendit(sock, _(" max_vols=%d auto_prune=%d VolRetention=%s\n"),
1424 res->res_pool.max_volumes, res->res_pool.AutoPrune,
1425 edit_utime(res->res_pool.VolRetention, ed1, sizeof(ed1)));
1426 sendit(sock, _(" VolUse=%s recycle=%d LabelFormat=%s\n"),
1427 edit_utime(res->res_pool.VolUseDuration, ed1, sizeof(ed1)),
1428 res->res_pool.Recycle,
1429 NPRT(res->res_pool.label_format));
1430 sendit(sock, _(" CleaningPrefix=%s LabelType=%d\n"),
1431 NPRT(res->res_pool.cleaning_prefix), res->res_pool.LabelType);
1432 sendit(sock, _(" RecyleOldest=%d PurgeOldest=%d ActionOnPurge=%d\n"),
1433 res->res_pool.recycle_oldest_volume,
1434 res->res_pool.purge_oldest_volume,
1435 res->res_pool.action_on_purge);
1436 sendit(sock, _(" MaxVolJobs=%d MaxVolFiles=%d MaxVolBytes=%s\n"),
1437 res->res_pool.MaxVolJobs,
1438 res->res_pool.MaxVolFiles,
1439 edit_uint64(res->res_pool.MaxVolBytes, ed1));
1440 sendit(sock, _(" MaxPoolBytes=%lld\n"), res->res_pool.MaxPoolBytes);
1441 sendit(sock, _(" MigTime=%s MigHiBytes=%s MigLoBytes=%s\n"),
1442 edit_utime(res->res_pool.MigrationTime, ed1, sizeof(ed1)),
1443 edit_uint64(res->res_pool.MigrationHighBytes, ed2),
1444 edit_uint64(res->res_pool.MigrationLowBytes, ed3));
1445 sendit(sock, _(" CacheRetention=%s\n"),
1446 edit_utime(res->res_pool.CacheRetention, ed1, sizeof(ed1)));
1447 sendit(sock, _(" JobRetention=%s FileRetention=%s\n"),
1448 edit_utime(res->res_pool.JobRetention, ed1, sizeof(ed1)),
1449 edit_utime(res->res_pool.FileRetention, ed2, sizeof(ed2)));
1450 if (res->res_pool.NextPool) {
1451 sendit(sock, _(" NextPool=%s\n"), res->res_pool.NextPool->name());
1452 }
1453 if (res->res_pool.RecyclePool) {
1454 sendit(sock, _(" RecyclePool=%s\n"), res->res_pool.RecyclePool->name());
1455 }
1456 if (res->res_pool.ScratchPool) {
1457 sendit(sock, _(" ScratchPool=%s\n"), res->res_pool.ScratchPool->name());
1458 }
1459 if (res->res_pool.catalog) {
1460 sendit(sock, _(" Catalog=%s\n"), res->res_pool.catalog->name());
1461 }
1462 if (res->res_pool.storage) {
1463 STORE *store;
1464 foreach_alist(store, res->res_pool.storage) {
1465 sendit(sock, _(" --> "));
1466 dump_resource(-R_STORAGE, (RES *)store, sendit, sock);
1467 }
1468 }
1469 if (res->res_pool.CopyPool) {
1470 POOL *copy;
1471 foreach_alist(copy, res->res_pool.CopyPool) {
1472 sendit(sock, _(" --> "));
1473 dump_resource(-R_POOL, (RES *)copy, sendit, sock);
1474 }
1475 }
1476
1477 break;
1478
1479 case R_MSGS:
1480 sendit(sock, _("Messages: name=%s\n"), res->res_msgs.hdr.name);
1481 if (res->res_msgs.mail_cmd)
1482 sendit(sock, _(" mailcmd=%s\n"), res->res_msgs.mail_cmd);
1483 if (res->res_msgs.operator_cmd)
1484 sendit(sock, _(" opcmd=%s\n"), res->res_msgs.operator_cmd);
1485 break;
1486
1487 case R_COLLECTOR:
1488 dump_collector_resource(res->res_collector, sendit, sock);
1489 break;
1490 default:
1491 sendit(sock, _("Unknown resource type %d in dump_resource.\n"), type);
1492 break;
1493 }
1494 if (recurse) {
1495 next = GetNextRes(0, (RES *)res);
1496 if (next) {
1497 dump_resource(type, next, sendit, sock);
1498 }
1499 }
1500 }
1501
1502 /*
1503 * Free all the members of an INCEXE structure
1504 */
free_incexe(INCEXE * incexe)1505 static void free_incexe(INCEXE *incexe)
1506 {
1507 incexe->name_list.destroy();
1508 incexe->plugin_list.destroy();
1509 for (int i=0; i<incexe->num_opts; i++) {
1510 FOPTS *fopt = incexe->opts_list[i];
1511 fopt->regex.destroy();
1512 fopt->regexdir.destroy();
1513 fopt->regexfile.destroy();
1514 fopt->wild.destroy();
1515 fopt->wilddir.destroy();
1516 fopt->wildfile.destroy();
1517 fopt->wildbase.destroy();
1518 fopt->base.destroy();
1519 fopt->fstype.destroy();
1520 fopt->drivetype.destroy();
1521 if (fopt->plugin) {
1522 free(fopt->plugin);
1523 }
1524 if (fopt->reader) {
1525 free(fopt->reader);
1526 }
1527 if (fopt->writer) {
1528 free(fopt->writer);
1529 }
1530 free(fopt);
1531 }
1532 if (incexe->opts_list) {
1533 free(incexe->opts_list);
1534 }
1535 if (incexe->ignoredir) {
1536 free(incexe->ignoredir);
1537 }
1538 free(incexe);
1539 }
1540
1541
1542 /*
1543 * Free memory of resource -- called when daemon terminates.
1544 * NB, we don't need to worry about freeing any references
1545 * to other resources as they will be freed when that
1546 * resource chain is traversed. Mainly we worry about freeing
1547 * allocated strings (names).
1548 */
free_resource(RES * rres,int type)1549 void free_resource(RES *rres, int type)
1550 {
1551 int num;
1552 URES *res = (URES *)rres;
1553
1554 if (res == NULL) {
1555 return;
1556 }
1557
1558 Dmsg3(200, "type=%d res=%p name=%s\n", type, res, res->res_dir.hdr.name);
1559 /* common stuff -- free the resource name and description */
1560 if (res->res_dir.hdr.name) {
1561 free(res->res_dir.hdr.name);
1562 }
1563 if (res->res_dir.hdr.desc) {
1564 free(res->res_dir.hdr.desc);
1565 }
1566
1567 switch (type) {
1568 case R_DIRECTOR:
1569 if (res->res_dir.working_directory) {
1570 free(res->res_dir.working_directory);
1571 }
1572 if (res->res_dir.scripts_directory) {
1573 free((char *)res->res_dir.scripts_directory);
1574 }
1575 if (res->res_dir.plugin_directory) {
1576 free((char *)res->res_dir.plugin_directory);
1577 }
1578 if (res->res_dir.pid_directory) {
1579 free(res->res_dir.pid_directory);
1580 }
1581 if (res->res_dir.subsys_directory) {
1582 free(res->res_dir.subsys_directory);
1583 }
1584 if (res->res_dir.password) {
1585 free(res->res_dir.password);
1586 }
1587 if (res->res_dir.query_file) {
1588 free(res->res_dir.query_file);
1589 }
1590 if (res->res_dir.DIRaddrs) {
1591 free_addresses(res->res_dir.DIRaddrs);
1592 }
1593 if (res->res_dir.DIRsrc_addr) {
1594 free_addresses(res->res_dir.DIRsrc_addr);
1595 }
1596 if (res->res_dir.tls_ctx) {
1597 free_tls_context(res->res_dir.tls_ctx);
1598 }
1599 if (res->res_dir.psk_ctx) {
1600 free_psk_context(res->res_dir.psk_ctx);
1601 }
1602 if (res->res_dir.tls_ca_certfile) {
1603 free(res->res_dir.tls_ca_certfile);
1604 }
1605 if (res->res_dir.tls_ca_certdir) {
1606 free(res->res_dir.tls_ca_certdir);
1607 }
1608 if (res->res_dir.tls_certfile) {
1609 free(res->res_dir.tls_certfile);
1610 }
1611 if (res->res_dir.tls_keyfile) {
1612 free(res->res_dir.tls_keyfile);
1613 }
1614 if (res->res_dir.tls_dhfile) {
1615 free(res->res_dir.tls_dhfile);
1616 }
1617 if (res->res_dir.tls_allowed_cns) {
1618 delete res->res_dir.tls_allowed_cns;
1619 }
1620 if (res->res_dir.verid) {
1621 free(res->res_dir.verid);
1622 }
1623 break;
1624 case R_DEVICE:
1625 case R_COUNTER:
1626 break;
1627 case R_CONSOLE:
1628 if (res->res_con.password) {
1629 free(res->res_con.password);
1630 }
1631 if (res->res_con.tls_ctx) {
1632 free_tls_context(res->res_con.tls_ctx);
1633 }
1634 if (res->res_con.psk_ctx) {
1635 free_psk_context(res->res_con.psk_ctx);
1636 }
1637 if (res->res_con.tls_ca_certfile) {
1638 free(res->res_con.tls_ca_certfile);
1639 }
1640 if (res->res_con.tls_ca_certdir) {
1641 free(res->res_con.tls_ca_certdir);
1642 }
1643 if (res->res_con.tls_certfile) {
1644 free(res->res_con.tls_certfile);
1645 }
1646 if (res->res_con.tls_keyfile) {
1647 free(res->res_con.tls_keyfile);
1648 }
1649 if (res->res_con.tls_dhfile) {
1650 free(res->res_con.tls_dhfile);
1651 }
1652 if (res->res_con.tls_allowed_cns) {
1653 delete res->res_con.tls_allowed_cns;
1654 }
1655 for (int i=0; i<Num_ACL; i++) {
1656 if (res->res_con.ACL_lists[i]) {
1657 delete res->res_con.ACL_lists[i];
1658 res->res_con.ACL_lists[i] = NULL;
1659 }
1660 }
1661 break;
1662 case R_CLIENT:
1663 if (res->res_client.client_address) {
1664 free(res->res_client.client_address);
1665 }
1666 if (res->res_client.fd_storage_address) {
1667 free(res->res_client.fd_storage_address);
1668 }
1669 if (res->res_client.password) {
1670 free(res->res_client.password);
1671 }
1672 if (res->res_client.tls_ctx) {
1673 free_tls_context(res->res_client.tls_ctx);
1674 }
1675 if (res->res_client.psk_ctx) {
1676 free_psk_context(res->res_client.psk_ctx);
1677 }
1678 if (res->res_client.tls_ca_certfile) {
1679 free(res->res_client.tls_ca_certfile);
1680 }
1681 if (res->res_client.tls_ca_certdir) {
1682 free(res->res_client.tls_ca_certdir);
1683 }
1684 if (res->res_client.tls_certfile) {
1685 free(res->res_client.tls_certfile);
1686 }
1687 if (res->res_client.tls_keyfile) {
1688 free(res->res_client.tls_keyfile);
1689 }
1690 if (res->res_client.tls_allowed_cns) {
1691 delete res->res_client.tls_allowed_cns;
1692 }
1693 break;
1694 case R_AUTOCHANGER:
1695 case R_STORAGE:
1696 if (res->res_store.address) {
1697 free(res->res_store.address);
1698 }
1699 if (res->res_store.fd_storage_address) {
1700 free(res->res_store.fd_storage_address);
1701 }
1702 if (res->res_store.password) {
1703 free(res->res_store.password);
1704 }
1705 if (res->res_store.media_type) {
1706 free(res->res_store.media_type);
1707 }
1708 if (res->res_store.ac_group) {
1709 free_pool_memory(res->res_store.ac_group);
1710 }
1711 if (res->res_store.device) {
1712 delete res->res_store.device;
1713 }
1714 if (res->res_store.tls_ctx) {
1715 free_tls_context(res->res_store.tls_ctx);
1716 }
1717 if (res->res_store.psk_ctx) {
1718 free_psk_context(res->res_store.psk_ctx);
1719 }
1720 if (res->res_store.tls_ca_certfile) {
1721 free(res->res_store.tls_ca_certfile);
1722 }
1723 if (res->res_store.tls_ca_certdir) {
1724 free(res->res_store.tls_ca_certdir);
1725 }
1726 if (res->res_store.tls_certfile) {
1727 free(res->res_store.tls_certfile);
1728 }
1729 if (res->res_store.tls_keyfile) {
1730 free(res->res_store.tls_keyfile);
1731 }
1732 break;
1733 case R_CATALOG:
1734 if (res->res_cat.db_address) {
1735 free(res->res_cat.db_address);
1736 }
1737 if (res->res_cat.db_socket) {
1738 free(res->res_cat.db_socket);
1739 }
1740 if (res->res_cat.db_user) {
1741 free(res->res_cat.db_user);
1742 }
1743 if (res->res_cat.db_name) {
1744 free(res->res_cat.db_name);
1745 }
1746 if (res->res_cat.db_driver) {
1747 free(res->res_cat.db_driver);
1748 }
1749 if (res->res_cat.db_password) {
1750 free(res->res_cat.db_password);
1751 }
1752 if (res->res_cat.db_ssl_mode) {
1753 free(res->res_cat.db_ssl_mode);
1754 }
1755 if (res->res_cat.db_ssl_key) {
1756 free(res->res_cat.db_ssl_key);
1757 }
1758 if (res->res_cat.db_ssl_cert) {
1759 free(res->res_cat.db_ssl_cert);
1760 }
1761 if (res->res_cat.db_ssl_ca) {
1762 free(res->res_cat.db_ssl_ca);
1763 }
1764 if (res->res_cat.db_ssl_capath) {
1765 free(res->res_cat.db_ssl_capath);
1766 }
1767 if (res->res_cat.db_ssl_cipher) {
1768 free(res->res_cat.db_ssl_cipher);
1769 }
1770 break;
1771 case R_FILESET:
1772 if ((num=res->res_fs.num_includes)) {
1773 while (--num >= 0) {
1774 free_incexe(res->res_fs.include_items[num]);
1775 }
1776 free(res->res_fs.include_items);
1777 }
1778 res->res_fs.num_includes = 0;
1779 if ((num=res->res_fs.num_excludes)) {
1780 while (--num >= 0) {
1781 free_incexe(res->res_fs.exclude_items[num]);
1782 }
1783 free(res->res_fs.exclude_items);
1784 }
1785 res->res_fs.num_excludes = 0;
1786 break;
1787 case R_POOL:
1788 if (res->res_pool.pool_type) {
1789 free(res->res_pool.pool_type);
1790 }
1791 if (res->res_pool.label_format) {
1792 free(res->res_pool.label_format);
1793 }
1794 if (res->res_pool.cleaning_prefix) {
1795 free(res->res_pool.cleaning_prefix);
1796 }
1797 if (res->res_pool.storage) {
1798 delete res->res_pool.storage;
1799 }
1800 break;
1801 case R_SCHEDULE:
1802 if (res->res_sch.run) {
1803 RUN *nrun, *next;
1804 nrun = res->res_sch.run;
1805 while (nrun) {
1806 next = nrun->next;
1807 free(nrun);
1808 nrun = next;
1809 }
1810 }
1811 break;
1812 case R_JOB:
1813 case R_JOBDEFS:
1814 if (res->res_job.RestoreWhere) {
1815 free(res->res_job.RestoreWhere);
1816 }
1817 if (res->res_job.RegexWhere) {
1818 free(res->res_job.RegexWhere);
1819 }
1820 if (res->res_job.strip_prefix) {
1821 free(res->res_job.strip_prefix);
1822 }
1823 if (res->res_job.add_prefix) {
1824 free(res->res_job.add_prefix);
1825 }
1826 if (res->res_job.add_suffix) {
1827 free(res->res_job.add_suffix);
1828 }
1829 if (res->res_job.RestoreBootstrap) {
1830 free(res->res_job.RestoreBootstrap);
1831 }
1832 if (res->res_job.RestoreClient) {
1833 free(res->res_job.RestoreClient);
1834 }
1835 if (res->res_job.WriteBootstrap) {
1836 free(res->res_job.WriteBootstrap);
1837 }
1838 if (res->res_job.PluginOptions) {
1839 free(res->res_job.PluginOptions);
1840 }
1841 if (res->res_job.selection_pattern) {
1842 free(res->res_job.selection_pattern);
1843 }
1844 if (res->res_job.run_cmds) {
1845 delete res->res_job.run_cmds;
1846 }
1847 if (res->res_job.storage) {
1848 delete res->res_job.storage;
1849 }
1850 if (res->res_job.base) {
1851 delete res->res_job.base;
1852 }
1853 if (res->res_job.RunScripts) {
1854 free_runscripts(res->res_job.RunScripts);
1855 delete res->res_job.RunScripts;
1856 }
1857 break;
1858 case R_MSGS:
1859 if (res->res_msgs.mail_cmd) {
1860 free(res->res_msgs.mail_cmd);
1861 }
1862 if (res->res_msgs.operator_cmd) {
1863 free(res->res_msgs.operator_cmd);
1864 }
1865 free_msgs_res((MSGS *)res); /* free message resource */
1866 res = NULL;
1867 break;
1868 case R_COLLECTOR:
1869 free_collector_resource(res->res_collector);
1870 break;
1871 default:
1872 printf(_("Unknown resource type %d in free_resource.\n"), type);
1873 }
1874 /* Common stuff again -- free the resource, recurse to next one */
1875 if (res) {
1876 free(res);
1877 }
1878 }
1879
1880 /* Get the resource object size */
get_resource_size(int type)1881 int get_resource_size(int type)
1882 {
1883 int size=-1;
1884 /*
1885 * The following code is only executed during pass 1
1886 */
1887 switch (type) {
1888 case R_DIRECTOR:
1889 size = sizeof(DIRRES);
1890 break;
1891 case R_CONSOLE:
1892 size = sizeof(CONRES);
1893 break;
1894 case R_CLIENT:
1895 size =sizeof(CLIENT);
1896 break;
1897 case R_STORAGE:
1898 size = sizeof(STORE);
1899 break;
1900 case R_CATALOG:
1901 size = sizeof(CAT);
1902 break;
1903 case R_JOB:
1904 case R_JOBDEFS:
1905 size = sizeof(JOB);
1906 break;
1907 case R_FILESET:
1908 size = sizeof(FILESET);
1909 break;
1910 case R_SCHEDULE:
1911 size = sizeof(SCHED);
1912 break;
1913 case R_POOL:
1914 size = sizeof(POOL);
1915 break;
1916 case R_MSGS:
1917 size = sizeof(MSGS);
1918 break;
1919 case R_COLLECTOR:
1920 size = sizeof(COLLECTOR);
1921 break;
1922 case R_COUNTER:
1923 size = sizeof(COUNTER);
1924 break;
1925 case R_DEVICE:
1926 /* error */
1927 break;
1928 default:
1929 /* error */
1930 break;
1931 }
1932 return size;
1933 }
1934
1935 /*
1936 * Save the new resource by chaining it into the head list for
1937 * the resource. If this is pass 2, we update any resource
1938 * pointers because they may not have been defined until
1939 * later in pass 1.
1940 */
save_resource(CONFIG * config,int type,RES_ITEM * items,int pass)1941 bool save_resource(CONFIG *config, int type, RES_ITEM *items, int pass)
1942 {
1943 URES *res;
1944 int rindex = type - r_first;
1945 int i, size = 0;
1946 bool error = false;
1947
1948 /* Check Job requirements after applying JobDefs */
1949 if (type != R_JOB && type != R_JOBDEFS) {
1950 /*
1951 * Ensure that all required items are present
1952 */
1953 for (i=0; items[i].name; i++) {
1954 if (items[i].flags & ITEM_REQUIRED) {
1955 if (!bit_is_set(i, res_all.res_dir.hdr.item_present)) {
1956 Mmsg(config->m_errmsg, _("\"%s\" directive is required in \"%s\" resource, but not found.\n"),
1957 items[i].name, resources[rindex].name);
1958 return false;
1959 }
1960 }
1961 /* If this triggers, take a look at lib/parse_conf.h */
1962 if (i >= MAX_RES_ITEMS) {
1963 Mmsg(config->m_errmsg, _("Too many directives in \"%s\" resource\n"), resources[rindex].name);
1964 return false;
1965 }
1966 }
1967 } else if (type == R_JOB) {
1968 /*
1969 * Ensure that the name item is present
1970 */
1971 if (items[0].flags & ITEM_REQUIRED) {
1972 if (!bit_is_set(0, res_all.res_dir.hdr.item_present)) {
1973 Mmsg(config->m_errmsg, _("\"%s\" directive is required in \"%s\" resource, but not found.\n"),
1974 items[0].name, resources[rindex].name);
1975 return false;
1976 }
1977 }
1978 }
1979
1980 /*
1981 * During pass 2 in each "store" routine, we looked up pointers
1982 * to all the resources referrenced in the current resource, now we
1983 * must copy their addresses from the static record to the allocated
1984 * record.
1985 */
1986 if (pass == 2) {
1987 switch (type) {
1988 /* Resources not containing a resource */
1989 case R_CATALOG:
1990 case R_MSGS:
1991 case R_FILESET:
1992 case R_DEVICE:
1993 break;
1994
1995 /*
1996 * Resources containing another resource or alist. First
1997 * look up the resource which contains another resource. It
1998 * was written during pass 1. Then stuff in the pointers to
1999 * the resources it contains, which were inserted this pass.
2000 * Finally, it will all be stored back.
2001 */
2002 case R_POOL:
2003 /* Find resource saved in pass 1 */
2004 if ((res = (URES *)GetResWithName(R_POOL, res_all.res_con.hdr.name)) == NULL) {
2005 Mmsg(config->m_errmsg, _("Cannot find Pool resource %s\n"), res_all.res_con.hdr.name);
2006 return false;
2007 }
2008 /* Explicitly copy resource pointers from this pass (res_all) */
2009 res->res_pool.NextPool = res_all.res_pool.NextPool;
2010 res->res_pool.RecyclePool = res_all.res_pool.RecyclePool;
2011 res->res_pool.ScratchPool = res_all.res_pool.ScratchPool;
2012 res->res_pool.storage = res_all.res_pool.storage;
2013 res->res_pool.catalog = res_all.res_pool.catalog;
2014 break;
2015 case R_CONSOLE:
2016 if ((res = (URES *)GetResWithName(R_CONSOLE, res_all.res_con.hdr.name)) == NULL) {
2017 Mmsg(config->m_errmsg, _("Cannot find Console resource %s\n"), res_all.res_con.hdr.name);
2018 return false;
2019 }
2020 res->res_con.tls_allowed_cns = res_all.res_con.tls_allowed_cns;
2021 break;
2022 case R_DIRECTOR:
2023 if ((res = (URES *)GetResWithName(R_DIRECTOR, res_all.res_dir.hdr.name)) == NULL) {
2024 Mmsg(config->m_errmsg, _("Cannot find Director resource %s\n"), res_all.res_dir.hdr.name);
2025 return false;
2026 }
2027 res->res_dir.messages = res_all.res_dir.messages;
2028 res->res_dir.tls_allowed_cns = res_all.res_dir.tls_allowed_cns;
2029 break;
2030 case R_AUTOCHANGER: /* alias for R_STORAGE */
2031 case R_STORAGE:
2032 type = R_STORAGE; /* force Storage type */
2033 if ((res = (URES *)GetResWithName(type, res_all.res_store.hdr.name)) == NULL) {
2034 Mmsg(config->m_errmsg, _("Cannot find Storage resource %s\n"),
2035 res_all.res_dir.hdr.name);
2036 return false;
2037 }
2038 /* we must explicitly copy the device alist pointer */
2039 res->res_store.device = res_all.res_store.device;
2040 res->res_store.changer = res_all.res_store.changer;
2041 res->res_store.shared_storage = res_all.res_store.shared_storage;
2042 res->res_store.autochanger = res_all.res_store.autochanger;
2043 /* The resource name is Autochanger instead of Storage
2044 * so we force the Autochanger attributes
2045 */
2046 if (strcasecmp(resources[rindex].name, "autochanger") == 0) {
2047 /* The Autochanger resource might be already defined */
2048 res->res_store.changer = (res->res_store.changer == NULL)? &res->res_store : res->res_store.changer;
2049 res->res_store.autochanger = true;
2050 }
2051 break;
2052 case R_JOB:
2053 case R_JOBDEFS:
2054 if ((res = (URES *)GetResWithName(type, res_all.res_dir.hdr.name)) == NULL) {
2055 Mmsg(config->m_errmsg, _("Cannot find Job resource %s\n"),
2056 res_all.res_dir.hdr.name);
2057 return false;
2058 }
2059 res->res_job.messages = res_all.res_job.messages;
2060 res->res_job.schedule = res_all.res_job.schedule;
2061 res->res_job.client = res_all.res_job.client;
2062 res->res_job.fileset = res_all.res_job.fileset;
2063 res->res_job.storage = res_all.res_job.storage;
2064 res->res_job.base = res_all.res_job.base;
2065 res->res_job.pool = res_all.res_job.pool;
2066 res->res_job.next_pool = res_all.res_job.next_pool;
2067 res->res_job.full_pool = res_all.res_job.full_pool;
2068 res->res_job.vfull_pool = res_all.res_job.vfull_pool;
2069 res->res_job.inc_pool = res_all.res_job.inc_pool;
2070 res->res_job.diff_pool = res_all.res_job.diff_pool;
2071 res->res_job.verify_job = res_all.res_job.verify_job;
2072 res->res_job.jobdefs = res_all.res_job.jobdefs;
2073 res->res_job.run_cmds = res_all.res_job.run_cmds;
2074 res->res_job.RunScripts = res_all.res_job.RunScripts;
2075
2076 /* TODO: JobDefs where/regexwhere doesn't work well (but this
2077 * is not very useful)
2078 * We have to set_bit(index, res_all.hdr.item_present);
2079 * or something like that
2080 */
2081
2082 /* we take RegexWhere before all other options */
2083 if (!res->res_job.RegexWhere
2084 &&
2085 (res->res_job.strip_prefix ||
2086 res->res_job.add_suffix ||
2087 res->res_job.add_prefix))
2088 {
2089 int len = bregexp_get_build_where_size(res->res_job.strip_prefix,
2090 res->res_job.add_prefix,
2091 res->res_job.add_suffix);
2092 res->res_job.RegexWhere = (char *) bmalloc (len * sizeof(char));
2093 bregexp_build_where(res->res_job.RegexWhere, len,
2094 res->res_job.strip_prefix,
2095 res->res_job.add_prefix,
2096 res->res_job.add_suffix);
2097 /* TODO: test bregexp */
2098 }
2099
2100 if (res->res_job.RegexWhere && res->res_job.RestoreWhere) {
2101 free(res->res_job.RestoreWhere);
2102 res->res_job.RestoreWhere = NULL;
2103 }
2104
2105 break;
2106 case R_COUNTER:
2107 if ((res = (URES *)GetResWithName(R_COUNTER, res_all.res_counter.hdr.name)) == NULL) {
2108 Mmsg(config->m_errmsg, _("Cannot find Counter resource %s\n"), res_all.res_counter.hdr.name);
2109 return false;
2110 }
2111 res->res_counter.Catalog = res_all.res_counter.Catalog;
2112 res->res_counter.WrapCounter = res_all.res_counter.WrapCounter;
2113 break;
2114
2115 case R_CLIENT:
2116 if ((res = (URES *)GetResWithName(R_CLIENT, res_all.res_client.name())) == NULL) {
2117 Mmsg(config->m_errmsg, _("Cannot find Client resource %s\n"), res_all.res_client.name());
2118 return false;
2119 }
2120 res->res_client.catalog = res_all.res_client.catalog;
2121 res->res_client.tls_allowed_cns = res_all.res_client.tls_allowed_cns;
2122 break;
2123 case R_SCHEDULE:
2124 /*
2125 * Schedule is a bit different in that it contains a RUN record
2126 * chain which isn't a "named" resource. This chain was linked
2127 * in by run_conf.c during pass 2, so here we jam the pointer
2128 * into the Schedule resource.
2129 */
2130 if ((res = (URES *)GetResWithName(R_SCHEDULE, res_all.res_client.name())) == NULL) {
2131 Mmsg(config->m_errmsg, _("Cannot find Schedule resource %s\n"), res_all.res_client.name());
2132 return false;
2133 }
2134 res->res_sch.run = res_all.res_sch.run;
2135 break;
2136 case R_COLLECTOR:
2137 if ((res = (URES *)GetResWithName(R_COLLECTOR, res_all.res_collector.hdr.name)) == NULL) {
2138 Mmsg(config->m_errmsg, _("Cannot find Statistics resource %s\n"), res_all.res_collector.hdr.name);
2139 return false;
2140 }
2141 res->res_collector.metrics = res_all.res_collector.metrics;
2142 // Dmsg2(100, "metrics = 0x%p 0x%p\n", res->res_collector.metrics, res_all.res_collector.metrics);
2143 break;
2144
2145 default:
2146 Emsg1(M_ERROR, 0, _("Unknown resource type %d in save_resource.\n"), type);
2147 error = true;
2148 break;
2149 }
2150 /* Note, the resource name was already saved during pass 1,
2151 * so here, we can just release it.
2152 */
2153 if (res_all.res_dir.hdr.name) {
2154 free(res_all.res_dir.hdr.name);
2155 res_all.res_dir.hdr.name = NULL;
2156 }
2157 if (res_all.res_dir.hdr.desc) {
2158 free(res_all.res_dir.hdr.desc);
2159 res_all.res_dir.hdr.desc = NULL;
2160 }
2161 return true;
2162 }
2163
2164 /* R_AUTOCHANGER is alias so turn it into an R_STORAGE */
2165 if (type == R_AUTOCHANGER) {
2166 type = R_STORAGE;
2167 rindex = type - r_first;
2168 }
2169
2170 /*
2171 * The following code is only executed during pass 1
2172 */
2173 size = get_resource_size(type);
2174 if (size < 0) {
2175 printf(_("Unknown resource type %d in save_resource.\n"), type);
2176 error = true;
2177 }
2178
2179 /* Common */
2180 if (!error) {
2181 if (!config->insert_res(rindex, size)) {
2182 return false;
2183 }
2184 }
2185 return true;
2186 }
2187
store_actiononpurge(LEX * lc,RES_ITEM * item,int index,int pass)2188 void store_actiononpurge(LEX *lc, RES_ITEM *item, int index, int pass)
2189 {
2190 uint32_t *destination = (uint32_t*)item->value;
2191 lex_get_token(lc, T_NAME);
2192 if (strcasecmp(lc->str, "truncate") == 0) {
2193 *destination = (*destination) | ON_PURGE_TRUNCATE;
2194 } else {
2195 scan_err2(lc, _("Expected one of: %s, got: %s"), "Truncate", lc->str);
2196 return;
2197 }
2198 scan_to_eol(lc);
2199 set_bit(index, res_all.hdr.item_present);
2200 }
2201
2202 /*
2203 * Store an autochanger resource. Used by Autochanger and
2204 * SharedStorage direcives.
2205 */
store_ac_res(LEX * lc,RES_ITEM * item,int index,int pass)2206 void store_ac_res(LEX *lc, RES_ITEM *item, int index, int pass)
2207 {
2208 RES *res;
2209 RES_ITEM *next = item + 1;
2210
2211 lex_get_token(lc, T_NAME);
2212 Dmsg1(100, "Got name=%s\n", lc->str);
2213 /*
2214 * For backward compatibility, if yes/no, set the next item
2215 */
2216 if (strcasecmp(item->name, "autochanger") == 0) {
2217 if (strcasecmp(lc->str, "yes") == 0 || strcasecmp(lc->str, "true") == 0) {
2218 *(bool *)(next->value) = true;
2219 *(item->value) = NULL;
2220 Dmsg2(100, "Item=%s got value=%s\n", item->name, lc->str);
2221 scan_to_eol(lc);
2222 return;
2223 } else if (strcasecmp(lc->str, "no") == 0 || strcasecmp(lc->str, "false") == 0) {
2224 *(bool *)(next->value) = false;
2225 *(item->value) = NULL;
2226 Dmsg2(100, "Item=%s got value=%s\n", item->name, lc->str);
2227 scan_to_eol(lc);
2228 return;
2229 }
2230 }
2231 Dmsg2(100, "Item=%s got value=%s\n", item->name, lc->str);
2232
2233 if (pass == 2) {
2234 res = GetResWithName(R_STORAGE, lc->str);
2235 if (res == NULL) {
2236 scan_err3(lc, _("Could not find Storage Resource %s referenced on line %d : %s\n"),
2237 lc->str, lc->line_no, lc->line);
2238 return;
2239 }
2240 if (*(item->value)) {
2241 scan_err3(lc, _("Attempt to redefine Storage resource \"%s\" referenced on line %d : %s\n"),
2242 item->name, lc->line_no, lc->line);
2243 return;
2244 }
2245 Dmsg2(100, "Store %s value=%p\n", lc->str, res);
2246 *(item->value) = (char *)res;
2247 if (strcasecmp(item->name, "autochanger") == 0) {
2248 *(bool *)(next->value) = true;
2249 }
2250 }
2251 scan_to_eol(lc);
2252 set_bit(index, res_all.hdr.item_present);
2253 }
2254
2255
2256 /*
2257 * Store Device. Note, the resource is created upon the
2258 * first reference. The details of the resource are obtained
2259 * later from the SD.
2260 */
store_device(LEX * lc,RES_ITEM * item,int index,int pass)2261 void store_device(LEX *lc, RES_ITEM *item, int index, int pass)
2262 {
2263 int rindex = R_DEVICE - r_first;
2264 int size = sizeof(DEVICE);
2265
2266 if (pass == 1) {
2267 URES *ures;
2268 RES *res;
2269
2270 lex_get_token(lc, T_NAME);
2271 rblist *list = res_head[rindex]->res_list;
2272 ures = (URES *)malloc(size);
2273 memset(ures, 0, size);
2274 ures->res_dev.hdr.name = bstrdup(lc->str);
2275 res = (RES *)ures;
2276 if (list->empty()) {
2277 list->insert(res, res_compare);
2278 res_head[rindex]->first = res;
2279 res_head[rindex]->last = res;
2280 } else {
2281 RES *item, *prev;
2282 prev = res_head[rindex]->last;
2283 item = (RES *)list->insert(res, res_compare);
2284 if (item == res) {
2285 prev->res_next = res;
2286 res_head[rindex]->last = res;
2287 } else {
2288 /* res not inserted */
2289 free(ures->res_dev.hdr.name);
2290 free(ures);
2291 }
2292 }
2293 scan_to_eol(lc);
2294 set_bit(index, res_all.hdr.item_present);
2295 } else {
2296 store_alist_res(lc, item, index, pass);
2297 }
2298 }
2299
2300 /*
2301 * Store Migration/Copy type
2302 *
2303 */
store_migtype(LEX * lc,RES_ITEM * item,int index,int pass)2304 void store_migtype(LEX *lc, RES_ITEM *item, int index, int pass)
2305 {
2306 int i;
2307
2308 lex_get_token(lc, T_NAME);
2309 /* Store the type both pass 1 and pass 2 */
2310 for (i=0; migtypes[i].type_name; i++) {
2311 if (strcasecmp(lc->str, migtypes[i].type_name) == 0) {
2312 *(uint32_t *)(item->value) = migtypes[i].job_type;
2313 i = 0;
2314 break;
2315 }
2316 }
2317 if (i != 0) {
2318 scan_err1(lc, _("Expected a Migration Job Type keyword, got: %s"), lc->str);
2319 }
2320 scan_to_eol(lc);
2321 set_bit(index, res_all.hdr.item_present);
2322 }
2323
2324
2325
2326 /*
2327 * Store JobType (backup, verify, restore)
2328 *
2329 */
store_jobtype(LEX * lc,RES_ITEM * item,int index,int pass)2330 void store_jobtype(LEX *lc, RES_ITEM *item, int index, int pass)
2331 {
2332 int i;
2333
2334 lex_get_token(lc, T_NAME);
2335 /* Store the type both pass 1 and pass 2 */
2336 for (i=0; jobtypes[i].type_name; i++) {
2337 if (strcasecmp(lc->str, jobtypes[i].type_name) == 0) {
2338 *(uint32_t *)(item->value) = jobtypes[i].job_type;
2339 i = 0;
2340 break;
2341 }
2342 }
2343 if (i != 0) {
2344 scan_err1(lc, _("Expected a Job Type keyword, got: %s"), lc->str);
2345 }
2346 scan_to_eol(lc);
2347 set_bit(index, res_all.hdr.item_present);
2348 }
2349
2350 /*
2351 * Store Job Level (Full, Incremental, ...)
2352 *
2353 */
store_level(LEX * lc,RES_ITEM * item,int index,int pass)2354 void store_level(LEX *lc, RES_ITEM *item, int index, int pass)
2355 {
2356 int i;
2357
2358 lex_get_token(lc, T_NAME);
2359 /* Store the level pass 2 so that type is defined */
2360 for (i=0; joblevels[i].level_name; i++) {
2361 if (strcasecmp(lc->str, joblevels[i].level_name) == 0) {
2362 *(uint32_t *)(item->value) = joblevels[i].level;
2363 i = 0;
2364 break;
2365 }
2366 }
2367 if (i != 0) {
2368 scan_err1(lc, _("Expected a Job Level keyword, got: %s"), lc->str);
2369 }
2370 scan_to_eol(lc);
2371 set_bit(index, res_all.hdr.item_present);
2372 }
2373
2374
store_replace(LEX * lc,RES_ITEM * item,int index,int pass)2375 void store_replace(LEX *lc, RES_ITEM *item, int index, int pass)
2376 {
2377 int i;
2378 lex_get_token(lc, T_NAME);
2379 /* Scan Replacement options */
2380 for (i=0; ReplaceOptions[i].name; i++) {
2381 if (strcasecmp(lc->str, ReplaceOptions[i].name) == 0) {
2382 *(uint32_t *)(item->value) = ReplaceOptions[i].token;
2383 i = 0;
2384 break;
2385 }
2386 }
2387 if (i != 0) {
2388 scan_err1(lc, _("Expected a Restore replacement option, got: %s"), lc->str);
2389 }
2390 scan_to_eol(lc);
2391 set_bit(index, res_all.hdr.item_present);
2392 }
2393
2394 /*
2395 * Store ACL (access control list)
2396 *
2397 */
store_acl(LEX * lc,RES_ITEM * item,int index,int pass)2398 void store_acl(LEX *lc, RES_ITEM *item, int index, int pass)
2399 {
2400 int token;
2401
2402 for (;;) {
2403 lex_get_token(lc, T_STRING);
2404 if (pass == 1) {
2405 if (((alist **)item->value)[item->code] == NULL) {
2406 ((alist **)item->value)[item->code] = New(alist(10, owned_by_alist));
2407 Dmsg1(900, "Defined new ACL alist at %d\n", item->code);
2408 }
2409 ((alist **)item->value)[item->code]->append(bstrdup(lc->str));
2410 Dmsg2(900, "Appended to %d %s\n", item->code, lc->str);
2411 }
2412 token = lex_get_token(lc, T_ALL);
2413 if (token == T_COMMA) {
2414 continue; /* get another ACL */
2415 }
2416 break;
2417 }
2418 set_bit(index, res_all.hdr.item_present);
2419 }
2420
2421 /* We build RunScripts items here */
2422 static RUNSCRIPT res_runscript;
2423
2424 /* Store a runscript->when in a bit field */
store_runscript_when(LEX * lc,RES_ITEM * item,int index,int pass)2425 static void store_runscript_when(LEX *lc, RES_ITEM *item, int index, int pass)
2426 {
2427 lex_get_token(lc, T_NAME);
2428
2429 if (strcasecmp(lc->str, "before") == 0) {
2430 *(uint32_t *)(item->value) = SCRIPT_Before ;
2431 } else if (strcasecmp(lc->str, "after") == 0) {
2432 *(uint32_t *)(item->value) = SCRIPT_After;
2433 } else if (strcasecmp(lc->str, "aftervss") == 0) {
2434 *(uint32_t *)(item->value) = SCRIPT_AfterVSS;
2435 } else if (strcasecmp(lc->str, "aftersnapshot") == 0) {
2436 *(uint32_t *)(item->value) = SCRIPT_AfterVSS;
2437 } else if (strcasecmp(lc->str, "always") == 0) {
2438 *(uint32_t *)(item->value) = SCRIPT_Any;
2439 } else {
2440 scan_err2(lc, _("Expect %s, got: %s"), "Before, After, AfterVSS or Always", lc->str);
2441 }
2442 scan_to_eol(lc);
2443 }
2444
2445 /* Store a runscript->target
2446 *
2447 */
store_runscript_target(LEX * lc,RES_ITEM * item,int index,int pass)2448 static void store_runscript_target(LEX *lc, RES_ITEM *item, int index, int pass)
2449 {
2450 lex_get_token(lc, T_STRING);
2451
2452 if (pass == 2) {
2453 if (strcmp(lc->str, "%c") == 0) {
2454 ((RUNSCRIPT*) item->value)->set_target(lc->str);
2455 } else if (strcasecmp(lc->str, "yes") == 0) {
2456 ((RUNSCRIPT*) item->value)->set_target("%c");
2457 } else if (strcasecmp(lc->str, "no") == 0) {
2458 ((RUNSCRIPT*) item->value)->set_target("");
2459 } else {
2460 RES *res = GetResWithName(R_CLIENT, lc->str);
2461 if (res == NULL) {
2462 scan_err3(lc, _("Could not find config Resource %s referenced on line %d : %s\n"),
2463 lc->str, lc->line_no, lc->line);
2464 }
2465
2466 ((RUNSCRIPT*) item->value)->set_target(lc->str);
2467 }
2468 }
2469 scan_to_eol(lc);
2470 }
2471
2472 /*
2473 * Store a runscript->command as a string and runscript->cmd_type as a pointer
2474 */
store_runscript_cmd(LEX * lc,RES_ITEM * item,int index,int pass)2475 static void store_runscript_cmd(LEX *lc, RES_ITEM *item, int index, int pass)
2476 {
2477 lex_get_token(lc, T_STRING);
2478
2479 if (pass == 2) {
2480 Dmsg2(1, "runscript cmd=%s type=%c\n", lc->str, item->code);
2481 POOLMEM *c = get_pool_memory(PM_FNAME);
2482 /* Each runscript command takes 2 entries in commands list */
2483 pm_strcpy(c, lc->str);
2484 ((RUNSCRIPT*) item->value)->commands->prepend(c); /* command line */
2485 ((RUNSCRIPT*) item->value)->commands->prepend((void *)(intptr_t)item->code); /* command type */
2486 }
2487 scan_to_eol(lc);
2488 }
2489
store_short_runscript(LEX * lc,RES_ITEM * item,int index,int pass)2490 static void store_short_runscript(LEX *lc, RES_ITEM *item, int index, int pass)
2491 {
2492 lex_get_token(lc, T_STRING);
2493 alist **runscripts = (alist **)(item->value) ;
2494
2495 if (pass == 2) {
2496 RUNSCRIPT *script = new_runscript();
2497 script->set_job_code_callback(job_code_callback_director);
2498
2499 script->set_command(lc->str);
2500
2501 /* TODO: remove all script->old_proto with bacula 1.42 */
2502
2503 if (strcasecmp(item->name, "runbeforejob") == 0) {
2504 script->when = SCRIPT_Before;
2505 script->fail_on_error = true;
2506 script->set_target("");
2507
2508 } else if (strcasecmp(item->name, "runafterjob") == 0) {
2509 script->when = SCRIPT_After;
2510 script->on_success = true;
2511 script->on_failure = false;
2512 script->set_target("");
2513
2514 } else if (strcasecmp(item->name, "clientrunbeforejob") == 0) {
2515 script->old_proto = true;
2516 script->when = SCRIPT_Before;
2517 script->set_target("%c");
2518 script->fail_on_error = true;
2519
2520 } else if (strcasecmp(item->name, "clientrunafterjob") == 0) {
2521 script->old_proto = true;
2522 script->when = SCRIPT_After;
2523 script->set_target("%c");
2524 script->on_success = true;
2525 script->on_failure = false;
2526
2527 } else if (strcasecmp(item->name, "consolerunbeforejob") == 0) {
2528 script->when = SCRIPT_Before;
2529 script->set_target("");
2530 script->fail_on_error = true;
2531 script->set_command(NPRT(script->command), CONSOLE_CMD);
2532
2533 } else if (strcasecmp(item->name, "consolerunafterjob") == 0) {
2534 script->when = SCRIPT_After;
2535 script->set_target("");
2536 script->on_success = true;
2537 script->on_failure = false;
2538 script->set_command(NPRT(script->command), CONSOLE_CMD);
2539
2540 } else if (strcasecmp(item->name, "runafterfailedjob") == 0) {
2541 script->when = SCRIPT_After;
2542 script->on_failure = true;
2543 script->on_success = false;
2544 script->set_target("");
2545 }
2546
2547 if (*runscripts == NULL) {
2548 *runscripts = New(alist(10, not_owned_by_alist));
2549 }
2550
2551 (*runscripts)->append(script);
2552 script->debug();
2553 }
2554 scan_to_eol(lc);
2555 set_bit(index, res_all.hdr.item_present);
2556 }
2557
2558 /* Store a bool in a bit field without modifing res_all.hdr
2559 * We can also add an option to store_bool to skip res_all.hdr
2560 */
store_runscript_bool(LEX * lc,RES_ITEM * item,int index,int pass)2561 void store_runscript_bool(LEX *lc, RES_ITEM *item, int index, int pass)
2562 {
2563 lex_get_token(lc, T_NAME);
2564 if (strcasecmp(lc->str, "yes") == 0 || strcasecmp(lc->str, "true") == 0) {
2565 *(bool *)(item->value) = true;
2566 } else if (strcasecmp(lc->str, "no") == 0 || strcasecmp(lc->str, "false") == 0) {
2567 *(bool *)(item->value) = false;
2568 } else {
2569 scan_err2(lc, _("Expect %s, got: %s"), "YES, NO, TRUE, or FALSE", lc->str); /* YES and NO must not be translated */
2570 }
2571 scan_to_eol(lc);
2572 }
2573
2574 /*
2575 * new RunScript items
2576 * name handler value code flags default_value
2577 */
2578 static RES_ITEM runscript_items[] = {
2579 {"command", store_runscript_cmd, {(char **)&res_runscript}, SHELL_CMD, 0, 0},
2580 {"console", store_runscript_cmd, {(char **)&res_runscript}, CONSOLE_CMD, 0, 0},
2581 {"target", store_runscript_target,{(char **)&res_runscript}, 0, 0, 0},
2582 {"runsonsuccess", store_runscript_bool, {(char **)&res_runscript.on_success},0, 0, 0},
2583 {"runsonfailure", store_runscript_bool, {(char **)&res_runscript.on_failure},0, 0, 0},
2584 {"failjobonerror",store_runscript_bool, {(char **)&res_runscript.fail_on_error},0, 0, 0},
2585 {"abortjobonerror",store_runscript_bool, {(char **)&res_runscript.fail_on_error},0, 0, 0},
2586 {"runswhen", store_runscript_when, {(char **)&res_runscript.when}, 0, 0, 0},
2587 {"runsonclient", store_runscript_target,{(char **)&res_runscript}, 0, 0, 0}, /* TODO */
2588 {NULL, NULL, {0}, 0, 0, 0}
2589 };
2590
2591 /*
2592 * Store RunScript info
2593 *
2594 * Note, when this routine is called, we are inside a Job
2595 * resource. We treat the RunScript like a sort of
2596 * mini-resource within the Job resource.
2597 */
store_runscript(LEX * lc,RES_ITEM * item,int index,int pass)2598 void store_runscript(LEX *lc, RES_ITEM *item, int index, int pass)
2599 {
2600 char *c;
2601 int token, i, t;
2602 alist **runscripts = (alist **)(item->value) ;
2603
2604 Dmsg1(200, "store_runscript: begin store_runscript pass=%i\n", pass);
2605
2606 token = lex_get_token(lc, T_SKIP_EOL);
2607
2608 if (token != T_BOB) {
2609 scan_err1(lc, _("Expecting open brace. Got %s"), lc->str);
2610 }
2611 /* setting on_success, on_failure, fail_on_error */
2612 res_runscript.reset_default();
2613
2614 if (pass == 2) {
2615 res_runscript.commands = New(alist(10, not_owned_by_alist));
2616 }
2617
2618 while ((token = lex_get_token(lc, T_SKIP_EOL)) != T_EOF) {
2619 if (token == T_EOB) {
2620 break;
2621 }
2622 if (token != T_IDENTIFIER) {
2623 scan_err1(lc, _("Expecting keyword, got: %s\n"), lc->str);
2624 }
2625 for (i=0; runscript_items[i].name; i++) {
2626 if (strcasecmp(runscript_items[i].name, lc->str) == 0) {
2627 token = lex_get_token(lc, T_SKIP_EOL);
2628 if (token != T_EQUALS) {
2629 scan_err1(lc, _("expected an equals, got: %s"), lc->str);
2630 }
2631
2632 /* Call item handler */
2633 runscript_items[i].handler(lc, &runscript_items[i], i, pass);
2634 i = -1;
2635 break;
2636 }
2637 }
2638
2639 if (i >=0) {
2640 scan_err1(lc, _("Keyword %s not permitted in this resource"), lc->str);
2641 }
2642 }
2643
2644 if (pass == 2) {
2645 /* run on client by default */
2646 if (res_runscript.target == NULL) {
2647 res_runscript.set_target("%c");
2648 }
2649 if (*runscripts == NULL) {
2650 *runscripts = New(alist(10, not_owned_by_alist));
2651 }
2652 /*
2653 * commands list contains 2 values per command
2654 * - POOLMEM command string (ex: /bin/true)
2655 * - int command type (ex: SHELL_CMD)
2656 */
2657 res_runscript.set_job_code_callback(job_code_callback_director);
2658 while ((c=(char*)res_runscript.commands->pop()) != NULL) {
2659 t = (intptr_t)res_runscript.commands->pop();
2660 RUNSCRIPT *script = new_runscript();
2661 memcpy(script, &res_runscript, sizeof(RUNSCRIPT));
2662 script->command = c;
2663 script->cmd_type = t;
2664 /* target is taken from res_runscript, each runscript object have
2665 * a copy
2666 */
2667 script->target = NULL;
2668 script->set_target(res_runscript.target);
2669
2670 (*runscripts)->append(script);
2671 script->debug();
2672 }
2673 delete res_runscript.commands;
2674 /* setting on_success, on_failure... cleanup target field */
2675 res_runscript.reset_default(true);
2676 }
2677
2678 scan_to_eol(lc);
2679 set_bit(index, res_all.hdr.item_present);
2680 }
2681
get_client_address(JCR * jcr,CLIENT * client,POOLMEM * & buf)2682 char *get_client_address(JCR *jcr, CLIENT *client, POOLMEM *&buf)
2683 {
2684 client->address(buf);
2685 if (buf[0] == '|') {
2686 POOL_MEM tmp;
2687 BPIPE *bpipe;
2688 int stat;
2689 edit_job_codes(jcr, tmp.addr(), buf+1, "", job_code_callback_director);
2690 bpipe = open_bpipe(tmp.c_str(), 0, "r");
2691 if (!bpipe) {
2692 berrno be;
2693 Jmsg(jcr, M_FATAL, 0, _("Cannot run program to determine the client address: %s. ERR=%s\n"),
2694 tmp.addr(), be.bstrerror());
2695 pm_strcpy(buf, "**invalid address**"); /* used when we cannot use the |command as address */
2696 goto bail_out;
2697 }
2698 fgets(buf, sizeof_pool_memory(buf), bpipe->rfd);
2699 strip_trailing_junk(buf);
2700 if ((stat=close_bpipe(bpipe)) != 0) {
2701 berrno be;
2702 Jmsg(jcr, M_FATAL, 0, _("Error running program to determine the client address: %s. stat=%d: ERR=%s\n"),
2703 tmp.c_str(), be.code(stat), be.bstrerror(stat));
2704 if (buf[0] == 0) {
2705 pm_strcpy(buf, "**invalid address**"); /* used when we cannot use the |command as address */
2706 }
2707 goto bail_out;
2708 }
2709 for(char *p = buf ; *p ; p++) {
2710 /* TODO: names are unicode now, so we need to extend this check */
2711 if (!(B_ISALPHA(*p) || B_ISDIGIT(*p) || *p=='.' || *p=='-' || *p=='_')) {
2712 Jmsg(jcr, M_FATAL, 0, _("Error running program \"%s\" to determine client address. "
2713 "ERR=Invalid character found %c\n"), tmp.c_str(), *p);
2714 pm_strcpy(buf, "**invalid command**"); /* We cannot use the |command as address */
2715 goto bail_out;
2716 }
2717 }
2718 }
2719 bail_out:
2720 return buf;
2721 }
2722
2723 /* callback function for edit_job_codes */
2724 /* See ../lib/util.c, function edit_job_codes, for more remaining codes */
job_code_callback_director(JCR * jcr,const char * param,char * buf,int buflen)2725 extern "C" char *job_code_callback_director(JCR *jcr, const char* param, char *buf, int buflen)
2726 {
2727 static char yes[] = "yes";
2728 static char no[] = "no";
2729 ASSERTD(buflen > 255, "buflen must be long enough to hold an ip address");
2730
2731 switch (param[0]) {
2732 case 'f':
2733 if (jcr->fileset) {
2734 return jcr->fileset->name();
2735 }
2736 break;
2737 case 'h':
2738 if (jcr->client) {
2739 POOL_MEM tmp;
2740 get_client_address(jcr, jcr->client, tmp.addr());
2741 return bstrncpy(buf, tmp.c_str(), buflen);
2742 }
2743 break;
2744 case 'p':
2745 if (jcr->pool) {
2746 return jcr->pool->name();
2747 }
2748 break;
2749 case 'w':
2750 if (jcr->wstore) {
2751 return jcr->wstore->name();
2752 }
2753 break;
2754 case 'x':
2755 return jcr->spool_data ? yes : no;
2756 case 'D':
2757 return my_name;
2758 case 'C':
2759 return jcr->cloned ? yes : no;
2760 case 'I':
2761 if (buflen >= 50) {
2762 if (jcr->wjcr) {
2763 edit_uint64(jcr->wjcr->JobId, buf);
2764 return buf;
2765 } else {
2766 edit_uint64(0, buf);
2767 return buf;
2768 }
2769 }
2770 }
2771 return NULL;
2772 }
2773
parse_dir_config(CONFIG * config,const char * configfile,int exit_code)2774 bool parse_dir_config(CONFIG *config, const char *configfile, int exit_code)
2775 {
2776 config->init(configfile, NULL, exit_code, (void *)&res_all, res_all_size,
2777 r_first, r_last, resources, &res_head);
2778 return config->parse_config();
2779 }
2780