2 Bacula(R) - The Network Backup Solution
4 Copyright (C) 2000-2015 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.client) {
717 sendit(sock, _(" --> "));
718 dump_resource(-R_CLIENT, (RES *)res->res_job.client, sendit, sock);
720 if (res->res_job.fileset) {
721 sendit(sock, _(" --> "));
722 dump_resource(-R_FILESET, (RES *)res->res_job.fileset, sendit, sock);
724 if (res->res_job.schedule) {
725 sendit(sock, _(" --> "));
726 dump_resource(-R_SCHEDULE, (RES *)res->res_job.schedule, sendit, sock);
728 if (res->res_job.RestoreWhere && !res->res_job.RegexWhere) {
729 sendit(sock, _(" --> Where=%s\n"), NPRT(res->res_job.RestoreWhere));
731 if (res->res_job.RegexWhere) {
732 sendit(sock, _(" --> RegexWhere=%s\n"), NPRT(res->res_job.RegexWhere));
734 if (res->res_job.RestoreBootstrap) {
735 sendit(sock, _(" --> Bootstrap=%s\n"), NPRT(res->res_job.RestoreBootstrap));
737 if (res->res_job.WriteBootstrap) {
738 sendit(sock, _(" --> WriteBootstrap=%s\n"), NPRT(res->res_job.WriteBootstrap));
740 if (res->res_job.PluginOptions) {
741 sendit(sock, _(" --> PluginOptions=%s\n"), NPRT(res->res_job.PluginOptions));
743 if (res->res_job.MaxRunTime) {
744 sendit(sock, _(" --> MaxRunTime=%u\n"), res->res_job.MaxRunTime);
746 if (res->res_job.MaxWaitTime) {
747 sendit(sock, _(" --> MaxWaitTime=%u\n"), res->res_job.MaxWaitTime);
749 if (res->res_job.MaxStartDelay) {
750 sendit(sock, _(" --> MaxStartDelay=%u\n"), res->res_job.MaxStartDelay);
752 if (res->res_job.MaxRunSchedTime) {
753 sendit(sock, _(" --> MaxRunSchedTime=%u\n"), res->res_job.MaxRunSchedTime);
755 if (res->res_job.storage) {
757 foreach_alist(store, res->res_job.storage) {
758 sendit(sock, _(" --> "));
759 dump_resource(-R_STORAGE, (RES *)store, sendit, sock);
762 if (res->res_job.base) {
764 foreach_alist(job, res->res_job.base) {
765 sendit(sock, _(" --> Base %s\n"), job->name());
768 if (res->res_job.RunScripts) {
770 foreach_alist(script, res->res_job.RunScripts) {
771 sendit(sock, _(" --> RunScript\n"));
772 sendit(sock, _(" --> Command=%s\n"), NPRT(script->command));
773 sendit(sock, _(" --> Target=%s\n"), NPRT(script->target));
774 sendit(sock, _(" --> RunOnSuccess=%u\n"), script->on_success);
775 sendit(sock, _(" --> RunOnFailure=%u\n"), script->on_failure);
776 sendit(sock, _(" --> FailJobOnError=%u\n"), script->fail_on_error);
777 sendit(sock, _(" --> RunWhen=%u\n"), script->when);
780 if (res->res_job.pool) {
781 sendit(sock, _(" --> "));
782 dump_resource(-R_POOL, (RES *)res->res_job.pool, sendit, sock);
784 if (res->res_job.full_pool) {
785 sendit(sock, _(" --> FullBackup"));
786 dump_resource(-R_POOL, (RES *)res->res_job.full_pool, sendit, sock);
788 if (res->res_job.inc_pool) {
789 sendit(sock, _(" --> IncrementalBackup"));
790 dump_resource(-R_POOL, (RES *)res->res_job.inc_pool, sendit, sock);
792 if (res->res_job.diff_pool) {
793 sendit(sock, _(" --> DifferentialBackup"));
794 dump_resource(-R_POOL, (RES *)res->res_job.diff_pool, sendit, sock);
796 if (res->res_job.verify_job) {
797 sendit(sock, _(" --> "));
798 dump_resource(-type, (RES *)res->res_job.verify_job, sendit, sock);
800 if (res->res_job.run_cmds) {
802 foreach_alist(runcmd, res->res_job.run_cmds) {
803 sendit(sock, _(" --> Run=%s\n"), runcmd);
806 if (res->res_job.selection_pattern) {
807 sendit(sock, _(" --> SelectionPattern=%s\n"), NPRT(res->res_job.selection_pattern));
809 if (res->res_job.messages) {
810 sendit(sock, _(" --> "));
811 dump_resource(-R_MSGS, (RES *)res->res_job.messages, sendit, sock);
818 if (!acl_access_ok(ua, FileSet_ACL, res->res_fs.hdr.name)) {
821 sendit(sock, _("FileSet: name=%s\n"), res->res_fs.hdr.name);
822 for (i=0; i<res->res_fs.num_includes; i++) {
823 INCEXE *incexe = res->res_fs.include_items[i];
824 for (j=0; j<incexe->num_opts; j++) {
825 FOPTS *fo = incexe->opts_list[j];
826 sendit(sock, " O %s\n", fo->opts);
828 bool enhanced_wild = false;
829 for (k=0; fo->opts[k]!='\0'; k++) {
830 if (fo->opts[k]=='W') {
831 enhanced_wild = true;
836 for (k=0; k<fo->regex.size(); k++) {
837 sendit(sock, " R %s\n", fo->regex.get(k));
839 for (k=0; k<fo->regexdir.size(); k++) {
840 sendit(sock, " RD %s\n", fo->regexdir.get(k));
842 for (k=0; k<fo->regexfile.size(); k++) {
843 sendit(sock, " RF %s\n", fo->regexfile.get(k));
845 for (k=0; k<fo->wild.size(); k++) {
846 sendit(sock, " W %s\n", fo->wild.get(k));
848 for (k=0; k<fo->wilddir.size(); k++) {
849 sendit(sock, " WD %s\n", fo->wilddir.get(k));
851 for (k=0; k<fo->wildfile.size(); k++) {
852 sendit(sock, " WF %s\n", fo->wildfile.get(k));
854 for (k=0; k<fo->wildbase.size(); k++) {
855 sendit(sock, " W%c %s\n", enhanced_wild ? 'B' : 'F', fo->wildbase.get(k));
857 for (k=0; k<fo->base.size(); k++) {
858 sendit(sock, " B %s\n", fo->base.get(k));
860 for (k=0; k<fo->fstype.size(); k++) {
861 sendit(sock, " X %s\n", fo->fstype.get(k));
863 for (k=0; k<fo->drivetype.size(); k++) {
864 sendit(sock, " XD %s\n", fo->drivetype.get(k));
867 sendit(sock, " G %s\n", fo->plugin);
870 sendit(sock, " D %s\n", fo->reader);
873 sendit(sock, " T %s\n", fo->writer);
875 sendit(sock, " N\n");
877 if (incexe->ignoredir) {
878 sendit(sock, " Z %s\n", incexe->ignoredir);
880 for (j=0; j<incexe->name_list.size(); j++) {
881 sendit(sock, " I %s\n", incexe->name_list.get(j));
883 if (incexe->name_list.size()) {
884 sendit(sock, " N\n");
886 for (j=0; j<incexe->plugin_list.size(); j++) {
887 sendit(sock, " P %s\n", incexe->plugin_list.get(j));
889 if (incexe->plugin_list.size()) {
890 sendit(sock, " N\n");
892 } /* end for over includes */
894 for (i=0; i<res->res_fs.num_excludes; i++) {
895 INCEXE *incexe = res->res_fs.exclude_items[i];
896 for (j=0; j<incexe->name_list.size(); j++) {
897 sendit(sock, " E %s\n", incexe->name_list.get(j));
899 if (incexe->name_list.size()) {
900 sendit(sock, " N\n");
904 } /* end case R_FILESET */
907 if (!acl_access_ok(ua, Schedule_ACL, res->res_sch.hdr.name)) {
911 if (res->res_sch.run) {
913 RUN *run = res->res_sch.run;
914 char buf[1000], num[30];
915 sendit(sock, _("Schedule: Name=%s Enabled=%d\n"),
916 res->res_sch.hdr.name, res->res_sch.enabled);
921 sendit(sock, _(" --> Run Level=%s\n"), level_to_str(run->level));
922 if (run->MaxRunSchedTime) {
923 sendit(sock, _(" MaxRunSchedTime=%u\n"), run->MaxRunSchedTime);
926 sendit(sock, _(" Priority=%u\n"), run->Priority);
928 bstrncpy(buf, _(" hour="), sizeof(buf));
929 for (i=0; i<24; i++) {
930 if (bit_is_set(i, run->hour)) {
931 bsnprintf(num, sizeof(num), "%d ", i);
932 bstrncat(buf, num, sizeof(buf));
935 bstrncat(buf, "\n", sizeof(buf));
937 bstrncpy(buf, _(" mday="), sizeof(buf));
938 for (i=0; i<32; i++) {
939 if (bit_is_set(i, run->mday)) {
940 bsnprintf(num, sizeof(num), "%d ", i);
941 bstrncat(buf, num, sizeof(buf));
944 bstrncat(buf, "\n", sizeof(buf));
946 bstrncpy(buf, _(" month="), sizeof(buf));
947 for (i=0; i<12; i++) {
948 if (bit_is_set(i, run->month)) {
949 bsnprintf(num, sizeof(num), "%d ", i);
950 bstrncat(buf, num, sizeof(buf));
953 bstrncat(buf, "\n", sizeof(buf));
955 bstrncpy(buf, _(" wday="), sizeof(buf));
956 for (i=0; i<7; i++) {
957 if (bit_is_set(i, run->wday)) {
958 bsnprintf(num, sizeof(num), "%d ", i);
959 bstrncat(buf, num, sizeof(buf));
962 bstrncat(buf, "\n", sizeof(buf));
964 bstrncpy(buf, _(" wom="), sizeof(buf));
965 for (i=0; i<6; i++) {
966 if (bit_is_set(i, run->wom)) {
967 bsnprintf(num, sizeof(num), "%d ", i);
968 bstrncat(buf, num, sizeof(buf));
971 bstrncat(buf, "\n", sizeof(buf));
973 bstrncpy(buf, _(" woy="), sizeof(buf));
974 for (i=0; i<54; i++) {
975 if (bit_is_set(i, run->woy)) {
976 bsnprintf(num, sizeof(num), "%d ", i);
977 bstrncat(buf, num, sizeof(buf));
980 bstrncat(buf, "\n", sizeof(buf));
982 sendit(sock, _(" mins=%d\n"), run->minute);
984 sendit(sock, _(" --> "));
985 dump_resource(-R_POOL, (RES *)run->pool, sendit, sock);
988 sendit(sock, _(" --> "));
989 dump_resource(-R_STORAGE, (RES *)run->storage, sendit, sock);
992 sendit(sock, _(" --> "));
993 dump_resource(-R_MSGS, (RES *)run->msgs, sendit, sock);
995 /* If another Run record is chained in, go print it */
1001 sendit(sock, _("Schedule: name=%s\n"), res->res_sch.hdr.name);
1006 if (!acl_access_ok(ua, Pool_ACL, res->res_pool.hdr.name)) {
1009 sendit(sock, _("Pool: name=%s PoolType=%s\n"), res->res_pool.hdr.name,
1010 res->res_pool.pool_type);
1011 sendit(sock, _(" use_cat=%d use_once=%d cat_files=%d\n"),
1012 res->res_pool.use_catalog, res->res_pool.use_volume_once,
1013 res->res_pool.catalog_files);
1014 sendit(sock, _(" max_vols=%d auto_prune=%d VolRetention=%s\n"),
1015 res->res_pool.max_volumes, res->res_pool.AutoPrune,
1016 edit_utime(res->res_pool.VolRetention, ed1, sizeof(ed1)));
1017 sendit(sock, _(" VolUse=%s recycle=%d LabelFormat=%s\n"),
1018 edit_utime(res->res_pool.VolUseDuration, ed1, sizeof(ed1)),
1019 res->res_pool.Recycle,
1020 NPRT(res->res_pool.label_format));
1021 sendit(sock, _(" CleaningPrefix=%s LabelType=%d\n"),
1022 NPRT(res->res_pool.cleaning_prefix), res->res_pool.LabelType);
1023 sendit(sock, _(" RecyleOldest=%d PurgeOldest=%d ActionOnPurge=%d\n"),
1024 res->res_pool.recycle_oldest_volume,
1025 res->res_pool.purge_oldest_volume,
1026 res->res_pool.action_on_purge);
1027 sendit(sock, _(" MaxVolJobs=%d MaxVolFiles=%d MaxVolBytes=%s\n"),
1028 res->res_pool.MaxVolJobs,
1029 res->res_pool.MaxVolFiles,
1030 edit_uint64(res->res_pool.MaxVolBytes, ed1));
1031 sendit(sock, _(" MigTime=%s MigHiBytes=%s MigLoBytes=%s\n"),
1032 edit_utime(res->res_pool.MigrationTime, ed1, sizeof(ed1)),
1033 edit_uint64(res->res_pool.MigrationHighBytes, ed2),
1034 edit_uint64(res->res_pool.MigrationLowBytes, ed3));
1035 sendit(sock, _(" JobRetention=%s FileRetention=%s\n"),
1036 edit_utime(res->res_pool.JobRetention, ed1, sizeof(ed1)),
1037 edit_utime(res->res_pool.FileRetention, ed2, sizeof(ed2)));
1038 if (res->res_pool.NextPool) {
1039 sendit(sock, _(" NextPool=%s\n"), res->res_pool.NextPool->name());
1041 if (res->res_pool.RecyclePool) {
1042 sendit(sock, _(" RecyclePool=%s\n"), res->res_pool.RecyclePool->name());
1044 if (res->res_pool.ScratchPool) {
1045 sendit(sock, _(" ScratchPool=%s\n"), res->res_pool.ScratchPool->name());
1047 if (res->res_pool.catalog) {
1048 sendit(sock, _(" Catalog=%s\n"), res->res_pool.catalog->name());
1050 if (res->res_pool.storage) {
1052 foreach_alist(store, res->res_pool.storage) {
1053 sendit(sock, _(" --> "));
1054 dump_resource(-R_STORAGE, (RES *)store, sendit, sock);
1057 if (res->res_pool.CopyPool) {
1059 foreach_alist(copy, res->res_pool.CopyPool) {
1060 sendit(sock, _(" --> "));
1061 dump_resource(-R_POOL, (RES *)copy, sendit, sock);
1068 sendit(sock, _("Messages: name=%s\n"), res->res_msgs.hdr.name);
1069 if (res->res_msgs.mail_cmd)
1070 sendit(sock, _(" mailcmd=%s\n"), res->res_msgs.mail_cmd);
1071 if (res->res_msgs.operator_cmd)
1072 sendit(sock, _(" opcmd=%s\n"), res->res_msgs.operator_cmd);
1076 sendit(sock, _("Unknown resource type %d in dump_resource.\n"), type);
1079 if (recurse && res->res_dir.hdr.next) {
1080 dump_resource(type, res->res_dir.hdr.next, sendit, sock);
1086 * Free all the members of an INCEXE structure
1088 static void free_incexe(INCEXE *incexe)
1090 incexe->name_list.destroy();
1091 incexe->plugin_list.destroy();
1092 for (int i=0; i<incexe->num_opts; i++) {
1093 FOPTS *fopt = incexe->opts_list[i];
1094 fopt->regex.destroy();
1095 fopt->regexdir.destroy();
1096 fopt->regexfile.destroy();
1097 fopt->wild.destroy();
1098 fopt->wilddir.destroy();
1099 fopt->wildfile.destroy();
1100 fopt->wildbase.destroy();
1101 fopt->base.destroy();
1102 fopt->fstype.destroy();
1103 fopt->drivetype.destroy();
1115 if (incexe->opts_list) {
1116 free(incexe->opts_list);
1118 if (incexe->ignoredir) {
1119 free(incexe->ignoredir);
1126 * Free memory of resource -- called when daemon terminates.
1127 * NB, we don't need to worry about freeing any references
1128 * to other resources as they will be freed when that
1129 * resource chain is traversed. Mainly we worry about freeing
1130 * allocated strings (names).
1132 void free_resource(RES *rres, int type)
1136 URES *res = (URES *)rres;
1142 Dmsg3(200, "type=%d res=%p name=%s\n", type, res, res->res_dir.hdr.name);
1143 /* common stuff -- free the resource name and description */
1144 nres = (RES *)res->res_dir.hdr.next;
1145 if (res->res_dir.hdr.name) {
1146 free(res->res_dir.hdr.name);
1148 if (res->res_dir.hdr.desc) {
1149 free(res->res_dir.hdr.desc);
1154 if (res->res_dir.working_directory) {
1155 free(res->res_dir.working_directory);
1157 if (res->res_dir.scripts_directory) {
1158 free((char *)res->res_dir.scripts_directory);
1160 if (res->res_dir.plugin_directory) {
1161 free((char *)res->res_dir.plugin_directory);
1163 if (res->res_dir.pid_directory) {
1164 free(res->res_dir.pid_directory);
1166 if (res->res_dir.subsys_directory) {
1167 free(res->res_dir.subsys_directory);
1169 if (res->res_dir.password) {
1170 free(res->res_dir.password);
1172 if (res->res_dir.query_file) {
1173 free(res->res_dir.query_file);
1175 if (res->res_dir.DIRaddrs) {
1176 free_addresses(res->res_dir.DIRaddrs);
1178 if (res->res_dir.DIRsrc_addr) {
1179 free_addresses(res->res_dir.DIRsrc_addr);
1181 if (res->res_dir.tls_ctx) {
1182 free_tls_context(res->res_dir.tls_ctx);
1184 if (res->res_dir.tls_ca_certfile) {
1185 free(res->res_dir.tls_ca_certfile);
1187 if (res->res_dir.tls_ca_certdir) {
1188 free(res->res_dir.tls_ca_certdir);
1190 if (res->res_dir.tls_certfile) {
1191 free(res->res_dir.tls_certfile);
1193 if (res->res_dir.tls_keyfile) {
1194 free(res->res_dir.tls_keyfile);
1196 if (res->res_dir.tls_dhfile) {
1197 free(res->res_dir.tls_dhfile);
1199 if (res->res_dir.tls_allowed_cns) {
1200 delete res->res_dir.tls_allowed_cns;
1202 if (res->res_dir.verid) {
1203 free(res->res_dir.verid);
1210 if (res->res_con.password) {
1211 free(res->res_con.password);
1213 if (res->res_con.tls_ctx) {
1214 free_tls_context(res->res_con.tls_ctx);
1216 if (res->res_con.tls_ca_certfile) {
1217 free(res->res_con.tls_ca_certfile);
1219 if (res->res_con.tls_ca_certdir) {
1220 free(res->res_con.tls_ca_certdir);
1222 if (res->res_con.tls_certfile) {
1223 free(res->res_con.tls_certfile);
1225 if (res->res_con.tls_keyfile) {
1226 free(res->res_con.tls_keyfile);
1228 if (res->res_con.tls_dhfile) {
1229 free(res->res_con.tls_dhfile);
1231 if (res->res_con.tls_allowed_cns) {
1232 delete res->res_con.tls_allowed_cns;
1234 for (int i=0; i<Num_ACL; i++) {
1235 if (res->res_con.ACL_lists[i]) {
1236 delete res->res_con.ACL_lists[i];
1237 res->res_con.ACL_lists[i] = NULL;
1242 if (res->res_client.address) {
1243 free(res->res_client.address);
1245 if (res->res_client.fd_storage_address) {
1246 free(res->res_client.fd_storage_address);
1248 if (res->res_client.password) {
1249 free(res->res_client.password);
1251 if (res->res_client.tls_ctx) {
1252 free_tls_context(res->res_client.tls_ctx);
1254 if (res->res_client.tls_ca_certfile) {
1255 free(res->res_client.tls_ca_certfile);
1257 if (res->res_client.tls_ca_certdir) {
1258 free(res->res_client.tls_ca_certdir);
1260 if (res->res_client.tls_certfile) {
1261 free(res->res_client.tls_certfile);
1263 if (res->res_client.tls_keyfile) {
1264 free(res->res_client.tls_keyfile);
1266 if (res->res_client.tls_allowed_cns) {
1267 delete res->res_client.tls_allowed_cns;
1271 if (res->res_store.address) {
1272 free(res->res_store.address);
1274 if (res->res_store.fd_storage_address) {
1275 free(res->res_store.fd_storage_address);
1277 if (res->res_store.password) {
1278 free(res->res_store.password);
1280 if (res->res_store.media_type) {
1281 free(res->res_store.media_type);
1283 if (res->res_store.device) {
1284 delete res->res_store.device;
1286 if (res->res_store.tls_ctx) {
1287 free_tls_context(res->res_store.tls_ctx);
1289 if (res->res_store.tls_ca_certfile) {
1290 free(res->res_store.tls_ca_certfile);
1292 if (res->res_store.tls_ca_certdir) {
1293 free(res->res_store.tls_ca_certdir);
1295 if (res->res_store.tls_certfile) {
1296 free(res->res_store.tls_certfile);
1298 if (res->res_store.tls_keyfile) {
1299 free(res->res_store.tls_keyfile);
1303 if (res->res_cat.db_address) {
1304 free(res->res_cat.db_address);
1306 if (res->res_cat.db_socket) {
1307 free(res->res_cat.db_socket);
1309 if (res->res_cat.db_user) {
1310 free(res->res_cat.db_user);
1312 if (res->res_cat.db_name) {
1313 free(res->res_cat.db_name);
1315 if (res->res_cat.db_driver) {
1316 free(res->res_cat.db_driver);
1318 if (res->res_cat.db_password) {
1319 free(res->res_cat.db_password);
1321 if (res->res_cat.db_ssl_key) {
1322 free(res->res_cat.db_ssl_key);
1324 if (res->res_cat.db_ssl_cert) {
1325 free(res->res_cat.db_ssl_cert);
1327 if (res->res_cat.db_ssl_ca) {
1328 free(res->res_cat.db_ssl_ca);
1330 if (res->res_cat.db_ssl_capath) {
1331 free(res->res_cat.db_ssl_capath);
1333 if (res->res_cat.db_ssl_cipher) {
1334 free(res->res_cat.db_ssl_cipher);
1338 if ((num=res->res_fs.num_includes)) {
1339 while (--num >= 0) {
1340 free_incexe(res->res_fs.include_items[num]);
1342 free(res->res_fs.include_items);
1344 res->res_fs.num_includes = 0;
1345 if ((num=res->res_fs.num_excludes)) {
1346 while (--num >= 0) {
1347 free_incexe(res->res_fs.exclude_items[num]);
1349 free(res->res_fs.exclude_items);
1351 res->res_fs.num_excludes = 0;
1354 if (res->res_pool.pool_type) {
1355 free(res->res_pool.pool_type);
1357 if (res->res_pool.label_format) {
1358 free(res->res_pool.label_format);
1360 if (res->res_pool.cleaning_prefix) {
1361 free(res->res_pool.cleaning_prefix);
1363 if (res->res_pool.storage) {
1364 delete res->res_pool.storage;
1368 if (res->res_sch.run) {
1370 nrun = res->res_sch.run;
1380 if (res->res_job.RestoreWhere) {
1381 free(res->res_job.RestoreWhere);
1383 if (res->res_job.RegexWhere) {
1384 free(res->res_job.RegexWhere);
1386 if (res->res_job.strip_prefix) {
1387 free(res->res_job.strip_prefix);
1389 if (res->res_job.add_prefix) {
1390 free(res->res_job.add_prefix);
1392 if (res->res_job.add_suffix) {
1393 free(res->res_job.add_suffix);
1395 if (res->res_job.RestoreBootstrap) {
1396 free(res->res_job.RestoreBootstrap);
1398 if (res->res_job.WriteBootstrap) {
1399 free(res->res_job.WriteBootstrap);
1401 if (res->res_job.PluginOptions) {
1402 free(res->res_job.PluginOptions);
1404 if (res->res_job.selection_pattern) {
1405 free(res->res_job.selection_pattern);
1407 if (res->res_job.run_cmds) {
1408 delete res->res_job.run_cmds;
1410 if (res->res_job.storage) {
1411 delete res->res_job.storage;
1413 if (res->res_job.base) {
1414 delete res->res_job.base;
1416 if (res->res_job.RunScripts) {
1417 free_runscripts(res->res_job.RunScripts);
1418 delete res->res_job.RunScripts;
1422 if (res->res_msgs.mail_cmd) {
1423 free(res->res_msgs.mail_cmd);
1425 if (res->res_msgs.operator_cmd) {
1426 free(res->res_msgs.operator_cmd);
1428 free_msgs_res((MSGS *)res); /* free message resource */
1432 printf(_("Unknown resource type %d in free_resource.\n"), type);
1434 /* Common stuff again -- free the resource, recurse to next one */
1439 free_resource(nres, type);
1444 * Save the new resource by chaining it into the head list for
1445 * the resource. If this is pass 2, we update any resource
1446 * pointers because they may not have been defined until
1449 void save_resource(int type, RES_ITEM *items, int pass)
1452 int rindex = type - r_first;
1456 /* Check Job requirements after applying JobDefs */
1457 if (type != R_JOB && type != R_JOBDEFS) {
1459 * Ensure that all required items are present
1461 for (i=0; items[i].name; i++) {
1462 if (items[i].flags & ITEM_REQUIRED) {
1463 if (!bit_is_set(i, res_all.res_dir.hdr.item_present)) {
1464 Emsg2(M_ERROR_TERM, 0, _("%s item is required in %s resource, but not found.\n"),
1465 items[i].name, resources[rindex]);
1468 /* If this triggers, take a look at lib/parse_conf.h */
1469 if (i >= MAX_RES_ITEMS) {
1470 Emsg1(M_ERROR_TERM, 0, _("Too many items in %s resource\n"), resources[rindex]);
1473 } else if (type == R_JOB) {
1475 * Ensure that the name item is present
1477 if (items[0].flags & ITEM_REQUIRED) {
1478 if (!bit_is_set(0, res_all.res_dir.hdr.item_present)) {
1479 Emsg2(M_ERROR_TERM, 0, _("%s item is required in %s resource, but not found.\n"),
1480 items[0].name, resources[rindex]);
1486 * During pass 2 in each "store" routine, we looked up pointers
1487 * to all the resources referrenced in the current resource, now we
1488 * must copy their addresses from the static record to the allocated
1493 /* Resources not containing a resource */
1501 * Resources containing another resource or alist. First
1502 * look up the resource which contains another resource. It
1503 * was written during pass 1. Then stuff in the pointers to
1504 * the resources it contains, which were inserted this pass.
1505 * Finally, it will all be stored back.
1508 /* Find resource saved in pass 1 */
1509 if ((res = (URES *)GetResWithName(R_POOL, res_all.res_con.hdr.name)) == NULL) {
1510 Emsg1(M_ERROR_TERM, 0, _("Cannot find Pool resource %s\n"), res_all.res_con.hdr.name);
1512 /* Explicitly copy resource pointers from this pass (res_all) */
1513 res->res_pool.NextPool = res_all.res_pool.NextPool;
1514 res->res_pool.RecyclePool = res_all.res_pool.RecyclePool;
1515 res->res_pool.ScratchPool = res_all.res_pool.ScratchPool;
1516 res->res_pool.storage = res_all.res_pool.storage;
1517 res->res_pool.catalog = res_all.res_pool.catalog;
1520 if ((res = (URES *)GetResWithName(R_CONSOLE, res_all.res_con.hdr.name)) == NULL) {
1521 Emsg1(M_ERROR_TERM, 0, _("Cannot find Console resource %s\n"), res_all.res_con.hdr.name);
1523 res->res_con.tls_allowed_cns = res_all.res_con.tls_allowed_cns;
1526 if ((res = (URES *)GetResWithName(R_DIRECTOR, res_all.res_dir.hdr.name)) == NULL) {
1527 Emsg1(M_ERROR_TERM, 0, _("Cannot find Director resource %s\n"), res_all.res_dir.hdr.name);
1529 res->res_dir.messages = res_all.res_dir.messages;
1530 res->res_dir.tls_allowed_cns = res_all.res_dir.tls_allowed_cns;
1533 if ((res = (URES *)GetResWithName(type, res_all.res_store.hdr.name)) == NULL) {
1534 Emsg1(M_ERROR_TERM, 0, _("Cannot find Storage resource %s\n"),
1535 res_all.res_dir.hdr.name);
1537 /* we must explicitly copy the device alist pointer */
1538 res->res_store.device = res_all.res_store.device;
1542 if ((res = (URES *)GetResWithName(type, res_all.res_dir.hdr.name)) == NULL) {
1543 Emsg1(M_ERROR_TERM, 0, _("Cannot find Job resource %s\n"),
1544 res_all.res_dir.hdr.name);
1546 res->res_job.messages = res_all.res_job.messages;
1547 res->res_job.schedule = res_all.res_job.schedule;
1548 res->res_job.client = res_all.res_job.client;
1549 res->res_job.fileset = res_all.res_job.fileset;
1550 res->res_job.storage = res_all.res_job.storage;
1551 res->res_job.base = res_all.res_job.base;
1552 res->res_job.pool = res_all.res_job.pool;
1553 res->res_job.next_pool = res_all.res_job.next_pool;
1554 res->res_job.full_pool = res_all.res_job.full_pool;
1555 res->res_job.inc_pool = res_all.res_job.inc_pool;
1556 res->res_job.diff_pool = res_all.res_job.diff_pool;
1557 res->res_job.verify_job = res_all.res_job.verify_job;
1558 res->res_job.jobdefs = res_all.res_job.jobdefs;
1559 res->res_job.run_cmds = res_all.res_job.run_cmds;
1560 res->res_job.RunScripts = res_all.res_job.RunScripts;
1562 /* TODO: JobDefs where/regexwhere doesn't work well (but this
1563 * is not very useful)
1564 * We have to set_bit(index, res_all.hdr.item_present);
1565 * or something like that
1568 /* we take RegexWhere before all other options */
1569 if (!res->res_job.RegexWhere
1571 (res->res_job.strip_prefix ||
1572 res->res_job.add_suffix ||
1573 res->res_job.add_prefix))
1575 int len = bregexp_get_build_where_size(res->res_job.strip_prefix,
1576 res->res_job.add_prefix,
1577 res->res_job.add_suffix);
1578 res->res_job.RegexWhere = (char *) bmalloc (len * sizeof(char));
1579 bregexp_build_where(res->res_job.RegexWhere, len,
1580 res->res_job.strip_prefix,
1581 res->res_job.add_prefix,
1582 res->res_job.add_suffix);
1583 /* TODO: test bregexp */
1586 if (res->res_job.RegexWhere && res->res_job.RestoreWhere) {
1587 free(res->res_job.RestoreWhere);
1588 res->res_job.RestoreWhere = NULL;
1593 if ((res = (URES *)GetResWithName(R_COUNTER, res_all.res_counter.hdr.name)) == NULL) {
1594 Emsg1(M_ERROR_TERM, 0, _("Cannot find Counter resource %s\n"), res_all.res_counter.hdr.name);
1596 res->res_counter.Catalog = res_all.res_counter.Catalog;
1597 res->res_counter.WrapCounter = res_all.res_counter.WrapCounter;
1601 if ((res = (URES *)GetResWithName(R_CLIENT, res_all.res_client.hdr.name)) == NULL) {
1602 Emsg1(M_ERROR_TERM, 0, _("Cannot find Client resource %s\n"), res_all.res_client.hdr.name);
1604 res->res_client.catalog = res_all.res_client.catalog;
1605 res->res_client.tls_allowed_cns = res_all.res_client.tls_allowed_cns;
1609 * Schedule is a bit different in that it contains a RUN record
1610 * chain which isn't a "named" resource. This chain was linked
1611 * in by run_conf.c during pass 2, so here we jam the pointer
1612 * into the Schedule resource.
1614 if ((res = (URES *)GetResWithName(R_SCHEDULE, res_all.res_client.hdr.name)) == NULL) {
1615 Emsg1(M_ERROR_TERM, 0, _("Cannot find Schedule resource %s\n"), res_all.res_client.hdr.name);
1617 res->res_sch.run = res_all.res_sch.run;
1620 Emsg1(M_ERROR, 0, _("Unknown resource type %d in save_resource.\n"), type);
1624 /* Note, the resource name was already saved during pass 1,
1625 * so here, we can just release it.
1627 if (res_all.res_dir.hdr.name) {
1628 free(res_all.res_dir.hdr.name);
1629 res_all.res_dir.hdr.name = NULL;
1631 if (res_all.res_dir.hdr.desc) {
1632 free(res_all.res_dir.hdr.desc);
1633 res_all.res_dir.hdr.desc = NULL;
1639 * The following code is only executed during pass 1
1643 size = sizeof(DIRRES);
1646 size = sizeof(CONRES);
1649 size =sizeof(CLIENT);
1652 size = sizeof(STORE);
1662 size = sizeof(FILESET);
1665 size = sizeof(SCHED);
1668 size = sizeof(POOL);
1671 size = sizeof(MSGS);
1674 size = sizeof(COUNTER);
1680 printf(_("Unknown resource type %d in save_resource.\n"), type);
1686 res = (URES *)malloc(size);
1687 memcpy(res, &res_all, size);
1688 if (!res_head[rindex]) {
1689 res_head[rindex] = (RES *)res; /* store first entry */
1690 Dmsg3(900, "Inserting first %s res: %s index=%d\n", res_to_str(type),
1691 res->res_dir.hdr.name, rindex);
1694 if (res->res_dir.hdr.name == NULL) {
1695 Emsg1(M_ERROR_TERM, 0, _("Name item is required in %s resource, but not found.\n"),
1698 /* Add new res to end of chain */
1699 for (last=next=res_head[rindex]; next; next=next->next) {
1701 if (strcmp(next->name, res->res_dir.hdr.name) == 0) {
1702 Emsg2(M_ERROR_TERM, 0,
1703 _("Attempt to define second %s resource named \"%s\" is not permitted.\n"),
1704 resources[rindex].name, res->res_dir.hdr.name);
1707 last->next = (RES *)res;
1708 Dmsg4(900, _("Inserting %s res: %s index=%d pass=%d\n"), res_to_str(type),
1709 res->res_dir.hdr.name, rindex, pass);
1714 void store_actiononpurge(LEX *lc, RES_ITEM *item, int index, int pass)
1716 uint32_t *destination = (uint32_t*)item->value;
1717 lex_get_token(lc, T_NAME);
1718 if (strcasecmp(lc->str, "truncate") == 0) {
1719 *destination = (*destination) | ON_PURGE_TRUNCATE;
1721 scan_err2(lc, _("Expected one of: %s, got: %s"), "Truncate", lc->str);
1725 set_bit(index, res_all.hdr.item_present);
1729 * Store Device. Note, the resource is created upon the
1730 * first reference. The details of the resource are obtained
1731 * later from the SD.
1733 static void store_device(LEX *lc, RES_ITEM *item, int index, int pass)
1736 int rindex = R_DEVICE - r_first;
1737 int size = sizeof(DEVICE);
1741 lex_get_token(lc, T_NAME);
1742 if (!res_head[rindex]) {
1743 res = (URES *)malloc(size);
1744 memset(res, 0, size);
1745 res->res_dev.hdr.name = bstrdup(lc->str);
1746 res_head[rindex] = (RES *)res; /* store first entry */
1747 Dmsg3(900, "Inserting first %s res: %s index=%d\n", res_to_str(R_DEVICE),
1748 res->res_dir.hdr.name, rindex);
1751 /* See if it is already defined */
1752 for (next=res_head[rindex]; next->next; next=next->next) {
1753 if (strcmp(next->name, lc->str) == 0) {
1759 res = (URES *)malloc(size);
1760 memset(res, 0, size);
1761 res->res_dev.hdr.name = bstrdup(lc->str);
1762 next->next = (RES *)res;
1763 Dmsg4(900, "Inserting %s res: %s index=%d pass=%d\n", res_to_str(R_DEVICE),
1764 res->res_dir.hdr.name, rindex, pass);
1769 set_bit(index, res_all.hdr.item_present);
1771 store_alist_res(lc, item, index, pass);
1776 * Store Migration/Copy type
1779 void store_migtype(LEX *lc, RES_ITEM *item, int index, int pass)
1783 lex_get_token(lc, T_NAME);
1784 /* Store the type both pass 1 and pass 2 */
1785 for (i=0; migtypes[i].type_name; i++) {
1786 if (strcasecmp(lc->str, migtypes[i].type_name) == 0) {
1787 *(uint32_t *)(item->value) = migtypes[i].job_type;
1793 scan_err1(lc, _("Expected a Migration Job Type keyword, got: %s"), lc->str);
1796 set_bit(index, res_all.hdr.item_present);
1802 * Store JobType (backup, verify, restore)
1805 void store_jobtype(LEX *lc, RES_ITEM *item, int index, int pass)
1809 lex_get_token(lc, T_NAME);
1810 /* Store the type both pass 1 and pass 2 */
1811 for (i=0; jobtypes[i].type_name; i++) {
1812 if (strcasecmp(lc->str, jobtypes[i].type_name) == 0) {
1813 *(uint32_t *)(item->value) = jobtypes[i].job_type;
1819 scan_err1(lc, _("Expected a Job Type keyword, got: %s"), lc->str);
1822 set_bit(index, res_all.hdr.item_present);
1826 * Store Job Level (Full, Incremental, ...)
1829 void store_level(LEX *lc, RES_ITEM *item, int index, int pass)
1833 lex_get_token(lc, T_NAME);
1834 /* Store the level pass 2 so that type is defined */
1835 for (i=0; joblevels[i].level_name; i++) {
1836 if (strcasecmp(lc->str, joblevels[i].level_name) == 0) {
1837 *(uint32_t *)(item->value) = joblevels[i].level;
1843 scan_err1(lc, _("Expected a Job Level keyword, got: %s"), lc->str);
1846 set_bit(index, res_all.hdr.item_present);
1850 void store_replace(LEX *lc, RES_ITEM *item, int index, int pass)
1853 lex_get_token(lc, T_NAME);
1854 /* Scan Replacement options */
1855 for (i=0; ReplaceOptions[i].name; i++) {
1856 if (strcasecmp(lc->str, ReplaceOptions[i].name) == 0) {
1857 *(uint32_t *)(item->value) = ReplaceOptions[i].token;
1863 scan_err1(lc, _("Expected a Restore replacement option, got: %s"), lc->str);
1866 set_bit(index, res_all.hdr.item_present);
1870 * Store ACL (access control list)
1873 void store_acl(LEX *lc, RES_ITEM *item, int index, int pass)
1878 lex_get_token(lc, T_STRING);
1880 if (((alist **)item->value)[item->code] == NULL) {
1881 ((alist **)item->value)[item->code] = New(alist(10, owned_by_alist));
1882 Dmsg1(900, "Defined new ACL alist at %d\n", item->code);
1884 ((alist **)item->value)[item->code]->append(bstrdup(lc->str));
1885 Dmsg2(900, "Appended to %d %s\n", item->code, lc->str);
1887 token = lex_get_token(lc, T_ALL);
1888 if (token == T_COMMA) {
1889 continue; /* get another ACL */
1893 set_bit(index, res_all.hdr.item_present);
1896 /* We build RunScripts items here */
1897 static RUNSCRIPT res_runscript;
1899 /* Store a runscript->when in a bit field */
1900 static void store_runscript_when(LEX *lc, RES_ITEM *item, int index, int pass)
1902 lex_get_token(lc, T_NAME);
1904 if (strcasecmp(lc->str, "before") == 0) {
1905 *(uint32_t *)(item->value) = SCRIPT_Before ;
1906 } else if (strcasecmp(lc->str, "after") == 0) {
1907 *(uint32_t *)(item->value) = SCRIPT_After;
1908 } else if (strcasecmp(lc->str, "aftervss") == 0) {
1909 *(uint32_t *)(item->value) = SCRIPT_AfterVSS;
1910 } else if (strcasecmp(lc->str, "aftersnapshot") == 0) {
1911 *(uint32_t *)(item->value) = SCRIPT_AfterVSS;
1912 } else if (strcasecmp(lc->str, "always") == 0) {
1913 *(uint32_t *)(item->value) = SCRIPT_Any;
1915 scan_err2(lc, _("Expect %s, got: %s"), "Before, After, AfterVSS or Always", lc->str);
1920 /* Store a runscript->target
1923 static void store_runscript_target(LEX *lc, RES_ITEM *item, int index, int pass)
1925 lex_get_token(lc, T_STRING);
1928 if (strcmp(lc->str, "%c") == 0) {
1929 ((RUNSCRIPT*) item->value)->set_target(lc->str);
1930 } else if (strcasecmp(lc->str, "yes") == 0) {
1931 ((RUNSCRIPT*) item->value)->set_target("%c");
1932 } else if (strcasecmp(lc->str, "no") == 0) {
1933 ((RUNSCRIPT*) item->value)->set_target("");
1935 RES *res = GetResWithName(R_CLIENT, lc->str);
1937 scan_err3(lc, _("Could not find config Resource %s referenced on line %d : %s\n"),
1938 lc->str, lc->line_no, lc->line);
1941 ((RUNSCRIPT*) item->value)->set_target(lc->str);
1948 * Store a runscript->command as a string and runscript->cmd_type as a pointer
1950 static void store_runscript_cmd(LEX *lc, RES_ITEM *item, int index, int pass)
1952 lex_get_token(lc, T_STRING);
1955 Dmsg2(1, "runscript cmd=%s type=%c\n", lc->str, item->code);
1956 POOLMEM *c = get_pool_memory(PM_FNAME);
1957 /* Each runscript command takes 2 entries in commands list */
1958 pm_strcpy(c, lc->str);
1959 ((RUNSCRIPT*) item->value)->commands->prepend(c); /* command line */
1960 ((RUNSCRIPT*) item->value)->commands->prepend((void *)(intptr_t)item->code); /* command type */
1965 static void store_short_runscript(LEX *lc, RES_ITEM *item, int index, int pass)
1967 lex_get_token(lc, T_STRING);
1968 alist **runscripts = (alist **)(item->value) ;
1971 RUNSCRIPT *script = new_runscript();
1972 script->set_job_code_callback(job_code_callback_director);
1974 script->set_command(lc->str);
1976 /* TODO: remove all script->old_proto with bacula 1.42 */
1978 if (strcasecmp(item->name, "runbeforejob") == 0) {
1979 script->when = SCRIPT_Before;
1980 script->fail_on_error = true;
1981 script->set_target("");
1983 } else if (strcasecmp(item->name, "runafterjob") == 0) {
1984 script->when = SCRIPT_After;
1985 script->on_success = true;
1986 script->on_failure = false;
1987 script->set_target("");
1989 } else if (strcasecmp(item->name, "clientrunbeforejob") == 0) {
1990 script->old_proto = true;
1991 script->when = SCRIPT_Before;
1992 script->set_target("%c");
1993 script->fail_on_error = true;
1995 } else if (strcasecmp(item->name, "clientrunafterjob") == 0) {
1996 script->old_proto = true;
1997 script->when = SCRIPT_After;
1998 script->set_target("%c");
1999 script->on_success = true;
2000 script->on_failure = false;
2002 } else if (strcasecmp(item->name, "consolerunbeforejob") == 0) {
2003 script->when = SCRIPT_Before;
2004 script->set_target("");
2005 script->fail_on_error = true;
2006 script->set_command(NPRT(script->command), CONSOLE_CMD);
2008 } else if (strcasecmp(item->name, "consolerunafterjob") == 0) {
2009 script->when = SCRIPT_After;
2010 script->set_target("");
2011 script->on_success = true;
2012 script->on_failure = false;
2013 script->set_command(NPRT(script->command), CONSOLE_CMD);
2015 } else if (strcasecmp(item->name, "runafterfailedjob") == 0) {
2016 script->when = SCRIPT_After;
2017 script->on_failure = true;
2018 script->on_success = false;
2019 script->set_target("");
2022 if (*runscripts == NULL) {
2023 *runscripts = New(alist(10, not_owned_by_alist));
2026 (*runscripts)->append(script);
2030 set_bit(index, res_all.hdr.item_present);
2033 /* Store a bool in a bit field without modifing res_all.hdr
2034 * We can also add an option to store_bool to skip res_all.hdr
2036 void store_runscript_bool(LEX *lc, RES_ITEM *item, int index, int pass)
2038 lex_get_token(lc, T_NAME);
2039 if (strcasecmp(lc->str, "yes") == 0 || strcasecmp(lc->str, "true") == 0) {
2040 *(bool *)(item->value) = true;
2041 } else if (strcasecmp(lc->str, "no") == 0 || strcasecmp(lc->str, "false") == 0) {
2042 *(bool *)(item->value) = false;
2044 scan_err2(lc, _("Expect %s, got: %s"), "YES, NO, TRUE, or FALSE", lc->str); /* YES and NO must not be translated */
2050 * new RunScript items
2051 * name handler value code flags default_value
2053 static RES_ITEM runscript_items[] = {
2054 {"command", store_runscript_cmd, {(char **)&res_runscript}, SHELL_CMD, 0, 0},
2055 {"console", store_runscript_cmd, {(char **)&res_runscript}, CONSOLE_CMD, 0, 0},
2056 {"target", store_runscript_target,{(char **)&res_runscript}, 0, 0, 0},
2057 {"runsonsuccess", store_runscript_bool, {(char **)&res_runscript.on_success},0, 0, 0},
2058 {"runsonfailure", store_runscript_bool, {(char **)&res_runscript.on_failure},0, 0, 0},
2059 {"failjobonerror",store_runscript_bool, {(char **)&res_runscript.fail_on_error},0, 0, 0},
2060 {"abortjobonerror",store_runscript_bool, {(char **)&res_runscript.fail_on_error},0, 0, 0},
2061 {"runswhen", store_runscript_when, {(char **)&res_runscript.when}, 0, 0, 0},
2062 {"runsonclient", store_runscript_target,{(char **)&res_runscript}, 0, 0, 0}, /* TODO */
2063 {NULL, NULL, {0}, 0, 0, 0}
2067 * Store RunScript info
2069 * Note, when this routine is called, we are inside a Job
2070 * resource. We treat the RunScript like a sort of
2071 * mini-resource within the Job resource.
2073 void store_runscript(LEX *lc, RES_ITEM *item, int index, int pass)
2077 alist **runscripts = (alist **)(item->value) ;
2079 Dmsg1(200, "store_runscript: begin store_runscript pass=%i\n", pass);
2081 token = lex_get_token(lc, T_SKIP_EOL);
2083 if (token != T_BOB) {
2084 scan_err1(lc, _("Expecting open brace. Got %s"), lc->str);
2086 /* setting on_success, on_failure, fail_on_error */
2087 res_runscript.reset_default();
2090 res_runscript.commands = New(alist(10, not_owned_by_alist));
2093 while ((token = lex_get_token(lc, T_SKIP_EOL)) != T_EOF) {
2094 if (token == T_EOB) {
2097 if (token != T_IDENTIFIER) {
2098 scan_err1(lc, _("Expecting keyword, got: %s\n"), lc->str);
2100 for (i=0; runscript_items[i].name; i++) {
2101 if (strcasecmp(runscript_items[i].name, lc->str) == 0) {
2102 token = lex_get_token(lc, T_SKIP_EOL);
2103 if (token != T_EQUALS) {
2104 scan_err1(lc, _("expected an equals, got: %s"), lc->str);
2107 /* Call item handler */
2108 runscript_items[i].handler(lc, &runscript_items[i], i, pass);
2115 scan_err1(lc, _("Keyword %s not permitted in this resource"), lc->str);
2120 /* run on client by default */
2121 if (res_runscript.target == NULL) {
2122 res_runscript.set_target("%c");
2124 if (*runscripts == NULL) {
2125 *runscripts = New(alist(10, not_owned_by_alist));
2128 * commands list contains 2 values per command
2129 * - POOLMEM command string (ex: /bin/true)
2130 * - int command type (ex: SHELL_CMD)
2132 res_runscript.set_job_code_callback(job_code_callback_director);
2133 while ((c=(char*)res_runscript.commands->pop()) != NULL) {
2134 t = (intptr_t)res_runscript.commands->pop();
2135 RUNSCRIPT *script = new_runscript();
2136 memcpy(script, &res_runscript, sizeof(RUNSCRIPT));
2137 script->command = c;
2138 script->cmd_type = t;
2139 /* target is taken from res_runscript, each runscript object have
2142 script->target = NULL;
2143 script->set_target(res_runscript.target);
2145 (*runscripts)->append(script);
2148 delete res_runscript.commands;
2149 /* setting on_success, on_failure... cleanup target field */
2150 res_runscript.reset_default(true);
2154 set_bit(index, res_all.hdr.item_present);
2157 /* callback function for edit_job_codes */
2158 /* See ../lib/util.c, function edit_job_codes, for more remaining codes */
2159 extern "C" char *job_code_callback_director(JCR *jcr, const char* param)
2161 static char yes[] = "yes";
2162 static char no[] = "no";
2166 return jcr->fileset->name();
2170 if (jcr->client && jcr->client->address) {
2171 return jcr->client->address;
2176 return jcr->pool->name();
2181 return jcr->wstore->name();
2185 return jcr->spool_data ? yes : no;
2189 return jcr->cloned ? yes : no;
2194 bool parse_dir_config(CONFIG *config, const char *configfile, int exit_code)
2196 config->init(configfile, NULL, exit_code, (void *)&res_all, res_all_size,
2197 r_first, r_last, resources, res_head);
2198 return config->parse_config();