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 /* Turned off for the moment */
256 {"MultipleConnections", store_bit, ITEM(res_cat.mult_db_connections), 0, 0, 0},
257 {"DisableBatchInsert", store_bool, ITEM(res_cat.disable_batch_insert), 0, ITEM_DEFAULT, false},
258 {NULL, NULL, {0}, 0, 0, 0}
262 * Job Resource Directives
264 * name handler value code flags default_value
266 RES_ITEM job_items[] = {
267 {"Name", store_name, ITEM(res_job.hdr.name), 0, ITEM_REQUIRED, 0},
268 {"Description", store_str, ITEM(res_job.hdr.desc), 0, 0, 0},
269 {"Type", store_jobtype, ITEM(res_job.JobType), 0, ITEM_REQUIRED, 0},
270 {"Level", store_level, ITEM(res_job.JobLevel), 0, 0, 0},
271 {"Messages", store_res, ITEM(res_job.messages), R_MSGS, ITEM_REQUIRED, 0},
272 {"Storage", store_alist_res, ITEM(res_job.storage), R_STORAGE, 0, 0},
273 {"Pool", store_res, ITEM(res_job.pool), R_POOL, ITEM_REQUIRED, 0},
274 {"NextPool", store_res, ITEM(res_job.next_pool), R_POOL, 0, 0},
275 {"FullBackupPool", store_res, ITEM(res_job.full_pool), R_POOL, 0, 0},
276 {"IncrementalBackupPool", store_res, ITEM(res_job.inc_pool), R_POOL, 0, 0},
277 {"DifferentialBackupPool", store_res, ITEM(res_job.diff_pool), R_POOL, 0, 0},
278 {"Client", store_res, ITEM(res_job.client), R_CLIENT, ITEM_REQUIRED, 0},
279 {"Fileset", store_res, ITEM(res_job.fileset), R_FILESET, ITEM_REQUIRED, 0},
280 {"Schedule", store_res, ITEM(res_job.schedule), R_SCHEDULE, 0, 0},
281 {"VerifyJob", store_res, ITEM(res_job.verify_job), R_JOB, 0, 0},
282 {"JobToVerify", store_res, ITEM(res_job.verify_job), R_JOB, 0, 0},
283 {"JobDefs", store_res, ITEM(res_job.jobdefs), R_JOBDEFS, 0, 0},
284 {"Run", store_alist_str, ITEM(res_job.run_cmds), 0, 0, 0},
285 /* Root of where to restore files */
286 {"Where", store_dir, ITEM(res_job.RestoreWhere), 0, 0, 0},
287 {"RegexWhere", store_str, ITEM(res_job.RegexWhere), 0, 0, 0},
288 {"StripPrefix", store_str, ITEM(res_job.strip_prefix), 0, 0, 0},
289 {"AddPrefix", store_str, ITEM(res_job.add_prefix), 0, 0, 0},
290 {"AddSuffix", store_str, ITEM(res_job.add_suffix), 0, 0, 0},
291 /* Where to find bootstrap during restore */
292 {"Bootstrap",store_dir, ITEM(res_job.RestoreBootstrap), 0, 0, 0},
293 /* Where to write bootstrap file during backup */
294 {"WriteBootstrap",store_dir, ITEM(res_job.WriteBootstrap), 0, 0, 0},
295 {"WriteVerifyList",store_dir,ITEM(res_job.WriteVerifyList), 0, 0, 0},
296 {"Replace", store_replace, ITEM(res_job.replace), 0, ITEM_DEFAULT, REPLACE_ALWAYS},
297 {"MaximumBandwidth", store_speed, ITEM(res_job.max_bandwidth), 0, 0, 0},
298 {"MaxRunSchedTime", store_time, ITEM(res_job.MaxRunSchedTime), 0, 0, 0},
299 {"MaxRunTime", store_time, ITEM(res_job.MaxRunTime), 0, 0, 0},
300 /* xxxMaxWaitTime are deprecated */
301 {"fullmaxwaittime", store_time, ITEM(res_job.FullMaxRunTime), 0, 0, 0},
302 {"incrementalmaxwaittime", store_time, ITEM(res_job.IncMaxRunTime), 0, 0, 0},
303 {"differentialmaxwaittime", store_time, ITEM(res_job.DiffMaxRunTime), 0, 0, 0},
304 {"FullMaxRunTime", store_time, ITEM(res_job.FullMaxRunTime), 0, 0, 0},
305 {"IncrementalMaxRunTime", store_time, ITEM(res_job.IncMaxRunTime), 0, 0, 0},
306 {"DifferentialMaxRunTime", store_time, ITEM(res_job.DiffMaxRunTime), 0, 0, 0},
307 {"MaxWaitTime", store_time, ITEM(res_job.MaxWaitTime), 0, 0, 0},
308 {"MaxStartDelay",store_time, ITEM(res_job.MaxStartDelay), 0, 0, 0},
309 {"MaxFullInterval", store_time, ITEM(res_job.MaxFullInterval), 0, 0, 0},
310 {"MaxDiffInterval", store_time, ITEM(res_job.MaxDiffInterval), 0, 0, 0},
311 {"PrefixLinks", store_bool, ITEM(res_job.PrefixLinks), 0, ITEM_DEFAULT, false},
312 {"PruneJobs", store_bool, ITEM(res_job.PruneJobs), 0, ITEM_DEFAULT, false},
313 {"PruneFiles", store_bool, ITEM(res_job.PruneFiles), 0, ITEM_DEFAULT, false},
314 {"PruneVolumes",store_bool, ITEM(res_job.PruneVolumes), 0, ITEM_DEFAULT, false},
315 {"PurgeMigrationJob", store_bool, ITEM(res_job.PurgeMigrateJob), 0, ITEM_DEFAULT, false},
316 {"Enabled", store_bool, ITEM(res_job.enabled), 0, ITEM_DEFAULT, true},
317 {"SnapshotRetention", store_time, ITEM(res_job.SnapRetention), 0, ITEM_DEFAULT, 0},
318 {"SpoolAttributes",store_bool, ITEM(res_job.SpoolAttributes), 0, ITEM_DEFAULT, true},
319 {"SpoolData", store_bool, ITEM(res_job.spool_data), 0, ITEM_DEFAULT, false},
320 {"SpoolSize", store_size64, ITEM(res_job.spool_size), 0, 0, 0},
321 {"ReRunFailedLevels", store_bool, ITEM(res_job.rerun_failed_levels), 0, ITEM_DEFAULT, false},
322 {"PreferMountedVolumes", store_bool, ITEM(res_job.PreferMountedVolumes), 0, ITEM_DEFAULT, true},
323 {"runbeforejob", store_short_runscript, ITEM(res_job.RunScripts), 0, 0, 0},
324 {"runafterjob", store_short_runscript, ITEM(res_job.RunScripts), 0, 0, 0},
325 {"runafterfailedjob", store_short_runscript, ITEM(res_job.RunScripts), 0, 0, 0},
326 {"clientrunbeforejob", store_short_runscript, ITEM(res_job.RunScripts), 0, 0, 0},
327 {"clientrunafterjob", store_short_runscript, ITEM(res_job.RunScripts), 0, 0, 0},
328 {"Runscript", store_runscript, ITEM(res_job.RunScripts), 0, ITEM_NO_EQUALS, 0},
329 {"MaximumConcurrentJobs", store_pint32, ITEM(res_job.MaxConcurrentJobs), 0, ITEM_DEFAULT, 1},
330 {"MaximumSpawnedJobs", store_pint32, ITEM(res_job.MaxSpawnedJobs), 0, ITEM_DEFAULT, 600},
331 {"RescheduleOnError", store_bool, ITEM(res_job.RescheduleOnError), 0, ITEM_DEFAULT, false},
332 {"RescheduleIncompleteJobs", store_bool, ITEM(res_job.RescheduleIncompleteJobs), 0, ITEM_DEFAULT, true},
333 {"RescheduleInterval", store_time, ITEM(res_job.RescheduleInterval), 0, ITEM_DEFAULT, 60 * 30},
334 {"RescheduleTimes", store_pint32, ITEM(res_job.RescheduleTimes), 0, 0, 0},
335 {"Priority", store_pint32, ITEM(res_job.Priority), 0, ITEM_DEFAULT, 10},
336 {"AllowMixedPriority", store_bool, ITEM(res_job.allow_mixed_priority), 0, ITEM_DEFAULT, false},
337 {"WritePartAfterJob", store_bool, ITEM(res_job.write_part_after_job), 0, ITEM_DEFAULT, true},
338 {"SelectionPattern", store_str, ITEM(res_job.selection_pattern), 0, 0, 0},
339 {"SelectionType", store_migtype, ITEM(res_job.selection_type), 0, 0, 0},
340 {"Accurate", store_bool, ITEM(res_job.accurate), 0,0,0},
341 {"AllowDuplicateJobs", store_bool, ITEM(res_job.AllowDuplicateJobs), 0, ITEM_DEFAULT, true},
342 {"allowhigherduplicates", store_bool, ITEM(res_job.AllowHigherDuplicates), 0, ITEM_DEFAULT, true},
343 {"CancelLowerLevelDuplicates", store_bool, ITEM(res_job.CancelLowerLevelDuplicates), 0, ITEM_DEFAULT, false},
344 {"CancelQueuedDuplicates", store_bool, ITEM(res_job.CancelQueuedDuplicates), 0, ITEM_DEFAULT, false},
345 {"CancelRunningDuplicates", store_bool, ITEM(res_job.CancelRunningDuplicates), 0, ITEM_DEFAULT, false},
346 {"PluginOptions", store_str, ITEM(res_job.PluginOptions), 0, 0, 0},
347 {"Base", store_alist_res, ITEM(res_job.base), R_JOB, 0, 0},
348 {NULL, NULL, {0}, 0, 0, 0}
353 * Name handler value code flags default_value
355 static RES_ITEM fs_items[] = {
356 {"Name", store_name, ITEM(res_fs.hdr.name), 0, ITEM_REQUIRED, 0},
357 {"Description", store_str, ITEM(res_fs.hdr.desc), 0, 0, 0},
358 {"IgnoreFilesetChanges", store_bool, ITEM(res_fs.ignore_fs_changes), 0, ITEM_DEFAULT, false},
359 {"EnableVss", store_bool, ITEM(res_fs.enable_vss), 0, ITEM_DEFAULT, true},
360 {"EnableSnapshot",store_bool, ITEM(res_fs.enable_snapshot), 0, ITEM_DEFAULT, false},
361 {"Include", store_inc, {0}, 0, ITEM_NO_EQUALS, 0},
362 {"Exclude", store_inc, {0}, 1, ITEM_NO_EQUALS, 0},
363 {NULL, NULL, {0}, 0, 0, 0}
366 /* Schedule -- see run_conf.c */
369 * name handler value code flags default_value
371 static RES_ITEM sch_items[] = {
372 {"Name", store_name, ITEM(res_sch.hdr.name), 0, ITEM_REQUIRED, 0},
373 {"Description", store_str, ITEM(res_sch.hdr.desc), 0, 0, 0},
374 {"Run", store_run, ITEM(res_sch.run), 0, 0, 0},
375 {"Enabled", store_bool, ITEM(res_sch.enabled), 0, ITEM_DEFAULT, true},
376 {NULL, NULL, {0}, 0, 0, 0}
381 * name handler value code flags default_value
383 static RES_ITEM pool_items[] = {
384 {"Name", store_name, ITEM(res_pool.hdr.name), 0, ITEM_REQUIRED, 0},
385 {"Description", store_str, ITEM(res_pool.hdr.desc), 0, 0, 0},
386 {"PoolType", store_strname, ITEM(res_pool.pool_type), 0, ITEM_REQUIRED, 0},
387 {"LabelFormat", store_strname, ITEM(res_pool.label_format), 0, 0, 0},
388 {"LabelType", store_label, ITEM(res_pool.LabelType), 0, 0, 0},
389 {"CleaningPrefix", store_strname, ITEM(res_pool.cleaning_prefix), 0, 0, 0},
390 {"UseCatalog", store_bool, ITEM(res_pool.use_catalog), 0, ITEM_DEFAULT, true},
391 {"UseVolumeOnce", store_bool, ITEM(res_pool.use_volume_once), 0, 0, 0},
392 {"PurgeOldestVolume", store_bool, ITEM(res_pool.purge_oldest_volume), 0, 0, 0},
393 {"ActionOnPurge", store_actiononpurge, ITEM(res_pool.action_on_purge), 0, 0, 0},
394 {"RecycleOldestVolume", store_bool, ITEM(res_pool.recycle_oldest_volume), 0, 0, 0},
395 {"RecycleCurrentVolume", store_bool, ITEM(res_pool.recycle_current_volume), 0, 0, 0},
396 {"MaximumVolumes", store_pint32, ITEM(res_pool.max_volumes), 0, 0, 0},
397 {"MaximumVolumeJobs", store_pint32, ITEM(res_pool.MaxVolJobs), 0, 0, 0},
398 {"MaximumVolumeFiles", store_pint32, ITEM(res_pool.MaxVolFiles), 0, 0, 0},
399 {"MaximumVolumeBytes", store_size64, ITEM(res_pool.MaxVolBytes), 0, 0, 0},
400 {"CatalogFiles", store_bool, ITEM(res_pool.catalog_files), 0, ITEM_DEFAULT, true},
401 {"VolumeRetention", store_time, ITEM(res_pool.VolRetention), 0, ITEM_DEFAULT, 60*60*24*365},
402 {"VolumeUseDuration", store_time, ITEM(res_pool.VolUseDuration), 0, 0, 0},
403 {"MigrationTime", store_time, ITEM(res_pool.MigrationTime), 0, 0, 0},
404 {"MigrationHighBytes", store_size64, ITEM(res_pool.MigrationHighBytes), 0, 0, 0},
405 {"MigrationLowBytes", store_size64, ITEM(res_pool.MigrationLowBytes), 0, 0, 0},
406 {"NextPool", store_res, ITEM(res_pool.NextPool), R_POOL, 0, 0},
407 {"Storage", store_alist_res, ITEM(res_pool.storage), R_STORAGE, 0, 0},
408 {"AutoPrune", store_bool, ITEM(res_pool.AutoPrune), 0, ITEM_DEFAULT, true},
409 {"Recycle", store_bool, ITEM(res_pool.Recycle), 0, ITEM_DEFAULT, true},
410 {"RecyclePool", store_res, ITEM(res_pool.RecyclePool), R_POOL, 0, 0},
411 {"ScratchPool", store_res, ITEM(res_pool.ScratchPool), R_POOL, 0, 0},
412 {"CopyPool", store_alist_res, ITEM(res_pool.CopyPool), R_POOL, 0, 0},
413 {"Catalog", store_res, ITEM(res_pool.catalog), R_CATALOG, 0, 0},
414 {"FileRetention", store_time, ITEM(res_pool.FileRetention), 0, 0, 0},
415 {"JobRetention", store_time, ITEM(res_pool.JobRetention), 0, 0, 0},
417 {NULL, NULL, {0}, 0, 0, 0}
422 * name handler value code flags default_value
424 static RES_ITEM counter_items[] = {
425 {"Name", store_name, ITEM(res_counter.hdr.name), 0, ITEM_REQUIRED, 0},
426 {"Description", store_str, ITEM(res_counter.hdr.desc), 0, 0, 0},
427 {"Minimum", store_int32, ITEM(res_counter.MinValue), 0, ITEM_DEFAULT, 0},
428 {"Maximum", store_pint32, ITEM(res_counter.MaxValue), 0, ITEM_DEFAULT, INT32_MAX},
429 {"WrapCounter", store_res, ITEM(res_counter.WrapCounter), R_COUNTER, 0, 0},
430 {"Catalog", store_res, ITEM(res_counter.Catalog), R_CATALOG, 0, 0},
431 {NULL, NULL, {0}, 0, 0, 0}
435 /* Message resource */
436 extern RES_ITEM msgs_items[];
439 * This is the master resource definition.
440 * It must have one item for each of the resources.
442 * NOTE!!! keep it in the same order as the R_codes
443 * or eliminate all resources[rindex].name
447 RES_TABLE resources[] = {
448 {"Director", dir_items, R_DIRECTOR},
449 {"Client", cli_items, R_CLIENT},
450 {"Job", job_items, R_JOB},
451 {"Storage", store_items, R_STORAGE},
452 {"Catalog", cat_items, R_CATALOG},
453 {"Schedule", sch_items, R_SCHEDULE},
454 {"Fileset", fs_items, R_FILESET},
455 {"Pool", pool_items, R_POOL},
456 {"Messages", msgs_items, R_MSGS},
457 {"Counter", counter_items, R_COUNTER},
458 {"Console", con_items, R_CONSOLE},
459 {"JobDefs", job_items, R_JOBDEFS},
460 {"Device", NULL, R_DEVICE}, /* info obtained from SD */
465 /* Keywords (RHS) permitted in Job Level records
467 * level_name level job_type
469 struct s_jl joblevels[] = {
470 {"Full", L_FULL, JT_BACKUP},
471 {"Base", L_BASE, JT_BACKUP},
472 {"Incremental", L_INCREMENTAL, JT_BACKUP},
473 {"Differential", L_DIFFERENTIAL, JT_BACKUP},
474 {"Since", L_SINCE, JT_BACKUP},
475 {"VirtualFull", L_VIRTUAL_FULL, JT_BACKUP},
476 {"Catalog", L_VERIFY_CATALOG, JT_VERIFY},
477 {"InitCatalog", L_VERIFY_INIT, JT_VERIFY},
478 {"VolumeToCatalog", L_VERIFY_VOLUME_TO_CATALOG, JT_VERIFY},
479 {"DiskToCatalog", L_VERIFY_DISK_TO_CATALOG, JT_VERIFY},
480 {"Data", L_VERIFY_DATA, JT_VERIFY},
481 {"Full", L_FULL, JT_COPY},
482 {"Incremental", L_INCREMENTAL, JT_COPY},
483 {"Differential", L_DIFFERENTIAL, JT_COPY},
484 {"Full", L_FULL, JT_MIGRATE},
485 {"Incremental", L_INCREMENTAL, JT_MIGRATE},
486 {"Differential", L_DIFFERENTIAL, JT_MIGRATE},
487 {" ", L_NONE, JT_ADMIN},
488 {" ", L_NONE, JT_RESTORE},
493 /* Keywords (RHS) permitted in Job type records
498 {"Backup", JT_BACKUP},
500 {"Verify", JT_VERIFY},
501 {"Restore", JT_RESTORE},
502 {"Migrate", JT_MIGRATE},
508 /* Keywords (RHS) permitted in Selection type records
513 {"SmallestVolume", MT_SMALLEST_VOL},
514 {"OldestVolume", MT_OLDEST_VOL},
515 {"PoolOccupancy", MT_POOL_OCCUPANCY},
516 {"PoolTime", MT_POOL_TIME},
517 {"PoolUncopiedJobs", MT_POOL_UNCOPIED_JOBS},
518 {"Client", MT_CLIENT},
519 {"Volume", MT_VOLUME},
521 {"SqlQuery", MT_SQLQUERY},
527 /* Options permitted in Restore replace= */
528 struct s_kw ReplaceOptions[] = {
529 {"Always", REPLACE_ALWAYS},
530 {"IfNewer", REPLACE_IFNEWER},
531 {"IfOlder", REPLACE_IFOLDER},
532 {"Never", REPLACE_NEVER},
536 char *CAT::display(POOLMEM *dst) {
537 Mmsg(dst,"catalog=%s\ndb_name=%s\ndb_driver=%s\ndb_user=%s\n"
538 "db_password=%s\ndb_address=%s\ndb_port=%i\n"
540 name(), NPRTB(db_name),
541 NPRTB(db_driver), NPRTB(db_user), NPRTB(db_password),
542 NPRTB(db_address), db_port, NPRTB(db_socket));
546 const char *level_to_str(int level)
549 static char level_no[30];
550 const char *str = level_no;
552 bsnprintf(level_no, sizeof(level_no), "%c (%d)", level, level); /* default if not found */
553 for (i=0; joblevels[i].level_name; i++) {
554 if (level == (int)joblevels[i].level) {
555 str = joblevels[i].level_name;
562 /* Dump contents of resource */
563 void dump_resource(int type, RES *ares, void sendit(void *sock, const char *fmt, ...), void *sock)
565 URES *res = (URES *)ares;
567 char ed1[100], ed2[100], ed3[100];
569 UAContext *ua = (UAContext *)sock;
572 sendit(sock, _("No %s resource defined\n"), res_to_str(type));
575 if (type < 0) { /* no recursion */
581 sendit(sock, _("Director: name=%s MaxJobs=%d FDtimeout=%s SDtimeout=%s\n"),
582 ares->name, res->res_dir.MaxConcurrentJobs,
583 edit_uint64(res->res_dir.FDConnectTimeout, ed1),
584 edit_uint64(res->res_dir.SDConnectTimeout, ed2));
585 if (res->res_dir.query_file) {
586 sendit(sock, _(" query_file=%s\n"), res->res_dir.query_file);
588 if (res->res_dir.messages) {
589 sendit(sock, _(" --> "));
590 dump_resource(-R_MSGS, (RES *)res->res_dir.messages, sendit, sock);
594 sendit(sock, _("Console: name=%s SSL=%d\n"),
595 res->res_con.hdr.name, res->res_con.tls_enable);
598 if (res->res_counter.WrapCounter) {
599 sendit(sock, _("Counter: name=%s min=%d max=%d cur=%d wrapcntr=%s\n"),
600 res->res_counter.hdr.name, res->res_counter.MinValue,
601 res->res_counter.MaxValue, res->res_counter.CurrentValue,
602 res->res_counter.WrapCounter->hdr.name);
604 sendit(sock, _("Counter: name=%s min=%d max=%d\n"),
605 res->res_counter.hdr.name, res->res_counter.MinValue,
606 res->res_counter.MaxValue);
608 if (res->res_counter.Catalog) {
609 sendit(sock, _(" --> "));
610 dump_resource(-R_CATALOG, (RES *)res->res_counter.Catalog, sendit, sock);
615 if (!acl_access_ok(ua, Client_ACL, res->res_client.hdr.name)) {
618 sendit(sock, _("Client: Name=%s Enabled=%d Address=%s FDport=%d MaxJobs=%u\n"),
619 res->res_client.hdr.name, res->res_client.enabled,
620 res->res_client.address, res->res_client.FDport,
621 res->res_client.MaxConcurrentJobs);
622 sendit(sock, _(" JobRetention=%s FileRetention=%s AutoPrune=%d\n"),
623 edit_utime(res->res_client.JobRetention, ed1, sizeof(ed1)),
624 edit_utime(res->res_client.FileRetention, ed2, sizeof(ed2)),
625 res->res_client.AutoPrune);
626 if (res->res_client.fd_storage_address) {
627 sendit(sock, " FDStorageAddress=%s\n", res->res_client.fd_storage_address);
629 if (res->res_client.max_bandwidth) {
630 sendit(sock, _(" MaximumBandwidth=%lld\n"),
631 res->res_client.max_bandwidth);
633 if (res->res_client.catalog) {
634 sendit(sock, _(" --> "));
635 dump_resource(-R_CATALOG, (RES *)res->res_client.catalog, sendit, sock);
642 sendit(sock, _("Device: name=%s ok=%d num_writers=%d max_writers=%d\n"
643 " reserved=%d open=%d append=%d read=%d labeled=%d offline=%d autochgr=%d\n"
644 " poolid=%s volname=%s MediaType=%s\n"),
645 dev->hdr.name, dev->found, dev->num_writers, dev->max_writers,
646 dev->reserved, dev->open, dev->append, dev->read, dev->labeled,
647 dev->offline, dev->autochanger,
648 edit_uint64(dev->PoolId, ed1),
649 dev->VolumeName, dev->MediaType);
653 if (!acl_access_ok(ua, Storage_ACL, res->res_store.hdr.name)) {
656 sendit(sock, _("Storage: name=%s address=%s SDport=%d MaxJobs=%u\n"
657 " DeviceName=%s MediaType=%s StorageId=%s Autochanger=%d\n"),
658 res->res_store.hdr.name, res->res_store.address, res->res_store.SDport,
659 res->res_store.MaxConcurrentJobs,
660 res->res_store.dev_name(),
661 res->res_store.media_type,
662 edit_int64(res->res_store.StorageId, ed1),
663 res->res_store.autochanger);
664 if (res->res_store.fd_storage_address) {
665 sendit(sock, " FDStorageAddress=%s\n", res->res_store.fd_storage_address);
670 if (!acl_access_ok(ua, Catalog_ACL, res->res_cat.hdr.name)) {
673 sendit(sock, _("Catalog: name=%s address=%s DBport=%d db_name=%s\n"
674 " db_driver=%s db_user=%s MutliDBConn=%d\n"),
675 res->res_cat.hdr.name, NPRT(res->res_cat.db_address),
676 res->res_cat.db_port, res->res_cat.db_name,
677 NPRT(res->res_cat.db_driver), NPRT(res->res_cat.db_user),
678 res->res_cat.mult_db_connections);
683 if (!acl_access_ok(ua, Job_ACL, res->res_job.hdr.name)) {
686 sendit(sock, _("%s: name=%s JobType=%d level=%s Priority=%d Enabled=%d\n"),
687 type == R_JOB ? _("Job") : _("JobDefs"),
688 res->res_job.hdr.name, res->res_job.JobType,
689 level_to_str(res->res_job.JobLevel), res->res_job.Priority,
690 res->res_job.enabled);
691 sendit(sock, _(" MaxJobs=%u Resched=%d Times=%d Interval=%s Spool=%d WritePartAfterJob=%d\n"),
692 res->res_job.MaxConcurrentJobs,
693 res->res_job.RescheduleOnError, res->res_job.RescheduleTimes,
694 edit_uint64_with_commas(res->res_job.RescheduleInterval, ed1),
695 res->res_job.spool_data, res->res_job.write_part_after_job);
696 if (res->res_job.spool_size) {
697 sendit(sock, _(" SpoolSize=%s\n"), edit_uint64(res->res_job.spool_size, ed1));
699 if (res->res_job.JobType == JT_BACKUP) {
700 sendit(sock, _(" Accurate=%d\n"), res->res_job.accurate);
702 if (res->res_job.max_bandwidth) {
703 sendit(sock, _(" MaximumBandwidth=%lld\n"),
704 res->res_job.max_bandwidth);
706 if (res->res_job.JobType == JT_MIGRATE || res->res_job.JobType == JT_COPY) {
707 sendit(sock, _(" SelectionType=%d\n"), res->res_job.selection_type);
709 if (res->res_job.client) {
710 sendit(sock, _(" --> "));
711 dump_resource(-R_CLIENT, (RES *)res->res_job.client, sendit, sock);
713 if (res->res_job.fileset) {
714 sendit(sock, _(" --> "));
715 dump_resource(-R_FILESET, (RES *)res->res_job.fileset, sendit, sock);
717 if (res->res_job.schedule) {
718 sendit(sock, _(" --> "));
719 dump_resource(-R_SCHEDULE, (RES *)res->res_job.schedule, sendit, sock);
721 if (res->res_job.RestoreWhere && !res->res_job.RegexWhere) {
722 sendit(sock, _(" --> Where=%s\n"), NPRT(res->res_job.RestoreWhere));
724 if (res->res_job.RegexWhere) {
725 sendit(sock, _(" --> RegexWhere=%s\n"), NPRT(res->res_job.RegexWhere));
727 if (res->res_job.RestoreBootstrap) {
728 sendit(sock, _(" --> Bootstrap=%s\n"), NPRT(res->res_job.RestoreBootstrap));
730 if (res->res_job.WriteBootstrap) {
731 sendit(sock, _(" --> WriteBootstrap=%s\n"), NPRT(res->res_job.WriteBootstrap));
733 if (res->res_job.PluginOptions) {
734 sendit(sock, _(" --> PluginOptions=%s\n"), NPRT(res->res_job.PluginOptions));
736 if (res->res_job.MaxRunTime) {
737 sendit(sock, _(" --> MaxRunTime=%u\n"), res->res_job.MaxRunTime);
739 if (res->res_job.MaxWaitTime) {
740 sendit(sock, _(" --> MaxWaitTime=%u\n"), res->res_job.MaxWaitTime);
742 if (res->res_job.MaxStartDelay) {
743 sendit(sock, _(" --> MaxStartDelay=%u\n"), res->res_job.MaxStartDelay);
745 if (res->res_job.MaxRunSchedTime) {
746 sendit(sock, _(" --> MaxRunSchedTime=%u\n"), res->res_job.MaxRunSchedTime);
748 if (res->res_job.storage) {
750 foreach_alist(store, res->res_job.storage) {
751 sendit(sock, _(" --> "));
752 dump_resource(-R_STORAGE, (RES *)store, sendit, sock);
755 if (res->res_job.base) {
757 foreach_alist(job, res->res_job.base) {
758 sendit(sock, _(" --> Base %s\n"), job->name());
761 if (res->res_job.RunScripts) {
763 foreach_alist(script, res->res_job.RunScripts) {
764 sendit(sock, _(" --> RunScript\n"));
765 sendit(sock, _(" --> Command=%s\n"), NPRT(script->command));
766 sendit(sock, _(" --> Target=%s\n"), NPRT(script->target));
767 sendit(sock, _(" --> RunOnSuccess=%u\n"), script->on_success);
768 sendit(sock, _(" --> RunOnFailure=%u\n"), script->on_failure);
769 sendit(sock, _(" --> FailJobOnError=%u\n"), script->fail_on_error);
770 sendit(sock, _(" --> RunWhen=%u\n"), script->when);
773 if (res->res_job.pool) {
774 sendit(sock, _(" --> "));
775 dump_resource(-R_POOL, (RES *)res->res_job.pool, sendit, sock);
777 if (res->res_job.full_pool) {
778 sendit(sock, _(" --> FullBackup"));
779 dump_resource(-R_POOL, (RES *)res->res_job.full_pool, sendit, sock);
781 if (res->res_job.inc_pool) {
782 sendit(sock, _(" --> IncrementalBackup"));
783 dump_resource(-R_POOL, (RES *)res->res_job.inc_pool, sendit, sock);
785 if (res->res_job.diff_pool) {
786 sendit(sock, _(" --> DifferentialBackup"));
787 dump_resource(-R_POOL, (RES *)res->res_job.diff_pool, sendit, sock);
789 if (res->res_job.verify_job) {
790 sendit(sock, _(" --> "));
791 dump_resource(-type, (RES *)res->res_job.verify_job, sendit, sock);
793 if (res->res_job.run_cmds) {
795 foreach_alist(runcmd, res->res_job.run_cmds) {
796 sendit(sock, _(" --> Run=%s\n"), runcmd);
799 if (res->res_job.selection_pattern) {
800 sendit(sock, _(" --> SelectionPattern=%s\n"), NPRT(res->res_job.selection_pattern));
802 if (res->res_job.messages) {
803 sendit(sock, _(" --> "));
804 dump_resource(-R_MSGS, (RES *)res->res_job.messages, sendit, sock);
811 if (!acl_access_ok(ua, FileSet_ACL, res->res_fs.hdr.name)) {
814 sendit(sock, _("FileSet: name=%s\n"), res->res_fs.hdr.name);
815 for (i=0; i<res->res_fs.num_includes; i++) {
816 INCEXE *incexe = res->res_fs.include_items[i];
817 for (j=0; j<incexe->num_opts; j++) {
818 FOPTS *fo = incexe->opts_list[j];
819 sendit(sock, " O %s\n", fo->opts);
821 bool enhanced_wild = false;
822 for (k=0; fo->opts[k]!='\0'; k++) {
823 if (fo->opts[k]=='W') {
824 enhanced_wild = true;
829 for (k=0; k<fo->regex.size(); k++) {
830 sendit(sock, " R %s\n", fo->regex.get(k));
832 for (k=0; k<fo->regexdir.size(); k++) {
833 sendit(sock, " RD %s\n", fo->regexdir.get(k));
835 for (k=0; k<fo->regexfile.size(); k++) {
836 sendit(sock, " RF %s\n", fo->regexfile.get(k));
838 for (k=0; k<fo->wild.size(); k++) {
839 sendit(sock, " W %s\n", fo->wild.get(k));
841 for (k=0; k<fo->wilddir.size(); k++) {
842 sendit(sock, " WD %s\n", fo->wilddir.get(k));
844 for (k=0; k<fo->wildfile.size(); k++) {
845 sendit(sock, " WF %s\n", fo->wildfile.get(k));
847 for (k=0; k<fo->wildbase.size(); k++) {
848 sendit(sock, " W%c %s\n", enhanced_wild ? 'B' : 'F', fo->wildbase.get(k));
850 for (k=0; k<fo->base.size(); k++) {
851 sendit(sock, " B %s\n", fo->base.get(k));
853 for (k=0; k<fo->fstype.size(); k++) {
854 sendit(sock, " X %s\n", fo->fstype.get(k));
856 for (k=0; k<fo->drivetype.size(); k++) {
857 sendit(sock, " XD %s\n", fo->drivetype.get(k));
860 sendit(sock, " G %s\n", fo->plugin);
863 sendit(sock, " D %s\n", fo->reader);
866 sendit(sock, " T %s\n", fo->writer);
868 sendit(sock, " N\n");
870 if (incexe->ignoredir) {
871 sendit(sock, " Z %s\n", incexe->ignoredir);
873 for (j=0; j<incexe->name_list.size(); j++) {
874 sendit(sock, " I %s\n", incexe->name_list.get(j));
876 if (incexe->name_list.size()) {
877 sendit(sock, " N\n");
879 for (j=0; j<incexe->plugin_list.size(); j++) {
880 sendit(sock, " P %s\n", incexe->plugin_list.get(j));
882 if (incexe->plugin_list.size()) {
883 sendit(sock, " N\n");
885 } /* end for over includes */
887 for (i=0; i<res->res_fs.num_excludes; i++) {
888 INCEXE *incexe = res->res_fs.exclude_items[i];
889 for (j=0; j<incexe->name_list.size(); j++) {
890 sendit(sock, " E %s\n", incexe->name_list.get(j));
892 if (incexe->name_list.size()) {
893 sendit(sock, " N\n");
897 } /* end case R_FILESET */
900 if (!acl_access_ok(ua, Schedule_ACL, res->res_sch.hdr.name)) {
904 if (res->res_sch.run) {
906 RUN *run = res->res_sch.run;
907 char buf[1000], num[30];
908 sendit(sock, _("Schedule: Name=%s Enabled=%d\n"),
909 res->res_sch.hdr.name, res->res_sch.enabled);
914 sendit(sock, _(" --> Run Level=%s\n"), level_to_str(run->level));
915 if (run->MaxRunSchedTime) {
916 sendit(sock, _(" MaxRunSchedTime=%u\n"), run->MaxRunSchedTime);
919 sendit(sock, _(" Priority=%u\n"), run->Priority);
921 bstrncpy(buf, _(" hour="), sizeof(buf));
922 for (i=0; i<24; i++) {
923 if (bit_is_set(i, run->hour)) {
924 bsnprintf(num, sizeof(num), "%d ", i);
925 bstrncat(buf, num, sizeof(buf));
928 bstrncat(buf, "\n", sizeof(buf));
930 bstrncpy(buf, _(" mday="), sizeof(buf));
931 for (i=0; i<32; i++) {
932 if (bit_is_set(i, run->mday)) {
933 bsnprintf(num, sizeof(num), "%d ", i);
934 bstrncat(buf, num, sizeof(buf));
937 bstrncat(buf, "\n", sizeof(buf));
939 bstrncpy(buf, _(" month="), sizeof(buf));
940 for (i=0; i<12; i++) {
941 if (bit_is_set(i, run->month)) {
942 bsnprintf(num, sizeof(num), "%d ", i);
943 bstrncat(buf, num, sizeof(buf));
946 bstrncat(buf, "\n", sizeof(buf));
948 bstrncpy(buf, _(" wday="), sizeof(buf));
949 for (i=0; i<7; i++) {
950 if (bit_is_set(i, run->wday)) {
951 bsnprintf(num, sizeof(num), "%d ", i);
952 bstrncat(buf, num, sizeof(buf));
955 bstrncat(buf, "\n", sizeof(buf));
957 bstrncpy(buf, _(" wom="), sizeof(buf));
958 for (i=0; i<6; i++) {
959 if (bit_is_set(i, run->wom)) {
960 bsnprintf(num, sizeof(num), "%d ", i);
961 bstrncat(buf, num, sizeof(buf));
964 bstrncat(buf, "\n", sizeof(buf));
966 bstrncpy(buf, _(" woy="), sizeof(buf));
967 for (i=0; i<54; i++) {
968 if (bit_is_set(i, run->woy)) {
969 bsnprintf(num, sizeof(num), "%d ", i);
970 bstrncat(buf, num, sizeof(buf));
973 bstrncat(buf, "\n", sizeof(buf));
975 sendit(sock, _(" mins=%d\n"), run->minute);
977 sendit(sock, _(" --> "));
978 dump_resource(-R_POOL, (RES *)run->pool, sendit, sock);
981 sendit(sock, _(" --> "));
982 dump_resource(-R_STORAGE, (RES *)run->storage, sendit, sock);
985 sendit(sock, _(" --> "));
986 dump_resource(-R_MSGS, (RES *)run->msgs, sendit, sock);
988 /* If another Run record is chained in, go print it */
994 sendit(sock, _("Schedule: name=%s\n"), res->res_sch.hdr.name);
999 if (!acl_access_ok(ua, Pool_ACL, res->res_pool.hdr.name)) {
1002 sendit(sock, _("Pool: name=%s PoolType=%s\n"), res->res_pool.hdr.name,
1003 res->res_pool.pool_type);
1004 sendit(sock, _(" use_cat=%d use_once=%d cat_files=%d\n"),
1005 res->res_pool.use_catalog, res->res_pool.use_volume_once,
1006 res->res_pool.catalog_files);
1007 sendit(sock, _(" max_vols=%d auto_prune=%d VolRetention=%s\n"),
1008 res->res_pool.max_volumes, res->res_pool.AutoPrune,
1009 edit_utime(res->res_pool.VolRetention, ed1, sizeof(ed1)));
1010 sendit(sock, _(" VolUse=%s recycle=%d LabelFormat=%s\n"),
1011 edit_utime(res->res_pool.VolUseDuration, ed1, sizeof(ed1)),
1012 res->res_pool.Recycle,
1013 NPRT(res->res_pool.label_format));
1014 sendit(sock, _(" CleaningPrefix=%s LabelType=%d\n"),
1015 NPRT(res->res_pool.cleaning_prefix), res->res_pool.LabelType);
1016 sendit(sock, _(" RecyleOldest=%d PurgeOldest=%d ActionOnPurge=%d\n"),
1017 res->res_pool.recycle_oldest_volume,
1018 res->res_pool.purge_oldest_volume,
1019 res->res_pool.action_on_purge);
1020 sendit(sock, _(" MaxVolJobs=%d MaxVolFiles=%d MaxVolBytes=%s\n"),
1021 res->res_pool.MaxVolJobs,
1022 res->res_pool.MaxVolFiles,
1023 edit_uint64(res->res_pool.MaxVolBytes, ed1));
1024 sendit(sock, _(" MigTime=%s MigHiBytes=%s MigLoBytes=%s\n"),
1025 edit_utime(res->res_pool.MigrationTime, ed1, sizeof(ed1)),
1026 edit_uint64(res->res_pool.MigrationHighBytes, ed2),
1027 edit_uint64(res->res_pool.MigrationLowBytes, ed3));
1028 sendit(sock, _(" JobRetention=%s FileRetention=%s\n"),
1029 edit_utime(res->res_pool.JobRetention, ed1, sizeof(ed1)),
1030 edit_utime(res->res_pool.FileRetention, ed2, sizeof(ed2)));
1031 if (res->res_pool.NextPool) {
1032 sendit(sock, _(" NextPool=%s\n"), res->res_pool.NextPool->name());
1034 if (res->res_pool.RecyclePool) {
1035 sendit(sock, _(" RecyclePool=%s\n"), res->res_pool.RecyclePool->name());
1037 if (res->res_pool.ScratchPool) {
1038 sendit(sock, _(" ScratchPool=%s\n"), res->res_pool.ScratchPool->name());
1040 if (res->res_pool.catalog) {
1041 sendit(sock, _(" Catalog=%s\n"), res->res_pool.catalog->name());
1043 if (res->res_pool.storage) {
1045 foreach_alist(store, res->res_pool.storage) {
1046 sendit(sock, _(" --> "));
1047 dump_resource(-R_STORAGE, (RES *)store, sendit, sock);
1050 if (res->res_pool.CopyPool) {
1052 foreach_alist(copy, res->res_pool.CopyPool) {
1053 sendit(sock, _(" --> "));
1054 dump_resource(-R_POOL, (RES *)copy, sendit, sock);
1061 sendit(sock, _("Messages: name=%s\n"), res->res_msgs.hdr.name);
1062 if (res->res_msgs.mail_cmd)
1063 sendit(sock, _(" mailcmd=%s\n"), res->res_msgs.mail_cmd);
1064 if (res->res_msgs.operator_cmd)
1065 sendit(sock, _(" opcmd=%s\n"), res->res_msgs.operator_cmd);
1069 sendit(sock, _("Unknown resource type %d in dump_resource.\n"), type);
1072 if (recurse && res->res_dir.hdr.next) {
1073 dump_resource(type, res->res_dir.hdr.next, sendit, sock);
1079 * Free all the members of an INCEXE structure
1081 static void free_incexe(INCEXE *incexe)
1083 incexe->name_list.destroy();
1084 incexe->plugin_list.destroy();
1085 for (int i=0; i<incexe->num_opts; i++) {
1086 FOPTS *fopt = incexe->opts_list[i];
1087 fopt->regex.destroy();
1088 fopt->regexdir.destroy();
1089 fopt->regexfile.destroy();
1090 fopt->wild.destroy();
1091 fopt->wilddir.destroy();
1092 fopt->wildfile.destroy();
1093 fopt->wildbase.destroy();
1094 fopt->base.destroy();
1095 fopt->fstype.destroy();
1096 fopt->drivetype.destroy();
1108 if (incexe->opts_list) {
1109 free(incexe->opts_list);
1111 if (incexe->ignoredir) {
1112 free(incexe->ignoredir);
1119 * Free memory of resource -- called when daemon terminates.
1120 * NB, we don't need to worry about freeing any references
1121 * to other resources as they will be freed when that
1122 * resource chain is traversed. Mainly we worry about freeing
1123 * allocated strings (names).
1125 void free_resource(RES *rres, int type)
1129 URES *res = (URES *)rres;
1135 Dmsg3(200, "type=%d res=%p name=%s\n", type, res, res->res_dir.hdr.name);
1136 /* common stuff -- free the resource name and description */
1137 nres = (RES *)res->res_dir.hdr.next;
1138 if (res->res_dir.hdr.name) {
1139 free(res->res_dir.hdr.name);
1141 if (res->res_dir.hdr.desc) {
1142 free(res->res_dir.hdr.desc);
1147 if (res->res_dir.working_directory) {
1148 free(res->res_dir.working_directory);
1150 if (res->res_dir.scripts_directory) {
1151 free((char *)res->res_dir.scripts_directory);
1153 if (res->res_dir.plugin_directory) {
1154 free((char *)res->res_dir.plugin_directory);
1156 if (res->res_dir.pid_directory) {
1157 free(res->res_dir.pid_directory);
1159 if (res->res_dir.subsys_directory) {
1160 free(res->res_dir.subsys_directory);
1162 if (res->res_dir.password) {
1163 free(res->res_dir.password);
1165 if (res->res_dir.query_file) {
1166 free(res->res_dir.query_file);
1168 if (res->res_dir.DIRaddrs) {
1169 free_addresses(res->res_dir.DIRaddrs);
1171 if (res->res_dir.DIRsrc_addr) {
1172 free_addresses(res->res_dir.DIRsrc_addr);
1174 if (res->res_dir.tls_ctx) {
1175 free_tls_context(res->res_dir.tls_ctx);
1177 if (res->res_dir.tls_ca_certfile) {
1178 free(res->res_dir.tls_ca_certfile);
1180 if (res->res_dir.tls_ca_certdir) {
1181 free(res->res_dir.tls_ca_certdir);
1183 if (res->res_dir.tls_certfile) {
1184 free(res->res_dir.tls_certfile);
1186 if (res->res_dir.tls_keyfile) {
1187 free(res->res_dir.tls_keyfile);
1189 if (res->res_dir.tls_dhfile) {
1190 free(res->res_dir.tls_dhfile);
1192 if (res->res_dir.tls_allowed_cns) {
1193 delete res->res_dir.tls_allowed_cns;
1195 if (res->res_dir.verid) {
1196 free(res->res_dir.verid);
1203 if (res->res_con.password) {
1204 free(res->res_con.password);
1206 if (res->res_con.tls_ctx) {
1207 free_tls_context(res->res_con.tls_ctx);
1209 if (res->res_con.tls_ca_certfile) {
1210 free(res->res_con.tls_ca_certfile);
1212 if (res->res_con.tls_ca_certdir) {
1213 free(res->res_con.tls_ca_certdir);
1215 if (res->res_con.tls_certfile) {
1216 free(res->res_con.tls_certfile);
1218 if (res->res_con.tls_keyfile) {
1219 free(res->res_con.tls_keyfile);
1221 if (res->res_con.tls_dhfile) {
1222 free(res->res_con.tls_dhfile);
1224 if (res->res_con.tls_allowed_cns) {
1225 delete res->res_con.tls_allowed_cns;
1227 for (int i=0; i<Num_ACL; i++) {
1228 if (res->res_con.ACL_lists[i]) {
1229 delete res->res_con.ACL_lists[i];
1230 res->res_con.ACL_lists[i] = NULL;
1235 if (res->res_client.address) {
1236 free(res->res_client.address);
1238 if (res->res_client.fd_storage_address) {
1239 free(res->res_client.fd_storage_address);
1241 if (res->res_client.password) {
1242 free(res->res_client.password);
1244 if (res->res_client.tls_ctx) {
1245 free_tls_context(res->res_client.tls_ctx);
1247 if (res->res_client.tls_ca_certfile) {
1248 free(res->res_client.tls_ca_certfile);
1250 if (res->res_client.tls_ca_certdir) {
1251 free(res->res_client.tls_ca_certdir);
1253 if (res->res_client.tls_certfile) {
1254 free(res->res_client.tls_certfile);
1256 if (res->res_client.tls_keyfile) {
1257 free(res->res_client.tls_keyfile);
1259 if (res->res_client.tls_allowed_cns) {
1260 delete res->res_client.tls_allowed_cns;
1264 if (res->res_store.address) {
1265 free(res->res_store.address);
1267 if (res->res_store.fd_storage_address) {
1268 free(res->res_store.fd_storage_address);
1270 if (res->res_store.password) {
1271 free(res->res_store.password);
1273 if (res->res_store.media_type) {
1274 free(res->res_store.media_type);
1276 if (res->res_store.device) {
1277 delete res->res_store.device;
1279 if (res->res_store.tls_ctx) {
1280 free_tls_context(res->res_store.tls_ctx);
1282 if (res->res_store.tls_ca_certfile) {
1283 free(res->res_store.tls_ca_certfile);
1285 if (res->res_store.tls_ca_certdir) {
1286 free(res->res_store.tls_ca_certdir);
1288 if (res->res_store.tls_certfile) {
1289 free(res->res_store.tls_certfile);
1291 if (res->res_store.tls_keyfile) {
1292 free(res->res_store.tls_keyfile);
1296 if (res->res_cat.db_address) {
1297 free(res->res_cat.db_address);
1299 if (res->res_cat.db_socket) {
1300 free(res->res_cat.db_socket);
1302 if (res->res_cat.db_user) {
1303 free(res->res_cat.db_user);
1305 if (res->res_cat.db_name) {
1306 free(res->res_cat.db_name);
1308 if (res->res_cat.db_driver) {
1309 free(res->res_cat.db_driver);
1311 if (res->res_cat.db_password) {
1312 free(res->res_cat.db_password);
1316 if ((num=res->res_fs.num_includes)) {
1317 while (--num >= 0) {
1318 free_incexe(res->res_fs.include_items[num]);
1320 free(res->res_fs.include_items);
1322 res->res_fs.num_includes = 0;
1323 if ((num=res->res_fs.num_excludes)) {
1324 while (--num >= 0) {
1325 free_incexe(res->res_fs.exclude_items[num]);
1327 free(res->res_fs.exclude_items);
1329 res->res_fs.num_excludes = 0;
1332 if (res->res_pool.pool_type) {
1333 free(res->res_pool.pool_type);
1335 if (res->res_pool.label_format) {
1336 free(res->res_pool.label_format);
1338 if (res->res_pool.cleaning_prefix) {
1339 free(res->res_pool.cleaning_prefix);
1341 if (res->res_pool.storage) {
1342 delete res->res_pool.storage;
1346 if (res->res_sch.run) {
1348 nrun = res->res_sch.run;
1358 if (res->res_job.RestoreWhere) {
1359 free(res->res_job.RestoreWhere);
1361 if (res->res_job.RegexWhere) {
1362 free(res->res_job.RegexWhere);
1364 if (res->res_job.strip_prefix) {
1365 free(res->res_job.strip_prefix);
1367 if (res->res_job.add_prefix) {
1368 free(res->res_job.add_prefix);
1370 if (res->res_job.add_suffix) {
1371 free(res->res_job.add_suffix);
1373 if (res->res_job.RestoreBootstrap) {
1374 free(res->res_job.RestoreBootstrap);
1376 if (res->res_job.WriteBootstrap) {
1377 free(res->res_job.WriteBootstrap);
1379 if (res->res_job.PluginOptions) {
1380 free(res->res_job.PluginOptions);
1382 if (res->res_job.selection_pattern) {
1383 free(res->res_job.selection_pattern);
1385 if (res->res_job.run_cmds) {
1386 delete res->res_job.run_cmds;
1388 if (res->res_job.storage) {
1389 delete res->res_job.storage;
1391 if (res->res_job.base) {
1392 delete res->res_job.base;
1394 if (res->res_job.RunScripts) {
1395 free_runscripts(res->res_job.RunScripts);
1396 delete res->res_job.RunScripts;
1400 if (res->res_msgs.mail_cmd) {
1401 free(res->res_msgs.mail_cmd);
1403 if (res->res_msgs.operator_cmd) {
1404 free(res->res_msgs.operator_cmd);
1406 free_msgs_res((MSGS *)res); /* free message resource */
1410 printf(_("Unknown resource type %d in free_resource.\n"), type);
1412 /* Common stuff again -- free the resource, recurse to next one */
1417 free_resource(nres, type);
1422 * Save the new resource by chaining it into the head list for
1423 * the resource. If this is pass 2, we update any resource
1424 * pointers because they may not have been defined until
1427 void save_resource(int type, RES_ITEM *items, int pass)
1430 int rindex = type - r_first;
1434 /* Check Job requirements after applying JobDefs */
1435 if (type != R_JOB && type != R_JOBDEFS) {
1437 * Ensure that all required items are present
1439 for (i=0; items[i].name; i++) {
1440 if (items[i].flags & ITEM_REQUIRED) {
1441 if (!bit_is_set(i, res_all.res_dir.hdr.item_present)) {
1442 Emsg2(M_ERROR_TERM, 0, _("%s item is required in %s resource, but not found.\n"),
1443 items[i].name, resources[rindex]);
1446 /* If this triggers, take a look at lib/parse_conf.h */
1447 if (i >= MAX_RES_ITEMS) {
1448 Emsg1(M_ERROR_TERM, 0, _("Too many items in %s resource\n"), resources[rindex]);
1451 } else if (type == R_JOB) {
1453 * Ensure that the name item is present
1455 if (items[0].flags & ITEM_REQUIRED) {
1456 if (!bit_is_set(0, res_all.res_dir.hdr.item_present)) {
1457 Emsg2(M_ERROR_TERM, 0, _("%s item is required in %s resource, but not found.\n"),
1458 items[0].name, resources[rindex]);
1464 * During pass 2 in each "store" routine, we looked up pointers
1465 * to all the resources referrenced in the current resource, now we
1466 * must copy their addresses from the static record to the allocated
1471 /* Resources not containing a resource */
1479 * Resources containing another resource or alist. First
1480 * look up the resource which contains another resource. It
1481 * was written during pass 1. Then stuff in the pointers to
1482 * the resources it contains, which were inserted this pass.
1483 * Finally, it will all be stored back.
1486 /* Find resource saved in pass 1 */
1487 if ((res = (URES *)GetResWithName(R_POOL, res_all.res_con.hdr.name)) == NULL) {
1488 Emsg1(M_ERROR_TERM, 0, _("Cannot find Pool resource %s\n"), res_all.res_con.hdr.name);
1490 /* Explicitly copy resource pointers from this pass (res_all) */
1491 res->res_pool.NextPool = res_all.res_pool.NextPool;
1492 res->res_pool.RecyclePool = res_all.res_pool.RecyclePool;
1493 res->res_pool.ScratchPool = res_all.res_pool.ScratchPool;
1494 res->res_pool.storage = res_all.res_pool.storage;
1495 res->res_pool.catalog = res_all.res_pool.catalog;
1498 if ((res = (URES *)GetResWithName(R_CONSOLE, res_all.res_con.hdr.name)) == NULL) {
1499 Emsg1(M_ERROR_TERM, 0, _("Cannot find Console resource %s\n"), res_all.res_con.hdr.name);
1501 res->res_con.tls_allowed_cns = res_all.res_con.tls_allowed_cns;
1504 if ((res = (URES *)GetResWithName(R_DIRECTOR, res_all.res_dir.hdr.name)) == NULL) {
1505 Emsg1(M_ERROR_TERM, 0, _("Cannot find Director resource %s\n"), res_all.res_dir.hdr.name);
1507 res->res_dir.messages = res_all.res_dir.messages;
1508 res->res_dir.tls_allowed_cns = res_all.res_dir.tls_allowed_cns;
1511 if ((res = (URES *)GetResWithName(type, res_all.res_store.hdr.name)) == NULL) {
1512 Emsg1(M_ERROR_TERM, 0, _("Cannot find Storage resource %s\n"),
1513 res_all.res_dir.hdr.name);
1515 /* we must explicitly copy the device alist pointer */
1516 res->res_store.device = res_all.res_store.device;
1520 if ((res = (URES *)GetResWithName(type, res_all.res_dir.hdr.name)) == NULL) {
1521 Emsg1(M_ERROR_TERM, 0, _("Cannot find Job resource %s\n"),
1522 res_all.res_dir.hdr.name);
1524 res->res_job.messages = res_all.res_job.messages;
1525 res->res_job.schedule = res_all.res_job.schedule;
1526 res->res_job.client = res_all.res_job.client;
1527 res->res_job.fileset = res_all.res_job.fileset;
1528 res->res_job.storage = res_all.res_job.storage;
1529 res->res_job.base = res_all.res_job.base;
1530 res->res_job.pool = res_all.res_job.pool;
1531 res->res_job.next_pool = res_all.res_job.next_pool;
1532 res->res_job.full_pool = res_all.res_job.full_pool;
1533 res->res_job.inc_pool = res_all.res_job.inc_pool;
1534 res->res_job.diff_pool = res_all.res_job.diff_pool;
1535 res->res_job.verify_job = res_all.res_job.verify_job;
1536 res->res_job.jobdefs = res_all.res_job.jobdefs;
1537 res->res_job.run_cmds = res_all.res_job.run_cmds;
1538 res->res_job.RunScripts = res_all.res_job.RunScripts;
1540 /* TODO: JobDefs where/regexwhere doesn't work well (but this
1541 * is not very useful)
1542 * We have to set_bit(index, res_all.hdr.item_present);
1543 * or something like that
1546 /* we take RegexWhere before all other options */
1547 if (!res->res_job.RegexWhere
1549 (res->res_job.strip_prefix ||
1550 res->res_job.add_suffix ||
1551 res->res_job.add_prefix))
1553 int len = bregexp_get_build_where_size(res->res_job.strip_prefix,
1554 res->res_job.add_prefix,
1555 res->res_job.add_suffix);
1556 res->res_job.RegexWhere = (char *) bmalloc (len * sizeof(char));
1557 bregexp_build_where(res->res_job.RegexWhere, len,
1558 res->res_job.strip_prefix,
1559 res->res_job.add_prefix,
1560 res->res_job.add_suffix);
1561 /* TODO: test bregexp */
1564 if (res->res_job.RegexWhere && res->res_job.RestoreWhere) {
1565 free(res->res_job.RestoreWhere);
1566 res->res_job.RestoreWhere = NULL;
1571 if ((res = (URES *)GetResWithName(R_COUNTER, res_all.res_counter.hdr.name)) == NULL) {
1572 Emsg1(M_ERROR_TERM, 0, _("Cannot find Counter resource %s\n"), res_all.res_counter.hdr.name);
1574 res->res_counter.Catalog = res_all.res_counter.Catalog;
1575 res->res_counter.WrapCounter = res_all.res_counter.WrapCounter;
1579 if ((res = (URES *)GetResWithName(R_CLIENT, res_all.res_client.hdr.name)) == NULL) {
1580 Emsg1(M_ERROR_TERM, 0, _("Cannot find Client resource %s\n"), res_all.res_client.hdr.name);
1582 res->res_client.catalog = res_all.res_client.catalog;
1583 res->res_client.tls_allowed_cns = res_all.res_client.tls_allowed_cns;
1587 * Schedule is a bit different in that it contains a RUN record
1588 * chain which isn't a "named" resource. This chain was linked
1589 * in by run_conf.c during pass 2, so here we jam the pointer
1590 * into the Schedule resource.
1592 if ((res = (URES *)GetResWithName(R_SCHEDULE, res_all.res_client.hdr.name)) == NULL) {
1593 Emsg1(M_ERROR_TERM, 0, _("Cannot find Schedule resource %s\n"), res_all.res_client.hdr.name);
1595 res->res_sch.run = res_all.res_sch.run;
1598 Emsg1(M_ERROR, 0, _("Unknown resource type %d in save_resource.\n"), type);
1602 /* Note, the resource name was already saved during pass 1,
1603 * so here, we can just release it.
1605 if (res_all.res_dir.hdr.name) {
1606 free(res_all.res_dir.hdr.name);
1607 res_all.res_dir.hdr.name = NULL;
1609 if (res_all.res_dir.hdr.desc) {
1610 free(res_all.res_dir.hdr.desc);
1611 res_all.res_dir.hdr.desc = NULL;
1617 * The following code is only executed during pass 1
1621 size = sizeof(DIRRES);
1624 size = sizeof(CONRES);
1627 size =sizeof(CLIENT);
1630 size = sizeof(STORE);
1640 size = sizeof(FILESET);
1643 size = sizeof(SCHED);
1646 size = sizeof(POOL);
1649 size = sizeof(MSGS);
1652 size = sizeof(COUNTER);
1658 printf(_("Unknown resource type %d in save_resource.\n"), type);
1664 res = (URES *)malloc(size);
1665 memcpy(res, &res_all, size);
1666 if (!res_head[rindex]) {
1667 res_head[rindex] = (RES *)res; /* store first entry */
1668 Dmsg3(900, "Inserting first %s res: %s index=%d\n", res_to_str(type),
1669 res->res_dir.hdr.name, rindex);
1672 if (res->res_dir.hdr.name == NULL) {
1673 Emsg1(M_ERROR_TERM, 0, _("Name item is required in %s resource, but not found.\n"),
1676 /* Add new res to end of chain */
1677 for (last=next=res_head[rindex]; next; next=next->next) {
1679 if (strcmp(next->name, res->res_dir.hdr.name) == 0) {
1680 Emsg2(M_ERROR_TERM, 0,
1681 _("Attempt to define second %s resource named \"%s\" is not permitted.\n"),
1682 resources[rindex].name, res->res_dir.hdr.name);
1685 last->next = (RES *)res;
1686 Dmsg4(900, _("Inserting %s res: %s index=%d pass=%d\n"), res_to_str(type),
1687 res->res_dir.hdr.name, rindex, pass);
1692 void store_actiononpurge(LEX *lc, RES_ITEM *item, int index, int pass)
1694 uint32_t *destination = (uint32_t*)item->value;
1695 lex_get_token(lc, T_NAME);
1696 if (strcasecmp(lc->str, "truncate") == 0) {
1697 *destination = (*destination) | ON_PURGE_TRUNCATE;
1699 scan_err2(lc, _("Expected one of: %s, got: %s"), "Truncate", lc->str);
1703 set_bit(index, res_all.hdr.item_present);
1707 * Store Device. Note, the resource is created upon the
1708 * first reference. The details of the resource are obtained
1709 * later from the SD.
1711 static void store_device(LEX *lc, RES_ITEM *item, int index, int pass)
1714 int rindex = R_DEVICE - r_first;
1715 int size = sizeof(DEVICE);
1719 lex_get_token(lc, T_NAME);
1720 if (!res_head[rindex]) {
1721 res = (URES *)malloc(size);
1722 memset(res, 0, size);
1723 res->res_dev.hdr.name = bstrdup(lc->str);
1724 res_head[rindex] = (RES *)res; /* store first entry */
1725 Dmsg3(900, "Inserting first %s res: %s index=%d\n", res_to_str(R_DEVICE),
1726 res->res_dir.hdr.name, rindex);
1729 /* See if it is already defined */
1730 for (next=res_head[rindex]; next->next; next=next->next) {
1731 if (strcmp(next->name, lc->str) == 0) {
1737 res = (URES *)malloc(size);
1738 memset(res, 0, size);
1739 res->res_dev.hdr.name = bstrdup(lc->str);
1740 next->next = (RES *)res;
1741 Dmsg4(900, "Inserting %s res: %s index=%d pass=%d\n", res_to_str(R_DEVICE),
1742 res->res_dir.hdr.name, rindex, pass);
1747 set_bit(index, res_all.hdr.item_present);
1749 store_alist_res(lc, item, index, pass);
1754 * Store Migration/Copy type
1757 void store_migtype(LEX *lc, RES_ITEM *item, int index, int pass)
1761 lex_get_token(lc, T_NAME);
1762 /* Store the type both pass 1 and pass 2 */
1763 for (i=0; migtypes[i].type_name; i++) {
1764 if (strcasecmp(lc->str, migtypes[i].type_name) == 0) {
1765 *(uint32_t *)(item->value) = migtypes[i].job_type;
1771 scan_err1(lc, _("Expected a Migration Job Type keyword, got: %s"), lc->str);
1774 set_bit(index, res_all.hdr.item_present);
1780 * Store JobType (backup, verify, restore)
1783 void store_jobtype(LEX *lc, RES_ITEM *item, int index, int pass)
1787 lex_get_token(lc, T_NAME);
1788 /* Store the type both pass 1 and pass 2 */
1789 for (i=0; jobtypes[i].type_name; i++) {
1790 if (strcasecmp(lc->str, jobtypes[i].type_name) == 0) {
1791 *(uint32_t *)(item->value) = jobtypes[i].job_type;
1797 scan_err1(lc, _("Expected a Job Type keyword, got: %s"), lc->str);
1800 set_bit(index, res_all.hdr.item_present);
1804 * Store Job Level (Full, Incremental, ...)
1807 void store_level(LEX *lc, RES_ITEM *item, int index, int pass)
1811 lex_get_token(lc, T_NAME);
1812 /* Store the level pass 2 so that type is defined */
1813 for (i=0; joblevels[i].level_name; i++) {
1814 if (strcasecmp(lc->str, joblevels[i].level_name) == 0) {
1815 *(uint32_t *)(item->value) = joblevels[i].level;
1821 scan_err1(lc, _("Expected a Job Level keyword, got: %s"), lc->str);
1824 set_bit(index, res_all.hdr.item_present);
1828 void store_replace(LEX *lc, RES_ITEM *item, int index, int pass)
1831 lex_get_token(lc, T_NAME);
1832 /* Scan Replacement options */
1833 for (i=0; ReplaceOptions[i].name; i++) {
1834 if (strcasecmp(lc->str, ReplaceOptions[i].name) == 0) {
1835 *(uint32_t *)(item->value) = ReplaceOptions[i].token;
1841 scan_err1(lc, _("Expected a Restore replacement option, got: %s"), lc->str);
1844 set_bit(index, res_all.hdr.item_present);
1848 * Store ACL (access control list)
1851 void store_acl(LEX *lc, RES_ITEM *item, int index, int pass)
1856 lex_get_token(lc, T_STRING);
1858 if (((alist **)item->value)[item->code] == NULL) {
1859 ((alist **)item->value)[item->code] = New(alist(10, owned_by_alist));
1860 Dmsg1(900, "Defined new ACL alist at %d\n", item->code);
1862 ((alist **)item->value)[item->code]->append(bstrdup(lc->str));
1863 Dmsg2(900, "Appended to %d %s\n", item->code, lc->str);
1865 token = lex_get_token(lc, T_ALL);
1866 if (token == T_COMMA) {
1867 continue; /* get another ACL */
1871 set_bit(index, res_all.hdr.item_present);
1874 /* We build RunScripts items here */
1875 static RUNSCRIPT res_runscript;
1877 /* Store a runscript->when in a bit field */
1878 static void store_runscript_when(LEX *lc, RES_ITEM *item, int index, int pass)
1880 lex_get_token(lc, T_NAME);
1882 if (strcasecmp(lc->str, "before") == 0) {
1883 *(uint32_t *)(item->value) = SCRIPT_Before ;
1884 } else if (strcasecmp(lc->str, "after") == 0) {
1885 *(uint32_t *)(item->value) = SCRIPT_After;
1886 } else if (strcasecmp(lc->str, "aftervss") == 0) {
1887 *(uint32_t *)(item->value) = SCRIPT_AfterVSS;
1888 } else if (strcasecmp(lc->str, "aftersnapshot") == 0) {
1889 *(uint32_t *)(item->value) = SCRIPT_AfterVSS;
1890 } else if (strcasecmp(lc->str, "always") == 0) {
1891 *(uint32_t *)(item->value) = SCRIPT_Any;
1893 scan_err2(lc, _("Expect %s, got: %s"), "Before, After, AfterVSS or Always", lc->str);
1898 /* Store a runscript->target
1901 static void store_runscript_target(LEX *lc, RES_ITEM *item, int index, int pass)
1903 lex_get_token(lc, T_STRING);
1906 if (strcmp(lc->str, "%c") == 0) {
1907 ((RUNSCRIPT*) item->value)->set_target(lc->str);
1908 } else if (strcasecmp(lc->str, "yes") == 0) {
1909 ((RUNSCRIPT*) item->value)->set_target("%c");
1910 } else if (strcasecmp(lc->str, "no") == 0) {
1911 ((RUNSCRIPT*) item->value)->set_target("");
1913 RES *res = GetResWithName(R_CLIENT, lc->str);
1915 scan_err3(lc, _("Could not find config Resource %s referenced on line %d : %s\n"),
1916 lc->str, lc->line_no, lc->line);
1919 ((RUNSCRIPT*) item->value)->set_target(lc->str);
1926 * Store a runscript->command as a string and runscript->cmd_type as a pointer
1928 static void store_runscript_cmd(LEX *lc, RES_ITEM *item, int index, int pass)
1930 lex_get_token(lc, T_STRING);
1933 Dmsg2(1, "runscript cmd=%s type=%c\n", lc->str, item->code);
1934 POOLMEM *c = get_pool_memory(PM_FNAME);
1935 /* Each runscript command takes 2 entries in commands list */
1936 pm_strcpy(c, lc->str);
1937 ((RUNSCRIPT*) item->value)->commands->prepend(c); /* command line */
1938 ((RUNSCRIPT*) item->value)->commands->prepend((void *)(intptr_t)item->code); /* command type */
1943 static void store_short_runscript(LEX *lc, RES_ITEM *item, int index, int pass)
1945 lex_get_token(lc, T_STRING);
1946 alist **runscripts = (alist **)(item->value) ;
1949 RUNSCRIPT *script = new_runscript();
1950 script->set_job_code_callback(job_code_callback_director);
1952 script->set_command(lc->str);
1954 /* TODO: remove all script->old_proto with bacula 1.42 */
1956 if (strcasecmp(item->name, "runbeforejob") == 0) {
1957 script->when = SCRIPT_Before;
1958 script->fail_on_error = true;
1959 script->set_target("");
1961 } else if (strcasecmp(item->name, "runafterjob") == 0) {
1962 script->when = SCRIPT_After;
1963 script->on_success = true;
1964 script->on_failure = false;
1965 script->set_target("");
1967 } else if (strcasecmp(item->name, "clientrunafterjob") == 0) {
1968 script->old_proto = true;
1969 script->when = SCRIPT_After;
1970 script->set_target("%c");
1971 script->on_success = true;
1972 script->on_failure = false;
1974 } else if (strcasecmp(item->name, "clientrunbeforejob") == 0) {
1975 script->old_proto = true;
1976 script->when = SCRIPT_Before;
1977 script->set_target("%c");
1978 script->fail_on_error = true;
1980 } else if (strcasecmp(item->name, "runafterfailedjob") == 0) {
1981 script->when = SCRIPT_After;
1982 script->on_failure = true;
1983 script->on_success = false;
1984 script->set_target("");
1987 if (*runscripts == NULL) {
1988 *runscripts = New(alist(10, not_owned_by_alist));
1991 (*runscripts)->append(script);
1995 set_bit(index, res_all.hdr.item_present);
1998 /* Store a bool in a bit field without modifing res_all.hdr
1999 * We can also add an option to store_bool to skip res_all.hdr
2001 void store_runscript_bool(LEX *lc, RES_ITEM *item, int index, int pass)
2003 lex_get_token(lc, T_NAME);
2004 if (strcasecmp(lc->str, "yes") == 0 || strcasecmp(lc->str, "true") == 0) {
2005 *(bool *)(item->value) = true;
2006 } else if (strcasecmp(lc->str, "no") == 0 || strcasecmp(lc->str, "false") == 0) {
2007 *(bool *)(item->value) = false;
2009 scan_err2(lc, _("Expect %s, got: %s"), "YES, NO, TRUE, or FALSE", lc->str); /* YES and NO must not be translated */
2015 * new RunScript items
2016 * name handler value code flags default_value
2018 static RES_ITEM runscript_items[] = {
2019 {"command", store_runscript_cmd, {(char **)&res_runscript}, SHELL_CMD, 0, 0},
2020 {"console", store_runscript_cmd, {(char **)&res_runscript}, CONSOLE_CMD, 0, 0},
2021 {"target", store_runscript_target,{(char **)&res_runscript}, 0, 0, 0},
2022 {"runsonsuccess", store_runscript_bool, {(char **)&res_runscript.on_success},0, 0, 0},
2023 {"runsonfailure", store_runscript_bool, {(char **)&res_runscript.on_failure},0, 0, 0},
2024 {"failjobonerror",store_runscript_bool, {(char **)&res_runscript.fail_on_error},0, 0, 0},
2025 {"abortjobonerror",store_runscript_bool, {(char **)&res_runscript.fail_on_error},0, 0, 0},
2026 {"runswhen", store_runscript_when, {(char **)&res_runscript.when}, 0, 0, 0},
2027 {"runsonclient", store_runscript_target,{(char **)&res_runscript}, 0, 0, 0}, /* TODO */
2028 {NULL, NULL, {0}, 0, 0, 0}
2032 * Store RunScript info
2034 * Note, when this routine is called, we are inside a Job
2035 * resource. We treat the RunScript like a sort of
2036 * mini-resource within the Job resource.
2038 void store_runscript(LEX *lc, RES_ITEM *item, int index, int pass)
2042 alist **runscripts = (alist **)(item->value) ;
2044 Dmsg1(200, "store_runscript: begin store_runscript pass=%i\n", pass);
2046 token = lex_get_token(lc, T_SKIP_EOL);
2048 if (token != T_BOB) {
2049 scan_err1(lc, _("Expecting open brace. Got %s"), lc->str);
2051 /* setting on_success, on_failure, fail_on_error */
2052 res_runscript.reset_default();
2055 res_runscript.commands = New(alist(10, not_owned_by_alist));
2058 while ((token = lex_get_token(lc, T_SKIP_EOL)) != T_EOF) {
2059 if (token == T_EOB) {
2062 if (token != T_IDENTIFIER) {
2063 scan_err1(lc, _("Expecting keyword, got: %s\n"), lc->str);
2065 for (i=0; runscript_items[i].name; i++) {
2066 if (strcasecmp(runscript_items[i].name, lc->str) == 0) {
2067 token = lex_get_token(lc, T_SKIP_EOL);
2068 if (token != T_EQUALS) {
2069 scan_err1(lc, _("expected an equals, got: %s"), lc->str);
2072 /* Call item handler */
2073 runscript_items[i].handler(lc, &runscript_items[i], i, pass);
2080 scan_err1(lc, _("Keyword %s not permitted in this resource"), lc->str);
2085 /* run on client by default */
2086 if (res_runscript.target == NULL) {
2087 res_runscript.set_target("%c");
2089 if (*runscripts == NULL) {
2090 *runscripts = New(alist(10, not_owned_by_alist));
2093 * commands list contains 2 values per command
2094 * - POOLMEM command string (ex: /bin/true)
2095 * - int command type (ex: SHELL_CMD)
2097 res_runscript.set_job_code_callback(job_code_callback_director);
2098 while ((c=(char*)res_runscript.commands->pop()) != NULL) {
2099 t = (intptr_t)res_runscript.commands->pop();
2100 RUNSCRIPT *script = new_runscript();
2101 memcpy(script, &res_runscript, sizeof(RUNSCRIPT));
2102 script->command = c;
2103 script->cmd_type = t;
2104 /* target is taken from res_runscript, each runscript object have
2107 script->target = NULL;
2108 script->set_target(res_runscript.target);
2110 (*runscripts)->append(script);
2113 delete res_runscript.commands;
2114 /* setting on_success, on_failure... cleanup target field */
2115 res_runscript.reset_default(true);
2119 set_bit(index, res_all.hdr.item_present);
2122 /* callback function for edit_job_codes */
2123 /* See ../lib/util.c, function edit_job_codes, for more remaining codes */
2124 extern "C" char *job_code_callback_director(JCR *jcr, const char* param)
2126 static char yes[] = "yes";
2127 static char no[] = "no";
2131 return jcr->fileset->name();
2135 if (jcr->client && jcr->client->address) {
2136 return jcr->client->address;
2141 return jcr->pool->name();
2146 return jcr->wstore->name();
2150 return jcr->spool_data ? yes : no;
2154 return jcr->cloned ? yes : no;
2159 bool parse_dir_config(CONFIG *config, const char *configfile, int exit_code)
2161 config->init(configfile, NULL, exit_code, (void *)&res_all, res_all_size,
2162 r_first, r_last, resources, res_head);
2163 return config->parse_config();