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 {"Runscript", store_runscript, ITEM(res_job.RunScripts), 0, ITEM_NO_EQUALS, 0},
334 {"MaximumConcurrentJobs", store_pint32, ITEM(res_job.MaxConcurrentJobs), 0, ITEM_DEFAULT, 1},
335 {"MaximumSpawnedJobs", store_pint32, ITEM(res_job.MaxSpawnedJobs), 0, ITEM_DEFAULT, 600},
336 {"RescheduleOnError", store_bool, ITEM(res_job.RescheduleOnError), 0, ITEM_DEFAULT, false},
337 {"RescheduleIncompleteJobs", store_bool, ITEM(res_job.RescheduleIncompleteJobs), 0, ITEM_DEFAULT, true},
338 {"RescheduleInterval", store_time, ITEM(res_job.RescheduleInterval), 0, ITEM_DEFAULT, 60 * 30},
339 {"RescheduleTimes", store_pint32, ITEM(res_job.RescheduleTimes), 0, 0, 0},
340 {"Priority", store_pint32, ITEM(res_job.Priority), 0, ITEM_DEFAULT, 10},
341 {"AllowMixedPriority", store_bool, ITEM(res_job.allow_mixed_priority), 0, ITEM_DEFAULT, false},
342 {"WritePartAfterJob", store_bool, ITEM(res_job.write_part_after_job), 0, ITEM_DEFAULT, true},
343 {"SelectionPattern", store_str, ITEM(res_job.selection_pattern), 0, 0, 0},
344 {"SelectionType", store_migtype, ITEM(res_job.selection_type), 0, 0, 0},
345 {"Accurate", store_bool, ITEM(res_job.accurate), 0,0,0},
346 {"AllowDuplicateJobs", store_bool, ITEM(res_job.AllowDuplicateJobs), 0, ITEM_DEFAULT, true},
347 {"allowhigherduplicates", store_bool, ITEM(res_job.AllowHigherDuplicates), 0, ITEM_DEFAULT, true},
348 {"CancelLowerLevelDuplicates", store_bool, ITEM(res_job.CancelLowerLevelDuplicates), 0, ITEM_DEFAULT, false},
349 {"CancelQueuedDuplicates", store_bool, ITEM(res_job.CancelQueuedDuplicates), 0, ITEM_DEFAULT, false},
350 {"CancelRunningDuplicates", store_bool, ITEM(res_job.CancelRunningDuplicates), 0, ITEM_DEFAULT, false},
351 {"PluginOptions", store_str, ITEM(res_job.PluginOptions), 0, 0, 0},
352 {"Base", store_alist_res, ITEM(res_job.base), R_JOB, 0, 0},
353 {NULL, NULL, {0}, 0, 0, 0}
358 * Name handler value code flags default_value
360 static RES_ITEM fs_items[] = {
361 {"Name", store_name, ITEM(res_fs.hdr.name), 0, ITEM_REQUIRED, 0},
362 {"Description", store_str, ITEM(res_fs.hdr.desc), 0, 0, 0},
363 {"IgnoreFilesetChanges", store_bool, ITEM(res_fs.ignore_fs_changes), 0, ITEM_DEFAULT, false},
364 {"EnableVss", store_bool, ITEM(res_fs.enable_vss), 0, ITEM_DEFAULT, true},
365 {"EnableSnapshot",store_bool, ITEM(res_fs.enable_snapshot), 0, ITEM_DEFAULT, false},
366 {"Include", store_inc, {0}, 0, ITEM_NO_EQUALS, 0},
367 {"Exclude", store_inc, {0}, 1, ITEM_NO_EQUALS, 0},
368 {NULL, NULL, {0}, 0, 0, 0}
371 /* Schedule -- see run_conf.c */
374 * name handler value code flags default_value
376 static RES_ITEM sch_items[] = {
377 {"Name", store_name, ITEM(res_sch.hdr.name), 0, ITEM_REQUIRED, 0},
378 {"Description", store_str, ITEM(res_sch.hdr.desc), 0, 0, 0},
379 {"Run", store_run, ITEM(res_sch.run), 0, 0, 0},
380 {"Enabled", store_bool, ITEM(res_sch.enabled), 0, ITEM_DEFAULT, true},
381 {NULL, NULL, {0}, 0, 0, 0}
386 * name handler value code flags default_value
388 static RES_ITEM pool_items[] = {
389 {"Name", store_name, ITEM(res_pool.hdr.name), 0, ITEM_REQUIRED, 0},
390 {"Description", store_str, ITEM(res_pool.hdr.desc), 0, 0, 0},
391 {"PoolType", store_strname, ITEM(res_pool.pool_type), 0, ITEM_REQUIRED, 0},
392 {"LabelFormat", store_strname, ITEM(res_pool.label_format), 0, 0, 0},
393 {"LabelType", store_label, ITEM(res_pool.LabelType), 0, 0, 0},
394 {"CleaningPrefix", store_strname, ITEM(res_pool.cleaning_prefix), 0, 0, 0},
395 {"UseCatalog", store_bool, ITEM(res_pool.use_catalog), 0, ITEM_DEFAULT, true},
396 {"UseVolumeOnce", store_bool, ITEM(res_pool.use_volume_once), 0, 0, 0},
397 {"PurgeOldestVolume", store_bool, ITEM(res_pool.purge_oldest_volume), 0, 0, 0},
398 {"ActionOnPurge", store_actiononpurge, ITEM(res_pool.action_on_purge), 0, 0, 0},
399 {"RecycleOldestVolume", store_bool, ITEM(res_pool.recycle_oldest_volume), 0, 0, 0},
400 {"RecycleCurrentVolume", store_bool, ITEM(res_pool.recycle_current_volume), 0, 0, 0},
401 {"MaximumVolumes", store_pint32, ITEM(res_pool.max_volumes), 0, 0, 0},
402 {"MaximumVolumeJobs", store_pint32, ITEM(res_pool.MaxVolJobs), 0, 0, 0},
403 {"MaximumVolumeFiles", store_pint32, ITEM(res_pool.MaxVolFiles), 0, 0, 0},
404 {"MaximumVolumeBytes", store_size64, ITEM(res_pool.MaxVolBytes), 0, 0, 0},
405 {"CatalogFiles", store_bool, ITEM(res_pool.catalog_files), 0, ITEM_DEFAULT, true},
406 {"VolumeRetention", store_time, ITEM(res_pool.VolRetention), 0, ITEM_DEFAULT, 60*60*24*365},
407 {"VolumeUseDuration", store_time, ITEM(res_pool.VolUseDuration), 0, 0, 0},
408 {"MigrationTime", store_time, ITEM(res_pool.MigrationTime), 0, 0, 0},
409 {"MigrationHighBytes", store_size64, ITEM(res_pool.MigrationHighBytes), 0, 0, 0},
410 {"MigrationLowBytes", store_size64, ITEM(res_pool.MigrationLowBytes), 0, 0, 0},
411 {"NextPool", store_res, ITEM(res_pool.NextPool), R_POOL, 0, 0},
412 {"Storage", store_alist_res, ITEM(res_pool.storage), R_STORAGE, 0, 0},
413 {"AutoPrune", store_bool, ITEM(res_pool.AutoPrune), 0, ITEM_DEFAULT, true},
414 {"Recycle", store_bool, ITEM(res_pool.Recycle), 0, ITEM_DEFAULT, true},
415 {"RecyclePool", store_res, ITEM(res_pool.RecyclePool), R_POOL, 0, 0},
416 {"ScratchPool", store_res, ITEM(res_pool.ScratchPool), R_POOL, 0, 0},
417 {"CopyPool", store_alist_res, ITEM(res_pool.CopyPool), R_POOL, 0, 0},
418 {"Catalog", store_res, ITEM(res_pool.catalog), R_CATALOG, 0, 0},
419 {"FileRetention", store_time, ITEM(res_pool.FileRetention), 0, 0, 0},
420 {"JobRetention", store_time, ITEM(res_pool.JobRetention), 0, 0, 0},
422 {NULL, NULL, {0}, 0, 0, 0}
427 * name handler value code flags default_value
429 static RES_ITEM counter_items[] = {
430 {"Name", store_name, ITEM(res_counter.hdr.name), 0, ITEM_REQUIRED, 0},
431 {"Description", store_str, ITEM(res_counter.hdr.desc), 0, 0, 0},
432 {"Minimum", store_int32, ITEM(res_counter.MinValue), 0, ITEM_DEFAULT, 0},
433 {"Maximum", store_pint32, ITEM(res_counter.MaxValue), 0, ITEM_DEFAULT, INT32_MAX},
434 {"WrapCounter", store_res, ITEM(res_counter.WrapCounter), R_COUNTER, 0, 0},
435 {"Catalog", store_res, ITEM(res_counter.Catalog), R_CATALOG, 0, 0},
436 {NULL, NULL, {0}, 0, 0, 0}
440 /* Message resource */
441 extern RES_ITEM msgs_items[];
444 * This is the master resource definition.
445 * It must have one item for each of the resources.
447 * NOTE!!! keep it in the same order as the R_codes
448 * or eliminate all resources[rindex].name
452 RES_TABLE resources[] = {
453 {"Director", dir_items, R_DIRECTOR},
454 {"Client", cli_items, R_CLIENT},
455 {"Job", job_items, R_JOB},
456 {"Storage", store_items, R_STORAGE},
457 {"Catalog", cat_items, R_CATALOG},
458 {"Schedule", sch_items, R_SCHEDULE},
459 {"Fileset", fs_items, R_FILESET},
460 {"Pool", pool_items, R_POOL},
461 {"Messages", msgs_items, R_MSGS},
462 {"Counter", counter_items, R_COUNTER},
463 {"Console", con_items, R_CONSOLE},
464 {"JobDefs", job_items, R_JOBDEFS},
465 {"Device", NULL, R_DEVICE}, /* info obtained from SD */
470 /* Keywords (RHS) permitted in Job Level records
472 * level_name level job_type
474 struct s_jl joblevels[] = {
475 {"Full", L_FULL, JT_BACKUP},
476 {"Base", L_BASE, JT_BACKUP},
477 {"Incremental", L_INCREMENTAL, JT_BACKUP},
478 {"Differential", L_DIFFERENTIAL, JT_BACKUP},
479 {"Since", L_SINCE, JT_BACKUP},
480 {"VirtualFull", L_VIRTUAL_FULL, JT_BACKUP},
481 {"Catalog", L_VERIFY_CATALOG, JT_VERIFY},
482 {"InitCatalog", L_VERIFY_INIT, JT_VERIFY},
483 {"VolumeToCatalog", L_VERIFY_VOLUME_TO_CATALOG, JT_VERIFY},
484 {"DiskToCatalog", L_VERIFY_DISK_TO_CATALOG, JT_VERIFY},
485 {"Data", L_VERIFY_DATA, JT_VERIFY},
486 {"Full", L_FULL, JT_COPY},
487 {"Incremental", L_INCREMENTAL, JT_COPY},
488 {"Differential", L_DIFFERENTIAL, JT_COPY},
489 {"Full", L_FULL, JT_MIGRATE},
490 {"Incremental", L_INCREMENTAL, JT_MIGRATE},
491 {"Differential", L_DIFFERENTIAL, JT_MIGRATE},
492 {" ", L_NONE, JT_ADMIN},
493 {" ", L_NONE, JT_RESTORE},
498 /* Keywords (RHS) permitted in Job type records
503 {"Backup", JT_BACKUP},
505 {"Verify", JT_VERIFY},
506 {"Restore", JT_RESTORE},
507 {"Migrate", JT_MIGRATE},
513 /* Keywords (RHS) permitted in Selection type records
518 {"SmallestVolume", MT_SMALLEST_VOL},
519 {"OldestVolume", MT_OLDEST_VOL},
520 {"PoolOccupancy", MT_POOL_OCCUPANCY},
521 {"PoolTime", MT_POOL_TIME},
522 {"PoolUncopiedJobs", MT_POOL_UNCOPIED_JOBS},
523 {"Client", MT_CLIENT},
524 {"Volume", MT_VOLUME},
526 {"SqlQuery", MT_SQLQUERY},
532 /* Options permitted in Restore replace= */
533 struct s_kw ReplaceOptions[] = {
534 {"Always", REPLACE_ALWAYS},
535 {"IfNewer", REPLACE_IFNEWER},
536 {"IfOlder", REPLACE_IFOLDER},
537 {"Never", REPLACE_NEVER},
541 char *CAT::display(POOLMEM *dst) {
542 Mmsg(dst,"catalog=%s\ndb_name=%s\ndb_driver=%s\ndb_user=%s\n"
543 "db_password=%s\ndb_address=%s\ndb_port=%i\n"
545 name(), NPRTB(db_name),
546 NPRTB(db_driver), NPRTB(db_user), NPRTB(db_password),
547 NPRTB(db_address), db_port, NPRTB(db_socket));
551 const char *level_to_str(int level)
554 static char level_no[30];
555 const char *str = level_no;
557 bsnprintf(level_no, sizeof(level_no), "%c (%d)", level, level); /* default if not found */
558 for (i=0; joblevels[i].level_name; i++) {
559 if (level == (int)joblevels[i].level) {
560 str = joblevels[i].level_name;
567 /* Dump contents of resource */
568 void dump_resource(int type, RES *ares, void sendit(void *sock, const char *fmt, ...), void *sock)
570 URES *res = (URES *)ares;
572 char ed1[100], ed2[100], ed3[100];
574 UAContext *ua = (UAContext *)sock;
577 sendit(sock, _("No %s resource defined\n"), res_to_str(type));
580 if (type < 0) { /* no recursion */
586 sendit(sock, _("Director: name=%s MaxJobs=%d FDtimeout=%s SDtimeout=%s\n"),
587 ares->name, res->res_dir.MaxConcurrentJobs,
588 edit_uint64(res->res_dir.FDConnectTimeout, ed1),
589 edit_uint64(res->res_dir.SDConnectTimeout, ed2));
590 if (res->res_dir.query_file) {
591 sendit(sock, _(" query_file=%s\n"), res->res_dir.query_file);
593 if (res->res_dir.messages) {
594 sendit(sock, _(" --> "));
595 dump_resource(-R_MSGS, (RES *)res->res_dir.messages, sendit, sock);
599 sendit(sock, _("Console: name=%s SSL=%d\n"),
600 res->res_con.hdr.name, res->res_con.tls_enable);
603 if (res->res_counter.WrapCounter) {
604 sendit(sock, _("Counter: name=%s min=%d max=%d cur=%d wrapcntr=%s\n"),
605 res->res_counter.hdr.name, res->res_counter.MinValue,
606 res->res_counter.MaxValue, res->res_counter.CurrentValue,
607 res->res_counter.WrapCounter->hdr.name);
609 sendit(sock, _("Counter: name=%s min=%d max=%d\n"),
610 res->res_counter.hdr.name, res->res_counter.MinValue,
611 res->res_counter.MaxValue);
613 if (res->res_counter.Catalog) {
614 sendit(sock, _(" --> "));
615 dump_resource(-R_CATALOG, (RES *)res->res_counter.Catalog, sendit, sock);
620 if (!acl_access_ok(ua, Client_ACL, res->res_client.hdr.name)) {
623 sendit(sock, _("Client: Name=%s Enabled=%d Address=%s FDport=%d MaxJobs=%u\n"),
624 res->res_client.hdr.name, res->res_client.enabled,
625 res->res_client.address, res->res_client.FDport,
626 res->res_client.MaxConcurrentJobs);
627 sendit(sock, _(" JobRetention=%s FileRetention=%s AutoPrune=%d\n"),
628 edit_utime(res->res_client.JobRetention, ed1, sizeof(ed1)),
629 edit_utime(res->res_client.FileRetention, ed2, sizeof(ed2)),
630 res->res_client.AutoPrune);
631 if (res->res_client.fd_storage_address) {
632 sendit(sock, " FDStorageAddress=%s\n", res->res_client.fd_storage_address);
634 if (res->res_client.max_bandwidth) {
635 sendit(sock, _(" MaximumBandwidth=%lld\n"),
636 res->res_client.max_bandwidth);
638 if (res->res_client.catalog) {
639 sendit(sock, _(" --> "));
640 dump_resource(-R_CATALOG, (RES *)res->res_client.catalog, sendit, sock);
647 sendit(sock, _("Device: name=%s ok=%d num_writers=%d max_writers=%d\n"
648 " reserved=%d open=%d append=%d read=%d labeled=%d offline=%d autochgr=%d\n"
649 " poolid=%s volname=%s MediaType=%s\n"),
650 dev->hdr.name, dev->found, dev->num_writers, dev->max_writers,
651 dev->reserved, dev->open, dev->append, dev->read, dev->labeled,
652 dev->offline, dev->autochanger,
653 edit_uint64(dev->PoolId, ed1),
654 dev->VolumeName, dev->MediaType);
658 if (!acl_access_ok(ua, Storage_ACL, res->res_store.hdr.name)) {
661 sendit(sock, _("Storage: name=%s address=%s SDport=%d MaxJobs=%u\n"
662 " DeviceName=%s MediaType=%s StorageId=%s Autochanger=%d\n"),
663 res->res_store.hdr.name, res->res_store.address, res->res_store.SDport,
664 res->res_store.MaxConcurrentJobs,
665 res->res_store.dev_name(),
666 res->res_store.media_type,
667 edit_int64(res->res_store.StorageId, ed1),
668 res->res_store.autochanger);
669 if (res->res_store.fd_storage_address) {
670 sendit(sock, " FDStorageAddress=%s\n", res->res_store.fd_storage_address);
675 if (!acl_access_ok(ua, Catalog_ACL, res->res_cat.hdr.name)) {
678 sendit(sock, _("Catalog: name=%s address=%s DBport=%d db_name=%s\n"
679 " db_driver=%s db_user=%s MutliDBConn=%d\n"),
680 res->res_cat.hdr.name, NPRT(res->res_cat.db_address),
681 res->res_cat.db_port, res->res_cat.db_name,
682 NPRT(res->res_cat.db_driver), NPRT(res->res_cat.db_user),
683 res->res_cat.mult_db_connections);
688 if (!acl_access_ok(ua, Job_ACL, res->res_job.hdr.name)) {
691 sendit(sock, _("%s: name=%s JobType=%d level=%s Priority=%d Enabled=%d\n"),
692 type == R_JOB ? _("Job") : _("JobDefs"),
693 res->res_job.hdr.name, res->res_job.JobType,
694 level_to_str(res->res_job.JobLevel), res->res_job.Priority,
695 res->res_job.enabled);
696 sendit(sock, _(" MaxJobs=%u Resched=%d Times=%d Interval=%s Spool=%d WritePartAfterJob=%d\n"),
697 res->res_job.MaxConcurrentJobs,
698 res->res_job.RescheduleOnError, res->res_job.RescheduleTimes,
699 edit_uint64_with_commas(res->res_job.RescheduleInterval, ed1),
700 res->res_job.spool_data, res->res_job.write_part_after_job);
701 if (res->res_job.spool_size) {
702 sendit(sock, _(" SpoolSize=%s\n"), edit_uint64(res->res_job.spool_size, ed1));
704 if (res->res_job.JobType == JT_BACKUP) {
705 sendit(sock, _(" Accurate=%d\n"), res->res_job.accurate);
707 if (res->res_job.max_bandwidth) {
708 sendit(sock, _(" MaximumBandwidth=%lld\n"),
709 res->res_job.max_bandwidth);
711 if (res->res_job.JobType == JT_MIGRATE || res->res_job.JobType == JT_COPY) {
712 sendit(sock, _(" SelectionType=%d\n"), res->res_job.selection_type);
714 if (res->res_job.client) {
715 sendit(sock, _(" --> "));
716 dump_resource(-R_CLIENT, (RES *)res->res_job.client, sendit, sock);
718 if (res->res_job.fileset) {
719 sendit(sock, _(" --> "));
720 dump_resource(-R_FILESET, (RES *)res->res_job.fileset, sendit, sock);
722 if (res->res_job.schedule) {
723 sendit(sock, _(" --> "));
724 dump_resource(-R_SCHEDULE, (RES *)res->res_job.schedule, sendit, sock);
726 if (res->res_job.RestoreWhere && !res->res_job.RegexWhere) {
727 sendit(sock, _(" --> Where=%s\n"), NPRT(res->res_job.RestoreWhere));
729 if (res->res_job.RegexWhere) {
730 sendit(sock, _(" --> RegexWhere=%s\n"), NPRT(res->res_job.RegexWhere));
732 if (res->res_job.RestoreBootstrap) {
733 sendit(sock, _(" --> Bootstrap=%s\n"), NPRT(res->res_job.RestoreBootstrap));
735 if (res->res_job.WriteBootstrap) {
736 sendit(sock, _(" --> WriteBootstrap=%s\n"), NPRT(res->res_job.WriteBootstrap));
738 if (res->res_job.PluginOptions) {
739 sendit(sock, _(" --> PluginOptions=%s\n"), NPRT(res->res_job.PluginOptions));
741 if (res->res_job.MaxRunTime) {
742 sendit(sock, _(" --> MaxRunTime=%u\n"), res->res_job.MaxRunTime);
744 if (res->res_job.MaxWaitTime) {
745 sendit(sock, _(" --> MaxWaitTime=%u\n"), res->res_job.MaxWaitTime);
747 if (res->res_job.MaxStartDelay) {
748 sendit(sock, _(" --> MaxStartDelay=%u\n"), res->res_job.MaxStartDelay);
750 if (res->res_job.MaxRunSchedTime) {
751 sendit(sock, _(" --> MaxRunSchedTime=%u\n"), res->res_job.MaxRunSchedTime);
753 if (res->res_job.storage) {
755 foreach_alist(store, res->res_job.storage) {
756 sendit(sock, _(" --> "));
757 dump_resource(-R_STORAGE, (RES *)store, sendit, sock);
760 if (res->res_job.base) {
762 foreach_alist(job, res->res_job.base) {
763 sendit(sock, _(" --> Base %s\n"), job->name());
766 if (res->res_job.RunScripts) {
768 foreach_alist(script, res->res_job.RunScripts) {
769 sendit(sock, _(" --> RunScript\n"));
770 sendit(sock, _(" --> Command=%s\n"), NPRT(script->command));
771 sendit(sock, _(" --> Target=%s\n"), NPRT(script->target));
772 sendit(sock, _(" --> RunOnSuccess=%u\n"), script->on_success);
773 sendit(sock, _(" --> RunOnFailure=%u\n"), script->on_failure);
774 sendit(sock, _(" --> FailJobOnError=%u\n"), script->fail_on_error);
775 sendit(sock, _(" --> RunWhen=%u\n"), script->when);
778 if (res->res_job.pool) {
779 sendit(sock, _(" --> "));
780 dump_resource(-R_POOL, (RES *)res->res_job.pool, sendit, sock);
782 if (res->res_job.full_pool) {
783 sendit(sock, _(" --> FullBackup"));
784 dump_resource(-R_POOL, (RES *)res->res_job.full_pool, sendit, sock);
786 if (res->res_job.inc_pool) {
787 sendit(sock, _(" --> IncrementalBackup"));
788 dump_resource(-R_POOL, (RES *)res->res_job.inc_pool, sendit, sock);
790 if (res->res_job.diff_pool) {
791 sendit(sock, _(" --> DifferentialBackup"));
792 dump_resource(-R_POOL, (RES *)res->res_job.diff_pool, sendit, sock);
794 if (res->res_job.verify_job) {
795 sendit(sock, _(" --> "));
796 dump_resource(-type, (RES *)res->res_job.verify_job, sendit, sock);
798 if (res->res_job.run_cmds) {
800 foreach_alist(runcmd, res->res_job.run_cmds) {
801 sendit(sock, _(" --> Run=%s\n"), runcmd);
804 if (res->res_job.selection_pattern) {
805 sendit(sock, _(" --> SelectionPattern=%s\n"), NPRT(res->res_job.selection_pattern));
807 if (res->res_job.messages) {
808 sendit(sock, _(" --> "));
809 dump_resource(-R_MSGS, (RES *)res->res_job.messages, sendit, sock);
816 if (!acl_access_ok(ua, FileSet_ACL, res->res_fs.hdr.name)) {
819 sendit(sock, _("FileSet: name=%s\n"), res->res_fs.hdr.name);
820 for (i=0; i<res->res_fs.num_includes; i++) {
821 INCEXE *incexe = res->res_fs.include_items[i];
822 for (j=0; j<incexe->num_opts; j++) {
823 FOPTS *fo = incexe->opts_list[j];
824 sendit(sock, " O %s\n", fo->opts);
826 bool enhanced_wild = false;
827 for (k=0; fo->opts[k]!='\0'; k++) {
828 if (fo->opts[k]=='W') {
829 enhanced_wild = true;
834 for (k=0; k<fo->regex.size(); k++) {
835 sendit(sock, " R %s\n", fo->regex.get(k));
837 for (k=0; k<fo->regexdir.size(); k++) {
838 sendit(sock, " RD %s\n", fo->regexdir.get(k));
840 for (k=0; k<fo->regexfile.size(); k++) {
841 sendit(sock, " RF %s\n", fo->regexfile.get(k));
843 for (k=0; k<fo->wild.size(); k++) {
844 sendit(sock, " W %s\n", fo->wild.get(k));
846 for (k=0; k<fo->wilddir.size(); k++) {
847 sendit(sock, " WD %s\n", fo->wilddir.get(k));
849 for (k=0; k<fo->wildfile.size(); k++) {
850 sendit(sock, " WF %s\n", fo->wildfile.get(k));
852 for (k=0; k<fo->wildbase.size(); k++) {
853 sendit(sock, " W%c %s\n", enhanced_wild ? 'B' : 'F', fo->wildbase.get(k));
855 for (k=0; k<fo->base.size(); k++) {
856 sendit(sock, " B %s\n", fo->base.get(k));
858 for (k=0; k<fo->fstype.size(); k++) {
859 sendit(sock, " X %s\n", fo->fstype.get(k));
861 for (k=0; k<fo->drivetype.size(); k++) {
862 sendit(sock, " XD %s\n", fo->drivetype.get(k));
865 sendit(sock, " G %s\n", fo->plugin);
868 sendit(sock, " D %s\n", fo->reader);
871 sendit(sock, " T %s\n", fo->writer);
873 sendit(sock, " N\n");
875 if (incexe->ignoredir) {
876 sendit(sock, " Z %s\n", incexe->ignoredir);
878 for (j=0; j<incexe->name_list.size(); j++) {
879 sendit(sock, " I %s\n", incexe->name_list.get(j));
881 if (incexe->name_list.size()) {
882 sendit(sock, " N\n");
884 for (j=0; j<incexe->plugin_list.size(); j++) {
885 sendit(sock, " P %s\n", incexe->plugin_list.get(j));
887 if (incexe->plugin_list.size()) {
888 sendit(sock, " N\n");
890 } /* end for over includes */
892 for (i=0; i<res->res_fs.num_excludes; i++) {
893 INCEXE *incexe = res->res_fs.exclude_items[i];
894 for (j=0; j<incexe->name_list.size(); j++) {
895 sendit(sock, " E %s\n", incexe->name_list.get(j));
897 if (incexe->name_list.size()) {
898 sendit(sock, " N\n");
902 } /* end case R_FILESET */
905 if (!acl_access_ok(ua, Schedule_ACL, res->res_sch.hdr.name)) {
909 if (res->res_sch.run) {
911 RUN *run = res->res_sch.run;
912 char buf[1000], num[30];
913 sendit(sock, _("Schedule: Name=%s Enabled=%d\n"),
914 res->res_sch.hdr.name, res->res_sch.enabled);
919 sendit(sock, _(" --> Run Level=%s\n"), level_to_str(run->level));
920 if (run->MaxRunSchedTime) {
921 sendit(sock, _(" MaxRunSchedTime=%u\n"), run->MaxRunSchedTime);
924 sendit(sock, _(" Priority=%u\n"), run->Priority);
926 bstrncpy(buf, _(" hour="), sizeof(buf));
927 for (i=0; i<24; i++) {
928 if (bit_is_set(i, run->hour)) {
929 bsnprintf(num, sizeof(num), "%d ", i);
930 bstrncat(buf, num, sizeof(buf));
933 bstrncat(buf, "\n", sizeof(buf));
935 bstrncpy(buf, _(" mday="), sizeof(buf));
936 for (i=0; i<32; i++) {
937 if (bit_is_set(i, run->mday)) {
938 bsnprintf(num, sizeof(num), "%d ", i);
939 bstrncat(buf, num, sizeof(buf));
942 bstrncat(buf, "\n", sizeof(buf));
944 bstrncpy(buf, _(" month="), sizeof(buf));
945 for (i=0; i<12; i++) {
946 if (bit_is_set(i, run->month)) {
947 bsnprintf(num, sizeof(num), "%d ", i);
948 bstrncat(buf, num, sizeof(buf));
951 bstrncat(buf, "\n", sizeof(buf));
953 bstrncpy(buf, _(" wday="), sizeof(buf));
954 for (i=0; i<7; i++) {
955 if (bit_is_set(i, run->wday)) {
956 bsnprintf(num, sizeof(num), "%d ", i);
957 bstrncat(buf, num, sizeof(buf));
960 bstrncat(buf, "\n", sizeof(buf));
962 bstrncpy(buf, _(" wom="), sizeof(buf));
963 for (i=0; i<6; i++) {
964 if (bit_is_set(i, run->wom)) {
965 bsnprintf(num, sizeof(num), "%d ", i);
966 bstrncat(buf, num, sizeof(buf));
969 bstrncat(buf, "\n", sizeof(buf));
971 bstrncpy(buf, _(" woy="), sizeof(buf));
972 for (i=0; i<54; i++) {
973 if (bit_is_set(i, run->woy)) {
974 bsnprintf(num, sizeof(num), "%d ", i);
975 bstrncat(buf, num, sizeof(buf));
978 bstrncat(buf, "\n", sizeof(buf));
980 sendit(sock, _(" mins=%d\n"), run->minute);
982 sendit(sock, _(" --> "));
983 dump_resource(-R_POOL, (RES *)run->pool, sendit, sock);
986 sendit(sock, _(" --> "));
987 dump_resource(-R_STORAGE, (RES *)run->storage, sendit, sock);
990 sendit(sock, _(" --> "));
991 dump_resource(-R_MSGS, (RES *)run->msgs, sendit, sock);
993 /* If another Run record is chained in, go print it */
999 sendit(sock, _("Schedule: name=%s\n"), res->res_sch.hdr.name);
1004 if (!acl_access_ok(ua, Pool_ACL, res->res_pool.hdr.name)) {
1007 sendit(sock, _("Pool: name=%s PoolType=%s\n"), res->res_pool.hdr.name,
1008 res->res_pool.pool_type);
1009 sendit(sock, _(" use_cat=%d use_once=%d cat_files=%d\n"),
1010 res->res_pool.use_catalog, res->res_pool.use_volume_once,
1011 res->res_pool.catalog_files);
1012 sendit(sock, _(" max_vols=%d auto_prune=%d VolRetention=%s\n"),
1013 res->res_pool.max_volumes, res->res_pool.AutoPrune,
1014 edit_utime(res->res_pool.VolRetention, ed1, sizeof(ed1)));
1015 sendit(sock, _(" VolUse=%s recycle=%d LabelFormat=%s\n"),
1016 edit_utime(res->res_pool.VolUseDuration, ed1, sizeof(ed1)),
1017 res->res_pool.Recycle,
1018 NPRT(res->res_pool.label_format));
1019 sendit(sock, _(" CleaningPrefix=%s LabelType=%d\n"),
1020 NPRT(res->res_pool.cleaning_prefix), res->res_pool.LabelType);
1021 sendit(sock, _(" RecyleOldest=%d PurgeOldest=%d ActionOnPurge=%d\n"),
1022 res->res_pool.recycle_oldest_volume,
1023 res->res_pool.purge_oldest_volume,
1024 res->res_pool.action_on_purge);
1025 sendit(sock, _(" MaxVolJobs=%d MaxVolFiles=%d MaxVolBytes=%s\n"),
1026 res->res_pool.MaxVolJobs,
1027 res->res_pool.MaxVolFiles,
1028 edit_uint64(res->res_pool.MaxVolBytes, ed1));
1029 sendit(sock, _(" MigTime=%s MigHiBytes=%s MigLoBytes=%s\n"),
1030 edit_utime(res->res_pool.MigrationTime, ed1, sizeof(ed1)),
1031 edit_uint64(res->res_pool.MigrationHighBytes, ed2),
1032 edit_uint64(res->res_pool.MigrationLowBytes, ed3));
1033 sendit(sock, _(" JobRetention=%s FileRetention=%s\n"),
1034 edit_utime(res->res_pool.JobRetention, ed1, sizeof(ed1)),
1035 edit_utime(res->res_pool.FileRetention, ed2, sizeof(ed2)));
1036 if (res->res_pool.NextPool) {
1037 sendit(sock, _(" NextPool=%s\n"), res->res_pool.NextPool->name());
1039 if (res->res_pool.RecyclePool) {
1040 sendit(sock, _(" RecyclePool=%s\n"), res->res_pool.RecyclePool->name());
1042 if (res->res_pool.ScratchPool) {
1043 sendit(sock, _(" ScratchPool=%s\n"), res->res_pool.ScratchPool->name());
1045 if (res->res_pool.catalog) {
1046 sendit(sock, _(" Catalog=%s\n"), res->res_pool.catalog->name());
1048 if (res->res_pool.storage) {
1050 foreach_alist(store, res->res_pool.storage) {
1051 sendit(sock, _(" --> "));
1052 dump_resource(-R_STORAGE, (RES *)store, sendit, sock);
1055 if (res->res_pool.CopyPool) {
1057 foreach_alist(copy, res->res_pool.CopyPool) {
1058 sendit(sock, _(" --> "));
1059 dump_resource(-R_POOL, (RES *)copy, sendit, sock);
1066 sendit(sock, _("Messages: name=%s\n"), res->res_msgs.hdr.name);
1067 if (res->res_msgs.mail_cmd)
1068 sendit(sock, _(" mailcmd=%s\n"), res->res_msgs.mail_cmd);
1069 if (res->res_msgs.operator_cmd)
1070 sendit(sock, _(" opcmd=%s\n"), res->res_msgs.operator_cmd);
1074 sendit(sock, _("Unknown resource type %d in dump_resource.\n"), type);
1077 if (recurse && res->res_dir.hdr.next) {
1078 dump_resource(type, res->res_dir.hdr.next, sendit, sock);
1084 * Free all the members of an INCEXE structure
1086 static void free_incexe(INCEXE *incexe)
1088 incexe->name_list.destroy();
1089 incexe->plugin_list.destroy();
1090 for (int i=0; i<incexe->num_opts; i++) {
1091 FOPTS *fopt = incexe->opts_list[i];
1092 fopt->regex.destroy();
1093 fopt->regexdir.destroy();
1094 fopt->regexfile.destroy();
1095 fopt->wild.destroy();
1096 fopt->wilddir.destroy();
1097 fopt->wildfile.destroy();
1098 fopt->wildbase.destroy();
1099 fopt->base.destroy();
1100 fopt->fstype.destroy();
1101 fopt->drivetype.destroy();
1113 if (incexe->opts_list) {
1114 free(incexe->opts_list);
1116 if (incexe->ignoredir) {
1117 free(incexe->ignoredir);
1124 * Free memory of resource -- called when daemon terminates.
1125 * NB, we don't need to worry about freeing any references
1126 * to other resources as they will be freed when that
1127 * resource chain is traversed. Mainly we worry about freeing
1128 * allocated strings (names).
1130 void free_resource(RES *rres, int type)
1134 URES *res = (URES *)rres;
1140 Dmsg3(200, "type=%d res=%p name=%s\n", type, res, res->res_dir.hdr.name);
1141 /* common stuff -- free the resource name and description */
1142 nres = (RES *)res->res_dir.hdr.next;
1143 if (res->res_dir.hdr.name) {
1144 free(res->res_dir.hdr.name);
1146 if (res->res_dir.hdr.desc) {
1147 free(res->res_dir.hdr.desc);
1152 if (res->res_dir.working_directory) {
1153 free(res->res_dir.working_directory);
1155 if (res->res_dir.scripts_directory) {
1156 free((char *)res->res_dir.scripts_directory);
1158 if (res->res_dir.plugin_directory) {
1159 free((char *)res->res_dir.plugin_directory);
1161 if (res->res_dir.pid_directory) {
1162 free(res->res_dir.pid_directory);
1164 if (res->res_dir.subsys_directory) {
1165 free(res->res_dir.subsys_directory);
1167 if (res->res_dir.password) {
1168 free(res->res_dir.password);
1170 if (res->res_dir.query_file) {
1171 free(res->res_dir.query_file);
1173 if (res->res_dir.DIRaddrs) {
1174 free_addresses(res->res_dir.DIRaddrs);
1176 if (res->res_dir.DIRsrc_addr) {
1177 free_addresses(res->res_dir.DIRsrc_addr);
1179 if (res->res_dir.tls_ctx) {
1180 free_tls_context(res->res_dir.tls_ctx);
1182 if (res->res_dir.tls_ca_certfile) {
1183 free(res->res_dir.tls_ca_certfile);
1185 if (res->res_dir.tls_ca_certdir) {
1186 free(res->res_dir.tls_ca_certdir);
1188 if (res->res_dir.tls_certfile) {
1189 free(res->res_dir.tls_certfile);
1191 if (res->res_dir.tls_keyfile) {
1192 free(res->res_dir.tls_keyfile);
1194 if (res->res_dir.tls_dhfile) {
1195 free(res->res_dir.tls_dhfile);
1197 if (res->res_dir.tls_allowed_cns) {
1198 delete res->res_dir.tls_allowed_cns;
1200 if (res->res_dir.verid) {
1201 free(res->res_dir.verid);
1208 if (res->res_con.password) {
1209 free(res->res_con.password);
1211 if (res->res_con.tls_ctx) {
1212 free_tls_context(res->res_con.tls_ctx);
1214 if (res->res_con.tls_ca_certfile) {
1215 free(res->res_con.tls_ca_certfile);
1217 if (res->res_con.tls_ca_certdir) {
1218 free(res->res_con.tls_ca_certdir);
1220 if (res->res_con.tls_certfile) {
1221 free(res->res_con.tls_certfile);
1223 if (res->res_con.tls_keyfile) {
1224 free(res->res_con.tls_keyfile);
1226 if (res->res_con.tls_dhfile) {
1227 free(res->res_con.tls_dhfile);
1229 if (res->res_con.tls_allowed_cns) {
1230 delete res->res_con.tls_allowed_cns;
1232 for (int i=0; i<Num_ACL; i++) {
1233 if (res->res_con.ACL_lists[i]) {
1234 delete res->res_con.ACL_lists[i];
1235 res->res_con.ACL_lists[i] = NULL;
1240 if (res->res_client.address) {
1241 free(res->res_client.address);
1243 if (res->res_client.fd_storage_address) {
1244 free(res->res_client.fd_storage_address);
1246 if (res->res_client.password) {
1247 free(res->res_client.password);
1249 if (res->res_client.tls_ctx) {
1250 free_tls_context(res->res_client.tls_ctx);
1252 if (res->res_client.tls_ca_certfile) {
1253 free(res->res_client.tls_ca_certfile);
1255 if (res->res_client.tls_ca_certdir) {
1256 free(res->res_client.tls_ca_certdir);
1258 if (res->res_client.tls_certfile) {
1259 free(res->res_client.tls_certfile);
1261 if (res->res_client.tls_keyfile) {
1262 free(res->res_client.tls_keyfile);
1264 if (res->res_client.tls_allowed_cns) {
1265 delete res->res_client.tls_allowed_cns;
1269 if (res->res_store.address) {
1270 free(res->res_store.address);
1272 if (res->res_store.fd_storage_address) {
1273 free(res->res_store.fd_storage_address);
1275 if (res->res_store.password) {
1276 free(res->res_store.password);
1278 if (res->res_store.media_type) {
1279 free(res->res_store.media_type);
1281 if (res->res_store.device) {
1282 delete res->res_store.device;
1284 if (res->res_store.tls_ctx) {
1285 free_tls_context(res->res_store.tls_ctx);
1287 if (res->res_store.tls_ca_certfile) {
1288 free(res->res_store.tls_ca_certfile);
1290 if (res->res_store.tls_ca_certdir) {
1291 free(res->res_store.tls_ca_certdir);
1293 if (res->res_store.tls_certfile) {
1294 free(res->res_store.tls_certfile);
1296 if (res->res_store.tls_keyfile) {
1297 free(res->res_store.tls_keyfile);
1301 if (res->res_cat.db_address) {
1302 free(res->res_cat.db_address);
1304 if (res->res_cat.db_socket) {
1305 free(res->res_cat.db_socket);
1307 if (res->res_cat.db_user) {
1308 free(res->res_cat.db_user);
1310 if (res->res_cat.db_name) {
1311 free(res->res_cat.db_name);
1313 if (res->res_cat.db_driver) {
1314 free(res->res_cat.db_driver);
1316 if (res->res_cat.db_password) {
1317 free(res->res_cat.db_password);
1319 if (res->res_cat.db_ssl_key) {
1320 free(res->res_cat.db_ssl_key);
1322 if (res->res_cat.db_ssl_cert) {
1323 free(res->res_cat.db_ssl_cert);
1325 if (res->res_cat.db_ssl_ca) {
1326 free(res->res_cat.db_ssl_ca);
1328 if (res->res_cat.db_ssl_capath) {
1329 free(res->res_cat.db_ssl_capath);
1331 if (res->res_cat.db_ssl_cipher) {
1332 free(res->res_cat.db_ssl_cipher);
1336 if ((num=res->res_fs.num_includes)) {
1337 while (--num >= 0) {
1338 free_incexe(res->res_fs.include_items[num]);
1340 free(res->res_fs.include_items);
1342 res->res_fs.num_includes = 0;
1343 if ((num=res->res_fs.num_excludes)) {
1344 while (--num >= 0) {
1345 free_incexe(res->res_fs.exclude_items[num]);
1347 free(res->res_fs.exclude_items);
1349 res->res_fs.num_excludes = 0;
1352 if (res->res_pool.pool_type) {
1353 free(res->res_pool.pool_type);
1355 if (res->res_pool.label_format) {
1356 free(res->res_pool.label_format);
1358 if (res->res_pool.cleaning_prefix) {
1359 free(res->res_pool.cleaning_prefix);
1361 if (res->res_pool.storage) {
1362 delete res->res_pool.storage;
1366 if (res->res_sch.run) {
1368 nrun = res->res_sch.run;
1378 if (res->res_job.RestoreWhere) {
1379 free(res->res_job.RestoreWhere);
1381 if (res->res_job.RegexWhere) {
1382 free(res->res_job.RegexWhere);
1384 if (res->res_job.strip_prefix) {
1385 free(res->res_job.strip_prefix);
1387 if (res->res_job.add_prefix) {
1388 free(res->res_job.add_prefix);
1390 if (res->res_job.add_suffix) {
1391 free(res->res_job.add_suffix);
1393 if (res->res_job.RestoreBootstrap) {
1394 free(res->res_job.RestoreBootstrap);
1396 if (res->res_job.WriteBootstrap) {
1397 free(res->res_job.WriteBootstrap);
1399 if (res->res_job.PluginOptions) {
1400 free(res->res_job.PluginOptions);
1402 if (res->res_job.selection_pattern) {
1403 free(res->res_job.selection_pattern);
1405 if (res->res_job.run_cmds) {
1406 delete res->res_job.run_cmds;
1408 if (res->res_job.storage) {
1409 delete res->res_job.storage;
1411 if (res->res_job.base) {
1412 delete res->res_job.base;
1414 if (res->res_job.RunScripts) {
1415 free_runscripts(res->res_job.RunScripts);
1416 delete res->res_job.RunScripts;
1420 if (res->res_msgs.mail_cmd) {
1421 free(res->res_msgs.mail_cmd);
1423 if (res->res_msgs.operator_cmd) {
1424 free(res->res_msgs.operator_cmd);
1426 free_msgs_res((MSGS *)res); /* free message resource */
1430 printf(_("Unknown resource type %d in free_resource.\n"), type);
1432 /* Common stuff again -- free the resource, recurse to next one */
1437 free_resource(nres, type);
1442 * Save the new resource by chaining it into the head list for
1443 * the resource. If this is pass 2, we update any resource
1444 * pointers because they may not have been defined until
1447 void save_resource(int type, RES_ITEM *items, int pass)
1450 int rindex = type - r_first;
1454 /* Check Job requirements after applying JobDefs */
1455 if (type != R_JOB && type != R_JOBDEFS) {
1457 * Ensure that all required items are present
1459 for (i=0; items[i].name; i++) {
1460 if (items[i].flags & ITEM_REQUIRED) {
1461 if (!bit_is_set(i, res_all.res_dir.hdr.item_present)) {
1462 Emsg2(M_ERROR_TERM, 0, _("%s item is required in %s resource, but not found.\n"),
1463 items[i].name, resources[rindex]);
1466 /* If this triggers, take a look at lib/parse_conf.h */
1467 if (i >= MAX_RES_ITEMS) {
1468 Emsg1(M_ERROR_TERM, 0, _("Too many items in %s resource\n"), resources[rindex]);
1471 } else if (type == R_JOB) {
1473 * Ensure that the name item is present
1475 if (items[0].flags & ITEM_REQUIRED) {
1476 if (!bit_is_set(0, res_all.res_dir.hdr.item_present)) {
1477 Emsg2(M_ERROR_TERM, 0, _("%s item is required in %s resource, but not found.\n"),
1478 items[0].name, resources[rindex]);
1484 * During pass 2 in each "store" routine, we looked up pointers
1485 * to all the resources referrenced in the current resource, now we
1486 * must copy their addresses from the static record to the allocated
1491 /* Resources not containing a resource */
1499 * Resources containing another resource or alist. First
1500 * look up the resource which contains another resource. It
1501 * was written during pass 1. Then stuff in the pointers to
1502 * the resources it contains, which were inserted this pass.
1503 * Finally, it will all be stored back.
1506 /* Find resource saved in pass 1 */
1507 if ((res = (URES *)GetResWithName(R_POOL, res_all.res_con.hdr.name)) == NULL) {
1508 Emsg1(M_ERROR_TERM, 0, _("Cannot find Pool resource %s\n"), res_all.res_con.hdr.name);
1510 /* Explicitly copy resource pointers from this pass (res_all) */
1511 res->res_pool.NextPool = res_all.res_pool.NextPool;
1512 res->res_pool.RecyclePool = res_all.res_pool.RecyclePool;
1513 res->res_pool.ScratchPool = res_all.res_pool.ScratchPool;
1514 res->res_pool.storage = res_all.res_pool.storage;
1515 res->res_pool.catalog = res_all.res_pool.catalog;
1518 if ((res = (URES *)GetResWithName(R_CONSOLE, res_all.res_con.hdr.name)) == NULL) {
1519 Emsg1(M_ERROR_TERM, 0, _("Cannot find Console resource %s\n"), res_all.res_con.hdr.name);
1521 res->res_con.tls_allowed_cns = res_all.res_con.tls_allowed_cns;
1524 if ((res = (URES *)GetResWithName(R_DIRECTOR, res_all.res_dir.hdr.name)) == NULL) {
1525 Emsg1(M_ERROR_TERM, 0, _("Cannot find Director resource %s\n"), res_all.res_dir.hdr.name);
1527 res->res_dir.messages = res_all.res_dir.messages;
1528 res->res_dir.tls_allowed_cns = res_all.res_dir.tls_allowed_cns;
1531 if ((res = (URES *)GetResWithName(type, res_all.res_store.hdr.name)) == NULL) {
1532 Emsg1(M_ERROR_TERM, 0, _("Cannot find Storage resource %s\n"),
1533 res_all.res_dir.hdr.name);
1535 /* we must explicitly copy the device alist pointer */
1536 res->res_store.device = res_all.res_store.device;
1540 if ((res = (URES *)GetResWithName(type, res_all.res_dir.hdr.name)) == NULL) {
1541 Emsg1(M_ERROR_TERM, 0, _("Cannot find Job resource %s\n"),
1542 res_all.res_dir.hdr.name);
1544 res->res_job.messages = res_all.res_job.messages;
1545 res->res_job.schedule = res_all.res_job.schedule;
1546 res->res_job.client = res_all.res_job.client;
1547 res->res_job.fileset = res_all.res_job.fileset;
1548 res->res_job.storage = res_all.res_job.storage;
1549 res->res_job.base = res_all.res_job.base;
1550 res->res_job.pool = res_all.res_job.pool;
1551 res->res_job.next_pool = res_all.res_job.next_pool;
1552 res->res_job.full_pool = res_all.res_job.full_pool;
1553 res->res_job.inc_pool = res_all.res_job.inc_pool;
1554 res->res_job.diff_pool = res_all.res_job.diff_pool;
1555 res->res_job.verify_job = res_all.res_job.verify_job;
1556 res->res_job.jobdefs = res_all.res_job.jobdefs;
1557 res->res_job.run_cmds = res_all.res_job.run_cmds;
1558 res->res_job.RunScripts = res_all.res_job.RunScripts;
1560 /* TODO: JobDefs where/regexwhere doesn't work well (but this
1561 * is not very useful)
1562 * We have to set_bit(index, res_all.hdr.item_present);
1563 * or something like that
1566 /* we take RegexWhere before all other options */
1567 if (!res->res_job.RegexWhere
1569 (res->res_job.strip_prefix ||
1570 res->res_job.add_suffix ||
1571 res->res_job.add_prefix))
1573 int len = bregexp_get_build_where_size(res->res_job.strip_prefix,
1574 res->res_job.add_prefix,
1575 res->res_job.add_suffix);
1576 res->res_job.RegexWhere = (char *) bmalloc (len * sizeof(char));
1577 bregexp_build_where(res->res_job.RegexWhere, len,
1578 res->res_job.strip_prefix,
1579 res->res_job.add_prefix,
1580 res->res_job.add_suffix);
1581 /* TODO: test bregexp */
1584 if (res->res_job.RegexWhere && res->res_job.RestoreWhere) {
1585 free(res->res_job.RestoreWhere);
1586 res->res_job.RestoreWhere = NULL;
1591 if ((res = (URES *)GetResWithName(R_COUNTER, res_all.res_counter.hdr.name)) == NULL) {
1592 Emsg1(M_ERROR_TERM, 0, _("Cannot find Counter resource %s\n"), res_all.res_counter.hdr.name);
1594 res->res_counter.Catalog = res_all.res_counter.Catalog;
1595 res->res_counter.WrapCounter = res_all.res_counter.WrapCounter;
1599 if ((res = (URES *)GetResWithName(R_CLIENT, res_all.res_client.hdr.name)) == NULL) {
1600 Emsg1(M_ERROR_TERM, 0, _("Cannot find Client resource %s\n"), res_all.res_client.hdr.name);
1602 res->res_client.catalog = res_all.res_client.catalog;
1603 res->res_client.tls_allowed_cns = res_all.res_client.tls_allowed_cns;
1607 * Schedule is a bit different in that it contains a RUN record
1608 * chain which isn't a "named" resource. This chain was linked
1609 * in by run_conf.c during pass 2, so here we jam the pointer
1610 * into the Schedule resource.
1612 if ((res = (URES *)GetResWithName(R_SCHEDULE, res_all.res_client.hdr.name)) == NULL) {
1613 Emsg1(M_ERROR_TERM, 0, _("Cannot find Schedule resource %s\n"), res_all.res_client.hdr.name);
1615 res->res_sch.run = res_all.res_sch.run;
1618 Emsg1(M_ERROR, 0, _("Unknown resource type %d in save_resource.\n"), type);
1622 /* Note, the resource name was already saved during pass 1,
1623 * so here, we can just release it.
1625 if (res_all.res_dir.hdr.name) {
1626 free(res_all.res_dir.hdr.name);
1627 res_all.res_dir.hdr.name = NULL;
1629 if (res_all.res_dir.hdr.desc) {
1630 free(res_all.res_dir.hdr.desc);
1631 res_all.res_dir.hdr.desc = NULL;
1637 * The following code is only executed during pass 1
1641 size = sizeof(DIRRES);
1644 size = sizeof(CONRES);
1647 size =sizeof(CLIENT);
1650 size = sizeof(STORE);
1660 size = sizeof(FILESET);
1663 size = sizeof(SCHED);
1666 size = sizeof(POOL);
1669 size = sizeof(MSGS);
1672 size = sizeof(COUNTER);
1678 printf(_("Unknown resource type %d in save_resource.\n"), type);
1684 res = (URES *)malloc(size);
1685 memcpy(res, &res_all, size);
1686 if (!res_head[rindex]) {
1687 res_head[rindex] = (RES *)res; /* store first entry */
1688 Dmsg3(900, "Inserting first %s res: %s index=%d\n", res_to_str(type),
1689 res->res_dir.hdr.name, rindex);
1692 if (res->res_dir.hdr.name == NULL) {
1693 Emsg1(M_ERROR_TERM, 0, _("Name item is required in %s resource, but not found.\n"),
1696 /* Add new res to end of chain */
1697 for (last=next=res_head[rindex]; next; next=next->next) {
1699 if (strcmp(next->name, res->res_dir.hdr.name) == 0) {
1700 Emsg2(M_ERROR_TERM, 0,
1701 _("Attempt to define second %s resource named \"%s\" is not permitted.\n"),
1702 resources[rindex].name, res->res_dir.hdr.name);
1705 last->next = (RES *)res;
1706 Dmsg4(900, _("Inserting %s res: %s index=%d pass=%d\n"), res_to_str(type),
1707 res->res_dir.hdr.name, rindex, pass);
1712 void store_actiononpurge(LEX *lc, RES_ITEM *item, int index, int pass)
1714 uint32_t *destination = (uint32_t*)item->value;
1715 lex_get_token(lc, T_NAME);
1716 if (strcasecmp(lc->str, "truncate") == 0) {
1717 *destination = (*destination) | ON_PURGE_TRUNCATE;
1719 scan_err2(lc, _("Expected one of: %s, got: %s"), "Truncate", lc->str);
1723 set_bit(index, res_all.hdr.item_present);
1727 * Store Device. Note, the resource is created upon the
1728 * first reference. The details of the resource are obtained
1729 * later from the SD.
1731 static void store_device(LEX *lc, RES_ITEM *item, int index, int pass)
1734 int rindex = R_DEVICE - r_first;
1735 int size = sizeof(DEVICE);
1739 lex_get_token(lc, T_NAME);
1740 if (!res_head[rindex]) {
1741 res = (URES *)malloc(size);
1742 memset(res, 0, size);
1743 res->res_dev.hdr.name = bstrdup(lc->str);
1744 res_head[rindex] = (RES *)res; /* store first entry */
1745 Dmsg3(900, "Inserting first %s res: %s index=%d\n", res_to_str(R_DEVICE),
1746 res->res_dir.hdr.name, rindex);
1749 /* See if it is already defined */
1750 for (next=res_head[rindex]; next->next; next=next->next) {
1751 if (strcmp(next->name, lc->str) == 0) {
1757 res = (URES *)malloc(size);
1758 memset(res, 0, size);
1759 res->res_dev.hdr.name = bstrdup(lc->str);
1760 next->next = (RES *)res;
1761 Dmsg4(900, "Inserting %s res: %s index=%d pass=%d\n", res_to_str(R_DEVICE),
1762 res->res_dir.hdr.name, rindex, pass);
1767 set_bit(index, res_all.hdr.item_present);
1769 store_alist_res(lc, item, index, pass);
1774 * Store Migration/Copy type
1777 void store_migtype(LEX *lc, RES_ITEM *item, int index, int pass)
1781 lex_get_token(lc, T_NAME);
1782 /* Store the type both pass 1 and pass 2 */
1783 for (i=0; migtypes[i].type_name; i++) {
1784 if (strcasecmp(lc->str, migtypes[i].type_name) == 0) {
1785 *(uint32_t *)(item->value) = migtypes[i].job_type;
1791 scan_err1(lc, _("Expected a Migration Job Type keyword, got: %s"), lc->str);
1794 set_bit(index, res_all.hdr.item_present);
1800 * Store JobType (backup, verify, restore)
1803 void store_jobtype(LEX *lc, RES_ITEM *item, int index, int pass)
1807 lex_get_token(lc, T_NAME);
1808 /* Store the type both pass 1 and pass 2 */
1809 for (i=0; jobtypes[i].type_name; i++) {
1810 if (strcasecmp(lc->str, jobtypes[i].type_name) == 0) {
1811 *(uint32_t *)(item->value) = jobtypes[i].job_type;
1817 scan_err1(lc, _("Expected a Job Type keyword, got: %s"), lc->str);
1820 set_bit(index, res_all.hdr.item_present);
1824 * Store Job Level (Full, Incremental, ...)
1827 void store_level(LEX *lc, RES_ITEM *item, int index, int pass)
1831 lex_get_token(lc, T_NAME);
1832 /* Store the level pass 2 so that type is defined */
1833 for (i=0; joblevels[i].level_name; i++) {
1834 if (strcasecmp(lc->str, joblevels[i].level_name) == 0) {
1835 *(uint32_t *)(item->value) = joblevels[i].level;
1841 scan_err1(lc, _("Expected a Job Level keyword, got: %s"), lc->str);
1844 set_bit(index, res_all.hdr.item_present);
1848 void store_replace(LEX *lc, RES_ITEM *item, int index, int pass)
1851 lex_get_token(lc, T_NAME);
1852 /* Scan Replacement options */
1853 for (i=0; ReplaceOptions[i].name; i++) {
1854 if (strcasecmp(lc->str, ReplaceOptions[i].name) == 0) {
1855 *(uint32_t *)(item->value) = ReplaceOptions[i].token;
1861 scan_err1(lc, _("Expected a Restore replacement option, got: %s"), lc->str);
1864 set_bit(index, res_all.hdr.item_present);
1868 * Store ACL (access control list)
1871 void store_acl(LEX *lc, RES_ITEM *item, int index, int pass)
1876 lex_get_token(lc, T_STRING);
1878 if (((alist **)item->value)[item->code] == NULL) {
1879 ((alist **)item->value)[item->code] = New(alist(10, owned_by_alist));
1880 Dmsg1(900, "Defined new ACL alist at %d\n", item->code);
1882 ((alist **)item->value)[item->code]->append(bstrdup(lc->str));
1883 Dmsg2(900, "Appended to %d %s\n", item->code, lc->str);
1885 token = lex_get_token(lc, T_ALL);
1886 if (token == T_COMMA) {
1887 continue; /* get another ACL */
1891 set_bit(index, res_all.hdr.item_present);
1894 /* We build RunScripts items here */
1895 static RUNSCRIPT res_runscript;
1897 /* Store a runscript->when in a bit field */
1898 static void store_runscript_when(LEX *lc, RES_ITEM *item, int index, int pass)
1900 lex_get_token(lc, T_NAME);
1902 if (strcasecmp(lc->str, "before") == 0) {
1903 *(uint32_t *)(item->value) = SCRIPT_Before ;
1904 } else if (strcasecmp(lc->str, "after") == 0) {
1905 *(uint32_t *)(item->value) = SCRIPT_After;
1906 } else if (strcasecmp(lc->str, "aftervss") == 0) {
1907 *(uint32_t *)(item->value) = SCRIPT_AfterVSS;
1908 } else if (strcasecmp(lc->str, "aftersnapshot") == 0) {
1909 *(uint32_t *)(item->value) = SCRIPT_AfterVSS;
1910 } else if (strcasecmp(lc->str, "always") == 0) {
1911 *(uint32_t *)(item->value) = SCRIPT_Any;
1913 scan_err2(lc, _("Expect %s, got: %s"), "Before, After, AfterVSS or Always", lc->str);
1918 /* Store a runscript->target
1921 static void store_runscript_target(LEX *lc, RES_ITEM *item, int index, int pass)
1923 lex_get_token(lc, T_STRING);
1926 if (strcmp(lc->str, "%c") == 0) {
1927 ((RUNSCRIPT*) item->value)->set_target(lc->str);
1928 } else if (strcasecmp(lc->str, "yes") == 0) {
1929 ((RUNSCRIPT*) item->value)->set_target("%c");
1930 } else if (strcasecmp(lc->str, "no") == 0) {
1931 ((RUNSCRIPT*) item->value)->set_target("");
1933 RES *res = GetResWithName(R_CLIENT, lc->str);
1935 scan_err3(lc, _("Could not find config Resource %s referenced on line %d : %s\n"),
1936 lc->str, lc->line_no, lc->line);
1939 ((RUNSCRIPT*) item->value)->set_target(lc->str);
1946 * Store a runscript->command as a string and runscript->cmd_type as a pointer
1948 static void store_runscript_cmd(LEX *lc, RES_ITEM *item, int index, int pass)
1950 lex_get_token(lc, T_STRING);
1953 Dmsg2(1, "runscript cmd=%s type=%c\n", lc->str, item->code);
1954 POOLMEM *c = get_pool_memory(PM_FNAME);
1955 /* Each runscript command takes 2 entries in commands list */
1956 pm_strcpy(c, lc->str);
1957 ((RUNSCRIPT*) item->value)->commands->prepend(c); /* command line */
1958 ((RUNSCRIPT*) item->value)->commands->prepend((void *)(intptr_t)item->code); /* command type */
1963 static void store_short_runscript(LEX *lc, RES_ITEM *item, int index, int pass)
1965 lex_get_token(lc, T_STRING);
1966 alist **runscripts = (alist **)(item->value) ;
1969 RUNSCRIPT *script = new_runscript();
1970 script->set_job_code_callback(job_code_callback_director);
1972 script->set_command(lc->str);
1974 /* TODO: remove all script->old_proto with bacula 1.42 */
1976 if (strcasecmp(item->name, "runbeforejob") == 0) {
1977 script->when = SCRIPT_Before;
1978 script->fail_on_error = true;
1979 script->set_target("");
1981 } else if (strcasecmp(item->name, "runafterjob") == 0) {
1982 script->when = SCRIPT_After;
1983 script->on_success = true;
1984 script->on_failure = false;
1985 script->set_target("");
1987 } else if (strcasecmp(item->name, "clientrunafterjob") == 0) {
1988 script->old_proto = true;
1989 script->when = SCRIPT_After;
1990 script->set_target("%c");
1991 script->on_success = true;
1992 script->on_failure = false;
1994 } else if (strcasecmp(item->name, "clientrunbeforejob") == 0) {
1995 script->old_proto = true;
1996 script->when = SCRIPT_Before;
1997 script->set_target("%c");
1998 script->fail_on_error = true;
2000 } else if (strcasecmp(item->name, "runafterfailedjob") == 0) {
2001 script->when = SCRIPT_After;
2002 script->on_failure = true;
2003 script->on_success = false;
2004 script->set_target("");
2007 if (*runscripts == NULL) {
2008 *runscripts = New(alist(10, not_owned_by_alist));
2011 (*runscripts)->append(script);
2015 set_bit(index, res_all.hdr.item_present);
2018 /* Store a bool in a bit field without modifing res_all.hdr
2019 * We can also add an option to store_bool to skip res_all.hdr
2021 void store_runscript_bool(LEX *lc, RES_ITEM *item, int index, int pass)
2023 lex_get_token(lc, T_NAME);
2024 if (strcasecmp(lc->str, "yes") == 0 || strcasecmp(lc->str, "true") == 0) {
2025 *(bool *)(item->value) = true;
2026 } else if (strcasecmp(lc->str, "no") == 0 || strcasecmp(lc->str, "false") == 0) {
2027 *(bool *)(item->value) = false;
2029 scan_err2(lc, _("Expect %s, got: %s"), "YES, NO, TRUE, or FALSE", lc->str); /* YES and NO must not be translated */
2035 * new RunScript items
2036 * name handler value code flags default_value
2038 static RES_ITEM runscript_items[] = {
2039 {"command", store_runscript_cmd, {(char **)&res_runscript}, SHELL_CMD, 0, 0},
2040 {"console", store_runscript_cmd, {(char **)&res_runscript}, CONSOLE_CMD, 0, 0},
2041 {"target", store_runscript_target,{(char **)&res_runscript}, 0, 0, 0},
2042 {"runsonsuccess", store_runscript_bool, {(char **)&res_runscript.on_success},0, 0, 0},
2043 {"runsonfailure", store_runscript_bool, {(char **)&res_runscript.on_failure},0, 0, 0},
2044 {"failjobonerror",store_runscript_bool, {(char **)&res_runscript.fail_on_error},0, 0, 0},
2045 {"abortjobonerror",store_runscript_bool, {(char **)&res_runscript.fail_on_error},0, 0, 0},
2046 {"runswhen", store_runscript_when, {(char **)&res_runscript.when}, 0, 0, 0},
2047 {"runsonclient", store_runscript_target,{(char **)&res_runscript}, 0, 0, 0}, /* TODO */
2048 {NULL, NULL, {0}, 0, 0, 0}
2052 * Store RunScript info
2054 * Note, when this routine is called, we are inside a Job
2055 * resource. We treat the RunScript like a sort of
2056 * mini-resource within the Job resource.
2058 void store_runscript(LEX *lc, RES_ITEM *item, int index, int pass)
2062 alist **runscripts = (alist **)(item->value) ;
2064 Dmsg1(200, "store_runscript: begin store_runscript pass=%i\n", pass);
2066 token = lex_get_token(lc, T_SKIP_EOL);
2068 if (token != T_BOB) {
2069 scan_err1(lc, _("Expecting open brace. Got %s"), lc->str);
2071 /* setting on_success, on_failure, fail_on_error */
2072 res_runscript.reset_default();
2075 res_runscript.commands = New(alist(10, not_owned_by_alist));
2078 while ((token = lex_get_token(lc, T_SKIP_EOL)) != T_EOF) {
2079 if (token == T_EOB) {
2082 if (token != T_IDENTIFIER) {
2083 scan_err1(lc, _("Expecting keyword, got: %s\n"), lc->str);
2085 for (i=0; runscript_items[i].name; i++) {
2086 if (strcasecmp(runscript_items[i].name, lc->str) == 0) {
2087 token = lex_get_token(lc, T_SKIP_EOL);
2088 if (token != T_EQUALS) {
2089 scan_err1(lc, _("expected an equals, got: %s"), lc->str);
2092 /* Call item handler */
2093 runscript_items[i].handler(lc, &runscript_items[i], i, pass);
2100 scan_err1(lc, _("Keyword %s not permitted in this resource"), lc->str);
2105 /* run on client by default */
2106 if (res_runscript.target == NULL) {
2107 res_runscript.set_target("%c");
2109 if (*runscripts == NULL) {
2110 *runscripts = New(alist(10, not_owned_by_alist));
2113 * commands list contains 2 values per command
2114 * - POOLMEM command string (ex: /bin/true)
2115 * - int command type (ex: SHELL_CMD)
2117 res_runscript.set_job_code_callback(job_code_callback_director);
2118 while ((c=(char*)res_runscript.commands->pop()) != NULL) {
2119 t = (intptr_t)res_runscript.commands->pop();
2120 RUNSCRIPT *script = new_runscript();
2121 memcpy(script, &res_runscript, sizeof(RUNSCRIPT));
2122 script->command = c;
2123 script->cmd_type = t;
2124 /* target is taken from res_runscript, each runscript object have
2127 script->target = NULL;
2128 script->set_target(res_runscript.target);
2130 (*runscripts)->append(script);
2133 delete res_runscript.commands;
2134 /* setting on_success, on_failure... cleanup target field */
2135 res_runscript.reset_default(true);
2139 set_bit(index, res_all.hdr.item_present);
2142 /* callback function for edit_job_codes */
2143 /* See ../lib/util.c, function edit_job_codes, for more remaining codes */
2144 extern "C" char *job_code_callback_director(JCR *jcr, const char* param)
2146 static char yes[] = "yes";
2147 static char no[] = "no";
2151 return jcr->fileset->name();
2155 if (jcr->client && jcr->client->address) {
2156 return jcr->client->address;
2161 return jcr->pool->name();
2166 return jcr->wstore->name();
2170 return jcr->spool_data ? yes : no;
2174 return jcr->cloned ? yes : no;
2179 bool parse_dir_config(CONFIG *config, const char *configfile, int exit_code)
2181 config->init(configfile, NULL, exit_code, (void *)&res_all, res_all_size,
2182 r_first, r_last, resources, res_head);
2183 return config->parse_config();