2 Bacula® - The Network Backup Solution
4 Copyright (C) 2000-2008 Free Software Foundation Europe e.V.
6 The main author of Bacula is Kern Sibbald, with contributions from
7 many others, a complete list can be found in the file AUTHORS.
8 This program is Free Software; you can redistribute it and/or
9 modify it under the terms of version two of the GNU General Public
10 License as published by the Free Software Foundation and included
13 This program is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
23 Bacula® is a registered trademark of John Walker.
24 The licensor of Bacula is the Free Software Foundation Europe
25 (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich,
26 Switzerland, email:ftf@fsfeurope.org.
29 * Main configuration file parser for Bacula Directors,
30 * some parts may be split into separate files such as
31 * the schedule configuration (run_config.c).
33 * Note, the configuration file parser consists of three parts
35 * 1. The generic lexical scanner in lib/lex.c and lib/lex.h
37 * 2. The generic config scanner in lib/parse_config.c and
39 * These files contain the parser code, some utility
40 * routines, and the common store routines (name, int,
43 * 3. The daemon specific file, which contains the Resource
44 * definitions as well as any specific store routines
45 * for the resource records.
47 * Kern Sibbald, January MM
56 /* Define the first and last resource ID record
57 * types. Note, these should be unique for each
58 * daemon though not a requirement.
60 int r_first = R_FIRST;
62 static RES *sres_head[R_LAST - R_FIRST + 1];
63 RES **res_head = sres_head;
65 /* Imported subroutines */
66 extern void store_run(LEX *lc, RES_ITEM *item, int index, int pass);
67 extern void store_finc(LEX *lc, RES_ITEM *item, int index, int pass);
68 extern void store_inc(LEX *lc, RES_ITEM *item, int index, int pass);
71 /* Forward referenced subroutines */
73 void store_jobtype(LEX *lc, RES_ITEM *item, int index, int pass);
74 void store_level(LEX *lc, RES_ITEM *item, int index, int pass);
75 void store_replace(LEX *lc, RES_ITEM *item, int index, int pass);
76 void store_acl(LEX *lc, RES_ITEM *item, int index, int pass);
77 void store_migtype(LEX *lc, RES_ITEM *item, int index, int pass);
78 static void store_device(LEX *lc, RES_ITEM *item, int index, int pass);
79 static void store_runscript(LEX *lc, RES_ITEM *item, int index, int pass);
80 static void store_runscript_when(LEX *lc, RES_ITEM *item, int index, int pass);
81 static void store_runscript_cmd(LEX *lc, RES_ITEM *item, int index, int pass);
82 static void store_short_runscript(LEX *lc, RES_ITEM *item, int index, int pass);
84 /* We build the current resource here as we are
85 * scanning the resource configuration definition,
86 * then move it to allocated memory when the resource
90 extern "C" { // work around visual compiler mangling variables
96 int res_all_size = sizeof(res_all);
99 /* Definition of records permitted within each
100 * resource with the routine to process the record
101 * information. NOTE! quoted names must be in lower case.
106 * name handler value code flags default_value
108 static RES_ITEM dir_items[] = {
109 {"name", store_name, ITEM(res_dir.hdr.name), 0, ITEM_REQUIRED, 0},
110 {"description", store_str, ITEM(res_dir.hdr.desc), 0, 0, 0},
111 {"messages", store_res, ITEM(res_dir.messages), R_MSGS, 0, 0},
112 {"dirport", store_addresses_port, ITEM(res_dir.DIRaddrs), 0, ITEM_DEFAULT, 9101},
113 {"diraddress", store_addresses_address, ITEM(res_dir.DIRaddrs), 0, ITEM_DEFAULT, 9101},
114 {"diraddresses",store_addresses, ITEM(res_dir.DIRaddrs), 0, ITEM_DEFAULT, 9101},
115 {"queryfile", store_dir, ITEM(res_dir.query_file), 0, ITEM_REQUIRED, 0},
116 {"workingdirectory", store_dir, ITEM(res_dir.working_directory), 0, ITEM_REQUIRED, 0},
117 {"plugindirectory", store_dir, ITEM(res_dir.plugin_directory), 0, 0, 0},
118 {"scriptsdirectory", store_dir, ITEM(res_dir.scripts_directory), 0, 0, 0},
119 {"piddirectory",store_dir, ITEM(res_dir.pid_directory), 0, ITEM_REQUIRED, 0},
120 {"subsysdirectory", store_dir, ITEM(res_dir.subsys_directory), 0, 0, 0},
121 {"maximumconcurrentjobs", store_pint, ITEM(res_dir.MaxConcurrentJobs), 0, ITEM_DEFAULT, 1},
122 {"password", store_password, ITEM(res_dir.password), 0, ITEM_REQUIRED, 0},
123 {"fdconnecttimeout", store_time,ITEM(res_dir.FDConnectTimeout), 0, ITEM_DEFAULT, 60 * 30},
124 {"sdconnecttimeout", store_time,ITEM(res_dir.SDConnectTimeout), 0, ITEM_DEFAULT, 60 * 30},
125 {"heartbeatinterval", store_time, ITEM(res_dir.heartbeat_interval), 0, ITEM_DEFAULT, 0},
126 {"tlsauthenticate", store_bool, ITEM(res_dir.tls_authenticate), 0, 0, 0},
127 {"tlsenable", store_bool, ITEM(res_dir.tls_enable), 0, 0, 0},
128 {"tlsrequire", store_bool, ITEM(res_dir.tls_require), 0, 0, 0},
129 {"tlsverifypeer", store_bool, ITEM(res_dir.tls_verify_peer), 0, ITEM_DEFAULT, true},
130 {"tlscacertificatefile", store_dir, ITEM(res_dir.tls_ca_certfile), 0, 0, 0},
131 {"tlscacertificatedir", store_dir, ITEM(res_dir.tls_ca_certdir), 0, 0, 0},
132 {"tlscertificate", store_dir, ITEM(res_dir.tls_certfile), 0, 0, 0},
133 {"tlskey", store_dir, ITEM(res_dir.tls_keyfile), 0, 0, 0},
134 {"tlsdhfile", store_dir, ITEM(res_dir.tls_dhfile), 0, 0, 0},
135 {"tlsallowedcn", store_alist_str, ITEM(res_dir.tls_allowed_cns), 0, 0, 0},
136 {"statisticsretention", store_time, ITEM(res_dir.stats_retention), 0, ITEM_DEFAULT, 60*60*24*31*12*5},
137 {NULL, NULL, {0}, 0, 0, 0}
143 * name handler value code flags default_value
145 static RES_ITEM con_items[] = {
146 {"name", store_name, ITEM(res_con.hdr.name), 0, ITEM_REQUIRED, 0},
147 {"description", store_str, ITEM(res_con.hdr.desc), 0, 0, 0},
148 {"password", store_password, ITEM(res_con.password), 0, ITEM_REQUIRED, 0},
149 {"jobacl", store_acl, ITEM(res_con.ACL_lists), Job_ACL, 0, 0},
150 {"clientacl", store_acl, ITEM(res_con.ACL_lists), Client_ACL, 0, 0},
151 {"storageacl", store_acl, ITEM(res_con.ACL_lists), Storage_ACL, 0, 0},
152 {"scheduleacl", store_acl, ITEM(res_con.ACL_lists), Schedule_ACL, 0, 0},
153 {"runacl", store_acl, ITEM(res_con.ACL_lists), Run_ACL, 0, 0},
154 {"poolacl", store_acl, ITEM(res_con.ACL_lists), Pool_ACL, 0, 0},
155 {"commandacl", store_acl, ITEM(res_con.ACL_lists), Command_ACL, 0, 0},
156 {"filesetacl", store_acl, ITEM(res_con.ACL_lists), FileSet_ACL, 0, 0},
157 {"catalogacl", store_acl, ITEM(res_con.ACL_lists), Catalog_ACL, 0, 0},
158 {"whereacl", store_acl, ITEM(res_con.ACL_lists), Where_ACL, 0, 0},
159 {"pluginoptionsacl", store_acl, ITEM(res_con.ACL_lists), PluginOptions_ACL, 0, 0},
160 {"tlsauthenticate", store_bool, ITEM(res_con.tls_authenticate), 0, 0, 0},
161 {"tlsenable", store_bool, ITEM(res_con.tls_enable), 0, 0, 0},
162 {"tlsrequire", store_bool, ITEM(res_con.tls_require), 0, 0, 0},
163 {"tlsverifypeer", store_bool, ITEM(res_con.tls_verify_peer), 0, ITEM_DEFAULT, true},
164 {"tlscacertificatefile", store_dir, ITEM(res_con.tls_ca_certfile), 0, 0, 0},
165 {"tlscacertificatedir", store_dir, ITEM(res_con.tls_ca_certdir), 0, 0, 0},
166 {"tlscertificate", store_dir, ITEM(res_con.tls_certfile), 0, 0, 0},
167 {"tlskey", store_dir, ITEM(res_con.tls_keyfile), 0, 0, 0},
168 {"tlsdhfile", store_dir, ITEM(res_con.tls_dhfile), 0, 0, 0},
169 {"tlsallowedcn", store_alist_str, ITEM(res_con.tls_allowed_cns), 0, 0, 0},
170 {NULL, NULL, {0}, 0, 0, 0}
175 * Client or File daemon resource
177 * name handler value code flags default_value
180 static RES_ITEM cli_items[] = {
181 {"name", store_name, ITEM(res_client.hdr.name), 0, ITEM_REQUIRED, 0},
182 {"description", store_str, ITEM(res_client.hdr.desc), 0, 0, 0},
183 {"address", store_str, ITEM(res_client.address), 0, ITEM_REQUIRED, 0},
184 {"fdaddress", store_str, ITEM(res_client.address), 0, 0, 0},
185 {"fdport", store_pint, ITEM(res_client.FDport), 0, ITEM_DEFAULT, 9102},
186 {"password", store_password, ITEM(res_client.password), 0, ITEM_REQUIRED, 0},
187 {"fdpassword", store_password, ITEM(res_client.password), 0, 0, 0},
188 {"catalog", store_res, ITEM(res_client.catalog), R_CATALOG, ITEM_REQUIRED, 0},
189 {"fileretention", store_time, ITEM(res_client.FileRetention), 0, ITEM_DEFAULT, 60*60*24*60},
190 {"jobretention", store_time, ITEM(res_client.JobRetention), 0, ITEM_DEFAULT, 60*60*24*180},
191 {"heartbeatinterval", store_time, ITEM(res_client.heartbeat_interval), 0, ITEM_DEFAULT, 0},
192 {"autoprune", store_bool, ITEM(res_client.AutoPrune), 0, ITEM_DEFAULT, true},
193 {"maximumconcurrentjobs", store_pint, ITEM(res_client.MaxConcurrentJobs), 0, ITEM_DEFAULT, 1},
194 {"tlsauthenticate", store_bool, ITEM(res_client.tls_authenticate), 0, 0, 0},
195 {"tlsenable", store_bool, ITEM(res_client.tls_enable), 0, 0, 0},
196 {"tlsrequire", store_bool, ITEM(res_client.tls_require), 0, 0, 0},
197 {"tlscacertificatefile", store_dir, ITEM(res_client.tls_ca_certfile), 0, 0, 0},
198 {"tlscacertificatedir", store_dir, ITEM(res_client.tls_ca_certdir), 0, 0, 0},
199 {"tlscertificate", store_dir, ITEM(res_client.tls_certfile), 0, 0, 0},
200 {"tlskey", store_dir, ITEM(res_client.tls_keyfile), 0, 0, 0},
201 {"tlsallowedcn", store_alist_str, ITEM(res_client.tls_allowed_cns), 0, 0, 0},
202 {NULL, NULL, {0}, 0, 0, 0}
205 /* Storage daemon resource
207 * name handler value code flags default_value
209 static RES_ITEM store_items[] = {
210 {"name", store_name, ITEM(res_store.hdr.name), 0, ITEM_REQUIRED, 0},
211 {"description", store_str, ITEM(res_store.hdr.desc), 0, 0, 0},
212 {"sdport", store_pint, ITEM(res_store.SDport), 0, ITEM_DEFAULT, 9103},
213 {"address", store_str, ITEM(res_store.address), 0, ITEM_REQUIRED, 0},
214 {"sdaddress", store_str, ITEM(res_store.address), 0, 0, 0},
215 {"password", store_password, ITEM(res_store.password), 0, ITEM_REQUIRED, 0},
216 {"sdpassword", store_password, ITEM(res_store.password), 0, 0, 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, 0},
220 {"enabled", store_bool, ITEM(res_store.enabled), 0, ITEM_DEFAULT, true},
221 {"heartbeatinterval", store_time, ITEM(res_store.heartbeat_interval), 0, ITEM_DEFAULT, 0},
222 {"maximumconcurrentjobs", store_pint, ITEM(res_store.MaxConcurrentJobs), 0, ITEM_DEFAULT, 1},
223 {"sddport", store_pint, ITEM(res_store.SDDport), 0, 0, 0}, /* deprecated */
224 {"tlsauthenticate", store_bool, ITEM(res_store.tls_authenticate), 0, 0, 0},
225 {"tlsenable", store_bool, ITEM(res_store.tls_enable), 0, 0, 0},
226 {"tlsrequire", store_bool, ITEM(res_store.tls_require), 0, 0, 0},
227 {"tlscacertificatefile", store_dir, ITEM(res_store.tls_ca_certfile), 0, 0, 0},
228 {"tlscacertificatedir", store_dir, ITEM(res_store.tls_ca_certdir), 0, 0, 0},
229 {"tlscertificate", store_dir, ITEM(res_store.tls_certfile), 0, 0, 0},
230 {"tlskey", store_dir, ITEM(res_store.tls_keyfile), 0, 0, 0},
231 {NULL, NULL, {0}, 0, 0, 0}
235 * Catalog Resource Directives
237 * name handler value code flags default_value
239 static RES_ITEM cat_items[] = {
240 {"name", store_name, ITEM(res_cat.hdr.name), 0, ITEM_REQUIRED, 0},
241 {"description", store_str, ITEM(res_cat.hdr.desc), 0, 0, 0},
242 {"address", store_str, ITEM(res_cat.db_address), 0, 0, 0},
243 {"dbaddress", store_str, ITEM(res_cat.db_address), 0, 0, 0},
244 {"dbport", store_pint, ITEM(res_cat.db_port), 0, 0, 0},
245 /* keep this password as store_str for the moment */
246 {"password", store_str, ITEM(res_cat.db_password), 0, 0, 0},
247 {"dbpassword", store_str, ITEM(res_cat.db_password), 0, 0, 0},
248 {"user", store_str, ITEM(res_cat.db_user), 0, 0, 0},
249 {"dbname", store_str, ITEM(res_cat.db_name), 0, ITEM_REQUIRED, 0},
250 {"dbdriver", store_str, ITEM(res_cat.db_driver), 0, 0, 0},
251 {"dbsocket", store_str, ITEM(res_cat.db_socket), 0, 0, 0},
252 /* Turned off for the moment */
253 {"multipleconnections", store_bit, ITEM(res_cat.mult_db_connections), 0, 0, 0},
254 {NULL, NULL, {0}, 0, 0, 0}
258 * Job Resource Directives
260 * name handler value code flags default_value
262 RES_ITEM job_items[] = {
263 {"name", store_name, ITEM(res_job.hdr.name), 0, ITEM_REQUIRED, 0},
264 {"description", store_str, ITEM(res_job.hdr.desc), 0, 0, 0},
265 {"type", store_jobtype, ITEM(res_job.JobType), 0, ITEM_REQUIRED, 0},
266 {"level", store_level, ITEM(res_job.JobLevel), 0, 0, 0},
267 {"messages", store_res, ITEM(res_job.messages), R_MSGS, ITEM_REQUIRED, 0},
268 {"storage", store_alist_res, ITEM(res_job.storage), R_STORAGE, 0, 0},
269 {"pool", store_res, ITEM(res_job.pool), R_POOL, ITEM_REQUIRED, 0},
270 {"fullbackuppool", store_res, ITEM(res_job.full_pool), R_POOL, 0, 0},
271 {"incrementalbackuppool", store_res, ITEM(res_job.inc_pool), R_POOL, 0, 0},
272 {"differentialbackuppool", store_res, ITEM(res_job.diff_pool), R_POOL, 0, 0},
273 {"client", store_res, ITEM(res_job.client), R_CLIENT, ITEM_REQUIRED, 0},
274 {"fileset", store_res, ITEM(res_job.fileset), R_FILESET, ITEM_REQUIRED, 0},
275 {"schedule", store_res, ITEM(res_job.schedule), R_SCHEDULE, 0, 0},
276 {"verifyjob", store_res, ITEM(res_job.verify_job), R_JOB, 0, 0},
277 {"jobtoverify", store_res, ITEM(res_job.verify_job), R_JOB, 0, 0},
278 {"jobdefs", store_res, ITEM(res_job.jobdefs), R_JOBDEFS, 0, 0},
279 {"run", store_alist_str, ITEM(res_job.run_cmds), 0, 0, 0},
280 /* Root of where to restore files */
281 {"where", store_dir, ITEM(res_job.RestoreWhere), 0, 0, 0},
282 {"regexwhere", store_str, ITEM(res_job.RegexWhere), 0, 0, 0},
283 {"stripprefix", store_str, ITEM(res_job.strip_prefix), 0, 0, 0},
284 {"addprefix", store_str, ITEM(res_job.add_prefix), 0, 0, 0},
285 {"addsuffix", store_str, ITEM(res_job.add_suffix), 0, 0, 0},
286 /* Where to find bootstrap during restore */
287 {"bootstrap",store_dir, ITEM(res_job.RestoreBootstrap), 0, 0, 0},
288 /* Where to write bootstrap file during backup */
289 {"writebootstrap",store_dir, ITEM(res_job.WriteBootstrap), 0, 0, 0},
290 {"writeverifylist",store_dir, ITEM(res_job.WriteVerifyList), 0, 0, 0},
291 {"replace", store_replace, ITEM(res_job.replace), 0, ITEM_DEFAULT, REPLACE_ALWAYS},
292 {"maxruntime", store_time, ITEM(res_job.MaxRunTime), 0, 0, 0},
293 {"fullmaxwaittime", store_time, ITEM(res_job.FullMaxWaitTime), 0, 0, 0},
294 {"incrementalmaxwaittime", store_time, ITEM(res_job.IncMaxWaitTime), 0, 0, 0},
295 {"differentialmaxwaittime", store_time, ITEM(res_job.DiffMaxWaitTime), 0, 0, 0},
296 {"maxwaittime", store_time, ITEM(res_job.MaxWaitTime), 0, 0, 0},
297 {"maxstartdelay",store_time, ITEM(res_job.MaxStartDelay), 0, 0, 0},
298 {"maxfullinterval", store_time, ITEM(res_job.MaxFullInterval), 0, 0, 0},
299 {"maxdiffinterval", store_time, ITEM(res_job.MaxDiffInterval), 0, 0, 0},
300 {"jobretention", store_time, ITEM(res_job.JobRetention), 0, 0, 0},
301 {"prefixlinks", store_bool, ITEM(res_job.PrefixLinks), 0, ITEM_DEFAULT, false},
302 {"prunejobs", store_bool, ITEM(res_job.PruneJobs), 0, ITEM_DEFAULT, false},
303 {"prunefiles", store_bool, ITEM(res_job.PruneFiles), 0, ITEM_DEFAULT, false},
304 {"prunevolumes",store_bool, ITEM(res_job.PruneVolumes), 0, ITEM_DEFAULT, false},
305 {"enabled", store_bool, ITEM(res_job.enabled), 0, ITEM_DEFAULT, true},
306 {"optimizejobscheduling",store_bool, ITEM(res_job.OptimizeJobScheduling), 0, ITEM_DEFAULT, false},
307 {"spoolattributes",store_bool, ITEM(res_job.SpoolAttributes), 0, ITEM_DEFAULT, false},
308 {"spooldata", store_bool, ITEM(res_job.spool_data), 0, ITEM_DEFAULT, false},
309 {"spoolsize", store_size, ITEM(res_job.spool_size), 0, 0, 0},
310 {"rerunfailedlevels", store_bool, ITEM(res_job.rerun_failed_levels), 0, ITEM_DEFAULT, false},
311 {"prefermountedvolumes", store_bool, ITEM(res_job.PreferMountedVolumes), 0, ITEM_DEFAULT, true},
312 {"runbeforejob", store_short_runscript, ITEM(res_job.RunScripts), 0, 0, 0},
313 {"runafterjob", store_short_runscript, ITEM(res_job.RunScripts), 0, 0, 0},
314 {"runafterfailedjob", store_short_runscript, ITEM(res_job.RunScripts), 0, 0, 0},
315 {"clientrunbeforejob", store_short_runscript, ITEM(res_job.RunScripts), 0, 0, 0},
316 {"clientrunafterjob", store_short_runscript, ITEM(res_job.RunScripts), 0, 0, 0},
317 {"maximumconcurrentjobs", store_pint, ITEM(res_job.MaxConcurrentJobs), 0, ITEM_DEFAULT, 1},
318 {"rescheduleonerror", store_bool, ITEM(res_job.RescheduleOnError), 0, ITEM_DEFAULT, false},
319 {"rescheduleinterval", store_time, ITEM(res_job.RescheduleInterval), 0, ITEM_DEFAULT, 60 * 30},
320 {"rescheduletimes", store_pint, ITEM(res_job.RescheduleTimes), 0, 0, 0},
321 {"priority", store_pint, ITEM(res_job.Priority), 0, ITEM_DEFAULT, 10},
322 {"writepartafterjob", store_bool, ITEM(res_job.write_part_after_job), 0, ITEM_DEFAULT, true},
323 {"selectionpattern", store_str, ITEM(res_job.selection_pattern), 0, 0, 0},
324 {"runscript", store_runscript, ITEM(res_job.RunScripts), 0, ITEM_NO_EQUALS, 0},
325 {"selectiontype", store_migtype, ITEM(res_job.selection_type), 0, 0, 0},
326 {"usestatistics", store_bool, ITEM(res_job.stats_enabled), 0, 0, 0},
327 {"accurate", store_bool, ITEM(res_job.accurate), 0,0,0},
328 {"allowduplicatejobs", store_bool, ITEM(res_job.AllowDuplicateJobs), 0, ITEM_DEFAULT, false},
329 {"allowhigherduplicates", store_bool, ITEM(res_job.AllowHigherDuplicates), 0, ITEM_DEFAULT, true},
330 {"cancelqueuedduplicates", store_bool, ITEM(res_job.CancelQueuedDuplicates), 0, ITEM_DEFAULT, true},
331 {"cancelrunningduplicates", store_bool, ITEM(res_job.CancelRunningDuplicates), 0, ITEM_DEFAULT, false},
332 {"pluginoptions", store_str, ITEM(res_job.PluginOptions), 0, 0, 0},
333 {NULL, NULL, {0}, 0, 0, 0}
338 * name handler value code flags default_value
340 static RES_ITEM fs_items[] = {
341 {"name", store_name, ITEM(res_fs.hdr.name), 0, ITEM_REQUIRED, 0},
342 {"description", store_str, ITEM(res_fs.hdr.desc), 0, 0, 0},
343 {"include", store_inc, {0}, 0, ITEM_NO_EQUALS, 0},
344 {"exclude", store_inc, {0}, 1, ITEM_NO_EQUALS, 0},
345 {"ignorefilesetchanges", store_bool, ITEM(res_fs.ignore_fs_changes), 0, ITEM_DEFAULT, false},
346 {"enablevss", store_bool, ITEM(res_fs.enable_vss), 0, ITEM_DEFAULT, true},
347 {NULL, NULL, {0}, 0, 0, 0}
350 /* Schedule -- see run_conf.c */
353 * name handler value code flags default_value
355 static RES_ITEM sch_items[] = {
356 {"name", store_name, ITEM(res_sch.hdr.name), 0, ITEM_REQUIRED, 0},
357 {"description", store_str, ITEM(res_sch.hdr.desc), 0, 0, 0},
358 {"run", store_run, ITEM(res_sch.run), 0, 0, 0},
359 {NULL, NULL, {0}, 0, 0, 0}
364 * name handler value code flags default_value
366 static RES_ITEM pool_items[] = {
367 {"name", store_name, ITEM(res_pool.hdr.name), 0, ITEM_REQUIRED, 0},
368 {"description", store_str, ITEM(res_pool.hdr.desc), 0, 0, 0},
369 {"pooltype", store_strname, ITEM(res_pool.pool_type), 0, ITEM_REQUIRED, 0},
370 {"labelformat", store_strname, ITEM(res_pool.label_format), 0, 0, 0},
371 {"labeltype", store_label, ITEM(res_pool.LabelType), 0, 0, 0},
372 {"cleaningprefix", store_strname, ITEM(res_pool.cleaning_prefix), 0, 0, 0},
373 {"usecatalog", store_bool, ITEM(res_pool.use_catalog), 0, ITEM_DEFAULT, true},
374 {"usevolumeonce", store_bool, ITEM(res_pool.use_volume_once), 0, 0, 0},
375 {"purgeoldestvolume", store_bool, ITEM(res_pool.purge_oldest_volume), 0, 0, 0},
376 {"recycleoldestvolume", store_bool, ITEM(res_pool.recycle_oldest_volume), 0, 0, 0},
377 {"recyclecurrentvolume", store_bool, ITEM(res_pool.recycle_current_volume), 0, 0, 0},
378 {"maximumvolumes", store_pint, ITEM(res_pool.max_volumes), 0, 0, 0},
379 {"maximumvolumejobs", store_pint, ITEM(res_pool.MaxVolJobs), 0, 0, 0},
380 {"maximumvolumefiles", store_pint, ITEM(res_pool.MaxVolFiles), 0, 0, 0},
381 {"maximumvolumebytes", store_size, ITEM(res_pool.MaxVolBytes), 0, 0, 0},
382 {"catalogfiles", store_bool, ITEM(res_pool.catalog_files), 0, ITEM_DEFAULT, true},
383 {"volumeretention", store_time, ITEM(res_pool.VolRetention), 0, ITEM_DEFAULT, 60*60*24*365},
384 {"volumeuseduration", store_time, ITEM(res_pool.VolUseDuration), 0, 0, 0},
385 {"migrationtime", store_time, ITEM(res_pool.MigrationTime), 0, 0, 0},
386 {"migrationhighbytes", store_size, ITEM(res_pool.MigrationHighBytes), 0, 0, 0},
387 {"migrationlowbytes", store_size, ITEM(res_pool.MigrationLowBytes), 0, 0, 0},
388 {"nextpool", store_res, ITEM(res_pool.NextPool), R_POOL, 0, 0},
389 {"storage", store_alist_res, ITEM(res_pool.storage), R_STORAGE, 0, 0},
390 {"autoprune", store_bool, ITEM(res_pool.AutoPrune), 0, ITEM_DEFAULT, true},
391 {"recycle", store_bool, ITEM(res_pool.Recycle), 0, ITEM_DEFAULT, true},
392 {"recyclepool", store_res, ITEM(res_pool.RecyclePool), R_POOL, 0, 0},
393 {"copypool", store_alist_res, ITEM(res_pool.CopyPool), R_POOL, 0, 0},
394 {"catalog", store_res, ITEM(res_pool.catalog), R_CATALOG, 0, 0},
395 {NULL, NULL, {0}, 0, 0, 0}
400 * name handler value code flags default_value
402 static RES_ITEM counter_items[] = {
403 {"name", store_name, ITEM(res_counter.hdr.name), 0, ITEM_REQUIRED, 0},
404 {"description", store_str, ITEM(res_counter.hdr.desc), 0, 0, 0},
405 {"minimum", store_int, ITEM(res_counter.MinValue), 0, ITEM_DEFAULT, 0},
406 {"maximum", store_pint, ITEM(res_counter.MaxValue), 0, ITEM_DEFAULT, INT32_MAX},
407 {"wrapcounter", store_res, ITEM(res_counter.WrapCounter), R_COUNTER, 0, 0},
408 {"catalog", store_res, ITEM(res_counter.Catalog), R_CATALOG, 0, 0},
409 {NULL, NULL, {0}, 0, 0, 0}
413 /* Message resource */
414 extern RES_ITEM msgs_items[];
417 * This is the master resource definition.
418 * It must have one item for each of the resources.
420 * NOTE!!! keep it in the same order as the R_codes
421 * or eliminate all resources[rindex].name
423 * name items rcode res_head
425 RES_TABLE resources[] = {
426 {"director", dir_items, R_DIRECTOR},
427 {"client", cli_items, R_CLIENT},
428 {"job", job_items, R_JOB},
429 {"storage", store_items, R_STORAGE},
430 {"catalog", cat_items, R_CATALOG},
431 {"schedule", sch_items, R_SCHEDULE},
432 {"fileset", fs_items, R_FILESET},
433 {"pool", pool_items, R_POOL},
434 {"messages", msgs_items, R_MSGS},
435 {"counter", counter_items, R_COUNTER},
436 {"console", con_items, R_CONSOLE},
437 {"jobdefs", job_items, R_JOBDEFS},
438 {"device", NULL, R_DEVICE}, /* info obtained from SD */
443 /* Keywords (RHS) permitted in Job Level records
445 * level_name level job_type
447 struct s_jl joblevels[] = {
448 {"Full", L_FULL, JT_BACKUP},
449 {"Base", L_BASE, JT_BACKUP},
450 {"Incremental", L_INCREMENTAL, JT_BACKUP},
451 {"Differential", L_DIFFERENTIAL, JT_BACKUP},
452 {"Since", L_SINCE, JT_BACKUP},
453 {"Catalog", L_VERIFY_CATALOG, JT_VERIFY},
454 {"InitCatalog", L_VERIFY_INIT, JT_VERIFY},
455 {"VolumeToCatalog", L_VERIFY_VOLUME_TO_CATALOG, JT_VERIFY},
456 {"DiskToCatalog", L_VERIFY_DISK_TO_CATALOG, JT_VERIFY},
457 {"Data", L_VERIFY_DATA, JT_VERIFY},
458 {" ", L_NONE, JT_ADMIN},
459 {" ", L_NONE, JT_RESTORE},
463 /* Keywords (RHS) permitted in Job type records
467 struct s_jt jobtypes[] = {
468 {"backup", JT_BACKUP},
470 {"verify", JT_VERIFY},
471 {"restore", JT_RESTORE},
472 {"migrate", JT_MIGRATE},
478 /* Keywords (RHS) permitted in Selection type records
482 struct s_jt migtypes[] = {
483 {"smallestvolume", MT_SMALLEST_VOL},
484 {"oldestvolume", MT_OLDEST_VOL},
485 {"pooloccupancy", MT_POOL_OCCUPANCY},
486 {"pooltime", MT_POOL_TIME},
487 {"client", MT_CLIENT},
488 {"volume", MT_VOLUME},
490 {"sqlquery", MT_SQLQUERY},
496 /* Options permitted in Restore replace= */
497 struct s_kw ReplaceOptions[] = {
498 {"always", REPLACE_ALWAYS},
499 {"ifnewer", REPLACE_IFNEWER},
500 {"ifolder", REPLACE_IFOLDER},
501 {"never", REPLACE_NEVER},
505 const char *level_to_str(int level)
508 static char level_no[30];
509 const char *str = level_no;
511 bsnprintf(level_no, sizeof(level_no), "%c (%d)", level, level); /* default if not found */
512 for (i=0; joblevels[i].level_name; i++) {
513 if (level == joblevels[i].level) {
514 str = joblevels[i].level_name;
521 /* Dump contents of resource */
522 void dump_resource(int type, RES *reshdr, void sendit(void *sock, const char *fmt, ...), void *sock)
524 URES *res = (URES *)reshdr;
526 char ed1[100], ed2[100], ed3[100];
530 sendit(sock, _("No %s resource defined\n"), res_to_str(type));
533 if (type < 0) { /* no recursion */
539 sendit(sock, _("Director: name=%s MaxJobs=%d FDtimeout=%s SDtimeout=%s\n"),
540 reshdr->name, res->res_dir.MaxConcurrentJobs,
541 edit_uint64(res->res_dir.FDConnectTimeout, ed1),
542 edit_uint64(res->res_dir.SDConnectTimeout, ed2));
543 if (res->res_dir.query_file) {
544 sendit(sock, _(" query_file=%s\n"), res->res_dir.query_file);
546 if (res->res_dir.messages) {
547 sendit(sock, _(" --> "));
548 dump_resource(-R_MSGS, (RES *)res->res_dir.messages, sendit, sock);
552 sendit(sock, _("Console: name=%s SSL=%d\n"),
553 res->res_con.hdr.name, res->res_con.tls_enable);
556 if (res->res_counter.WrapCounter) {
557 sendit(sock, _("Counter: name=%s min=%d max=%d cur=%d wrapcntr=%s\n"),
558 res->res_counter.hdr.name, res->res_counter.MinValue,
559 res->res_counter.MaxValue, res->res_counter.CurrentValue,
560 res->res_counter.WrapCounter->hdr.name);
562 sendit(sock, _("Counter: name=%s min=%d max=%d\n"),
563 res->res_counter.hdr.name, res->res_counter.MinValue,
564 res->res_counter.MaxValue);
566 if (res->res_counter.Catalog) {
567 sendit(sock, _(" --> "));
568 dump_resource(-R_CATALOG, (RES *)res->res_counter.Catalog, sendit, sock);
573 sendit(sock, _("Client: name=%s address=%s FDport=%d MaxJobs=%u\n"),
574 res->res_client.hdr.name, res->res_client.address, res->res_client.FDport,
575 res->res_client.MaxConcurrentJobs);
576 sendit(sock, _(" JobRetention=%s FileRetention=%s AutoPrune=%d\n"),
577 edit_utime(res->res_client.JobRetention, ed1, sizeof(ed1)),
578 edit_utime(res->res_client.FileRetention, ed2, sizeof(ed2)),
579 res->res_client.AutoPrune);
580 if (res->res_client.catalog) {
581 sendit(sock, _(" --> "));
582 dump_resource(-R_CATALOG, (RES *)res->res_client.catalog, sendit, sock);
589 sendit(sock, _("Device: name=%s ok=%d num_writers=%d max_writers=%d\n"
590 " reserved=%d open=%d append=%d read=%d labeled=%d offline=%d autochgr=%d\n"
591 " poolid=%s volname=%s MediaType=%s\n"),
592 dev->hdr.name, dev->found, dev->num_writers, dev->max_writers,
593 dev->reserved, dev->open, dev->append, dev->read, dev->labeled,
594 dev->offline, dev->autochanger,
595 edit_uint64(dev->PoolId, ed1),
596 dev->VolumeName, dev->MediaType);
600 sendit(sock, _("Storage: name=%s address=%s SDport=%d MaxJobs=%u\n"
601 " DeviceName=%s MediaType=%s StorageId=%s\n"),
602 res->res_store.hdr.name, res->res_store.address, res->res_store.SDport,
603 res->res_store.MaxConcurrentJobs,
604 res->res_store.dev_name(),
605 res->res_store.media_type,
606 edit_int64(res->res_store.StorageId, ed1));
610 sendit(sock, _("Catalog: name=%s address=%s DBport=%d db_name=%s\n"
611 " db_driver=%s db_user=%s MutliDBConn=%d\n"),
612 res->res_cat.hdr.name, NPRT(res->res_cat.db_address),
613 res->res_cat.db_port, res->res_cat.db_name,
614 NPRT(res->res_cat.db_driver), NPRT(res->res_cat.db_user),
615 res->res_cat.mult_db_connections);
620 sendit(sock, _("%s: name=%s JobType=%d level=%s Priority=%d Enabled=%d\n"),
621 type == R_JOB ? _("Job") : _("JobDefs"),
622 res->res_job.hdr.name, res->res_job.JobType,
623 level_to_str(res->res_job.JobLevel), res->res_job.Priority,
624 res->res_job.enabled);
625 sendit(sock, _(" MaxJobs=%u Resched=%d Times=%d Interval=%s Spool=%d WritePartAfterJob=%d\n"),
626 res->res_job.MaxConcurrentJobs,
627 res->res_job.RescheduleOnError, res->res_job.RescheduleTimes,
628 edit_uint64_with_commas(res->res_job.RescheduleInterval, ed1),
629 res->res_job.spool_data, res->res_job.write_part_after_job);
630 if (res->res_job.spool_size) {
631 sendit(sock, _(" SpoolSize=%s\n"), edit_uint64(res->res_job.spool_size, ed1));
633 if (res->res_job.JobType == JT_BACKUP) {
634 sendit(sock, _(" Accurate=%d\n"), res->res_job.accurate);
636 if (res->res_job.JobType == JT_MIGRATE || res->res_job.JobType == JT_COPY) {
637 sendit(sock, _(" SelectionType=%d\n"), res->res_job.selection_type);
639 if (res->res_job.client) {
640 sendit(sock, _(" --> "));
641 dump_resource(-R_CLIENT, (RES *)res->res_job.client, sendit, sock);
643 if (res->res_job.fileset) {
644 sendit(sock, _(" --> "));
645 dump_resource(-R_FILESET, (RES *)res->res_job.fileset, sendit, sock);
647 if (res->res_job.schedule) {
648 sendit(sock, _(" --> "));
649 dump_resource(-R_SCHEDULE, (RES *)res->res_job.schedule, sendit, sock);
651 if (res->res_job.RestoreWhere && !res->res_job.RegexWhere) {
652 sendit(sock, _(" --> Where=%s\n"), NPRT(res->res_job.RestoreWhere));
654 if (res->res_job.RegexWhere) {
655 sendit(sock, _(" --> RegexWhere=%s\n"), NPRT(res->res_job.RegexWhere));
657 if (res->res_job.stats_enabled) {
658 sendit(sock, _(" --> StatsEnabled=%d\n"), res->res_job.stats_enabled);
660 if (res->res_job.RestoreBootstrap) {
661 sendit(sock, _(" --> Bootstrap=%s\n"), NPRT(res->res_job.RestoreBootstrap));
663 if (res->res_job.WriteBootstrap) {
664 sendit(sock, _(" --> WriteBootstrap=%s\n"), NPRT(res->res_job.WriteBootstrap));
666 if (res->res_job.PluginOptions) {
667 sendit(sock, _(" --> PluginOptions=%s\n"), NPRT(res->res_job.PluginOptions));
669 if (res->res_job.storage) {
671 foreach_alist(store, res->res_job.storage) {
672 sendit(sock, _(" --> "));
673 dump_resource(-R_STORAGE, (RES *)store, sendit, sock);
676 if (res->res_job.RunScripts) {
678 foreach_alist(script, res->res_job.RunScripts) {
679 sendit(sock, _(" --> RunScript\n"));
680 sendit(sock, _(" --> Command=%s\n"), NPRT(script->command));
681 sendit(sock, _(" --> Target=%s\n"), NPRT(script->target));
682 sendit(sock, _(" --> RunOnSuccess=%u\n"), script->on_success);
683 sendit(sock, _(" --> RunOnFailure=%u\n"), script->on_failure);
684 sendit(sock, _(" --> FailJobOnError=%u\n"), script->fail_on_error);
685 sendit(sock, _(" --> RunWhen=%u\n"), script->when);
688 if (res->res_job.pool) {
689 sendit(sock, _(" --> "));
690 dump_resource(-R_POOL, (RES *)res->res_job.pool, sendit, sock);
692 if (res->res_job.full_pool) {
693 sendit(sock, _(" --> "));
694 dump_resource(-R_POOL, (RES *)res->res_job.full_pool, sendit, sock);
696 if (res->res_job.inc_pool) {
697 sendit(sock, _(" --> "));
698 dump_resource(-R_POOL, (RES *)res->res_job.inc_pool, sendit, sock);
700 if (res->res_job.diff_pool) {
701 sendit(sock, _(" --> "));
702 dump_resource(-R_POOL, (RES *)res->res_job.diff_pool, sendit, sock);
704 if (res->res_job.verify_job) {
705 sendit(sock, _(" --> "));
706 dump_resource(-type, (RES *)res->res_job.verify_job, sendit, sock);
708 if (res->res_job.run_cmds) {
710 foreach_alist(runcmd, res->res_job.run_cmds) {
711 sendit(sock, _(" --> Run=%s\n"), runcmd);
714 if (res->res_job.selection_pattern) {
715 sendit(sock, _(" --> SelectionPattern=%s\n"), NPRT(res->res_job.selection_pattern));
717 if (res->res_job.messages) {
718 sendit(sock, _(" --> "));
719 dump_resource(-R_MSGS, (RES *)res->res_job.messages, sendit, sock);
726 sendit(sock, _("FileSet: name=%s\n"), res->res_fs.hdr.name);
727 for (i=0; i<res->res_fs.num_includes; i++) {
728 INCEXE *incexe = res->res_fs.include_items[i];
729 for (j=0; j<incexe->num_opts; j++) {
730 FOPTS *fo = incexe->opts_list[j];
731 sendit(sock, " O %s\n", fo->opts);
733 bool enhanced_wild = false;
734 for (k=0; fo->opts[k]!='\0'; k++) {
735 if (fo->opts[k]=='W') {
736 enhanced_wild = true;
741 for (k=0; k<fo->regex.size(); k++) {
742 sendit(sock, " R %s\n", fo->regex.get(k));
744 for (k=0; k<fo->regexdir.size(); k++) {
745 sendit(sock, " RD %s\n", fo->regexdir.get(k));
747 for (k=0; k<fo->regexfile.size(); k++) {
748 sendit(sock, " RF %s\n", fo->regexfile.get(k));
750 for (k=0; k<fo->wild.size(); k++) {
751 sendit(sock, " W %s\n", fo->wild.get(k));
753 for (k=0; k<fo->wilddir.size(); k++) {
754 sendit(sock, " WD %s\n", fo->wilddir.get(k));
756 for (k=0; k<fo->wildfile.size(); k++) {
757 sendit(sock, " WF %s\n", fo->wildfile.get(k));
759 for (k=0; k<fo->wildbase.size(); k++) {
760 sendit(sock, " W%c %s\n", enhanced_wild ? 'B' : 'F', fo->wildbase.get(k));
762 for (k=0; k<fo->base.size(); k++) {
763 sendit(sock, " B %s\n", fo->base.get(k));
765 for (k=0; k<fo->fstype.size(); k++) {
766 sendit(sock, " X %s\n", fo->fstype.get(k));
768 for (k=0; k<fo->drivetype.size(); k++) {
769 sendit(sock, " XD %s\n", fo->drivetype.get(k));
772 sendit(sock, " G %s\n", fo->plugin);
775 sendit(sock, " D %s\n", fo->reader);
778 sendit(sock, " T %s\n", fo->writer);
780 sendit(sock, " N\n");
782 for (j=0; j<incexe->name_list.size(); j++) {
783 sendit(sock, " I %s\n", incexe->name_list.get(j));
785 if (incexe->name_list.size()) {
786 sendit(sock, " N\n");
788 for (j=0; j<incexe->plugin_list.size(); j++) {
789 sendit(sock, " P %s\n", incexe->plugin_list.get(j));
791 if (incexe->plugin_list.size()) {
792 sendit(sock, " N\n");
797 for (i=0; i<res->res_fs.num_excludes; i++) {
798 INCEXE *incexe = res->res_fs.exclude_items[i];
799 for (j=0; j<incexe->name_list.size(); j++) {
800 sendit(sock, " E %s\n", incexe->name_list.get(j));
802 if (incexe->name_list.size()) {
803 sendit(sock, " N\n");
810 if (res->res_sch.run) {
812 RUN *run = res->res_sch.run;
813 char buf[1000], num[30];
814 sendit(sock, _("Schedule: name=%s\n"), res->res_sch.hdr.name);
819 sendit(sock, _(" --> Run Level=%s\n"), level_to_str(run->level));
820 bstrncpy(buf, _(" hour="), sizeof(buf));
821 for (i=0; i<24; i++) {
822 if (bit_is_set(i, run->hour)) {
823 bsnprintf(num, sizeof(num), "%d ", i);
824 bstrncat(buf, num, sizeof(buf));
827 bstrncat(buf, "\n", sizeof(buf));
829 bstrncpy(buf, _(" mday="), sizeof(buf));
830 for (i=0; i<31; i++) {
831 if (bit_is_set(i, run->mday)) {
832 bsnprintf(num, sizeof(num), "%d ", i);
833 bstrncat(buf, num, sizeof(buf));
836 bstrncat(buf, "\n", sizeof(buf));
838 bstrncpy(buf, _(" month="), sizeof(buf));
839 for (i=0; i<12; i++) {
840 if (bit_is_set(i, run->month)) {
841 bsnprintf(num, sizeof(num), "%d ", i);
842 bstrncat(buf, num, sizeof(buf));
845 bstrncat(buf, "\n", sizeof(buf));
847 bstrncpy(buf, _(" wday="), sizeof(buf));
848 for (i=0; i<7; i++) {
849 if (bit_is_set(i, run->wday)) {
850 bsnprintf(num, sizeof(num), "%d ", i);
851 bstrncat(buf, num, sizeof(buf));
854 bstrncat(buf, "\n", sizeof(buf));
856 bstrncpy(buf, _(" wom="), sizeof(buf));
857 for (i=0; i<5; i++) {
858 if (bit_is_set(i, run->wom)) {
859 bsnprintf(num, sizeof(num), "%d ", i);
860 bstrncat(buf, num, sizeof(buf));
863 bstrncat(buf, "\n", sizeof(buf));
865 bstrncpy(buf, _(" woy="), sizeof(buf));
866 for (i=0; i<54; i++) {
867 if (bit_is_set(i, run->woy)) {
868 bsnprintf(num, sizeof(num), "%d ", i);
869 bstrncat(buf, num, sizeof(buf));
872 bstrncat(buf, "\n", sizeof(buf));
874 sendit(sock, _(" mins=%d\n"), run->minute);
876 sendit(sock, _(" --> "));
877 dump_resource(-R_POOL, (RES *)run->pool, sendit, sock);
880 sendit(sock, _(" --> "));
881 dump_resource(-R_STORAGE, (RES *)run->storage, sendit, sock);
884 sendit(sock, _(" --> "));
885 dump_resource(-R_MSGS, (RES *)run->msgs, sendit, sock);
887 /* If another Run record is chained in, go print it */
893 sendit(sock, _("Schedule: name=%s\n"), res->res_sch.hdr.name);
898 sendit(sock, _("Pool: name=%s PoolType=%s\n"), res->res_pool.hdr.name,
899 res->res_pool.pool_type);
900 sendit(sock, _(" use_cat=%d use_once=%d cat_files=%d\n"),
901 res->res_pool.use_catalog, res->res_pool.use_volume_once,
902 res->res_pool.catalog_files);
903 sendit(sock, _(" max_vols=%d auto_prune=%d VolRetention=%s\n"),
904 res->res_pool.max_volumes, res->res_pool.AutoPrune,
905 edit_utime(res->res_pool.VolRetention, ed1, sizeof(ed1)));
906 sendit(sock, _(" VolUse=%s recycle=%d LabelFormat=%s\n"),
907 edit_utime(res->res_pool.VolUseDuration, ed1, sizeof(ed1)),
908 res->res_pool.Recycle,
909 NPRT(res->res_pool.label_format));
910 sendit(sock, _(" CleaningPrefix=%s LabelType=%d\n"),
911 NPRT(res->res_pool.cleaning_prefix), res->res_pool.LabelType);
912 sendit(sock, _(" RecyleOldest=%d PurgeOldest=%d\n"),
913 res->res_pool.recycle_oldest_volume,
914 res->res_pool.purge_oldest_volume);
915 sendit(sock, _(" MaxVolJobs=%d MaxVolFiles=%d MaxVolBytes=%s\n"),
916 res->res_pool.MaxVolJobs,
917 res->res_pool.MaxVolFiles,
918 edit_uint64(res->res_pool.MaxVolFiles, ed1));
919 sendit(sock, _(" MigTime=%s MigHiBytes=%s MigLoBytes=%s\n"),
920 edit_utime(res->res_pool.MigrationTime, ed1, sizeof(ed1)),
921 edit_uint64(res->res_pool.MigrationHighBytes, ed2),
922 edit_uint64(res->res_pool.MigrationLowBytes, ed3));
923 if (res->res_pool.NextPool) {
924 sendit(sock, _(" NextPool=%s\n"), res->res_pool.NextPool->name());
926 if (res->res_pool.RecyclePool) {
927 sendit(sock, _(" RecyclePool=%s\n"), res->res_pool.RecyclePool->name());
929 if (res->res_pool.catalog) {
930 sendit(sock, _(" Catalog=%s\n"), res->res_pool.catalog->name());
932 if (res->res_pool.storage) {
934 foreach_alist(store, res->res_pool.storage) {
935 sendit(sock, _(" --> "));
936 dump_resource(-R_STORAGE, (RES *)store, sendit, sock);
939 if (res->res_pool.CopyPool) {
941 foreach_alist(copy, res->res_pool.CopyPool) {
942 sendit(sock, _(" --> "));
943 dump_resource(-R_POOL, (RES *)copy, sendit, sock);
950 sendit(sock, _("Messages: name=%s\n"), res->res_msgs.hdr.name);
951 if (res->res_msgs.mail_cmd)
952 sendit(sock, _(" mailcmd=%s\n"), res->res_msgs.mail_cmd);
953 if (res->res_msgs.operator_cmd)
954 sendit(sock, _(" opcmd=%s\n"), res->res_msgs.operator_cmd);
958 sendit(sock, _("Unknown resource type %d in dump_resource.\n"), type);
961 if (recurse && res->res_dir.hdr.next) {
962 dump_resource(type, res->res_dir.hdr.next, sendit, sock);
967 * Free all the members of an INCEXE structure
969 static void free_incexe(INCEXE *incexe)
971 incexe->name_list.destroy();
972 incexe->plugin_list.destroy();
973 for (int i=0; i<incexe->num_opts; i++) {
974 FOPTS *fopt = incexe->opts_list[i];
975 fopt->regex.destroy();
976 fopt->regexdir.destroy();
977 fopt->regexfile.destroy();
978 fopt->wild.destroy();
979 fopt->wilddir.destroy();
980 fopt->wildfile.destroy();
981 fopt->wildbase.destroy();
982 fopt->base.destroy();
983 fopt->fstype.destroy();
984 fopt->drivetype.destroy();
996 if (incexe->opts_list) {
997 free(incexe->opts_list);
1003 * Free memory of resource -- called when daemon terminates.
1004 * NB, we don't need to worry about freeing any references
1005 * to other resources as they will be freed when that
1006 * resource chain is traversed. Mainly we worry about freeing
1007 * allocated strings (names).
1009 void free_resource(RES *sres, int type)
1012 RES *nres; /* next resource if linked */
1013 URES *res = (URES *)sres;
1018 /* common stuff -- free the resource name and description */
1019 nres = (RES *)res->res_dir.hdr.next;
1020 if (res->res_dir.hdr.name) {
1021 free(res->res_dir.hdr.name);
1023 if (res->res_dir.hdr.desc) {
1024 free(res->res_dir.hdr.desc);
1029 if (res->res_dir.working_directory) {
1030 free(res->res_dir.working_directory);
1032 if (res->res_dir.scripts_directory) {
1033 free((char *)res->res_dir.scripts_directory);
1035 if (res->res_dir.plugin_directory) {
1036 free((char *)res->res_dir.plugin_directory);
1038 if (res->res_dir.pid_directory) {
1039 free(res->res_dir.pid_directory);
1041 if (res->res_dir.subsys_directory) {
1042 free(res->res_dir.subsys_directory);
1044 if (res->res_dir.password) {
1045 free(res->res_dir.password);
1047 if (res->res_dir.query_file) {
1048 free(res->res_dir.query_file);
1050 if (res->res_dir.DIRaddrs) {
1051 free_addresses(res->res_dir.DIRaddrs);
1053 if (res->res_dir.tls_ctx) {
1054 free_tls_context(res->res_dir.tls_ctx);
1056 if (res->res_dir.tls_ca_certfile) {
1057 free(res->res_dir.tls_ca_certfile);
1059 if (res->res_dir.tls_ca_certdir) {
1060 free(res->res_dir.tls_ca_certdir);
1062 if (res->res_dir.tls_certfile) {
1063 free(res->res_dir.tls_certfile);
1065 if (res->res_dir.tls_keyfile) {
1066 free(res->res_dir.tls_keyfile);
1068 if (res->res_dir.tls_dhfile) {
1069 free(res->res_dir.tls_dhfile);
1071 if (res->res_dir.tls_allowed_cns) {
1072 delete res->res_dir.tls_allowed_cns;
1079 if (res->res_con.password) {
1080 free(res->res_con.password);
1082 if (res->res_con.tls_ctx) {
1083 free_tls_context(res->res_con.tls_ctx);
1085 if (res->res_con.tls_ca_certfile) {
1086 free(res->res_con.tls_ca_certfile);
1088 if (res->res_con.tls_ca_certdir) {
1089 free(res->res_con.tls_ca_certdir);
1091 if (res->res_con.tls_certfile) {
1092 free(res->res_con.tls_certfile);
1094 if (res->res_con.tls_keyfile) {
1095 free(res->res_con.tls_keyfile);
1097 if (res->res_con.tls_dhfile) {
1098 free(res->res_con.tls_dhfile);
1100 if (res->res_con.tls_allowed_cns) {
1101 delete res->res_con.tls_allowed_cns;
1103 for (int i=0; i<Num_ACL; i++) {
1104 if (res->res_con.ACL_lists[i]) {
1105 delete res->res_con.ACL_lists[i];
1106 res->res_con.ACL_lists[i] = NULL;
1111 if (res->res_client.address) {
1112 free(res->res_client.address);
1114 if (res->res_client.password) {
1115 free(res->res_client.password);
1117 if (res->res_client.tls_ctx) {
1118 free_tls_context(res->res_client.tls_ctx);
1120 if (res->res_client.tls_ca_certfile) {
1121 free(res->res_client.tls_ca_certfile);
1123 if (res->res_client.tls_ca_certdir) {
1124 free(res->res_client.tls_ca_certdir);
1126 if (res->res_client.tls_certfile) {
1127 free(res->res_client.tls_certfile);
1129 if (res->res_client.tls_keyfile) {
1130 free(res->res_client.tls_keyfile);
1132 if (res->res_client.tls_allowed_cns) {
1133 delete res->res_client.tls_allowed_cns;
1137 if (res->res_store.address) {
1138 free(res->res_store.address);
1140 if (res->res_store.password) {
1141 free(res->res_store.password);
1143 if (res->res_store.media_type) {
1144 free(res->res_store.media_type);
1146 if (res->res_store.device) {
1147 delete res->res_store.device;
1149 if (res->res_store.tls_ctx) {
1150 free_tls_context(res->res_store.tls_ctx);
1152 if (res->res_store.tls_ca_certfile) {
1153 free(res->res_store.tls_ca_certfile);
1155 if (res->res_store.tls_ca_certdir) {
1156 free(res->res_store.tls_ca_certdir);
1158 if (res->res_store.tls_certfile) {
1159 free(res->res_store.tls_certfile);
1161 if (res->res_store.tls_keyfile) {
1162 free(res->res_store.tls_keyfile);
1166 if (res->res_cat.db_address) {
1167 free(res->res_cat.db_address);
1169 if (res->res_cat.db_socket) {
1170 free(res->res_cat.db_socket);
1172 if (res->res_cat.db_user) {
1173 free(res->res_cat.db_user);
1175 if (res->res_cat.db_name) {
1176 free(res->res_cat.db_name);
1178 if (res->res_cat.db_driver) {
1179 free(res->res_cat.db_driver);
1181 if (res->res_cat.db_password) {
1182 free(res->res_cat.db_password);
1186 if ((num=res->res_fs.num_includes)) {
1187 while (--num >= 0) {
1188 free_incexe(res->res_fs.include_items[num]);
1190 free(res->res_fs.include_items);
1192 res->res_fs.num_includes = 0;
1193 if ((num=res->res_fs.num_excludes)) {
1194 while (--num >= 0) {
1195 free_incexe(res->res_fs.exclude_items[num]);
1197 free(res->res_fs.exclude_items);
1199 res->res_fs.num_excludes = 0;
1202 if (res->res_pool.pool_type) {
1203 free(res->res_pool.pool_type);
1205 if (res->res_pool.label_format) {
1206 free(res->res_pool.label_format);
1208 if (res->res_pool.cleaning_prefix) {
1209 free(res->res_pool.cleaning_prefix);
1211 if (res->res_pool.storage) {
1212 delete res->res_pool.storage;
1216 if (res->res_sch.run) {
1218 nrun = res->res_sch.run;
1228 if (res->res_job.RestoreWhere) {
1229 free(res->res_job.RestoreWhere);
1231 if (res->res_job.RegexWhere) {
1232 free(res->res_job.RegexWhere);
1234 if (res->res_job.strip_prefix) {
1235 free(res->res_job.strip_prefix);
1237 if (res->res_job.add_prefix) {
1238 free(res->res_job.add_prefix);
1240 if (res->res_job.add_suffix) {
1241 free(res->res_job.add_suffix);
1243 if (res->res_job.RestoreBootstrap) {
1244 free(res->res_job.RestoreBootstrap);
1246 if (res->res_job.WriteBootstrap) {
1247 free(res->res_job.WriteBootstrap);
1249 if (res->res_job.PluginOptions) {
1250 free(res->res_job.PluginOptions);
1252 if (res->res_job.selection_pattern) {
1253 free(res->res_job.selection_pattern);
1255 if (res->res_job.run_cmds) {
1256 delete res->res_job.run_cmds;
1258 if (res->res_job.storage) {
1259 delete res->res_job.storage;
1261 if (res->res_job.RunScripts) {
1262 free_runscripts(res->res_job.RunScripts);
1263 delete res->res_job.RunScripts;
1267 if (res->res_msgs.mail_cmd) {
1268 free(res->res_msgs.mail_cmd);
1270 if (res->res_msgs.operator_cmd) {
1271 free(res->res_msgs.operator_cmd);
1273 free_msgs_res((MSGS *)res); /* free message resource */
1277 printf(_("Unknown resource type %d in free_resource.\n"), type);
1279 /* Common stuff again -- free the resource, recurse to next one */
1284 free_resource(nres, type);
1289 * Save the new resource by chaining it into the head list for
1290 * the resource. If this is pass 2, we update any resource
1291 * pointers because they may not have been defined until
1294 void save_resource(int type, RES_ITEM *items, int pass)
1297 int rindex = type - r_first;
1301 /* Check Job requirements after applying JobDefs */
1302 if (type != R_JOB && type != R_JOBDEFS) {
1304 * Ensure that all required items are present
1306 for (i=0; items[i].name; i++) {
1307 if (items[i].flags & ITEM_REQUIRED) {
1308 if (!bit_is_set(i, res_all.res_dir.hdr.item_present)) {
1309 Emsg2(M_ERROR_TERM, 0, _("%s item is required in %s resource, but not found.\n"),
1310 items[i].name, resources[rindex]);
1313 /* If this triggers, take a look at lib/parse_conf.h */
1314 if (i >= MAX_RES_ITEMS) {
1315 Emsg1(M_ERROR_TERM, 0, _("Too many items in %s resource\n"), resources[rindex]);
1318 } else if (type == R_JOB) {
1320 * Ensure that the name item is present
1322 if (items[0].flags & ITEM_REQUIRED) {
1323 if (!bit_is_set(0, res_all.res_dir.hdr.item_present)) {
1324 Emsg2(M_ERROR_TERM, 0, _("%s item is required in %s resource, but not found.\n"),
1325 items[0].name, resources[rindex]);
1331 * During pass 2 in each "store" routine, we looked up pointers
1332 * to all the resources referrenced in the current resource, now we
1333 * must copy their addresses from the static record to the allocated
1338 /* Resources not containing a resource */
1346 * Resources containing another resource or alist. First
1347 * look up the resource which contains another resource. It
1348 * was written during pass 1. Then stuff in the pointers to
1349 * the resources it contains, which were inserted this pass.
1350 * Finally, it will all be stored back.
1353 /* Find resource saved in pass 1 */
1354 if ((res = (URES *)GetResWithName(R_POOL, res_all.res_con.hdr.name)) == NULL) {
1355 Emsg1(M_ERROR_TERM, 0, _("Cannot find Pool resource %s\n"), res_all.res_con.hdr.name);
1357 /* Explicitly copy resource pointers from this pass (res_all) */
1358 res->res_pool.NextPool = res_all.res_pool.NextPool;
1359 res->res_pool.RecyclePool = res_all.res_pool.RecyclePool;
1360 res->res_pool.storage = res_all.res_pool.storage;
1361 res->res_pool.catalog = res_all.res_pool.catalog;
1364 if ((res = (URES *)GetResWithName(R_CONSOLE, res_all.res_con.hdr.name)) == NULL) {
1365 Emsg1(M_ERROR_TERM, 0, _("Cannot find Console resource %s\n"), res_all.res_con.hdr.name);
1367 res->res_con.tls_allowed_cns = res_all.res_con.tls_allowed_cns;
1370 if ((res = (URES *)GetResWithName(R_DIRECTOR, res_all.res_dir.hdr.name)) == NULL) {
1371 Emsg1(M_ERROR_TERM, 0, _("Cannot find Director resource %s\n"), res_all.res_dir.hdr.name);
1373 res->res_dir.messages = res_all.res_dir.messages;
1374 res->res_dir.tls_allowed_cns = res_all.res_dir.tls_allowed_cns;
1377 if ((res = (URES *)GetResWithName(type, res_all.res_store.hdr.name)) == NULL) {
1378 Emsg1(M_ERROR_TERM, 0, _("Cannot find Storage resource %s\n"),
1379 res_all.res_dir.hdr.name);
1381 /* we must explicitly copy the device alist pointer */
1382 res->res_store.device = res_all.res_store.device;
1386 if ((res = (URES *)GetResWithName(type, res_all.res_dir.hdr.name)) == NULL) {
1387 Emsg1(M_ERROR_TERM, 0, _("Cannot find Job resource %s\n"),
1388 res_all.res_dir.hdr.name);
1390 res->res_job.messages = res_all.res_job.messages;
1391 res->res_job.schedule = res_all.res_job.schedule;
1392 res->res_job.client = res_all.res_job.client;
1393 res->res_job.fileset = res_all.res_job.fileset;
1394 res->res_job.storage = res_all.res_job.storage;
1395 res->res_job.pool = res_all.res_job.pool;
1396 res->res_job.full_pool = res_all.res_job.full_pool;
1397 res->res_job.inc_pool = res_all.res_job.inc_pool;
1398 res->res_job.diff_pool = res_all.res_job.diff_pool;
1399 res->res_job.verify_job = res_all.res_job.verify_job;
1400 res->res_job.jobdefs = res_all.res_job.jobdefs;
1401 res->res_job.run_cmds = res_all.res_job.run_cmds;
1402 res->res_job.RunScripts = res_all.res_job.RunScripts;
1404 /* TODO: JobDefs where/regexwhere doesn't work well (but this
1405 * is not very useful)
1406 * We have to set_bit(index, res_all.hdr.item_present);
1407 * or something like that
1410 /* we take RegexWhere before all other options */
1411 if (!res->res_job.RegexWhere
1413 (res->res_job.strip_prefix ||
1414 res->res_job.add_suffix ||
1415 res->res_job.add_prefix))
1417 int len = bregexp_get_build_where_size(res->res_job.strip_prefix,
1418 res->res_job.add_prefix,
1419 res->res_job.add_suffix);
1420 res->res_job.RegexWhere = (char *) bmalloc (len * sizeof(char));
1421 bregexp_build_where(res->res_job.RegexWhere, len,
1422 res->res_job.strip_prefix,
1423 res->res_job.add_prefix,
1424 res->res_job.add_suffix);
1425 /* TODO: test bregexp */
1428 if (res->res_job.RegexWhere && res->res_job.RestoreWhere) {
1429 free(res->res_job.RestoreWhere);
1430 res->res_job.RestoreWhere = NULL;
1435 if ((res = (URES *)GetResWithName(R_COUNTER, res_all.res_counter.hdr.name)) == NULL) {
1436 Emsg1(M_ERROR_TERM, 0, _("Cannot find Counter resource %s\n"), res_all.res_counter.hdr.name);
1438 res->res_counter.Catalog = res_all.res_counter.Catalog;
1439 res->res_counter.WrapCounter = res_all.res_counter.WrapCounter;
1443 if ((res = (URES *)GetResWithName(R_CLIENT, res_all.res_client.hdr.name)) == NULL) {
1444 Emsg1(M_ERROR_TERM, 0, _("Cannot find Client resource %s\n"), res_all.res_client.hdr.name);
1446 res->res_client.catalog = res_all.res_client.catalog;
1447 res->res_client.tls_allowed_cns = res_all.res_client.tls_allowed_cns;
1451 * Schedule is a bit different in that it contains a RUN record
1452 * chain which isn't a "named" resource. This chain was linked
1453 * in by run_conf.c during pass 2, so here we jam the pointer
1454 * into the Schedule resource.
1456 if ((res = (URES *)GetResWithName(R_SCHEDULE, res_all.res_client.hdr.name)) == NULL) {
1457 Emsg1(M_ERROR_TERM, 0, _("Cannot find Schedule resource %s\n"), res_all.res_client.hdr.name);
1459 res->res_sch.run = res_all.res_sch.run;
1462 Emsg1(M_ERROR, 0, _("Unknown resource type %d in save_resource.\n"), type);
1466 /* Note, the resource name was already saved during pass 1,
1467 * so here, we can just release it.
1469 if (res_all.res_dir.hdr.name) {
1470 free(res_all.res_dir.hdr.name);
1471 res_all.res_dir.hdr.name = NULL;
1473 if (res_all.res_dir.hdr.desc) {
1474 free(res_all.res_dir.hdr.desc);
1475 res_all.res_dir.hdr.desc = NULL;
1481 * The following code is only executed during pass 1
1485 size = sizeof(DIRRES);
1488 size = sizeof(CONRES);
1491 size =sizeof(CLIENT);
1494 size = sizeof(STORE);
1504 size = sizeof(FILESET);
1507 size = sizeof(SCHED);
1510 size = sizeof(POOL);
1513 size = sizeof(MSGS);
1516 size = sizeof(COUNTER);
1522 printf(_("Unknown resource type %d in save_resource.\n"), type);
1528 res = (URES *)malloc(size);
1529 memcpy(res, &res_all, size);
1530 if (!res_head[rindex]) {
1531 res_head[rindex] = (RES *)res; /* store first entry */
1532 Dmsg3(900, "Inserting first %s res: %s index=%d\n", res_to_str(type),
1533 res->res_dir.hdr.name, rindex);
1536 if (res->res_dir.hdr.name == NULL) {
1537 Emsg1(M_ERROR_TERM, 0, _("Name item is required in %s resource, but not found.\n"),
1540 /* Add new res to end of chain */
1541 for (last=next=res_head[rindex]; next; next=next->next) {
1543 if (strcmp(next->name, res->res_dir.hdr.name) == 0) {
1544 Emsg2(M_ERROR_TERM, 0,
1545 _("Attempt to define second %s resource named \"%s\" is not permitted.\n"),
1546 resources[rindex].name, res->res_dir.hdr.name);
1549 last->next = (RES *)res;
1550 Dmsg4(900, _("Inserting %s res: %s index=%d pass=%d\n"), res_to_str(type),
1551 res->res_dir.hdr.name, rindex, pass);
1557 * Store Device. Note, the resource is created upon the
1558 * first reference. The details of the resource are obtained
1559 * later from the SD.
1561 static void store_device(LEX *lc, RES_ITEM *item, int index, int pass)
1565 int rindex = R_DEVICE - r_first;
1566 int size = sizeof(DEVICE);
1570 token = lex_get_token(lc, T_NAME);
1571 if (!res_head[rindex]) {
1572 res = (URES *)malloc(size);
1573 memset(res, 0, size);
1574 res->res_dev.hdr.name = bstrdup(lc->str);
1575 res_head[rindex] = (RES *)res; /* store first entry */
1576 Dmsg3(900, "Inserting first %s res: %s index=%d\n", res_to_str(R_DEVICE),
1577 res->res_dir.hdr.name, rindex);
1580 /* See if it is already defined */
1581 for (next=res_head[rindex]; next->next; next=next->next) {
1582 if (strcmp(next->name, lc->str) == 0) {
1588 res = (URES *)malloc(size);
1589 memset(res, 0, size);
1590 res->res_dev.hdr.name = bstrdup(lc->str);
1591 next->next = (RES *)res;
1592 Dmsg4(900, "Inserting %s res: %s index=%d pass=%d\n", res_to_str(R_DEVICE),
1593 res->res_dir.hdr.name, rindex, pass);
1598 set_bit(index, res_all.hdr.item_present);
1600 store_alist_res(lc, item, index, pass);
1605 * Store JobType (backup, verify, restore)
1608 void store_migtype(LEX *lc, RES_ITEM *item, int index, int pass)
1612 token = lex_get_token(lc, T_NAME);
1613 /* Store the type both pass 1 and pass 2 */
1614 for (i=0; migtypes[i].type_name; i++) {
1615 if (strcasecmp(lc->str, migtypes[i].type_name) == 0) {
1616 *(int *)(item->value) = migtypes[i].job_type;
1622 scan_err1(lc, _("Expected a Migration Job Type keyword, got: %s"), lc->str);
1625 set_bit(index, res_all.hdr.item_present);
1631 * Store JobType (backup, verify, restore)
1634 void store_jobtype(LEX *lc, RES_ITEM *item, int index, int pass)
1638 token = lex_get_token(lc, T_NAME);
1639 /* Store the type both pass 1 and pass 2 */
1640 for (i=0; jobtypes[i].type_name; i++) {
1641 if (strcasecmp(lc->str, jobtypes[i].type_name) == 0) {
1642 *(int *)(item->value) = jobtypes[i].job_type;
1648 scan_err1(lc, _("Expected a Job Type keyword, got: %s"), lc->str);
1651 set_bit(index, res_all.hdr.item_present);
1655 * Store Job Level (Full, Incremental, ...)
1658 void store_level(LEX *lc, RES_ITEM *item, int index, int pass)
1662 token = lex_get_token(lc, T_NAME);
1663 /* Store the level pass 2 so that type is defined */
1664 for (i=0; joblevels[i].level_name; i++) {
1665 if (strcasecmp(lc->str, joblevels[i].level_name) == 0) {
1666 *(int *)(item->value) = joblevels[i].level;
1672 scan_err1(lc, _("Expected a Job Level keyword, got: %s"), lc->str);
1675 set_bit(index, res_all.hdr.item_present);
1679 void store_replace(LEX *lc, RES_ITEM *item, int index, int pass)
1682 token = lex_get_token(lc, T_NAME);
1683 /* Scan Replacement options */
1684 for (i=0; ReplaceOptions[i].name; i++) {
1685 if (strcasecmp(lc->str, ReplaceOptions[i].name) == 0) {
1686 *(int *)(item->value) = ReplaceOptions[i].token;
1692 scan_err1(lc, _("Expected a Restore replacement option, got: %s"), lc->str);
1695 set_bit(index, res_all.hdr.item_present);
1699 * Store ACL (access control list)
1702 void store_acl(LEX *lc, RES_ITEM *item, int index, int pass)
1707 token = lex_get_token(lc, T_STRING);
1709 if (((alist **)item->value)[item->code] == NULL) {
1710 ((alist **)item->value)[item->code] = New(alist(10, owned_by_alist));
1711 Dmsg1(900, "Defined new ACL alist at %d\n", item->code);
1713 ((alist **)item->value)[item->code]->append(bstrdup(lc->str));
1714 Dmsg2(900, "Appended to %d %s\n", item->code, lc->str);
1716 token = lex_get_token(lc, T_ALL);
1717 if (token == T_COMMA) {
1718 continue; /* get another ACL */
1722 set_bit(index, res_all.hdr.item_present);
1725 /* We build RunScripts items here */
1726 static RUNSCRIPT res_runscript;
1728 /* Store a runscript->when in a bit field */
1729 static void store_runscript_when(LEX *lc, RES_ITEM *item, int index, int pass)
1731 lex_get_token(lc, T_NAME);
1733 if (strcasecmp(lc->str, "before") == 0) {
1734 *(int *)(item->value) = SCRIPT_Before ;
1735 } else if (strcasecmp(lc->str, "after") == 0) {
1736 *(int *)(item->value) = SCRIPT_After;
1737 } else if (strcasecmp(lc->str, "aftervss") == 0) {
1738 *(int *)(item->value) = SCRIPT_AfterVSS;
1739 } else if (strcasecmp(lc->str, "always") == 0) {
1740 *(int *)(item->value) = SCRIPT_Any;
1742 scan_err2(lc, _("Expect %s, got: %s"), "Before, After, AfterVSS or Always", lc->str);
1747 /* Store a runscript->target
1750 static void store_runscript_target(LEX *lc, RES_ITEM *item, int index, int pass)
1752 lex_get_token(lc, T_STRING);
1755 if (strcmp(lc->str, "%c") == 0) {
1756 ((RUNSCRIPT*) item->value)->set_target(lc->str);
1757 } else if (strcasecmp(lc->str, "yes") == 0) {
1758 ((RUNSCRIPT*) item->value)->set_target("%c");
1759 } else if (strcasecmp(lc->str, "no") == 0) {
1760 ((RUNSCRIPT*) item->value)->set_target("");
1762 RES *res = GetResWithName(R_CLIENT, lc->str);
1764 scan_err3(lc, _("Could not find config Resource %s referenced on line %d : %s\n"),
1765 lc->str, lc->line_no, lc->line);
1768 ((RUNSCRIPT*) item->value)->set_target(lc->str);
1775 * Store a runscript->command as a string and runscript->cmd_type as a pointer
1777 static void store_runscript_cmd(LEX *lc, RES_ITEM *item, int index, int pass)
1779 lex_get_token(lc, T_STRING);
1782 Dmsg2(1, "runscript cmd=%s type=%c\n", lc->str, item->code);
1783 POOLMEM *c = get_pool_memory(PM_FNAME);
1784 /* Each runscript command takes 2 entries in commands list */
1785 pm_strcpy(c, lc->str);
1786 ((RUNSCRIPT*) item->value)->commands->prepend(c); /* command line */
1787 ((RUNSCRIPT*) item->value)->commands->prepend((void *)item->code); /* command type */
1792 static void store_short_runscript(LEX *lc, RES_ITEM *item, int index, int pass)
1794 lex_get_token(lc, T_STRING);
1795 alist **runscripts = (alist **)(item->value) ;
1798 RUNSCRIPT *script = new_runscript();
1799 script->set_job_code_callback(job_code_callback_filesetname);
1801 script->set_command(lc->str);
1803 /* TODO: remove all script->old_proto with bacula 1.42 */
1805 if (strcmp(item->name, "runbeforejob") == 0) {
1806 script->when = SCRIPT_Before;
1807 script->fail_on_error = true;
1808 script->set_target("");
1810 } else if (strcmp(item->name, "runafterjob") == 0) {
1811 script->when = SCRIPT_After;
1812 script->on_success = true;
1813 script->on_failure = false;
1814 script->set_target("");
1816 } else if (strcmp(item->name, "clientrunafterjob") == 0) {
1817 script->old_proto = true;
1818 script->when = SCRIPT_After;
1819 script->set_target("%c");
1820 script->on_success = true;
1821 script->on_failure = false;
1823 } else if (strcmp(item->name, "clientrunbeforejob") == 0) {
1824 script->old_proto = true;
1825 script->when = SCRIPT_Before;
1826 script->set_target("%c");
1827 script->fail_on_error = true;
1829 } else if (strcmp(item->name, "runafterfailedjob") == 0) {
1830 script->when = SCRIPT_After;
1831 script->on_failure = true;
1832 script->on_success = false;
1833 script->set_target("");
1836 if (*runscripts == NULL) {
1837 *runscripts = New(alist(10, not_owned_by_alist));
1840 (*runscripts)->append(script);
1847 /* Store a bool in a bit field without modifing res_all.hdr
1848 * We can also add an option to store_bool to skip res_all.hdr
1850 void store_runscript_bool(LEX *lc, RES_ITEM *item, int index, int pass)
1852 lex_get_token(lc, T_NAME);
1853 if (strcasecmp(lc->str, "yes") == 0 || strcasecmp(lc->str, "true") == 0) {
1854 *(bool *)(item->value) = true;
1855 } else if (strcasecmp(lc->str, "no") == 0 || strcasecmp(lc->str, "false") == 0) {
1856 *(bool *)(item->value) = false;
1858 scan_err2(lc, _("Expect %s, got: %s"), "YES, NO, TRUE, or FALSE", lc->str); /* YES and NO must not be translated */
1864 * new RunScript items
1865 * name handler value code flags default_value
1867 static RES_ITEM runscript_items[] = {
1868 {"command", store_runscript_cmd, {(char **)&res_runscript}, SHELL_CMD, 0, 0},
1869 {"console", store_runscript_cmd, {(char **)&res_runscript}, CONSOLE_CMD, 0, 0},
1870 {"target", store_runscript_target,{(char **)&res_runscript}, 0, 0, 0},
1871 {"runsonsuccess", store_runscript_bool, {(char **)&res_runscript.on_success},0, 0, 0},
1872 {"runsonfailure", store_runscript_bool, {(char **)&res_runscript.on_failure},0, 0, 0},
1873 {"failjobonerror",store_runscript_bool, {(char **)&res_runscript.fail_on_error},0, 0, 0},
1874 {"abortjobonerror",store_runscript_bool, {(char **)&res_runscript.fail_on_error},0, 0, 0},
1875 {"runswhen", store_runscript_when, {(char **)&res_runscript.when}, 0, 0, 0},
1876 {"runsonclient", store_runscript_target,{(char **)&res_runscript}, 0, 0, 0}, /* TODO */
1877 {NULL, NULL, {0}, 0, 0, 0}
1881 * Store RunScript info
1883 * Note, when this routine is called, we are inside a Job
1884 * resource. We treat the RunScript like a sort of
1885 * mini-resource within the Job resource.
1887 static void store_runscript(LEX *lc, RES_ITEM *item, int index, int pass)
1891 alist **runscripts = (alist **)(item->value) ;
1893 Dmsg1(200, "store_runscript: begin store_runscript pass=%i\n", pass);
1895 token = lex_get_token(lc, T_SKIP_EOL);
1897 if (token != T_BOB) {
1898 scan_err1(lc, _("Expecting open brace. Got %s"), lc->str);
1900 /* setting on_success, on_failure, fail_on_error */
1901 res_runscript.reset_default();
1904 res_runscript.commands = New(alist(10, not_owned_by_alist));
1907 while ((token = lex_get_token(lc, T_SKIP_EOL)) != T_EOF) {
1908 if (token == T_EOB) {
1911 if (token != T_IDENTIFIER) {
1912 scan_err1(lc, _("Expecting keyword, got: %s\n"), lc->str);
1914 for (i=0; runscript_items[i].name; i++) {
1915 if (strcasecmp(runscript_items[i].name, lc->str) == 0) {
1916 token = lex_get_token(lc, T_SKIP_EOL);
1917 if (token != T_EQUALS) {
1918 scan_err1(lc, _("expected an equals, got: %s"), lc->str);
1921 /* Call item handler */
1922 runscript_items[i].handler(lc, &runscript_items[i], i, pass);
1929 scan_err1(lc, _("Keyword %s not permitted in this resource"), lc->str);
1934 /* run on client by default */
1935 if (res_runscript.target == NULL) {
1936 res_runscript.set_target("%c");
1938 if (*runscripts == NULL) {
1939 *runscripts = New(alist(10, not_owned_by_alist));
1942 * commands list contains 2 values per command
1943 * - POOLMEM command string (ex: /bin/true)
1944 * - int command type (ex: SHELL_CMD)
1946 res_runscript.set_job_code_callback(job_code_callback_filesetname);
1947 while ((c=(char*)res_runscript.commands->pop()) != NULL) {
1948 t = (long)res_runscript.commands->pop();
1949 RUNSCRIPT *script = new_runscript();
1950 memcpy(script, &res_runscript, sizeof(RUNSCRIPT));
1951 script->command = c;
1952 script->cmd_type = t;
1953 /* target is taken from res_runscript, each runscript object have
1956 script->target = NULL;
1957 script->set_target(res_runscript.target);
1959 (*runscripts)->append(script);
1962 delete res_runscript.commands;
1963 /* setting on_success, on_failure... cleanup target field */
1964 res_runscript.reset_default(true);
1968 set_bit(index, res_all.hdr.item_present);
1971 /* callback function for edit_job_codes */
1972 extern "C" char *job_code_callback_filesetname(JCR *jcr, const char* param)
1974 if (param[0] == 'f') {
1975 return jcr->fileset->name();