2 Bacula(R) - The Network Backup Solution
4 Copyright (C) 2000-2016 Kern Sibbald
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.
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.
14 This notice must be preserved when any source code is
15 conveyed and/or propagated.
17 Bacula(R) is a registered trademark of Kern Sibbald.
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).
24 * Note, the configuration file parser consists of three parts
26 * 1. The generic lexical scanner in lib/lex.c and lib/lex.h
28 * 2. The generic config scanner in lib/parse_config.c and
30 * These files contain the parser code, some utility
31 * routines, and the common store routines (name, int,
34 * 3. The daemon specific file, which contains the Resource
35 * definitions as well as any specific store routines
36 * for the resource records.
38 * Kern Sibbald, January MM
46 /* Define the first and last resource ID record
47 * types. Note, these should be unique for each
48 * daemon though not a requirement.
50 int32_t r_first = R_FIRST;
51 int32_t r_last = R_LAST;
52 static RES *sres_head[R_LAST - R_FIRST + 1];
53 RES **res_head = sres_head;
55 /* Imported subroutines */
56 extern void store_run(LEX *lc, RES_ITEM *item, int index, int pass);
57 extern void store_finc(LEX *lc, RES_ITEM *item, int index, int pass);
58 extern void store_inc(LEX *lc, RES_ITEM *item, int index, int pass);
61 /* Forward referenced subroutines */
63 void store_jobtype(LEX *lc, RES_ITEM *item, int index, int pass);
64 void store_level(LEX *lc, RES_ITEM *item, int index, int pass);
65 void store_replace(LEX *lc, RES_ITEM *item, int index, int pass);
66 void store_acl(LEX *lc, RES_ITEM *item, int index, int pass);
67 void store_migtype(LEX *lc, RES_ITEM *item, int index, int pass);
68 static void store_device(LEX *lc, RES_ITEM *item, int index, int pass);
69 void store_actiononpurge(LEX *lc, RES_ITEM *item, int index, int pass);
70 static void store_runscript_when(LEX *lc, RES_ITEM *item, int index, int pass);
71 static void store_runscript_cmd(LEX *lc, RES_ITEM *item, int index, int pass);
72 static void store_short_runscript(LEX *lc, RES_ITEM *item, int index, int pass);
74 /* We build the current resource here as we are
75 * scanning the resource configuration definition,
76 * then move it to allocated memory when the resource
80 extern "C" { // work around visual compiler mangling variables
86 int32_t res_all_size = sizeof(res_all);
89 * Definition of records permitted within each
90 * resource with the routine to process the record
96 * name handler value code flags default_value
98 static RES_ITEM dir_items[] = {
99 {"Name", store_name, ITEM(res_dir.hdr.name), 0, ITEM_REQUIRED, 0},
100 {"Description", store_str, ITEM(res_dir.hdr.desc), 0, 0, 0},
101 {"Messages", store_res, ITEM(res_dir.messages), R_MSGS, 0, 0},
102 {"DirPort", store_addresses_port, ITEM(res_dir.DIRaddrs), 0, ITEM_DEFAULT, 9101},
103 {"DirAddress", store_addresses_address, ITEM(res_dir.DIRaddrs), 0, ITEM_DEFAULT, 9101},
104 {"DirAddresses",store_addresses, ITEM(res_dir.DIRaddrs), 0, ITEM_DEFAULT, 9101},
105 {"DirSourceAddress",store_addresses_address, ITEM(res_dir.DIRsrc_addr), 0, ITEM_DEFAULT, 0},
106 {"QueryFile", store_dir, ITEM(res_dir.query_file), 0, ITEM_REQUIRED, 0},
107 {"WorkingDirectory", store_dir, ITEM(res_dir.working_directory), 0, ITEM_REQUIRED, 0},
108 {"PluginDirectory", store_dir, ITEM(res_dir.plugin_directory), 0, 0, 0},
109 {"ScriptsDirectory", store_dir, ITEM(res_dir.scripts_directory), 0, 0, 0},
110 {"PidDirectory", store_dir, ITEM(res_dir.pid_directory), 0, ITEM_REQUIRED, 0},
111 {"SubsysDirectory", store_dir, ITEM(res_dir.subsys_directory), 0, 0, 0},
112 {"MaximumConcurrentJobs", store_pint32, ITEM(res_dir.MaxConcurrentJobs), 0, ITEM_DEFAULT, 1},
113 {"MaximumReloadRequests", store_pint32, ITEM(res_dir.MaxReload), 0, ITEM_DEFAULT, 32},
114 {"MaximumConsoleConnections", store_pint32, ITEM(res_dir.MaxConsoleConnect), 0, ITEM_DEFAULT, 20},
115 {"Password", store_password, ITEM(res_dir.password), 0, ITEM_REQUIRED, 0},
116 {"FdConnectTimeout", store_time,ITEM(res_dir.FDConnectTimeout), 0, ITEM_DEFAULT, 3 * 60},
117 {"SdConnectTimeout", store_time,ITEM(res_dir.SDConnectTimeout), 0, ITEM_DEFAULT, 30 * 60},
118 {"HeartbeatInterval", store_time, ITEM(res_dir.heartbeat_interval), 0, ITEM_DEFAULT, 5 * 60},
119 {"TlsAuthenticate", store_bool, ITEM(res_dir.tls_authenticate), 0, 0, 0},
120 {"TlsEnable", store_bool, ITEM(res_dir.tls_enable), 0, 0, 0},
121 {"TlsRequire", store_bool, ITEM(res_dir.tls_require), 0, 0, 0},
122 {"TlsVerifyPeer", store_bool, ITEM(res_dir.tls_verify_peer), 0, ITEM_DEFAULT, true},
123 {"TlsCaCertificateFile", store_dir, ITEM(res_dir.tls_ca_certfile), 0, 0, 0},
124 {"TlsCaCertificateDir", store_dir, ITEM(res_dir.tls_ca_certdir), 0, 0, 0},
125 {"TlsCertificate", store_dir, ITEM(res_dir.tls_certfile), 0, 0, 0},
126 {"TlsKey", store_dir, ITEM(res_dir.tls_keyfile), 0, 0, 0},
127 {"TlsDhFile", store_dir, ITEM(res_dir.tls_dhfile), 0, 0, 0},
128 {"TlsAllowedCn", store_alist_str, ITEM(res_dir.tls_allowed_cns), 0, 0, 0},
129 {"StatisticsRetention", store_time, ITEM(res_dir.stats_retention), 0, ITEM_DEFAULT, 60*60*24*31*12*5},
130 {"VerId", store_str, ITEM(res_dir.verid), 0, 0, 0},
131 {NULL, NULL, {0}, 0, 0, 0}
137 * name handler value code flags default_value
139 static RES_ITEM con_items[] = {
140 {"Name", store_name, ITEM(res_con.hdr.name), 0, ITEM_REQUIRED, 0},
141 {"Description", store_str, ITEM(res_con.hdr.desc), 0, 0, 0},
142 {"Password", store_password, ITEM(res_con.password), 0, ITEM_REQUIRED, 0},
143 {"JobAcl", store_acl, ITEM(res_con.ACL_lists), Job_ACL, 0, 0},
144 {"ClientAcl", store_acl, ITEM(res_con.ACL_lists), Client_ACL, 0, 0},
145 {"StorageAcl", store_acl, ITEM(res_con.ACL_lists), Storage_ACL, 0, 0},
146 {"ScheduleAcl", store_acl, ITEM(res_con.ACL_lists), Schedule_ACL, 0, 0},
147 {"RunAcl", store_acl, ITEM(res_con.ACL_lists), Run_ACL, 0, 0},
148 {"PoolAcl", store_acl, ITEM(res_con.ACL_lists), Pool_ACL, 0, 0},
149 {"CommandAcl", store_acl, ITEM(res_con.ACL_lists), Command_ACL, 0, 0},
150 {"FilesetAcl", store_acl, ITEM(res_con.ACL_lists), FileSet_ACL, 0, 0},
151 {"CatalogAcl", store_acl, ITEM(res_con.ACL_lists), Catalog_ACL, 0, 0},
152 {"WhereAcl", store_acl, ITEM(res_con.ACL_lists), Where_ACL, 0, 0},
153 {"PluginOptionsAcl", store_acl, ITEM(res_con.ACL_lists), PluginOptions_ACL, 0, 0},
154 {"TlsAuthenticate", store_bool, ITEM(res_con.tls_authenticate), 0, 0, 0},
155 {"TlsEnable", store_bool, ITEM(res_con.tls_enable), 0, 0, 0},
156 {"TlsRequire", store_bool, ITEM(res_con.tls_require), 0, 0, 0},
157 {"TlsVerifyPeer", store_bool, ITEM(res_con.tls_verify_peer), 0, ITEM_DEFAULT, true},
158 {"TlsCaCertificateFile", store_dir, ITEM(res_con.tls_ca_certfile), 0, 0, 0},
159 {"TlsCaCertificateDir", store_dir, ITEM(res_con.tls_ca_certdir), 0, 0, 0},
160 {"TlsCertificate", store_dir, ITEM(res_con.tls_certfile), 0, 0, 0},
161 {"TlsKey", store_dir, ITEM(res_con.tls_keyfile), 0, 0, 0},
162 {"TlsDhFile", store_dir, ITEM(res_con.tls_dhfile), 0, 0, 0},
163 {"TlsAllowedCn", store_alist_str, ITEM(res_con.tls_allowed_cns), 0, 0, 0},
164 {NULL, NULL, {0}, 0, 0, 0}
169 * Client or File daemon resource
171 * name handler value code flags default_value
174 static RES_ITEM cli_items[] = {
175 {"Name", store_name, ITEM(res_client.hdr.name), 0, ITEM_REQUIRED, 0},
176 {"Description", store_str, ITEM(res_client.hdr.desc), 0, 0, 0},
177 {"fdaddress", store_str, ITEM(res_client.address), 0, 0, 0},
178 {"Address", store_str, ITEM(res_client.address), 0, ITEM_REQUIRED, 0},
179 {"FdPort", store_pint32, ITEM(res_client.FDport), 0, ITEM_DEFAULT, 9102},
180 {"fdpassword", store_password, ITEM(res_client.password), 0, 0, 0},
181 {"Password", store_password, ITEM(res_client.password), 0, ITEM_REQUIRED, 0},
182 {"FdStorageAddress", store_str, ITEM(res_client.fd_storage_address), 0, 0, 0},
183 {"Catalog", store_res, ITEM(res_client.catalog), R_CATALOG, ITEM_REQUIRED, 0},
184 {"FileRetention", store_time, ITEM(res_client.FileRetention), 0, ITEM_DEFAULT, 60*60*24*60},
185 {"JobRetention", store_time, ITEM(res_client.JobRetention), 0, ITEM_DEFAULT, 60*60*24*180},
186 {"HeartbeatInterval", store_time, ITEM(res_client.heartbeat_interval), 0, ITEM_DEFAULT, 5 * 60},
187 {"AutoPrune", store_bool, ITEM(res_client.AutoPrune), 0, ITEM_DEFAULT, true},
188 {"SDCallsClient", store_bool, ITEM(res_client.sd_calls_client), 0, ITEM_DEFAULT, false},
189 {"SnapshotRetention", store_time, ITEM(res_client.SnapRetention), 0, ITEM_DEFAULT, 0},
190 {"MaximumConcurrentJobs", store_pint32, ITEM(res_client.MaxConcurrentJobs), 0, ITEM_DEFAULT, 1},
191 {"TlsAuthenticate", store_bool, ITEM(res_client.tls_authenticate), 0, 0, 0},
192 {"TlsEnable", store_bool, ITEM(res_client.tls_enable), 0, 0, 0},
193 {"TlsRequire", store_bool, ITEM(res_client.tls_require), 0, 0, 0},
194 {"TlsCaCertificateFile", store_dir, ITEM(res_client.tls_ca_certfile), 0, 0, 0},
195 {"TlsCaCertificateDir", store_dir, ITEM(res_client.tls_ca_certdir), 0, 0, 0},
196 {"TlsCertificate", store_dir, ITEM(res_client.tls_certfile), 0, 0, 0},
197 {"TlsKey", store_dir, ITEM(res_client.tls_keyfile), 0, 0, 0},
198 {"TlsAllowedCn", store_alist_str, ITEM(res_client.tls_allowed_cns), 0, 0, 0},
199 {"MaximumBandwidthPerJob", store_speed, ITEM(res_client.max_bandwidth), 0, 0, 0},
200 {"Enabled", store_bool, ITEM(res_client.enabled), 0, ITEM_DEFAULT, true},
201 {NULL, NULL, {0}, 0, 0, 0}
204 /* Storage daemon resource
206 * name handler value code flags default_value
208 static RES_ITEM store_items[] = {
209 {"Name", store_name, ITEM(res_store.hdr.name), 0, ITEM_REQUIRED, 0},
210 {"Description", store_str, ITEM(res_store.hdr.desc), 0, 0, 0},
211 {"SdPort", store_pint32, ITEM(res_store.SDport), 0, ITEM_DEFAULT, 9103},
212 {"sdaddress", store_str, ITEM(res_store.address), 0, 0, 0},
213 {"Address", store_str, ITEM(res_store.address), 0, ITEM_REQUIRED, 0},
214 {"FdStorageAddress", store_str, ITEM(res_store.fd_storage_address), 0, 0, 0},
215 {"sdpassword", store_password, ITEM(res_store.password), 0, 0, 0},
216 {"Password", store_password, ITEM(res_store.password), 0, ITEM_REQUIRED, 0},
217 {"Device", store_device, ITEM(res_store.device), R_DEVICE, ITEM_REQUIRED, 0},
218 {"MediaType", store_strname, ITEM(res_store.media_type), 0, ITEM_REQUIRED, 0},
219 {"Autochanger", store_bool, ITEM(res_store.autochanger), 0, ITEM_DEFAULT, false},
220 {"Enabled", store_bool, ITEM(res_store.enabled), 0, ITEM_DEFAULT, true},
221 {"AllowCompression", store_bool, ITEM(res_store.AllowCompress), 0, ITEM_DEFAULT, true},
222 {"HeartbeatInterval", store_time, ITEM(res_store.heartbeat_interval), 0, ITEM_DEFAULT, 5 * 60},
223 {"MaximumConcurrentJobs", store_pint32, ITEM(res_store.MaxConcurrentJobs), 0, ITEM_DEFAULT, 1},
224 {"MaximumConcurrentReadjobs", store_pint32, ITEM(res_store.MaxConcurrentReadJobs), 0, ITEM_DEFAULT, 0},
225 {"sddport", store_pint32, ITEM(res_store.SDDport), 0, 0, 0}, /* deprecated */
226 {"TlsAuthenticate", store_bool, ITEM(res_store.tls_authenticate), 0, 0, 0},
227 {"TlsEnable", store_bool, ITEM(res_store.tls_enable), 0, 0, 0},
228 {"TlsRequire", store_bool, ITEM(res_store.tls_require), 0, 0, 0},
229 {"TlsCaCertificateFile", store_dir, ITEM(res_store.tls_ca_certfile), 0, 0, 0},
230 {"TlsCaCertificateDir", store_dir, ITEM(res_store.tls_ca_certdir), 0, 0, 0},
231 {"TlsCertificate", store_dir, ITEM(res_store.tls_certfile), 0, 0, 0},
232 {"TlsKey", store_dir, ITEM(res_store.tls_keyfile), 0, 0, 0},
233 {NULL, NULL, {0}, 0, 0, 0}
237 * Catalog Resource Directives
239 * name handler value code flags default_value
241 static RES_ITEM cat_items[] = {
242 {"Name", store_name, ITEM(res_cat.hdr.name), 0, ITEM_REQUIRED, 0},
243 {"Description", store_str, ITEM(res_cat.hdr.desc), 0, 0, 0},
244 {"dbaddress", store_str, ITEM(res_cat.db_address), 0, 0, 0},
245 {"Address", store_str, ITEM(res_cat.db_address), 0, 0, 0},
246 {"DbPort", store_pint32, ITEM(res_cat.db_port), 0, 0, 0},
247 /* keep this password as store_str for the moment */
248 {"dbpassword", store_str, ITEM(res_cat.db_password), 0, 0, 0},
249 {"Password", store_str, ITEM(res_cat.db_password), 0, 0, 0},
250 {"dbuser", store_str, ITEM(res_cat.db_user), 0, 0, 0},
251 {"User", store_str, ITEM(res_cat.db_user), 0, 0, 0},
252 {"DbName", store_str, ITEM(res_cat.db_name), 0, ITEM_REQUIRED, 0},
253 {"dbdriver", store_str, ITEM(res_cat.db_driver), 0, 0, 0},
254 {"DbSocket", store_str, ITEM(res_cat.db_socket), 0, 0, 0},
255 {"dbsslkey", store_str, ITEM(res_cat.db_ssl_key), 0, 0, 0},
256 {"dbsslcert", store_str, ITEM(res_cat.db_ssl_cert), 0, 0, 0},
257 {"dbsslca", store_str, ITEM(res_cat.db_ssl_ca), 0, 0, 0},
258 {"dbsslcapath", store_str, ITEM(res_cat.db_ssl_capath), 0, 0, 0},
259 {"dbsslcipher", store_str, ITEM(res_cat.db_ssl_cipher), 0, 0, 0},
260 /* Turned off for the moment */
261 {"MultipleConnections", store_bit, ITEM(res_cat.mult_db_connections), 0, 0, 0},
262 {"DisableBatchInsert", store_bool, ITEM(res_cat.disable_batch_insert), 0, ITEM_DEFAULT, false},
263 {NULL, NULL, {0}, 0, 0, 0}
267 * Job Resource Directives
269 * name handler value code flags default_value
271 RES_ITEM job_items[] = {
272 {"Name", store_name, ITEM(res_job.hdr.name), 0, ITEM_REQUIRED, 0},
273 {"Description", store_str, ITEM(res_job.hdr.desc), 0, 0, 0},
274 {"Type", store_jobtype, ITEM(res_job.JobType), 0, ITEM_REQUIRED, 0},
275 {"Level", store_level, ITEM(res_job.JobLevel), 0, 0, 0},
276 {"Messages", store_res, ITEM(res_job.messages), R_MSGS, ITEM_REQUIRED, 0},
277 {"Storage", store_alist_res, ITEM(res_job.storage), R_STORAGE, 0, 0},
278 {"Pool", store_res, ITEM(res_job.pool), R_POOL, ITEM_REQUIRED, 0},
279 {"NextPool", store_res, ITEM(res_job.next_pool), R_POOL, 0, 0},
280 {"FullBackupPool", store_res, ITEM(res_job.full_pool), R_POOL, 0, 0},
281 {"IncrementalBackupPool", store_res, ITEM(res_job.inc_pool), R_POOL, 0, 0},
282 {"DifferentialBackupPool", store_res, ITEM(res_job.diff_pool), R_POOL, 0, 0},
283 {"Client", store_res, ITEM(res_job.client), R_CLIENT, ITEM_REQUIRED, 0},
284 {"Fileset", store_res, ITEM(res_job.fileset), R_FILESET, ITEM_REQUIRED, 0},
285 {"Schedule", store_res, ITEM(res_job.schedule), R_SCHEDULE, 0, 0},
286 {"VerifyJob", store_res, ITEM(res_job.verify_job), R_JOB, 0, 0},
287 {"JobToVerify", store_res, ITEM(res_job.verify_job), R_JOB, 0, 0},
288 {"JobDefs", store_res, ITEM(res_job.jobdefs), R_JOBDEFS, 0, 0},
289 {"Run", store_alist_str, ITEM(res_job.run_cmds), 0, 0, 0},
290 /* Root of where to restore files */
291 {"Where", store_dir, ITEM(res_job.RestoreWhere), 0, 0, 0},
292 {"RegexWhere", store_str, ITEM(res_job.RegexWhere), 0, 0, 0},
293 {"StripPrefix", store_str, ITEM(res_job.strip_prefix), 0, 0, 0},
294 {"AddPrefix", store_str, ITEM(res_job.add_prefix), 0, 0, 0},
295 {"AddSuffix", store_str, ITEM(res_job.add_suffix), 0, 0, 0},
296 /* Where to find bootstrap during restore */
297 {"Bootstrap",store_dir, ITEM(res_job.RestoreBootstrap), 0, 0, 0},
298 /* Where to write bootstrap file during backup */
299 {"WriteBootstrap",store_dir, ITEM(res_job.WriteBootstrap), 0, 0, 0},
300 {"WriteVerifyList",store_dir,ITEM(res_job.WriteVerifyList), 0, 0, 0},
301 {"Replace", store_replace, ITEM(res_job.replace), 0, ITEM_DEFAULT, REPLACE_ALWAYS},
302 {"MaximumBandwidth", store_speed, ITEM(res_job.max_bandwidth), 0, 0, 0},
303 {"MaxRunSchedTime", store_time, ITEM(res_job.MaxRunSchedTime), 0, 0, 0},
304 {"MaxRunTime", store_time, ITEM(res_job.MaxRunTime), 0, 0, 0},
305 /* xxxMaxWaitTime are deprecated */
306 {"fullmaxwaittime", store_time, ITEM(res_job.FullMaxRunTime), 0, 0, 0},
307 {"incrementalmaxwaittime", store_time, ITEM(res_job.IncMaxRunTime), 0, 0, 0},
308 {"differentialmaxwaittime", store_time, ITEM(res_job.DiffMaxRunTime), 0, 0, 0},
309 {"FullMaxRunTime", store_time, ITEM(res_job.FullMaxRunTime), 0, 0, 0},
310 {"IncrementalMaxRunTime", store_time, ITEM(res_job.IncMaxRunTime), 0, 0, 0},
311 {"DifferentialMaxRunTime", store_time, ITEM(res_job.DiffMaxRunTime), 0, 0, 0},
312 {"MaxWaitTime", store_time, ITEM(res_job.MaxWaitTime), 0, 0, 0},
313 {"MaxStartDelay",store_time, ITEM(res_job.MaxStartDelay), 0, 0, 0},
314 {"MaxFullInterval", store_time, ITEM(res_job.MaxFullInterval), 0, 0, 0},
315 {"MaxDiffInterval", store_time, ITEM(res_job.MaxDiffInterval), 0, 0, 0},
316 {"PrefixLinks", store_bool, ITEM(res_job.PrefixLinks), 0, ITEM_DEFAULT, false},
317 {"PruneJobs", store_bool, ITEM(res_job.PruneJobs), 0, ITEM_DEFAULT, false},
318 {"PruneFiles", store_bool, ITEM(res_job.PruneFiles), 0, ITEM_DEFAULT, false},
319 {"PruneVolumes",store_bool, ITEM(res_job.PruneVolumes), 0, ITEM_DEFAULT, false},
320 {"PurgeMigrationJob", store_bool, ITEM(res_job.PurgeMigrateJob), 0, ITEM_DEFAULT, false},
321 {"Enabled", store_bool, ITEM(res_job.enabled), 0, ITEM_DEFAULT, true},
322 {"SnapshotRetention", store_time, ITEM(res_job.SnapRetention), 0, ITEM_DEFAULT, 0},
323 {"SpoolAttributes",store_bool, ITEM(res_job.SpoolAttributes), 0, ITEM_DEFAULT, true},
324 {"SpoolData", store_bool, ITEM(res_job.spool_data), 0, ITEM_DEFAULT, false},
325 {"SpoolSize", store_size64, ITEM(res_job.spool_size), 0, 0, 0},
326 {"ReRunFailedLevels", store_bool, ITEM(res_job.rerun_failed_levels), 0, ITEM_DEFAULT, false},
327 {"PreferMountedVolumes", store_bool, ITEM(res_job.PreferMountedVolumes), 0, ITEM_DEFAULT, true},
328 {"RunBeforeJob", store_short_runscript, ITEM(res_job.RunScripts), 0, 0, 0},
329 {"RunAfterJob", store_short_runscript, ITEM(res_job.RunScripts), 0, 0, 0},
330 {"RunAfterFailedJob", store_short_runscript, ITEM(res_job.RunScripts), 0, 0, 0},
331 {"ClientRunBeforeJob", store_short_runscript, ITEM(res_job.RunScripts), 0, 0, 0},
332 {"ClientRunAfterJob", store_short_runscript, ITEM(res_job.RunScripts), 0, 0, 0},
333 {"ConsoleRunBeforeJob", store_short_runscript, ITEM(res_job.RunScripts), 0, 0, 0},
334 {"ConsoleRunAfterJob", store_short_runscript, ITEM(res_job.RunScripts), 0, 0, 0},
335 {"Runscript", store_runscript, ITEM(res_job.RunScripts), 0, ITEM_NO_EQUALS, 0},
336 {"MaximumConcurrentJobs", store_pint32, ITEM(res_job.MaxConcurrentJobs), 0, ITEM_DEFAULT, 1},
337 {"MaximumSpawnedJobs", store_pint32, ITEM(res_job.MaxSpawnedJobs), 0, ITEM_DEFAULT, 600},
338 {"RescheduleOnError", store_bool, ITEM(res_job.RescheduleOnError), 0, ITEM_DEFAULT, false},
339 {"RescheduleIncompleteJobs", store_bool, ITEM(res_job.RescheduleIncompleteJobs), 0, ITEM_DEFAULT, true},
340 {"RescheduleInterval", store_time, ITEM(res_job.RescheduleInterval), 0, ITEM_DEFAULT, 60 * 30},
341 {"RescheduleTimes", store_pint32, ITEM(res_job.RescheduleTimes), 0, 0, 0},
342 {"Priority", store_pint32, ITEM(res_job.Priority), 0, ITEM_DEFAULT, 10},
343 {"AllowMixedPriority", store_bool, ITEM(res_job.allow_mixed_priority), 0, ITEM_DEFAULT, false},
344 {"WritePartAfterJob", store_bool, ITEM(res_job.write_part_after_job), 0, ITEM_DEFAULT, true},
345 {"SelectionPattern", store_str, ITEM(res_job.selection_pattern), 0, 0, 0},
346 {"SelectionType", store_migtype, ITEM(res_job.selection_type), 0, 0, 0},
347 {"Accurate", store_bool, ITEM(res_job.accurate), 0,0,0},
348 {"AllowDuplicateJobs", store_bool, ITEM(res_job.AllowDuplicateJobs), 0, ITEM_DEFAULT, true},
349 {"allowhigherduplicates", store_bool, ITEM(res_job.AllowHigherDuplicates), 0, ITEM_DEFAULT, true},
350 {"CancelLowerLevelDuplicates", store_bool, ITEM(res_job.CancelLowerLevelDuplicates), 0, ITEM_DEFAULT, false},
351 {"CancelQueuedDuplicates", store_bool, ITEM(res_job.CancelQueuedDuplicates), 0, ITEM_DEFAULT, false},
352 {"CancelRunningDuplicates", store_bool, ITEM(res_job.CancelRunningDuplicates), 0, ITEM_DEFAULT, false},
353 {"PluginOptions", store_str, ITEM(res_job.PluginOptions), 0, 0, 0},
354 {"Base", store_alist_res, ITEM(res_job.base), R_JOB, 0, 0},
355 {NULL, NULL, {0}, 0, 0, 0}
360 * Name handler value code flags default_value
362 static RES_ITEM fs_items[] = {
363 {"Name", store_name, ITEM(res_fs.hdr.name), 0, ITEM_REQUIRED, 0},
364 {"Description", store_str, ITEM(res_fs.hdr.desc), 0, 0, 0},
365 {"IgnoreFilesetChanges", store_bool, ITEM(res_fs.ignore_fs_changes), 0, ITEM_DEFAULT, false},
366 {"EnableVss", store_bool, ITEM(res_fs.enable_vss), 0, ITEM_DEFAULT, true},
367 {"EnableSnapshot",store_bool, ITEM(res_fs.enable_snapshot), 0, ITEM_DEFAULT, false},
368 {"Include", store_inc, {0}, 0, ITEM_NO_EQUALS, 0},
369 {"Exclude", store_inc, {0}, 1, ITEM_NO_EQUALS, 0},
370 {NULL, NULL, {0}, 0, 0, 0}
373 /* Schedule -- see run_conf.c */
376 * name handler value code flags default_value
378 static RES_ITEM sch_items[] = {
379 {"Name", store_name, ITEM(res_sch.hdr.name), 0, ITEM_REQUIRED, 0},
380 {"Description", store_str, ITEM(res_sch.hdr.desc), 0, 0, 0},
381 {"Run", store_run, ITEM(res_sch.run), 0, 0, 0},
382 {"Enabled", store_bool, ITEM(res_sch.enabled), 0, ITEM_DEFAULT, true},
383 {NULL, NULL, {0}, 0, 0, 0}
388 * name handler value code flags default_value
390 static RES_ITEM pool_items[] = {
391 {"Name", store_name, ITEM(res_pool.hdr.name), 0, ITEM_REQUIRED, 0},
392 {"Description", store_str, ITEM(res_pool.hdr.desc), 0, 0, 0},
393 {"PoolType", store_strname, ITEM(res_pool.pool_type), 0, ITEM_REQUIRED, 0},
394 {"LabelFormat", store_strname, ITEM(res_pool.label_format), 0, 0, 0},
395 {"LabelType", store_label, ITEM(res_pool.LabelType), 0, 0, 0},
396 {"CleaningPrefix", store_strname, ITEM(res_pool.cleaning_prefix), 0, 0, 0},
397 {"UseCatalog", store_bool, ITEM(res_pool.use_catalog), 0, ITEM_DEFAULT, true},
398 {"UseVolumeOnce", store_bool, ITEM(res_pool.use_volume_once), 0, 0, 0},
399 {"PurgeOldestVolume", store_bool, ITEM(res_pool.purge_oldest_volume), 0, 0, 0},
400 {"ActionOnPurge", store_actiononpurge, ITEM(res_pool.action_on_purge), 0, 0, 0},
401 {"RecycleOldestVolume", store_bool, ITEM(res_pool.recycle_oldest_volume), 0, 0, 0},
402 {"RecycleCurrentVolume", store_bool, ITEM(res_pool.recycle_current_volume), 0, 0, 0},
403 {"MaximumVolumes", store_pint32, ITEM(res_pool.max_volumes), 0, 0, 0},
404 {"MaximumVolumeJobs", store_pint32, ITEM(res_pool.MaxVolJobs), 0, 0, 0},
405 {"MaximumVolumeFiles", store_pint32, ITEM(res_pool.MaxVolFiles), 0, 0, 0},
406 {"MaximumVolumeBytes", store_size64, ITEM(res_pool.MaxVolBytes), 0, 0, 0},
407 {"CatalogFiles", store_bool, ITEM(res_pool.catalog_files), 0, ITEM_DEFAULT, true},
408 {"VolumeRetention", store_time, ITEM(res_pool.VolRetention), 0, ITEM_DEFAULT, 60*60*24*365},
409 {"VolumeUseDuration", store_time, ITEM(res_pool.VolUseDuration), 0, 0, 0},
410 {"MigrationTime", store_time, ITEM(res_pool.MigrationTime), 0, 0, 0},
411 {"MigrationHighBytes", store_size64, ITEM(res_pool.MigrationHighBytes), 0, 0, 0},
412 {"MigrationLowBytes", store_size64, ITEM(res_pool.MigrationLowBytes), 0, 0, 0},
413 {"NextPool", store_res, ITEM(res_pool.NextPool), R_POOL, 0, 0},
414 {"Storage", store_alist_res, ITEM(res_pool.storage), R_STORAGE, 0, 0},
415 {"AutoPrune", store_bool, ITEM(res_pool.AutoPrune), 0, ITEM_DEFAULT, true},
416 {"Recycle", store_bool, ITEM(res_pool.Recycle), 0, ITEM_DEFAULT, true},
417 {"RecyclePool", store_res, ITEM(res_pool.RecyclePool), R_POOL, 0, 0},
418 {"ScratchPool", store_res, ITEM(res_pool.ScratchPool), R_POOL, 0, 0},
419 {"CopyPool", store_alist_res, ITEM(res_pool.CopyPool), R_POOL, 0, 0},
420 {"Catalog", store_res, ITEM(res_pool.catalog), R_CATALOG, 0, 0},
421 {"FileRetention", store_time, ITEM(res_pool.FileRetention), 0, 0, 0},
422 {"JobRetention", store_time, ITEM(res_pool.JobRetention), 0, 0, 0},
424 {NULL, NULL, {0}, 0, 0, 0}
429 * name handler value code flags default_value
431 static RES_ITEM counter_items[] = {
432 {"Name", store_name, ITEM(res_counter.hdr.name), 0, ITEM_REQUIRED, 0},
433 {"Description", store_str, ITEM(res_counter.hdr.desc), 0, 0, 0},
434 {"Minimum", store_int32, ITEM(res_counter.MinValue), 0, ITEM_DEFAULT, 0},
435 {"Maximum", store_pint32, ITEM(res_counter.MaxValue), 0, ITEM_DEFAULT, INT32_MAX},
436 {"WrapCounter", store_res, ITEM(res_counter.WrapCounter), R_COUNTER, 0, 0},
437 {"Catalog", store_res, ITEM(res_counter.Catalog), R_CATALOG, 0, 0},
438 {NULL, NULL, {0}, 0, 0, 0}
442 /* Message resource */
443 extern RES_ITEM msgs_items[];
446 * This is the master resource definition.
447 * It must have one item for each of the resources.
449 * NOTE!!! keep it in the same order as the R_codes
450 * or eliminate all resources[rindex].name
454 RES_TABLE resources[] = {
455 {"Director", dir_items, R_DIRECTOR},
456 {"Client", cli_items, R_CLIENT},
457 {"Job", job_items, R_JOB},
458 {"Storage", store_items, R_STORAGE},
459 {"Catalog", cat_items, R_CATALOG},
460 {"Schedule", sch_items, R_SCHEDULE},
461 {"Fileset", fs_items, R_FILESET},
462 {"Pool", pool_items, R_POOL},
463 {"Messages", msgs_items, R_MSGS},
464 {"Counter", counter_items, R_COUNTER},
465 {"Console", con_items, R_CONSOLE},
466 {"JobDefs", job_items, R_JOBDEFS},
467 {"Device", NULL, R_DEVICE}, /* info obtained from SD */
472 /* Keywords (RHS) permitted in Job Level records
474 * level_name level job_type
476 struct s_jl joblevels[] = {
477 {"Full", L_FULL, JT_BACKUP},
478 {"Base", L_BASE, JT_BACKUP},
479 {"Incremental", L_INCREMENTAL, JT_BACKUP},
480 {"Differential", L_DIFFERENTIAL, JT_BACKUP},
481 {"Since", L_SINCE, JT_BACKUP},
482 {"VirtualFull", L_VIRTUAL_FULL, JT_BACKUP},
483 {"Catalog", L_VERIFY_CATALOG, JT_VERIFY},
484 {"InitCatalog", L_VERIFY_INIT, JT_VERIFY},
485 {"VolumeToCatalog", L_VERIFY_VOLUME_TO_CATALOG, JT_VERIFY},
486 {"DiskToCatalog", L_VERIFY_DISK_TO_CATALOG, JT_VERIFY},
487 {"Data", L_VERIFY_DATA, JT_VERIFY},
488 {"Full", L_FULL, JT_COPY},
489 {"Incremental", L_INCREMENTAL, JT_COPY},
490 {"Differential", L_DIFFERENTIAL, JT_COPY},
491 {"Full", L_FULL, JT_MIGRATE},
492 {"Incremental", L_INCREMENTAL, JT_MIGRATE},
493 {"Differential", L_DIFFERENTIAL, JT_MIGRATE},
494 {" ", L_NONE, JT_ADMIN},
495 {" ", L_NONE, JT_RESTORE},
500 /* Keywords (RHS) permitted in Job type records
505 {"Backup", JT_BACKUP},
507 {"Verify", JT_VERIFY},
508 {"Restore", JT_RESTORE},
509 {"Migrate", JT_MIGRATE},
515 /* Keywords (RHS) permitted in Selection type records
520 {"SmallestVolume", MT_SMALLEST_VOL},
521 {"OldestVolume", MT_OLDEST_VOL},
522 {"PoolOccupancy", MT_POOL_OCCUPANCY},
523 {"PoolTime", MT_POOL_TIME},
524 {"PoolUncopiedJobs", MT_POOL_UNCOPIED_JOBS},
525 {"Client", MT_CLIENT},
526 {"Volume", MT_VOLUME},
528 {"SqlQuery", MT_SQLQUERY},
534 /* Options permitted in Restore replace= */
535 struct s_kw ReplaceOptions[] = {
536 {"Always", REPLACE_ALWAYS},
537 {"IfNewer", REPLACE_IFNEWER},
538 {"IfOlder", REPLACE_IFOLDER},
539 {"Never", REPLACE_NEVER},
543 char *CAT::display(POOLMEM *dst) {
544 Mmsg(dst,"catalog=%s\ndb_name=%s\ndb_driver=%s\ndb_user=%s\n"
545 "db_password=%s\ndb_address=%s\ndb_port=%i\n"
547 name(), NPRTB(db_name),
548 NPRTB(db_driver), NPRTB(db_user), NPRTB(db_password),
549 NPRTB(db_address), db_port, NPRTB(db_socket));
553 const char *level_to_str(int level)
556 static char level_no[30];
557 const char *str = level_no;
559 bsnprintf(level_no, sizeof(level_no), "%c (%d)", level, level); /* default if not found */
560 for (i=0; joblevels[i].level_name; i++) {
561 if (level == (int)joblevels[i].level) {
562 str = joblevels[i].level_name;
569 /* Dump contents of resource */
570 void dump_resource(int type, RES *ares, void sendit(void *sock, const char *fmt, ...), void *sock)
572 URES *res = (URES *)ares;
574 char ed1[100], ed2[100], ed3[100];
576 UAContext *ua = (UAContext *)sock;
579 sendit(sock, _("No %s resource defined\n"), res_to_str(type));
582 if (type < 0) { /* no recursion */
588 sendit(sock, _("Director: name=%s MaxJobs=%d FDtimeout=%s SDtimeout=%s\n"),
589 ares->name, res->res_dir.MaxConcurrentJobs,
590 edit_uint64(res->res_dir.FDConnectTimeout, ed1),
591 edit_uint64(res->res_dir.SDConnectTimeout, ed2));
592 if (res->res_dir.query_file) {
593 sendit(sock, _(" query_file=%s\n"), res->res_dir.query_file);
595 if (res->res_dir.messages) {
596 sendit(sock, _(" --> "));
597 dump_resource(-R_MSGS, (RES *)res->res_dir.messages, sendit, sock);
601 sendit(sock, _("Console: name=%s SSL=%d\n"),
602 res->res_con.hdr.name, res->res_con.tls_enable);
605 if (res->res_counter.WrapCounter) {
606 sendit(sock, _("Counter: name=%s min=%d max=%d cur=%d wrapcntr=%s\n"),
607 res->res_counter.hdr.name, res->res_counter.MinValue,
608 res->res_counter.MaxValue, res->res_counter.CurrentValue,
609 res->res_counter.WrapCounter->hdr.name);
611 sendit(sock, _("Counter: name=%s min=%d max=%d\n"),
612 res->res_counter.hdr.name, res->res_counter.MinValue,
613 res->res_counter.MaxValue);
615 if (res->res_counter.Catalog) {
616 sendit(sock, _(" --> "));
617 dump_resource(-R_CATALOG, (RES *)res->res_counter.Catalog, sendit, sock);
622 if (!acl_access_ok(ua, Client_ACL, res->res_client.hdr.name)) {
625 sendit(sock, _("Client: Name=%s Enabled=%d Address=%s FDport=%d MaxJobs=%u\n"),
626 res->res_client.hdr.name, res->res_client.enabled,
627 res->res_client.address, res->res_client.FDport,
628 res->res_client.MaxConcurrentJobs);
629 sendit(sock, _(" JobRetention=%s FileRetention=%s AutoPrune=%d\n"),
630 edit_utime(res->res_client.JobRetention, ed1, sizeof(ed1)),
631 edit_utime(res->res_client.FileRetention, ed2, sizeof(ed2)),
632 res->res_client.AutoPrune);
633 if (res->res_client.fd_storage_address) {
634 sendit(sock, " FDStorageAddress=%s\n", res->res_client.fd_storage_address);
636 if (res->res_client.max_bandwidth) {
637 sendit(sock, _(" MaximumBandwidth=%lld\n"),
638 res->res_client.max_bandwidth);
640 if (res->res_client.catalog) {
641 sendit(sock, _(" --> "));
642 dump_resource(-R_CATALOG, (RES *)res->res_client.catalog, sendit, sock);
649 sendit(sock, _("Device: name=%s ok=%d num_writers=%d max_writers=%d\n"
650 " reserved=%d open=%d append=%d read=%d labeled=%d offline=%d autochgr=%d\n"
651 " poolid=%s volname=%s MediaType=%s\n"),
652 dev->hdr.name, dev->found, dev->num_writers, dev->max_writers,
653 dev->reserved, dev->open, dev->append, dev->read, dev->labeled,
654 dev->offline, dev->autochanger,
655 edit_uint64(dev->PoolId, ed1),
656 dev->VolumeName, dev->MediaType);
660 if (!acl_access_ok(ua, Storage_ACL, res->res_store.hdr.name)) {
663 sendit(sock, _("Storage: name=%s address=%s SDport=%d MaxJobs=%u\n"
664 " DeviceName=%s MediaType=%s StorageId=%s Autochanger=%d\n"),
665 res->res_store.hdr.name, res->res_store.address, res->res_store.SDport,
666 res->res_store.MaxConcurrentJobs,
667 res->res_store.dev_name(),
668 res->res_store.media_type,
669 edit_int64(res->res_store.StorageId, ed1),
670 res->res_store.autochanger);
671 if (res->res_store.fd_storage_address) {
672 sendit(sock, " FDStorageAddress=%s\n", res->res_store.fd_storage_address);
677 if (!acl_access_ok(ua, Catalog_ACL, res->res_cat.hdr.name)) {
680 sendit(sock, _("Catalog: name=%s address=%s DBport=%d db_name=%s\n"
681 " db_driver=%s db_user=%s MutliDBConn=%d\n"),
682 res->res_cat.hdr.name, NPRT(res->res_cat.db_address),
683 res->res_cat.db_port, res->res_cat.db_name,
684 NPRT(res->res_cat.db_driver), NPRT(res->res_cat.db_user),
685 res->res_cat.mult_db_connections);
690 if (!acl_access_ok(ua, Job_ACL, res->res_job.hdr.name)) {
693 sendit(sock, _("%s: name=%s JobType=%d level=%s Priority=%d Enabled=%d\n"),
694 type == R_JOB ? _("Job") : _("JobDefs"),
695 res->res_job.hdr.name, res->res_job.JobType,
696 level_to_str(res->res_job.JobLevel), res->res_job.Priority,
697 res->res_job.enabled);
698 sendit(sock, _(" MaxJobs=%u Resched=%d Times=%d Interval=%s Spool=%d WritePartAfterJob=%d\n"),
699 res->res_job.MaxConcurrentJobs,
700 res->res_job.RescheduleOnError, res->res_job.RescheduleTimes,
701 edit_uint64_with_commas(res->res_job.RescheduleInterval, ed1),
702 res->res_job.spool_data, res->res_job.write_part_after_job);
703 if (res->res_job.spool_size) {
704 sendit(sock, _(" SpoolSize=%s\n"), edit_uint64(res->res_job.spool_size, ed1));
706 if (res->res_job.JobType == JT_BACKUP) {
707 sendit(sock, _(" Accurate=%d\n"), res->res_job.accurate);
709 if (res->res_job.max_bandwidth) {
710 sendit(sock, _(" MaximumBandwidth=%lld\n"),
711 res->res_job.max_bandwidth);
713 if (res->res_job.JobType == JT_MIGRATE || res->res_job.JobType == JT_COPY) {
714 sendit(sock, _(" SelectionType=%d\n"), res->res_job.selection_type);
716 if (res->res_job.JobType == JT_RESTORE) {
717 sendit(sock, _(" PrefixLinks=%d\n"), res->res_job.PrefixLinks);
719 if (res->res_job.client) {
720 sendit(sock, _(" --> "));
721 dump_resource(-R_CLIENT, (RES *)res->res_job.client, sendit, sock);
723 if (res->res_job.fileset) {
724 sendit(sock, _(" --> "));
725 dump_resource(-R_FILESET, (RES *)res->res_job.fileset, sendit, sock);
727 if (res->res_job.schedule) {
728 sendit(sock, _(" --> "));
729 dump_resource(-R_SCHEDULE, (RES *)res->res_job.schedule, sendit, sock);
731 if (res->res_job.RestoreWhere && !res->res_job.RegexWhere) {
732 sendit(sock, _(" --> Where=%s\n"), NPRT(res->res_job.RestoreWhere));
734 if (res->res_job.RegexWhere) {
735 sendit(sock, _(" --> RegexWhere=%s\n"), NPRT(res->res_job.RegexWhere));
737 if (res->res_job.RestoreBootstrap) {
738 sendit(sock, _(" --> Bootstrap=%s\n"), NPRT(res->res_job.RestoreBootstrap));
740 if (res->res_job.WriteBootstrap) {
741 sendit(sock, _(" --> WriteBootstrap=%s\n"), NPRT(res->res_job.WriteBootstrap));
743 if (res->res_job.PluginOptions) {
744 sendit(sock, _(" --> PluginOptions=%s\n"), NPRT(res->res_job.PluginOptions));
746 if (res->res_job.MaxRunTime) {
747 sendit(sock, _(" --> MaxRunTime=%u\n"), res->res_job.MaxRunTime);
749 if (res->res_job.MaxWaitTime) {
750 sendit(sock, _(" --> MaxWaitTime=%u\n"), res->res_job.MaxWaitTime);
752 if (res->res_job.MaxStartDelay) {
753 sendit(sock, _(" --> MaxStartDelay=%u\n"), res->res_job.MaxStartDelay);
755 if (res->res_job.MaxRunSchedTime) {
756 sendit(sock, _(" --> MaxRunSchedTime=%u\n"), res->res_job.MaxRunSchedTime);
758 if (res->res_job.storage) {
760 foreach_alist(store, res->res_job.storage) {
761 sendit(sock, _(" --> "));
762 dump_resource(-R_STORAGE, (RES *)store, sendit, sock);
765 if (res->res_job.base) {
767 foreach_alist(job, res->res_job.base) {
768 sendit(sock, _(" --> Base %s\n"), job->name());
771 if (res->res_job.RunScripts) {
773 foreach_alist(script, res->res_job.RunScripts) {
774 sendit(sock, _(" --> RunScript\n"));
775 sendit(sock, _(" --> Command=%s\n"), NPRT(script->command));
776 sendit(sock, _(" --> Target=%s\n"), NPRT(script->target));
777 sendit(sock, _(" --> RunOnSuccess=%u\n"), script->on_success);
778 sendit(sock, _(" --> RunOnFailure=%u\n"), script->on_failure);
779 sendit(sock, _(" --> FailJobOnError=%u\n"), script->fail_on_error);
780 sendit(sock, _(" --> RunWhen=%u\n"), script->when);
783 if (res->res_job.pool) {
784 sendit(sock, _(" --> "));
785 dump_resource(-R_POOL, (RES *)res->res_job.pool, sendit, sock);
787 if (res->res_job.full_pool) {
788 sendit(sock, _(" --> FullBackup"));
789 dump_resource(-R_POOL, (RES *)res->res_job.full_pool, sendit, sock);
791 if (res->res_job.inc_pool) {
792 sendit(sock, _(" --> IncrementalBackup"));
793 dump_resource(-R_POOL, (RES *)res->res_job.inc_pool, sendit, sock);
795 if (res->res_job.diff_pool) {
796 sendit(sock, _(" --> DifferentialBackup"));
797 dump_resource(-R_POOL, (RES *)res->res_job.diff_pool, sendit, sock);
799 if (res->res_job.verify_job) {
800 sendit(sock, _(" --> "));
801 dump_resource(-type, (RES *)res->res_job.verify_job, sendit, sock);
803 if (res->res_job.run_cmds) {
805 foreach_alist(runcmd, res->res_job.run_cmds) {
806 sendit(sock, _(" --> Run=%s\n"), runcmd);
809 if (res->res_job.selection_pattern) {
810 sendit(sock, _(" --> SelectionPattern=%s\n"), NPRT(res->res_job.selection_pattern));
812 if (res->res_job.messages) {
813 sendit(sock, _(" --> "));
814 dump_resource(-R_MSGS, (RES *)res->res_job.messages, sendit, sock);
821 if (!acl_access_ok(ua, FileSet_ACL, res->res_fs.hdr.name)) {
824 sendit(sock, _("FileSet: name=%s\n"), res->res_fs.hdr.name);
825 for (i=0; i<res->res_fs.num_includes; i++) {
826 INCEXE *incexe = res->res_fs.include_items[i];
827 for (j=0; j<incexe->num_opts; j++) {
828 FOPTS *fo = incexe->opts_list[j];
829 sendit(sock, " O %s\n", fo->opts);
831 bool enhanced_wild = false;
832 for (k=0; fo->opts[k]!='\0'; k++) {
833 if (fo->opts[k]=='W') {
834 enhanced_wild = true;
839 for (k=0; k<fo->regex.size(); k++) {
840 sendit(sock, " R %s\n", fo->regex.get(k));
842 for (k=0; k<fo->regexdir.size(); k++) {
843 sendit(sock, " RD %s\n", fo->regexdir.get(k));
845 for (k=0; k<fo->regexfile.size(); k++) {
846 sendit(sock, " RF %s\n", fo->regexfile.get(k));
848 for (k=0; k<fo->wild.size(); k++) {
849 sendit(sock, " W %s\n", fo->wild.get(k));
851 for (k=0; k<fo->wilddir.size(); k++) {
852 sendit(sock, " WD %s\n", fo->wilddir.get(k));
854 for (k=0; k<fo->wildfile.size(); k++) {
855 sendit(sock, " WF %s\n", fo->wildfile.get(k));
857 for (k=0; k<fo->wildbase.size(); k++) {
858 sendit(sock, " W%c %s\n", enhanced_wild ? 'B' : 'F', fo->wildbase.get(k));
860 for (k=0; k<fo->base.size(); k++) {
861 sendit(sock, " B %s\n", fo->base.get(k));
863 for (k=0; k<fo->fstype.size(); k++) {
864 sendit(sock, " X %s\n", fo->fstype.get(k));
866 for (k=0; k<fo->drivetype.size(); k++) {
867 sendit(sock, " XD %s\n", fo->drivetype.get(k));
870 sendit(sock, " G %s\n", fo->plugin);
873 sendit(sock, " D %s\n", fo->reader);
876 sendit(sock, " T %s\n", fo->writer);
878 sendit(sock, " N\n");
880 if (incexe->ignoredir) {
881 sendit(sock, " Z %s\n", incexe->ignoredir);
883 for (j=0; j<incexe->name_list.size(); j++) {
884 sendit(sock, " I %s\n", incexe->name_list.get(j));
886 if (incexe->name_list.size()) {
887 sendit(sock, " N\n");
889 for (j=0; j<incexe->plugin_list.size(); j++) {
890 sendit(sock, " P %s\n", incexe->plugin_list.get(j));
892 if (incexe->plugin_list.size()) {
893 sendit(sock, " N\n");
895 } /* end for over includes */
897 for (i=0; i<res->res_fs.num_excludes; i++) {
898 INCEXE *incexe = res->res_fs.exclude_items[i];
899 for (j=0; j<incexe->name_list.size(); j++) {
900 sendit(sock, " E %s\n", incexe->name_list.get(j));
902 if (incexe->name_list.size()) {
903 sendit(sock, " N\n");
907 } /* end case R_FILESET */
910 if (!acl_access_ok(ua, Schedule_ACL, res->res_sch.hdr.name)) {
914 if (res->res_sch.run) {
916 RUN *run = res->res_sch.run;
917 char buf[1000], num[30];
918 sendit(sock, _("Schedule: Name=%s Enabled=%d\n"),
919 res->res_sch.hdr.name, res->res_sch.enabled);
924 sendit(sock, _(" --> Run Level=%s\n"), level_to_str(run->level));
925 if (run->MaxRunSchedTime) {
926 sendit(sock, _(" MaxRunSchedTime=%u\n"), run->MaxRunSchedTime);
929 sendit(sock, _(" Priority=%u\n"), run->Priority);
931 bstrncpy(buf, _(" hour="), sizeof(buf));
932 for (i=0; i<24; i++) {
933 if (bit_is_set(i, run->hour)) {
934 bsnprintf(num, sizeof(num), "%d ", i);
935 bstrncat(buf, num, sizeof(buf));
938 bstrncat(buf, "\n", sizeof(buf));
940 bstrncpy(buf, _(" mday="), sizeof(buf));
941 for (i=0; i<32; i++) {
942 if (bit_is_set(i, run->mday)) {
943 bsnprintf(num, sizeof(num), "%d ", i);
944 bstrncat(buf, num, sizeof(buf));
947 bstrncat(buf, "\n", sizeof(buf));
949 bstrncpy(buf, _(" month="), sizeof(buf));
950 for (i=0; i<12; i++) {
951 if (bit_is_set(i, run->month)) {
952 bsnprintf(num, sizeof(num), "%d ", i);
953 bstrncat(buf, num, sizeof(buf));
956 bstrncat(buf, "\n", sizeof(buf));
958 bstrncpy(buf, _(" wday="), sizeof(buf));
959 for (i=0; i<7; i++) {
960 if (bit_is_set(i, run->wday)) {
961 bsnprintf(num, sizeof(num), "%d ", i);
962 bstrncat(buf, num, sizeof(buf));
965 bstrncat(buf, "\n", sizeof(buf));
967 bstrncpy(buf, _(" wom="), sizeof(buf));
968 for (i=0; i<6; i++) {
969 if (bit_is_set(i, run->wom)) {
970 bsnprintf(num, sizeof(num), "%d ", i);
971 bstrncat(buf, num, sizeof(buf));
974 bstrncat(buf, "\n", sizeof(buf));
976 bstrncpy(buf, _(" woy="), sizeof(buf));
977 for (i=0; i<54; i++) {
978 if (bit_is_set(i, run->woy)) {
979 bsnprintf(num, sizeof(num), "%d ", i);
980 bstrncat(buf, num, sizeof(buf));
983 bstrncat(buf, "\n", sizeof(buf));
985 sendit(sock, _(" mins=%d\n"), run->minute);
987 sendit(sock, _(" --> "));
988 dump_resource(-R_POOL, (RES *)run->pool, sendit, sock);
991 sendit(sock, _(" --> "));
992 dump_resource(-R_STORAGE, (RES *)run->storage, sendit, sock);
995 sendit(sock, _(" --> "));
996 dump_resource(-R_MSGS, (RES *)run->msgs, sendit, sock);
998 /* If another Run record is chained in, go print it */
1004 sendit(sock, _("Schedule: name=%s\n"), res->res_sch.hdr.name);
1009 if (!acl_access_ok(ua, Pool_ACL, res->res_pool.hdr.name)) {
1012 sendit(sock, _("Pool: name=%s PoolType=%s\n"), res->res_pool.hdr.name,
1013 res->res_pool.pool_type);
1014 sendit(sock, _(" use_cat=%d use_once=%d cat_files=%d\n"),
1015 res->res_pool.use_catalog, res->res_pool.use_volume_once,
1016 res->res_pool.catalog_files);
1017 sendit(sock, _(" max_vols=%d auto_prune=%d VolRetention=%s\n"),
1018 res->res_pool.max_volumes, res->res_pool.AutoPrune,
1019 edit_utime(res->res_pool.VolRetention, ed1, sizeof(ed1)));
1020 sendit(sock, _(" VolUse=%s recycle=%d LabelFormat=%s\n"),
1021 edit_utime(res->res_pool.VolUseDuration, ed1, sizeof(ed1)),
1022 res->res_pool.Recycle,
1023 NPRT(res->res_pool.label_format));
1024 sendit(sock, _(" CleaningPrefix=%s LabelType=%d\n"),
1025 NPRT(res->res_pool.cleaning_prefix), res->res_pool.LabelType);
1026 sendit(sock, _(" RecyleOldest=%d PurgeOldest=%d ActionOnPurge=%d\n"),
1027 res->res_pool.recycle_oldest_volume,
1028 res->res_pool.purge_oldest_volume,
1029 res->res_pool.action_on_purge);
1030 sendit(sock, _(" MaxVolJobs=%d MaxVolFiles=%d MaxVolBytes=%s\n"),
1031 res->res_pool.MaxVolJobs,
1032 res->res_pool.MaxVolFiles,
1033 edit_uint64(res->res_pool.MaxVolBytes, ed1));
1034 sendit(sock, _(" MigTime=%s MigHiBytes=%s MigLoBytes=%s\n"),
1035 edit_utime(res->res_pool.MigrationTime, ed1, sizeof(ed1)),
1036 edit_uint64(res->res_pool.MigrationHighBytes, ed2),
1037 edit_uint64(res->res_pool.MigrationLowBytes, ed3));
1038 sendit(sock, _(" JobRetention=%s FileRetention=%s\n"),
1039 edit_utime(res->res_pool.JobRetention, ed1, sizeof(ed1)),
1040 edit_utime(res->res_pool.FileRetention, ed2, sizeof(ed2)));
1041 if (res->res_pool.NextPool) {
1042 sendit(sock, _(" NextPool=%s\n"), res->res_pool.NextPool->name());
1044 if (res->res_pool.RecyclePool) {
1045 sendit(sock, _(" RecyclePool=%s\n"), res->res_pool.RecyclePool->name());
1047 if (res->res_pool.ScratchPool) {
1048 sendit(sock, _(" ScratchPool=%s\n"), res->res_pool.ScratchPool->name());
1050 if (res->res_pool.catalog) {
1051 sendit(sock, _(" Catalog=%s\n"), res->res_pool.catalog->name());
1053 if (res->res_pool.storage) {
1055 foreach_alist(store, res->res_pool.storage) {
1056 sendit(sock, _(" --> "));
1057 dump_resource(-R_STORAGE, (RES *)store, sendit, sock);
1060 if (res->res_pool.CopyPool) {
1062 foreach_alist(copy, res->res_pool.CopyPool) {
1063 sendit(sock, _(" --> "));
1064 dump_resource(-R_POOL, (RES *)copy, sendit, sock);
1071 sendit(sock, _("Messages: name=%s\n"), res->res_msgs.hdr.name);
1072 if (res->res_msgs.mail_cmd)
1073 sendit(sock, _(" mailcmd=%s\n"), res->res_msgs.mail_cmd);
1074 if (res->res_msgs.operator_cmd)
1075 sendit(sock, _(" opcmd=%s\n"), res->res_msgs.operator_cmd);
1079 sendit(sock, _("Unknown resource type %d in dump_resource.\n"), type);
1082 if (recurse && res->res_dir.hdr.next) {
1083 dump_resource(type, res->res_dir.hdr.next, sendit, sock);
1089 * Free all the members of an INCEXE structure
1091 static void free_incexe(INCEXE *incexe)
1093 incexe->name_list.destroy();
1094 incexe->plugin_list.destroy();
1095 for (int i=0; i<incexe->num_opts; i++) {
1096 FOPTS *fopt = incexe->opts_list[i];
1097 fopt->regex.destroy();
1098 fopt->regexdir.destroy();
1099 fopt->regexfile.destroy();
1100 fopt->wild.destroy();
1101 fopt->wilddir.destroy();
1102 fopt->wildfile.destroy();
1103 fopt->wildbase.destroy();
1104 fopt->base.destroy();
1105 fopt->fstype.destroy();
1106 fopt->drivetype.destroy();
1118 if (incexe->opts_list) {
1119 free(incexe->opts_list);
1121 if (incexe->ignoredir) {
1122 free(incexe->ignoredir);
1129 * Free memory of resource -- called when daemon terminates.
1130 * NB, we don't need to worry about freeing any references
1131 * to other resources as they will be freed when that
1132 * resource chain is traversed. Mainly we worry about freeing
1133 * allocated strings (names).
1135 void free_resource(RES *rres, int type)
1139 URES *res = (URES *)rres;
1145 Dmsg3(200, "type=%d res=%p name=%s\n", type, res, res->res_dir.hdr.name);
1146 /* common stuff -- free the resource name and description */
1147 nres = (RES *)res->res_dir.hdr.next;
1148 if (res->res_dir.hdr.name) {
1149 free(res->res_dir.hdr.name);
1151 if (res->res_dir.hdr.desc) {
1152 free(res->res_dir.hdr.desc);
1157 if (res->res_dir.working_directory) {
1158 free(res->res_dir.working_directory);
1160 if (res->res_dir.scripts_directory) {
1161 free((char *)res->res_dir.scripts_directory);
1163 if (res->res_dir.plugin_directory) {
1164 free((char *)res->res_dir.plugin_directory);
1166 if (res->res_dir.pid_directory) {
1167 free(res->res_dir.pid_directory);
1169 if (res->res_dir.subsys_directory) {
1170 free(res->res_dir.subsys_directory);
1172 if (res->res_dir.password) {
1173 free(res->res_dir.password);
1175 if (res->res_dir.query_file) {
1176 free(res->res_dir.query_file);
1178 if (res->res_dir.DIRaddrs) {
1179 free_addresses(res->res_dir.DIRaddrs);
1181 if (res->res_dir.DIRsrc_addr) {
1182 free_addresses(res->res_dir.DIRsrc_addr);
1184 if (res->res_dir.tls_ctx) {
1185 free_tls_context(res->res_dir.tls_ctx);
1187 if (res->res_dir.tls_ca_certfile) {
1188 free(res->res_dir.tls_ca_certfile);
1190 if (res->res_dir.tls_ca_certdir) {
1191 free(res->res_dir.tls_ca_certdir);
1193 if (res->res_dir.tls_certfile) {
1194 free(res->res_dir.tls_certfile);
1196 if (res->res_dir.tls_keyfile) {
1197 free(res->res_dir.tls_keyfile);
1199 if (res->res_dir.tls_dhfile) {
1200 free(res->res_dir.tls_dhfile);
1202 if (res->res_dir.tls_allowed_cns) {
1203 delete res->res_dir.tls_allowed_cns;
1205 if (res->res_dir.verid) {
1206 free(res->res_dir.verid);
1213 if (res->res_con.password) {
1214 free(res->res_con.password);
1216 if (res->res_con.tls_ctx) {
1217 free_tls_context(res->res_con.tls_ctx);
1219 if (res->res_con.tls_ca_certfile) {
1220 free(res->res_con.tls_ca_certfile);
1222 if (res->res_con.tls_ca_certdir) {
1223 free(res->res_con.tls_ca_certdir);
1225 if (res->res_con.tls_certfile) {
1226 free(res->res_con.tls_certfile);
1228 if (res->res_con.tls_keyfile) {
1229 free(res->res_con.tls_keyfile);
1231 if (res->res_con.tls_dhfile) {
1232 free(res->res_con.tls_dhfile);
1234 if (res->res_con.tls_allowed_cns) {
1235 delete res->res_con.tls_allowed_cns;
1237 for (int i=0; i<Num_ACL; i++) {
1238 if (res->res_con.ACL_lists[i]) {
1239 delete res->res_con.ACL_lists[i];
1240 res->res_con.ACL_lists[i] = NULL;
1245 if (res->res_client.address) {
1246 free(res->res_client.address);
1248 if (res->res_client.fd_storage_address) {
1249 free(res->res_client.fd_storage_address);
1251 if (res->res_client.password) {
1252 free(res->res_client.password);
1254 if (res->res_client.tls_ctx) {
1255 free_tls_context(res->res_client.tls_ctx);
1257 if (res->res_client.tls_ca_certfile) {
1258 free(res->res_client.tls_ca_certfile);
1260 if (res->res_client.tls_ca_certdir) {
1261 free(res->res_client.tls_ca_certdir);
1263 if (res->res_client.tls_certfile) {
1264 free(res->res_client.tls_certfile);
1266 if (res->res_client.tls_keyfile) {
1267 free(res->res_client.tls_keyfile);
1269 if (res->res_client.tls_allowed_cns) {
1270 delete res->res_client.tls_allowed_cns;
1274 if (res->res_store.address) {
1275 free(res->res_store.address);
1277 if (res->res_store.fd_storage_address) {
1278 free(res->res_store.fd_storage_address);
1280 if (res->res_store.password) {
1281 free(res->res_store.password);
1283 if (res->res_store.media_type) {
1284 free(res->res_store.media_type);
1286 if (res->res_store.device) {
1287 delete res->res_store.device;
1289 if (res->res_store.tls_ctx) {
1290 free_tls_context(res->res_store.tls_ctx);
1292 if (res->res_store.tls_ca_certfile) {
1293 free(res->res_store.tls_ca_certfile);
1295 if (res->res_store.tls_ca_certdir) {
1296 free(res->res_store.tls_ca_certdir);
1298 if (res->res_store.tls_certfile) {
1299 free(res->res_store.tls_certfile);
1301 if (res->res_store.tls_keyfile) {
1302 free(res->res_store.tls_keyfile);
1306 if (res->res_cat.db_address) {
1307 free(res->res_cat.db_address);
1309 if (res->res_cat.db_socket) {
1310 free(res->res_cat.db_socket);
1312 if (res->res_cat.db_user) {
1313 free(res->res_cat.db_user);
1315 if (res->res_cat.db_name) {
1316 free(res->res_cat.db_name);
1318 if (res->res_cat.db_driver) {
1319 free(res->res_cat.db_driver);
1321 if (res->res_cat.db_password) {
1322 free(res->res_cat.db_password);
1324 if (res->res_cat.db_ssl_key) {
1325 free(res->res_cat.db_ssl_key);
1327 if (res->res_cat.db_ssl_cert) {
1328 free(res->res_cat.db_ssl_cert);
1330 if (res->res_cat.db_ssl_ca) {
1331 free(res->res_cat.db_ssl_ca);
1333 if (res->res_cat.db_ssl_capath) {
1334 free(res->res_cat.db_ssl_capath);
1336 if (res->res_cat.db_ssl_cipher) {
1337 free(res->res_cat.db_ssl_cipher);
1341 if ((num=res->res_fs.num_includes)) {
1342 while (--num >= 0) {
1343 free_incexe(res->res_fs.include_items[num]);
1345 free(res->res_fs.include_items);
1347 res->res_fs.num_includes = 0;
1348 if ((num=res->res_fs.num_excludes)) {
1349 while (--num >= 0) {
1350 free_incexe(res->res_fs.exclude_items[num]);
1352 free(res->res_fs.exclude_items);
1354 res->res_fs.num_excludes = 0;
1357 if (res->res_pool.pool_type) {
1358 free(res->res_pool.pool_type);
1360 if (res->res_pool.label_format) {
1361 free(res->res_pool.label_format);
1363 if (res->res_pool.cleaning_prefix) {
1364 free(res->res_pool.cleaning_prefix);
1366 if (res->res_pool.storage) {
1367 delete res->res_pool.storage;
1371 if (res->res_sch.run) {
1373 nrun = res->res_sch.run;
1383 if (res->res_job.RestoreWhere) {
1384 free(res->res_job.RestoreWhere);
1386 if (res->res_job.RegexWhere) {
1387 free(res->res_job.RegexWhere);
1389 if (res->res_job.strip_prefix) {
1390 free(res->res_job.strip_prefix);
1392 if (res->res_job.add_prefix) {
1393 free(res->res_job.add_prefix);
1395 if (res->res_job.add_suffix) {
1396 free(res->res_job.add_suffix);
1398 if (res->res_job.RestoreBootstrap) {
1399 free(res->res_job.RestoreBootstrap);
1401 if (res->res_job.WriteBootstrap) {
1402 free(res->res_job.WriteBootstrap);
1404 if (res->res_job.PluginOptions) {
1405 free(res->res_job.PluginOptions);
1407 if (res->res_job.selection_pattern) {
1408 free(res->res_job.selection_pattern);
1410 if (res->res_job.run_cmds) {
1411 delete res->res_job.run_cmds;
1413 if (res->res_job.storage) {
1414 delete res->res_job.storage;
1416 if (res->res_job.base) {
1417 delete res->res_job.base;
1419 if (res->res_job.RunScripts) {
1420 free_runscripts(res->res_job.RunScripts);
1421 delete res->res_job.RunScripts;
1425 if (res->res_msgs.mail_cmd) {
1426 free(res->res_msgs.mail_cmd);
1428 if (res->res_msgs.operator_cmd) {
1429 free(res->res_msgs.operator_cmd);
1431 free_msgs_res((MSGS *)res); /* free message resource */
1435 printf(_("Unknown resource type %d in free_resource.\n"), type);
1437 /* Common stuff again -- free the resource, recurse to next one */
1442 free_resource(nres, type);
1447 * Save the new resource by chaining it into the head list for
1448 * the resource. If this is pass 2, we update any resource
1449 * pointers because they may not have been defined until
1452 void save_resource(int type, RES_ITEM *items, int pass)
1455 int rindex = type - r_first;
1459 /* Check Job requirements after applying JobDefs */
1460 if (type != R_JOB && type != R_JOBDEFS) {
1462 * Ensure that all required items are present
1464 for (i=0; items[i].name; i++) {
1465 if (items[i].flags & ITEM_REQUIRED) {
1466 if (!bit_is_set(i, res_all.res_dir.hdr.item_present)) {
1467 Emsg2(M_ERROR_TERM, 0, _("\"%s\" directive is required in \"%s\" resource, but not found.\n"),
1468 items[i].name, resources[rindex].name);
1471 /* If this triggers, take a look at lib/parse_conf.h */
1472 if (i >= MAX_RES_ITEMS) {
1473 Emsg1(M_ERROR_TERM, 0, _("Too many directive in \"%s\" resource\n"), resources[rindex].name);
1476 } else if (type == R_JOB) {
1478 * Ensure that the name item is present
1480 if (items[0].flags & ITEM_REQUIRED) {
1481 if (!bit_is_set(0, res_all.res_dir.hdr.item_present)) {
1482 Emsg2(M_ERROR_TERM, 0, _("\"%s\" directive is required in \"%s\" resource, but not found.\n"),
1483 items[0].name, resources[rindex].name);
1489 * During pass 2 in each "store" routine, we looked up pointers
1490 * to all the resources referrenced in the current resource, now we
1491 * must copy their addresses from the static record to the allocated
1496 /* Resources not containing a resource */
1504 * Resources containing another resource or alist. First
1505 * look up the resource which contains another resource. It
1506 * was written during pass 1. Then stuff in the pointers to
1507 * the resources it contains, which were inserted this pass.
1508 * Finally, it will all be stored back.
1511 /* Find resource saved in pass 1 */
1512 if ((res = (URES *)GetResWithName(R_POOL, res_all.res_con.hdr.name)) == NULL) {
1513 Emsg1(M_ERROR_TERM, 0, _("Cannot find Pool resource %s\n"), res_all.res_con.hdr.name);
1515 /* Explicitly copy resource pointers from this pass (res_all) */
1516 res->res_pool.NextPool = res_all.res_pool.NextPool;
1517 res->res_pool.RecyclePool = res_all.res_pool.RecyclePool;
1518 res->res_pool.ScratchPool = res_all.res_pool.ScratchPool;
1519 res->res_pool.storage = res_all.res_pool.storage;
1520 res->res_pool.catalog = res_all.res_pool.catalog;
1523 if ((res = (URES *)GetResWithName(R_CONSOLE, res_all.res_con.hdr.name)) == NULL) {
1524 Emsg1(M_ERROR_TERM, 0, _("Cannot find Console resource %s\n"), res_all.res_con.hdr.name);
1526 res->res_con.tls_allowed_cns = res_all.res_con.tls_allowed_cns;
1529 if ((res = (URES *)GetResWithName(R_DIRECTOR, res_all.res_dir.hdr.name)) == NULL) {
1530 Emsg1(M_ERROR_TERM, 0, _("Cannot find Director resource %s\n"), res_all.res_dir.hdr.name);
1532 res->res_dir.messages = res_all.res_dir.messages;
1533 res->res_dir.tls_allowed_cns = res_all.res_dir.tls_allowed_cns;
1536 if ((res = (URES *)GetResWithName(type, res_all.res_store.hdr.name)) == NULL) {
1537 Emsg1(M_ERROR_TERM, 0, _("Cannot find Storage resource %s\n"),
1538 res_all.res_dir.hdr.name);
1540 /* we must explicitly copy the device alist pointer */
1541 res->res_store.device = res_all.res_store.device;
1545 if ((res = (URES *)GetResWithName(type, res_all.res_dir.hdr.name)) == NULL) {
1546 Emsg1(M_ERROR_TERM, 0, _("Cannot find Job resource %s\n"),
1547 res_all.res_dir.hdr.name);
1549 res->res_job.messages = res_all.res_job.messages;
1550 res->res_job.schedule = res_all.res_job.schedule;
1551 res->res_job.client = res_all.res_job.client;
1552 res->res_job.fileset = res_all.res_job.fileset;
1553 res->res_job.storage = res_all.res_job.storage;
1554 res->res_job.base = res_all.res_job.base;
1555 res->res_job.pool = res_all.res_job.pool;
1556 res->res_job.next_pool = res_all.res_job.next_pool;
1557 res->res_job.full_pool = res_all.res_job.full_pool;
1558 res->res_job.inc_pool = res_all.res_job.inc_pool;
1559 res->res_job.diff_pool = res_all.res_job.diff_pool;
1560 res->res_job.verify_job = res_all.res_job.verify_job;
1561 res->res_job.jobdefs = res_all.res_job.jobdefs;
1562 res->res_job.run_cmds = res_all.res_job.run_cmds;
1563 res->res_job.RunScripts = res_all.res_job.RunScripts;
1565 /* TODO: JobDefs where/regexwhere doesn't work well (but this
1566 * is not very useful)
1567 * We have to set_bit(index, res_all.hdr.item_present);
1568 * or something like that
1571 /* we take RegexWhere before all other options */
1572 if (!res->res_job.RegexWhere
1574 (res->res_job.strip_prefix ||
1575 res->res_job.add_suffix ||
1576 res->res_job.add_prefix))
1578 int len = bregexp_get_build_where_size(res->res_job.strip_prefix,
1579 res->res_job.add_prefix,
1580 res->res_job.add_suffix);
1581 res->res_job.RegexWhere = (char *) bmalloc (len * sizeof(char));
1582 bregexp_build_where(res->res_job.RegexWhere, len,
1583 res->res_job.strip_prefix,
1584 res->res_job.add_prefix,
1585 res->res_job.add_suffix);
1586 /* TODO: test bregexp */
1589 if (res->res_job.RegexWhere && res->res_job.RestoreWhere) {
1590 free(res->res_job.RestoreWhere);
1591 res->res_job.RestoreWhere = NULL;
1596 if ((res = (URES *)GetResWithName(R_COUNTER, res_all.res_counter.hdr.name)) == NULL) {
1597 Emsg1(M_ERROR_TERM, 0, _("Cannot find Counter resource %s\n"), res_all.res_counter.hdr.name);
1599 res->res_counter.Catalog = res_all.res_counter.Catalog;
1600 res->res_counter.WrapCounter = res_all.res_counter.WrapCounter;
1604 if ((res = (URES *)GetResWithName(R_CLIENT, res_all.res_client.hdr.name)) == NULL) {
1605 Emsg1(M_ERROR_TERM, 0, _("Cannot find Client resource %s\n"), res_all.res_client.hdr.name);
1607 res->res_client.catalog = res_all.res_client.catalog;
1608 res->res_client.tls_allowed_cns = res_all.res_client.tls_allowed_cns;
1612 * Schedule is a bit different in that it contains a RUN record
1613 * chain which isn't a "named" resource. This chain was linked
1614 * in by run_conf.c during pass 2, so here we jam the pointer
1615 * into the Schedule resource.
1617 if ((res = (URES *)GetResWithName(R_SCHEDULE, res_all.res_client.hdr.name)) == NULL) {
1618 Emsg1(M_ERROR_TERM, 0, _("Cannot find Schedule resource %s\n"), res_all.res_client.hdr.name);
1620 res->res_sch.run = res_all.res_sch.run;
1623 Emsg1(M_ERROR, 0, _("Unknown resource type %d in save_resource.\n"), type);
1627 /* Note, the resource name was already saved during pass 1,
1628 * so here, we can just release it.
1630 if (res_all.res_dir.hdr.name) {
1631 free(res_all.res_dir.hdr.name);
1632 res_all.res_dir.hdr.name = NULL;
1634 if (res_all.res_dir.hdr.desc) {
1635 free(res_all.res_dir.hdr.desc);
1636 res_all.res_dir.hdr.desc = NULL;
1642 * The following code is only executed during pass 1
1646 size = sizeof(DIRRES);
1649 size = sizeof(CONRES);
1652 size =sizeof(CLIENT);
1655 size = sizeof(STORE);
1665 size = sizeof(FILESET);
1668 size = sizeof(SCHED);
1671 size = sizeof(POOL);
1674 size = sizeof(MSGS);
1677 size = sizeof(COUNTER);
1683 printf(_("Unknown resource type %d in save_resource.\n"), type);
1689 res = (URES *)malloc(size);
1690 memcpy(res, &res_all, size);
1691 if (!res_head[rindex]) {
1692 res_head[rindex] = (RES *)res; /* store first entry */
1693 Dmsg3(900, "Inserting first %s res: %s index=%d\n", res_to_str(type),
1694 res->res_dir.hdr.name, rindex);
1697 if (res->res_dir.hdr.name == NULL) {
1698 Emsg1(M_ERROR_TERM, 0, _("A Name directive is required in \"%s\" resource, but not found.\n"),
1699 resources[rindex].name);
1701 /* Add new res to end of chain */
1702 for (last=next=res_head[rindex]; next; next=next->next) {
1704 if (strcmp(next->name, res->res_dir.hdr.name) == 0) {
1705 Emsg2(M_ERROR_TERM, 0,
1706 _("Attempt to define second \"%s\" resource named \"%s\" is not permitted.\n"),
1707 resources[rindex].name, res->res_dir.hdr.name);
1710 last->next = (RES *)res;
1711 Dmsg4(900, _("Inserting %s res: %s index=%d pass=%d\n"), res_to_str(type),
1712 res->res_dir.hdr.name, rindex, pass);
1717 void store_actiononpurge(LEX *lc, RES_ITEM *item, int index, int pass)
1719 uint32_t *destination = (uint32_t*)item->value;
1720 lex_get_token(lc, T_NAME);
1721 if (strcasecmp(lc->str, "truncate") == 0) {
1722 *destination = (*destination) | ON_PURGE_TRUNCATE;
1724 scan_err2(lc, _("Expected one of: %s, got: %s"), "Truncate", lc->str);
1728 set_bit(index, res_all.hdr.item_present);
1732 * Store Device. Note, the resource is created upon the
1733 * first reference. The details of the resource are obtained
1734 * later from the SD.
1736 static void store_device(LEX *lc, RES_ITEM *item, int index, int pass)
1739 int rindex = R_DEVICE - r_first;
1740 int size = sizeof(DEVICE);
1744 lex_get_token(lc, T_NAME);
1745 if (!res_head[rindex]) {
1746 res = (URES *)malloc(size);
1747 memset(res, 0, size);
1748 res->res_dev.hdr.name = bstrdup(lc->str);
1749 res_head[rindex] = (RES *)res; /* store first entry */
1750 Dmsg3(900, "Inserting first %s res: %s index=%d\n", res_to_str(R_DEVICE),
1751 res->res_dir.hdr.name, rindex);
1754 /* See if it is already defined */
1755 for (next=res_head[rindex]; next->next; next=next->next) {
1756 if (strcmp(next->name, lc->str) == 0) {
1762 res = (URES *)malloc(size);
1763 memset(res, 0, size);
1764 res->res_dev.hdr.name = bstrdup(lc->str);
1765 next->next = (RES *)res;
1766 Dmsg4(900, "Inserting %s res: %s index=%d pass=%d\n", res_to_str(R_DEVICE),
1767 res->res_dir.hdr.name, rindex, pass);
1772 set_bit(index, res_all.hdr.item_present);
1774 store_alist_res(lc, item, index, pass);
1779 * Store Migration/Copy type
1782 void store_migtype(LEX *lc, RES_ITEM *item, int index, int pass)
1786 lex_get_token(lc, T_NAME);
1787 /* Store the type both pass 1 and pass 2 */
1788 for (i=0; migtypes[i].type_name; i++) {
1789 if (strcasecmp(lc->str, migtypes[i].type_name) == 0) {
1790 *(uint32_t *)(item->value) = migtypes[i].job_type;
1796 scan_err1(lc, _("Expected a Migration Job Type keyword, got: %s"), lc->str);
1799 set_bit(index, res_all.hdr.item_present);
1805 * Store JobType (backup, verify, restore)
1808 void store_jobtype(LEX *lc, RES_ITEM *item, int index, int pass)
1812 lex_get_token(lc, T_NAME);
1813 /* Store the type both pass 1 and pass 2 */
1814 for (i=0; jobtypes[i].type_name; i++) {
1815 if (strcasecmp(lc->str, jobtypes[i].type_name) == 0) {
1816 *(uint32_t *)(item->value) = jobtypes[i].job_type;
1822 scan_err1(lc, _("Expected a Job Type keyword, got: %s"), lc->str);
1825 set_bit(index, res_all.hdr.item_present);
1829 * Store Job Level (Full, Incremental, ...)
1832 void store_level(LEX *lc, RES_ITEM *item, int index, int pass)
1836 lex_get_token(lc, T_NAME);
1837 /* Store the level pass 2 so that type is defined */
1838 for (i=0; joblevels[i].level_name; i++) {
1839 if (strcasecmp(lc->str, joblevels[i].level_name) == 0) {
1840 *(uint32_t *)(item->value) = joblevels[i].level;
1846 scan_err1(lc, _("Expected a Job Level keyword, got: %s"), lc->str);
1849 set_bit(index, res_all.hdr.item_present);
1853 void store_replace(LEX *lc, RES_ITEM *item, int index, int pass)
1856 lex_get_token(lc, T_NAME);
1857 /* Scan Replacement options */
1858 for (i=0; ReplaceOptions[i].name; i++) {
1859 if (strcasecmp(lc->str, ReplaceOptions[i].name) == 0) {
1860 *(uint32_t *)(item->value) = ReplaceOptions[i].token;
1866 scan_err1(lc, _("Expected a Restore replacement option, got: %s"), lc->str);
1869 set_bit(index, res_all.hdr.item_present);
1873 * Store ACL (access control list)
1876 void store_acl(LEX *lc, RES_ITEM *item, int index, int pass)
1881 lex_get_token(lc, T_STRING);
1883 if (((alist **)item->value)[item->code] == NULL) {
1884 ((alist **)item->value)[item->code] = New(alist(10, owned_by_alist));
1885 Dmsg1(900, "Defined new ACL alist at %d\n", item->code);
1887 ((alist **)item->value)[item->code]->append(bstrdup(lc->str));
1888 Dmsg2(900, "Appended to %d %s\n", item->code, lc->str);
1890 token = lex_get_token(lc, T_ALL);
1891 if (token == T_COMMA) {
1892 continue; /* get another ACL */
1896 set_bit(index, res_all.hdr.item_present);
1899 /* We build RunScripts items here */
1900 static RUNSCRIPT res_runscript;
1902 /* Store a runscript->when in a bit field */
1903 static void store_runscript_when(LEX *lc, RES_ITEM *item, int index, int pass)
1905 lex_get_token(lc, T_NAME);
1907 if (strcasecmp(lc->str, "before") == 0) {
1908 *(uint32_t *)(item->value) = SCRIPT_Before ;
1909 } else if (strcasecmp(lc->str, "after") == 0) {
1910 *(uint32_t *)(item->value) = SCRIPT_After;
1911 } else if (strcasecmp(lc->str, "aftervss") == 0) {
1912 *(uint32_t *)(item->value) = SCRIPT_AfterVSS;
1913 } else if (strcasecmp(lc->str, "aftersnapshot") == 0) {
1914 *(uint32_t *)(item->value) = SCRIPT_AfterVSS;
1915 } else if (strcasecmp(lc->str, "always") == 0) {
1916 *(uint32_t *)(item->value) = SCRIPT_Any;
1918 scan_err2(lc, _("Expect %s, got: %s"), "Before, After, AfterVSS or Always", lc->str);
1923 /* Store a runscript->target
1926 static void store_runscript_target(LEX *lc, RES_ITEM *item, int index, int pass)
1928 lex_get_token(lc, T_STRING);
1931 if (strcmp(lc->str, "%c") == 0) {
1932 ((RUNSCRIPT*) item->value)->set_target(lc->str);
1933 } else if (strcasecmp(lc->str, "yes") == 0) {
1934 ((RUNSCRIPT*) item->value)->set_target("%c");
1935 } else if (strcasecmp(lc->str, "no") == 0) {
1936 ((RUNSCRIPT*) item->value)->set_target("");
1938 RES *res = GetResWithName(R_CLIENT, lc->str);
1940 scan_err3(lc, _("Could not find config Resource %s referenced on line %d : %s\n"),
1941 lc->str, lc->line_no, lc->line);
1944 ((RUNSCRIPT*) item->value)->set_target(lc->str);
1951 * Store a runscript->command as a string and runscript->cmd_type as a pointer
1953 static void store_runscript_cmd(LEX *lc, RES_ITEM *item, int index, int pass)
1955 lex_get_token(lc, T_STRING);
1958 Dmsg2(1, "runscript cmd=%s type=%c\n", lc->str, item->code);
1959 POOLMEM *c = get_pool_memory(PM_FNAME);
1960 /* Each runscript command takes 2 entries in commands list */
1961 pm_strcpy(c, lc->str);
1962 ((RUNSCRIPT*) item->value)->commands->prepend(c); /* command line */
1963 ((RUNSCRIPT*) item->value)->commands->prepend((void *)(intptr_t)item->code); /* command type */
1968 static void store_short_runscript(LEX *lc, RES_ITEM *item, int index, int pass)
1970 lex_get_token(lc, T_STRING);
1971 alist **runscripts = (alist **)(item->value) ;
1974 RUNSCRIPT *script = new_runscript();
1975 script->set_job_code_callback(job_code_callback_director);
1977 script->set_command(lc->str);
1979 /* TODO: remove all script->old_proto with bacula 1.42 */
1981 if (strcasecmp(item->name, "runbeforejob") == 0) {
1982 script->when = SCRIPT_Before;
1983 script->fail_on_error = true;
1984 script->set_target("");
1986 } else if (strcasecmp(item->name, "runafterjob") == 0) {
1987 script->when = SCRIPT_After;
1988 script->on_success = true;
1989 script->on_failure = false;
1990 script->set_target("");
1992 } else if (strcasecmp(item->name, "clientrunbeforejob") == 0) {
1993 script->old_proto = true;
1994 script->when = SCRIPT_Before;
1995 script->set_target("%c");
1996 script->fail_on_error = true;
1998 } else if (strcasecmp(item->name, "clientrunafterjob") == 0) {
1999 script->old_proto = true;
2000 script->when = SCRIPT_After;
2001 script->set_target("%c");
2002 script->on_success = true;
2003 script->on_failure = false;
2005 } else if (strcasecmp(item->name, "consolerunbeforejob") == 0) {
2006 script->when = SCRIPT_Before;
2007 script->set_target("");
2008 script->fail_on_error = true;
2009 script->set_command(NPRT(script->command), CONSOLE_CMD);
2011 } else if (strcasecmp(item->name, "consolerunafterjob") == 0) {
2012 script->when = SCRIPT_After;
2013 script->set_target("");
2014 script->on_success = true;
2015 script->on_failure = false;
2016 script->set_command(NPRT(script->command), CONSOLE_CMD);
2018 } else if (strcasecmp(item->name, "runafterfailedjob") == 0) {
2019 script->when = SCRIPT_After;
2020 script->on_failure = true;
2021 script->on_success = false;
2022 script->set_target("");
2025 if (*runscripts == NULL) {
2026 *runscripts = New(alist(10, not_owned_by_alist));
2029 (*runscripts)->append(script);
2033 set_bit(index, res_all.hdr.item_present);
2036 /* Store a bool in a bit field without modifing res_all.hdr
2037 * We can also add an option to store_bool to skip res_all.hdr
2039 void store_runscript_bool(LEX *lc, RES_ITEM *item, int index, int pass)
2041 lex_get_token(lc, T_NAME);
2042 if (strcasecmp(lc->str, "yes") == 0 || strcasecmp(lc->str, "true") == 0) {
2043 *(bool *)(item->value) = true;
2044 } else if (strcasecmp(lc->str, "no") == 0 || strcasecmp(lc->str, "false") == 0) {
2045 *(bool *)(item->value) = false;
2047 scan_err2(lc, _("Expect %s, got: %s"), "YES, NO, TRUE, or FALSE", lc->str); /* YES and NO must not be translated */
2053 * new RunScript items
2054 * name handler value code flags default_value
2056 static RES_ITEM runscript_items[] = {
2057 {"command", store_runscript_cmd, {(char **)&res_runscript}, SHELL_CMD, 0, 0},
2058 {"console", store_runscript_cmd, {(char **)&res_runscript}, CONSOLE_CMD, 0, 0},
2059 {"target", store_runscript_target,{(char **)&res_runscript}, 0, 0, 0},
2060 {"runsonsuccess", store_runscript_bool, {(char **)&res_runscript.on_success},0, 0, 0},
2061 {"runsonfailure", store_runscript_bool, {(char **)&res_runscript.on_failure},0, 0, 0},
2062 {"failjobonerror",store_runscript_bool, {(char **)&res_runscript.fail_on_error},0, 0, 0},
2063 {"abortjobonerror",store_runscript_bool, {(char **)&res_runscript.fail_on_error},0, 0, 0},
2064 {"runswhen", store_runscript_when, {(char **)&res_runscript.when}, 0, 0, 0},
2065 {"runsonclient", store_runscript_target,{(char **)&res_runscript}, 0, 0, 0}, /* TODO */
2066 {NULL, NULL, {0}, 0, 0, 0}
2070 * Store RunScript info
2072 * Note, when this routine is called, we are inside a Job
2073 * resource. We treat the RunScript like a sort of
2074 * mini-resource within the Job resource.
2076 void store_runscript(LEX *lc, RES_ITEM *item, int index, int pass)
2080 alist **runscripts = (alist **)(item->value) ;
2082 Dmsg1(200, "store_runscript: begin store_runscript pass=%i\n", pass);
2084 token = lex_get_token(lc, T_SKIP_EOL);
2086 if (token != T_BOB) {
2087 scan_err1(lc, _("Expecting open brace. Got %s"), lc->str);
2089 /* setting on_success, on_failure, fail_on_error */
2090 res_runscript.reset_default();
2093 res_runscript.commands = New(alist(10, not_owned_by_alist));
2096 while ((token = lex_get_token(lc, T_SKIP_EOL)) != T_EOF) {
2097 if (token == T_EOB) {
2100 if (token != T_IDENTIFIER) {
2101 scan_err1(lc, _("Expecting keyword, got: %s\n"), lc->str);
2103 for (i=0; runscript_items[i].name; i++) {
2104 if (strcasecmp(runscript_items[i].name, lc->str) == 0) {
2105 token = lex_get_token(lc, T_SKIP_EOL);
2106 if (token != T_EQUALS) {
2107 scan_err1(lc, _("expected an equals, got: %s"), lc->str);
2110 /* Call item handler */
2111 runscript_items[i].handler(lc, &runscript_items[i], i, pass);
2118 scan_err1(lc, _("Keyword %s not permitted in this resource"), lc->str);
2123 /* run on client by default */
2124 if (res_runscript.target == NULL) {
2125 res_runscript.set_target("%c");
2127 if (*runscripts == NULL) {
2128 *runscripts = New(alist(10, not_owned_by_alist));
2131 * commands list contains 2 values per command
2132 * - POOLMEM command string (ex: /bin/true)
2133 * - int command type (ex: SHELL_CMD)
2135 res_runscript.set_job_code_callback(job_code_callback_director);
2136 while ((c=(char*)res_runscript.commands->pop()) != NULL) {
2137 t = (intptr_t)res_runscript.commands->pop();
2138 RUNSCRIPT *script = new_runscript();
2139 memcpy(script, &res_runscript, sizeof(RUNSCRIPT));
2140 script->command = c;
2141 script->cmd_type = t;
2142 /* target is taken from res_runscript, each runscript object have
2145 script->target = NULL;
2146 script->set_target(res_runscript.target);
2148 (*runscripts)->append(script);
2151 delete res_runscript.commands;
2152 /* setting on_success, on_failure... cleanup target field */
2153 res_runscript.reset_default(true);
2157 set_bit(index, res_all.hdr.item_present);
2160 /* callback function for edit_job_codes */
2161 /* See ../lib/util.c, function edit_job_codes, for more remaining codes */
2162 extern "C" char *job_code_callback_director(JCR *jcr, const char* param)
2164 static char yes[] = "yes";
2165 static char no[] = "no";
2166 static char nothing[] = "";
2174 return jcr->fileset->name();
2178 if (jcr->client && jcr->client->address) {
2179 return jcr->client->address;
2184 return jcr->pool->name();
2189 return jcr->wstore->name();
2193 return jcr->spool_data ? yes : no;
2197 return jcr->cloned ? yes : no;
2202 bool parse_dir_config(CONFIG *config, const char *configfile, int exit_code)
2204 config->init(configfile, NULL, exit_code, (void *)&res_all, res_all_size,
2205 r_first, r_last, resources, res_head);
2206 return config->parse_config();