1 /**
2 BAREOS® - Backup Archiving REcovery Open Sourced
3
4 Copyright (C) 2000-2011 Free Software Foundation Europe e.V.
5 Copyright (C) 2011-2012 Planets Communications B.V.
6 Copyright (C) 2013-2018 Bareos GmbH & Co. KG
7
8 This program is Free Software; you can redistribute it and/or
9 modify it under the terms of version three of the GNU Affero General Public
10 License as published by the Free Software Foundation and included
11 in the file LICENSE.
12
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 Affero General Public License for more details.
17
18 You should have received a copy of the GNU Affero 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
21 02110-1301, USA.
22 */
23 /**
24 * Kern Sibbald, January MM
25 */
26 /***
27 * @file
28 * Main configuration file parser for BAREOS Directors,
29 * some parts may be split into separate files such as
30 * the schedule configuration (run_config.c).
31 *
32 * Note, the configuration file parser consists of three parts
33 *
34 * 1. The generic lexical scanner in lib/lex.c and lib/lex.h
35 *
36 * 2. The generic config scanner in lib/parse_config.c and
37 * lib/parse_config.h.
38 *
39 * These files contain the parser code, some utility
40 * routines, and the common store routines (name, int,
41 * string).
42 *
43 * 3. The daemon specific file, which contains the Resource
44 * definitions as well as any specific store routines
45 * for the resource records.
46 *
47 */
48
49 #define NEED_JANSSON_NAMESPACE 1
50 #include "include/bareos.h"
51 #include "dird.h"
52 #include "dird/inc_conf.h"
53 #include "dird/dird_globals.h"
54 #include "lib/tls_conf.h"
55 #include "lib/qualified_resource_name_type_converter.h"
56
57 namespace directordaemon {
58
59 /**
60 * Used by print_config_schema_json
61 */
62 extern struct s_kw RunFields[];
63
64 /**
65 * Define the first and last resource ID record
66 * types. Note, these should be unique for each
67 * daemon though not a requirement.
68 */
69 static CommonResourceHeader *sres_head[R_LAST - R_FIRST + 1];
70 static CommonResourceHeader **res_head = sres_head;
71 static PoolMem *configure_usage_string = NULL;
72
73 /**
74 * Set default indention e.g. 2 spaces.
75 */
76 #define DEFAULT_INDENT_STRING " "
77
78 /**
79 * Imported subroutines
80 */
81 extern void StoreInc(LEX *lc, ResourceItem *item, int index, int pass);
82 extern void StoreRun(LEX *lc, ResourceItem *item, int index, int pass);
83
84 /**
85 * Forward referenced subroutines
86 */
87 static void CreateAndAddUserAgentConsoleResource(ConfigurationParser &my_config);
88 static bool SaveResource(int type, ResourceItem *items, int pass);
89 static void FreeResource(CommonResourceHeader *sres, int type);
90 static void DumpResource(int type,
91 CommonResourceHeader *ures,
92 void sendit(void *sock, const char *fmt, ...),
93 void *sock,
94 bool hide_sensitive_data,
95 bool verbose);
96 /**
97 * We build the current resource here as we are
98 * scanning the resource configuration definition,
99 * then move it to allocated memory when the resource
100 * scan is complete.
101 */
102 static UnionOfResources res_all;
103 static int32_t res_all_size = sizeof(res_all);
104
105 /**
106 * Definition of records permitted within each
107 * resource with the routine to process the record
108 * information.
109 *
110 * Director Resource
111 *
112 * name handler value code flags default_value
113 */
114 static ResourceItem dir_items[] = {
115 { "Name", CFG_TYPE_NAME, ITEM(res_dir.hdr.name), 0, CFG_ITEM_REQUIRED, NULL, NULL,
116 "The name of the resource." },
117 { "Description", CFG_TYPE_STR, ITEM(res_dir.hdr.desc), 0, 0, NULL, NULL, NULL },
118 { "Messages", CFG_TYPE_RES, ITEM(res_dir.messages), R_MSGS, 0, NULL, NULL, NULL },
119 { "DirPort", CFG_TYPE_ADDRESSES_PORT, ITEM(res_dir.DIRaddrs), 0, CFG_ITEM_DEFAULT, DIR_DEFAULT_PORT, NULL, NULL },
120 { "DirAddress", CFG_TYPE_ADDRESSES_ADDRESS, ITEM(res_dir.DIRaddrs), 0, CFG_ITEM_DEFAULT, DIR_DEFAULT_PORT, NULL, NULL },
121 { "DirAddresses", CFG_TYPE_ADDRESSES, ITEM(res_dir.DIRaddrs), 0, CFG_ITEM_DEFAULT, DIR_DEFAULT_PORT, NULL, NULL },
122 { "DirSourceAddress", CFG_TYPE_ADDRESSES_ADDRESS, ITEM(res_dir.DIRsrc_addr), 0, CFG_ITEM_DEFAULT, "0", NULL, NULL },
123 { "QueryFile", CFG_TYPE_DIR, ITEM(res_dir.query_file), 0, CFG_ITEM_REQUIRED, NULL, NULL, NULL },
124 { "WorkingDirectory", CFG_TYPE_DIR, ITEM(res_dir.working_directory), 0, CFG_ITEM_DEFAULT | CFG_ITEM_PLATFORM_SPECIFIC, _PATH_BAREOS_WORKINGDIR, NULL, NULL },
125 { "PidDirectory", CFG_TYPE_DIR, ITEM(res_dir.pid_directory), 0, CFG_ITEM_DEFAULT | CFG_ITEM_PLATFORM_SPECIFIC, _PATH_BAREOS_PIDDIR, NULL, NULL },
126 { "PluginDirectory", CFG_TYPE_DIR, ITEM(res_dir.plugin_directory), 0, 0, NULL,
127 "14.2.0-", "Plugins are loaded from this directory. To load only specific plugins, use 'Plugin Names'." },
128 { "PluginNames", CFG_TYPE_PLUGIN_NAMES, ITEM(res_dir.plugin_names), 0, 0, NULL,
129 "14.2.0-", "List of plugins, that should get loaded from 'Plugin Directory' (only basenames, '-dir.so' is added automatically). If empty, all plugins will get loaded." },
130 { "ScriptsDirectory", CFG_TYPE_DIR, ITEM(res_dir.scripts_directory), 0, 0, NULL, NULL, "This directive is currently unused." },
131 #if defined(HAVE_DYNAMIC_CATS_BACKENDS)
132 { "BackendDirectory", CFG_TYPE_ALIST_DIR, ITEM(res_dir.backend_directories), 0, CFG_ITEM_DEFAULT | CFG_ITEM_PLATFORM_SPECIFIC, _PATH_BAREOS_BACKENDDIR, NULL, NULL },
133 #endif
134 { "Subscriptions", CFG_TYPE_PINT32, ITEM(res_dir.subscriptions), 0, CFG_ITEM_DEFAULT, "0", "12.4.4-", NULL },
135 { "SubSysDirectory", CFG_TYPE_DIR, ITEM(res_dir.subsys_directory), 0, CFG_ITEM_DEPRECATED, NULL, "-12.4.0", NULL },
136 { "MaximumConcurrentJobs", CFG_TYPE_PINT32, ITEM(res_dir.MaxConcurrentJobs), 0, CFG_ITEM_DEFAULT, "1", NULL, NULL },
137 { "MaximumConnections", CFG_TYPE_PINT32, ITEM(res_dir.MaxConnections), 0, CFG_ITEM_DEFAULT, "30", NULL, NULL },
138 { "MaximumConsoleConnections", CFG_TYPE_PINT32, ITEM(res_dir.MaxConsoleConnections), 0, CFG_ITEM_DEFAULT, "20", NULL, NULL },
139 { "Password", CFG_TYPE_AUTOPASSWORD, ITEM(res_dir.password_), 0, CFG_ITEM_REQUIRED, NULL, NULL, NULL },
140 { "FdConnectTimeout", CFG_TYPE_TIME, ITEM(res_dir.FDConnectTimeout), 0, CFG_ITEM_DEFAULT, "180" /* 3 minutes */, NULL, NULL },
141 { "SdConnectTimeout", CFG_TYPE_TIME, ITEM(res_dir.SDConnectTimeout), 0, CFG_ITEM_DEFAULT, "1800" /* 30 minutes */, NULL, NULL },
142 { "HeartbeatInterval", CFG_TYPE_TIME, ITEM(res_dir.heartbeat_interval), 0, CFG_ITEM_DEFAULT, "0", NULL, NULL },
143 { "StatisticsRetention", CFG_TYPE_TIME, ITEM(res_dir.stats_retention), 0, CFG_ITEM_DEFAULT, "160704000" /* 5 years */, NULL, NULL },
144 { "StatisticsCollectInterval", CFG_TYPE_PINT32, ITEM(res_dir.stats_collect_interval), 0, CFG_ITEM_DEFAULT, "150", "14.2.0-", NULL },
145 { "VerId", CFG_TYPE_STR, ITEM(res_dir.verid), 0, 0, NULL, NULL, NULL },
146 { "OptimizeForSize", CFG_TYPE_BOOL, ITEM(res_dir.optimize_for_size), 0, CFG_ITEM_DEFAULT, "false", NULL, NULL },
147 { "OptimizeForSpeed", CFG_TYPE_BOOL, ITEM(res_dir.optimize_for_speed), 0, CFG_ITEM_DEFAULT, "false", NULL, NULL },
148 { "OmitDefaults", CFG_TYPE_BOOL, ITEM(res_dir.omit_defaults), 0, CFG_ITEM_DEFAULT | CFG_ITEM_DEPRECATED, "true",
149 NULL, "Omit config variables with default values when dumping the config." },
150 { "KeyEncryptionKey", CFG_TYPE_AUTOPASSWORD, ITEM(res_dir.keyencrkey), 1, 0, NULL, NULL, NULL },
151 { "NdmpSnooping", CFG_TYPE_BOOL, ITEM(res_dir.ndmp_snooping), 0, 0, NULL, "13.2.0-", NULL },
152 { "NdmpLogLevel", CFG_TYPE_PINT32, ITEM(res_dir.ndmp_loglevel), 0, CFG_ITEM_DEFAULT, "4", "13.2.0-", NULL },
153 { "AbsoluteJobTimeout", CFG_TYPE_PINT32, ITEM(res_dir.jcr_watchdog_time), 0, 0, NULL, "14.2.0-", NULL },
154 { "Auditing", CFG_TYPE_BOOL, ITEM(res_dir.auditing), 0, CFG_ITEM_DEFAULT, "false", "14.2.0-", NULL },
155 { "AuditEvents", CFG_TYPE_AUDIT, ITEM(res_dir.audit_events), 0, 0, NULL, "14.2.0-", NULL },
156 { "SecureEraseCommand", CFG_TYPE_STR, ITEM(res_dir.secure_erase_cmdline), 0, 0, NULL, "15.2.1-",
157 "Specify command that will be called when bareos unlinks files." },
158 { "LogTimestampFormat", CFG_TYPE_STR, ITEM(res_dir.log_timestamp_format), 0, 0, NULL, "15.2.3-", NULL },
159 TLS_COMMON_CONFIG(res_dir),
160 TLS_CERT_CONFIG(res_dir),
161 { NULL, 0, { 0 }, 0, 0, NULL, NULL, NULL }
162 };
163
164 /**
165 * Profile Resource
166 *
167 * name handler value code flags default_value
168 */
169 static ResourceItem profile_items[] = {
170 { "Name", CFG_TYPE_NAME, ITEM(res_profile.hdr.name), 0, CFG_ITEM_REQUIRED, NULL, NULL,
171 "The name of the resource." },
172 { "Description", CFG_TYPE_STR, ITEM(res_profile.hdr.desc), 0, 0, NULL, NULL,
173 "Additional information about the resource. Only used for UIs." },
174 { "JobACL", CFG_TYPE_ACL, ITEM(res_profile.ACL_lists), Job_ACL, 0, NULL, NULL,
175 "Lists the Job resources, this resource has access to. The special keyword *all* allows access to all Job resources." },
176 { "ClientACL", CFG_TYPE_ACL, ITEM(res_profile.ACL_lists), Client_ACL, 0, NULL, NULL,
177 "Lists the Client resources, this resource has access to. The special keyword *all* allows access to all Client resources." },
178 { "StorageACL", CFG_TYPE_ACL, ITEM(res_profile.ACL_lists), Storage_ACL, 0, NULL, NULL,
179 "Lists the Storage resources, this resource has access to. The special keyword *all* allows access to all Storage resources." },
180 { "ScheduleACL", CFG_TYPE_ACL, ITEM(res_profile.ACL_lists), Schedule_ACL, 0, NULL, NULL,
181 "Lists the Schedule resources, this resource has access to. The special keyword *all* allows access to all Schedule resources." },
182 { "PoolACL", CFG_TYPE_ACL, ITEM(res_profile.ACL_lists), Pool_ACL, 0, NULL, NULL,
183 "Lists the Pool resources, this resource has access to. The special keyword *all* allows access to all Pool resources." },
184 { "CommandACL", CFG_TYPE_ACL, ITEM(res_profile.ACL_lists), Command_ACL, 0, NULL, NULL,
185 "Lists the commands, this resource has access to. The special keyword *all* allows using commands." },
186 { "FileSetACL", CFG_TYPE_ACL, ITEM(res_profile.ACL_lists), FileSet_ACL, 0, NULL, NULL,
187 "Lists the File Set resources, this resource has access to. The special keyword *all* allows access to all File Set resources." },
188 { "CatalogACL", CFG_TYPE_ACL, ITEM(res_profile.ACL_lists), Catalog_ACL, 0, NULL, NULL,
189 "Lists the Catalog resources, this resource has access to. The special keyword *all* allows access to all Catalog resources." },
190 { "WhereACL", CFG_TYPE_ACL, ITEM(res_profile.ACL_lists), Where_ACL, 0, NULL, NULL,
191 "Specifies the base directories, where files could be restored. An empty string allows restores to all directories." },
192 { "PluginOptionsACL", CFG_TYPE_ACL, ITEM(res_profile.ACL_lists), PluginOptions_ACL, 0, NULL, NULL,
193 "Specifies the allowed plugin options. An empty strings allows all Plugin Options." },
194 { NULL, 0, { 0 }, 0, 0, NULL, NULL, NULL }
195 };
196
197 /**
198 * Console Resource
199 *
200 * name handler value code flags default_value
201 */
202 static ResourceItem con_items[] = {
203 { "Name", CFG_TYPE_NAME, ITEM(res_con.hdr.name), 0, CFG_ITEM_REQUIRED, NULL, NULL, NULL },
204 { "Description", CFG_TYPE_STR, ITEM(res_con.hdr.desc), 0, 0, NULL, NULL, NULL },
205 { "Password", CFG_TYPE_AUTOPASSWORD, ITEM(res_con.password_), 0, CFG_ITEM_REQUIRED, NULL, NULL, NULL },
206 { "JobACL", CFG_TYPE_ACL, ITEM(res_con.ACL_lists), Job_ACL, 0, NULL, NULL, NULL },
207 { "ClientACL", CFG_TYPE_ACL, ITEM(res_con.ACL_lists), Client_ACL, 0, NULL, NULL, NULL },
208 { "StorageACL", CFG_TYPE_ACL, ITEM(res_con.ACL_lists), Storage_ACL, 0, NULL, NULL, NULL },
209 { "ScheduleACL", CFG_TYPE_ACL, ITEM(res_con.ACL_lists), Schedule_ACL, 0, NULL, NULL, NULL },
210 { "RunACL", CFG_TYPE_ACL, ITEM(res_con.ACL_lists), Run_ACL, 0, NULL, NULL, NULL },
211 { "PoolACL", CFG_TYPE_ACL, ITEM(res_con.ACL_lists), Pool_ACL, 0, NULL, NULL, NULL },
212 { "CommandACL", CFG_TYPE_ACL, ITEM(res_con.ACL_lists), Command_ACL, 0, NULL, NULL, NULL },
213 { "FileSetACL", CFG_TYPE_ACL, ITEM(res_con.ACL_lists), FileSet_ACL, 0, NULL, NULL, NULL },
214 { "CatalogACL", CFG_TYPE_ACL, ITEM(res_con.ACL_lists), Catalog_ACL, 0, NULL, NULL, NULL },
215 { "WhereACL", CFG_TYPE_ACL, ITEM(res_con.ACL_lists), Where_ACL, 0, NULL, NULL, NULL },
216 { "PluginOptionsACL", CFG_TYPE_ACL, ITEM(res_con.ACL_lists), PluginOptions_ACL, 0, NULL, NULL, NULL },
217 { "Profile", CFG_TYPE_ALIST_RES, ITEM(res_con.profiles), R_PROFILE, 0, NULL, "14.2.3-",
218 "Profiles can be assigned to a Console. ACL are checked until either a deny ACL is found or an allow ACL. "
219 "First the console ACL is checked then any profile the console is linked to." },
220 { "UsePamAuthentication", CFG_TYPE_BOOL, ITEM(res_con.use_pam_authentication_), 0, CFG_ITEM_DEFAULT,
221 "false", "18.2.4-", NULL },
222 TLS_COMMON_CONFIG(res_con),
223 TLS_CERT_CONFIG(res_con),
224 { NULL, 0, { 0 }, 0, 0, NULL, NULL, NULL }
225 };
226
227 /**
228 * Client or File daemon resource
229 *
230 * name handler value code flags default_value
231 */
232 static ResourceItem cli_items[] = {
233 { "Name", CFG_TYPE_NAME, ITEM(res_client.hdr.name), 0, CFG_ITEM_REQUIRED, NULL, NULL,
234 "The name of the resource." },
235 { "Description", CFG_TYPE_STR, ITEM(res_client.hdr.desc), 0, 0, NULL, NULL, NULL },
236 { "Protocol", CFG_TYPE_AUTHPROTOCOLTYPE, ITEM(res_client.Protocol), 0, CFG_ITEM_DEFAULT, "Native", "13.2.0-", NULL },
237 { "AuthType", CFG_TYPE_AUTHTYPE, ITEM(res_client.AuthType), 0, CFG_ITEM_DEFAULT, "None", NULL, NULL },
238 { "Address", CFG_TYPE_STR, ITEM(res_client.address), 0, CFG_ITEM_REQUIRED, NULL, NULL, NULL },
239 { "LanAddress", CFG_TYPE_STR, ITEM(res_client.lanaddress), 0, CFG_ITEM_DEFAULT, NULL, "16.2.6-",
240 "Sets additional address used for connections between Client and Storage Daemon inside separate network."},
241 { "FdAddress", CFG_TYPE_STR, ITEM(res_client.address), 0, CFG_ITEM_ALIAS, NULL, NULL, "Alias for Address." },
242 { "Port", CFG_TYPE_PINT32, ITEM(res_client.FDport), 0, CFG_ITEM_DEFAULT, FD_DEFAULT_PORT, NULL, NULL },
243 { "FdPort", CFG_TYPE_PINT32, ITEM(res_client.FDport), 0, CFG_ITEM_DEFAULT | CFG_ITEM_ALIAS, FD_DEFAULT_PORT, NULL, NULL },
244 { "Username", CFG_TYPE_STR, ITEM(res_client.username), 0, 0, NULL, NULL, NULL },
245 { "Password", CFG_TYPE_AUTOPASSWORD, ITEM(res_client.password_), 0, CFG_ITEM_REQUIRED, NULL, NULL, NULL },
246 { "FdPassword", CFG_TYPE_AUTOPASSWORD, ITEM(res_client.password_), 0, CFG_ITEM_ALIAS, NULL, NULL, NULL },
247 { "Catalog", CFG_TYPE_RES, ITEM(res_client.catalog), R_CATALOG, 0, NULL, NULL, NULL },
248 { "Passive", CFG_TYPE_BOOL, ITEM(res_client.passive), 0, CFG_ITEM_DEFAULT, "false", "13.2.0-",
249 "If enabled, the Storage Daemon will initiate the network connection to the Client. If disabled, the Client will initiate the network connection to the Storage Daemon." },
250 { "ConnectionFromDirectorToClient", CFG_TYPE_BOOL, ITEM(res_client.conn_from_dir_to_fd), 0, CFG_ITEM_DEFAULT, "true", "16.2.2",
251 "Let the Director initiate the network connection to the Client." },
252 { "AllowClientConnect", CFG_TYPE_BOOL, ITEM(res_client.conn_from_fd_to_dir), 0, CFG_ITEM_DEPRECATED | CFG_ITEM_ALIAS, NULL, NULL,
253 "Alias of \"Connection From Client To Director\"." },
254 { "ConnectionFromClientToDirector", CFG_TYPE_BOOL, ITEM(res_client.conn_from_fd_to_dir), 0, CFG_ITEM_DEFAULT, "false", "16.2.2",
255 "The Director will accept incoming network connection from this Client." },
256 { "Enabled", CFG_TYPE_BOOL, ITEM(res_client.enabled), 0, CFG_ITEM_DEFAULT, "true", NULL,
257 "En- or disable this resource." },
258 { "HardQuota", CFG_TYPE_SIZE64, ITEM(res_client.HardQuota), 0, CFG_ITEM_DEFAULT, "0", NULL, NULL },
259 { "SoftQuota", CFG_TYPE_SIZE64, ITEM(res_client.SoftQuota), 0, CFG_ITEM_DEFAULT, "0", NULL, NULL },
260 { "SoftQuotaGracePeriod", CFG_TYPE_TIME, ITEM(res_client.SoftQuotaGracePeriod), 0, CFG_ITEM_DEFAULT, "0", NULL, NULL },
261 { "StrictQuotas", CFG_TYPE_BOOL, ITEM(res_client.StrictQuotas), 0, CFG_ITEM_DEFAULT, "false", NULL, NULL },
262 { "QuotaIncludeFailedJobs", CFG_TYPE_BOOL, ITEM(res_client.QuotaIncludeFailedJobs), 0, CFG_ITEM_DEFAULT, "true", NULL, NULL },
263 { "FileRetention", CFG_TYPE_TIME, ITEM(res_client.FileRetention), 0, CFG_ITEM_DEFAULT, "5184000" /* 60 days */, NULL, NULL },
264 { "JobRetention", CFG_TYPE_TIME, ITEM(res_client.JobRetention), 0, CFG_ITEM_DEFAULT, "15552000" /* 180 days */, NULL, NULL },
265 { "HeartbeatInterval", CFG_TYPE_TIME, ITEM(res_client.heartbeat_interval), 0, CFG_ITEM_DEFAULT, "0", NULL, NULL },
266 { "AutoPrune", CFG_TYPE_BOOL, ITEM(res_client.AutoPrune), 0, CFG_ITEM_DEFAULT, "false", NULL, NULL },
267 { "MaximumConcurrentJobs", CFG_TYPE_PINT32, ITEM(res_client.MaxConcurrentJobs), 0, CFG_ITEM_DEFAULT, "1", NULL, NULL },
268 { "MaximumBandwidthPerJob", CFG_TYPE_SPEED, ITEM(res_client.max_bandwidth), 0, 0, NULL, NULL, NULL },
269 { "NdmpLogLevel", CFG_TYPE_PINT32, ITEM(res_client.ndmp_loglevel), 0, CFG_ITEM_DEFAULT, "4", NULL, NULL },
270 { "NdmpBlockSize", CFG_TYPE_SIZE32, ITEM(res_client.ndmp_blocksize), 0, CFG_ITEM_DEFAULT, "64512", NULL, NULL },
271 { "NdmpUseLmdb", CFG_TYPE_BOOL, ITEM(res_client.ndmp_use_lmdb), 0, CFG_ITEM_DEFAULT, "true", NULL, NULL },
272 TLS_COMMON_CONFIG(res_client),
273 TLS_CERT_CONFIG(res_client),
274 { NULL, 0, { 0 }, 0, 0, NULL, NULL, NULL }
275 };
276
277 /** Storage daemon resource
278 *
279 * name handler value code flags default_value
280 */
281 static ResourceItem store_items[] = {
282 { "Name", CFG_TYPE_NAME, ITEM(res_store.hdr.name), 0, CFG_ITEM_REQUIRED, NULL, NULL,
283 "The name of the resource." },
284 { "Description", CFG_TYPE_STR, ITEM(res_store.hdr.desc), 0, 0, NULL, NULL, NULL },
285 { "Protocol", CFG_TYPE_AUTHPROTOCOLTYPE, ITEM(res_store.Protocol), 0, CFG_ITEM_DEFAULT, "Native", NULL, NULL },
286 { "AuthType", CFG_TYPE_AUTHTYPE, ITEM(res_store.AuthType), 0, CFG_ITEM_DEFAULT, "None", NULL, NULL },
287 { "Address", CFG_TYPE_STR, ITEM(res_store.address), 0, CFG_ITEM_REQUIRED, NULL, NULL, NULL },
288 { "LanAddress", CFG_TYPE_STR, ITEM(res_store.lanaddress), 0, CFG_ITEM_DEFAULT, NULL, "16.2.6-",
289 "Sets additional address used for connections between Client and Storage Daemon inside separate network."},
290 { "SdAddress", CFG_TYPE_STR, ITEM(res_store.address), 0, CFG_ITEM_ALIAS, NULL, NULL, "Alias for Address." },
291 { "Port", CFG_TYPE_PINT32, ITEM(res_store.SDport), 0, CFG_ITEM_DEFAULT, SD_DEFAULT_PORT, NULL, NULL },
292 { "SdPort", CFG_TYPE_PINT32, ITEM(res_store.SDport), 0, CFG_ITEM_DEFAULT | CFG_ITEM_ALIAS, SD_DEFAULT_PORT, NULL, "Alias for Port." },
293 { "Username", CFG_TYPE_STR, ITEM(res_store.username), 0, 0, NULL, NULL, NULL },
294 { "Password", CFG_TYPE_AUTOPASSWORD, ITEM(res_store.password_), 0, CFG_ITEM_REQUIRED, NULL, NULL, NULL },
295 { "SdPassword", CFG_TYPE_AUTOPASSWORD, ITEM(res_store.password_), 0, CFG_ITEM_ALIAS, NULL, NULL, "Alias for Password." },
296 { "Device", CFG_TYPE_DEVICE, ITEM(res_store.device), R_DEVICE, CFG_ITEM_REQUIRED, NULL, NULL, NULL },
297 { "MediaType", CFG_TYPE_STRNAME, ITEM(res_store.media_type), 0, CFG_ITEM_REQUIRED, NULL, NULL, NULL },
298 { "AutoChanger", CFG_TYPE_BOOL, ITEM(res_store.autochanger), 0, CFG_ITEM_DEFAULT, "false", NULL, NULL },
299 { "Enabled", CFG_TYPE_BOOL, ITEM(res_store.enabled), 0, CFG_ITEM_DEFAULT, "true", NULL,
300 "En- or disable this resource." },
301 { "AllowCompression", CFG_TYPE_BOOL, ITEM(res_store.AllowCompress), 0, CFG_ITEM_DEFAULT, "true", NULL, NULL },
302 { "HeartbeatInterval", CFG_TYPE_TIME, ITEM(res_store.heartbeat_interval), 0, CFG_ITEM_DEFAULT, "0", NULL, NULL },
303 { "CacheStatusInterval", CFG_TYPE_TIME, ITEM(res_store.cache_status_interval), 0, CFG_ITEM_DEFAULT, "30", NULL, NULL },
304 { "MaximumConcurrentJobs", CFG_TYPE_PINT32, ITEM(res_store.MaxConcurrentJobs), 0, CFG_ITEM_DEFAULT, "1", NULL, NULL },
305 { "MaximumConcurrentReadJobs", CFG_TYPE_PINT32, ITEM(res_store.MaxConcurrentReadJobs), 0, CFG_ITEM_DEFAULT, "0", NULL, NULL },
306 { "SddPort", CFG_TYPE_PINT32, ITEM(res_store.SDDport), 0, CFG_ITEM_DEPRECATED, NULL, "-12.4.0", NULL },
307 { "PairedStorage", CFG_TYPE_RES, ITEM(res_store.paired_storage), R_STORAGE, 0, NULL, NULL, NULL },
308 { "MaximumBandwidthPerJob", CFG_TYPE_SPEED, ITEM(res_store.max_bandwidth), 0, 0, NULL, NULL, NULL },
309 { "CollectStatistics", CFG_TYPE_BOOL, ITEM(res_store.collectstats), 0, CFG_ITEM_DEFAULT, "false", NULL, NULL },
310 { "NdmpChangerDevice", CFG_TYPE_STRNAME, ITEM(res_store.ndmp_changer_device), 0, 0, NULL, "16.2.4-",
311 "Allows direct control of a Storage Daemon Auto Changer device by the Director. Only used in NDMP_NATIVE environments." },
312 // TapeDevice has never been used in production and intended for NDMP_NATIVE only.
313 // Instead of TapeDevice, the required Devices should be configured using the Device directive.
314 //{ "TapeDevice", CFG_TYPE_ALIST_STR, ITEM(res_store.tape_devices), 0, CFG_ITEM_ALIAS | CFG_ITEM_DEPRECATED, NULL, "16.2.4-17.2.2",
315 // "Allows direct control of Storage Daemon Tape devices by the Director. Only used in NDMP_NATIVE environments." },
316 TLS_COMMON_CONFIG(res_store),
317 TLS_CERT_CONFIG(res_store),
318 { NULL, 0, { 0 }, 0, 0, NULL, NULL, NULL }
319 };
320
321 /**
322 * Catalog Resource Directives
323 *
324 * name handler value code flags default_value
325 */
326 static ResourceItem cat_items[] = {
327 { "Name", CFG_TYPE_NAME, ITEM(res_cat.hdr.name), 0, CFG_ITEM_REQUIRED, NULL, NULL,
328 "The name of the resource." },
329 { "Description", CFG_TYPE_STR, ITEM(res_cat.hdr.desc), 0, 0, NULL, NULL, NULL },
330 { "Address", CFG_TYPE_STR, ITEM(res_cat.db_address), 0, CFG_ITEM_ALIAS, NULL, NULL, NULL },
331 { "DbAddress", CFG_TYPE_STR, ITEM(res_cat.db_address), 0, 0, NULL, NULL, NULL },
332 { "DbPort", CFG_TYPE_PINT32, ITEM(res_cat.db_port), 0, 0, NULL, NULL, NULL },
333 { "Password", CFG_TYPE_AUTOPASSWORD, ITEM(res_cat.db_password), 0, CFG_ITEM_ALIAS, NULL, NULL, NULL },
334 { "DbPassword", CFG_TYPE_AUTOPASSWORD, ITEM(res_cat.db_password), 0, 0, NULL, NULL, NULL },
335 { "DbUser", CFG_TYPE_STR, ITEM(res_cat.db_user), 0, 0, NULL, NULL, NULL },
336 { "User", CFG_TYPE_STR, ITEM(res_cat.db_user), 0, CFG_ITEM_ALIAS, NULL, NULL, NULL },
337 { "DbName", CFG_TYPE_STR, ITEM(res_cat.db_name), 0, CFG_ITEM_REQUIRED, NULL, NULL, NULL },
338 #ifdef HAVE_DYNAMIC_CATS_BACKENDS
339 { "DbDriver", CFG_TYPE_STR, ITEM(res_cat.db_driver), 0, CFG_ITEM_REQUIRED, NULL, NULL, NULL },
340 #else
341 { "DbDriver", CFG_TYPE_STR, ITEM(res_cat.db_driver), 0, 0, NULL, NULL, NULL },
342 #endif
343 { "DbSocket", CFG_TYPE_STR, ITEM(res_cat.db_socket), 0, 0, NULL, NULL, NULL },
344 /* Turned off for the moment */
345 { "MultipleConnections", CFG_TYPE_BIT, ITEM(res_cat.mult_db_connections), 0, 0, NULL, NULL, NULL },
346 { "DisableBatchInsert", CFG_TYPE_BOOL, ITEM(res_cat.disable_batch_insert), 0, CFG_ITEM_DEFAULT, "false", NULL, NULL },
347 { "Reconnect", CFG_TYPE_BOOL, ITEM(res_cat.try_reconnect), 0, CFG_ITEM_DEFAULT, "false",
348 "15.1.0-", "Try to reconnect a database connection when its dropped" },
349 { "ExitOnFatal", CFG_TYPE_BOOL, ITEM(res_cat.exit_on_fatal), 0, CFG_ITEM_DEFAULT, "false",
350 "15.1.0-", "Make any fatal error in the connection to the database exit the program" },
351 { "MinConnections", CFG_TYPE_PINT32, ITEM(res_cat.pooling_min_connections), 0, CFG_ITEM_DEFAULT, "1", NULL,
352 "This directive is used by the experimental database pooling functionality. Only use this for non production sites. This sets the minimum number of connections to a database to keep in this database pool." },
353 { "MaxConnections", CFG_TYPE_PINT32, ITEM(res_cat.pooling_max_connections), 0, CFG_ITEM_DEFAULT, "5", NULL,
354 "This directive is used by the experimental database pooling functionality. Only use this for non production sites. This sets the maximum number of connections to a database to keep in this database pool." },
355 { "IncConnections", CFG_TYPE_PINT32, ITEM(res_cat.pooling_increment_connections), 0, CFG_ITEM_DEFAULT, "1", NULL,
356 "This directive is used by the experimental database pooling functionality. Only use this for non production sites. This sets the number of connections to add to a database pool when not enough connections are available on the pool anymore." },
357 { "IdleTimeout", CFG_TYPE_PINT32, ITEM(res_cat.pooling_idle_timeout), 0, CFG_ITEM_DEFAULT, "30", NULL,
358 "This directive is used by the experimental database pooling functionality. Only use this for non production sites. This sets the idle time after which a database pool should be shrinked." },
359 { "ValidateTimeout", CFG_TYPE_PINT32, ITEM(res_cat.pooling_validate_timeout), 0, CFG_ITEM_DEFAULT, "120", NULL,
360 "This directive is used by the experimental database pooling functionality. Only use this for non production sites. This sets the validation timeout after which the database connection is polled to see if its still alive." },
361 { NULL, 0, { 0 }, 0, 0, NULL, NULL, NULL }
362 };
363
364 /**
365 * Job Resource Directives
366 *
367 * name handler value code flags default_value
368 */
369 ResourceItem job_items[] = {
370 { "Name", CFG_TYPE_NAME, ITEM(res_job.hdr.name), 0, CFG_ITEM_REQUIRED, NULL, NULL,
371 "The name of the resource." },
372 { "Description", CFG_TYPE_STR, ITEM(res_job.hdr.desc), 0, 0, NULL, NULL, NULL },
373 { "Type", CFG_TYPE_JOBTYPE, ITEM(res_job.JobType), 0, CFG_ITEM_REQUIRED, NULL, NULL, NULL },
374 { "Protocol", CFG_TYPE_PROTOCOLTYPE, ITEM(res_job.Protocol), 0, CFG_ITEM_DEFAULT, "Native", NULL, NULL },
375 { "BackupFormat", CFG_TYPE_STR, ITEM(res_job.backup_format), 0, CFG_ITEM_DEFAULT, "Native", NULL, NULL },
376 { "Level", CFG_TYPE_LEVEL, ITEM(res_job.JobLevel), 0, 0, NULL, NULL, NULL },
377 { "Messages", CFG_TYPE_RES, ITEM(res_job.messages), R_MSGS, CFG_ITEM_REQUIRED, NULL, NULL, NULL },
378 { "Storage", CFG_TYPE_ALIST_RES, ITEM(res_job.storage), R_STORAGE, 0, NULL, NULL, NULL },
379 { "Pool", CFG_TYPE_RES, ITEM(res_job.pool), R_POOL, CFG_ITEM_REQUIRED, NULL, NULL, NULL },
380 { "FullBackupPool", CFG_TYPE_RES, ITEM(res_job.full_pool), R_POOL, 0, NULL, NULL, NULL },
381 { "VirtualFullBackupPool", CFG_TYPE_RES, ITEM(res_job.vfull_pool), R_POOL, 0, NULL, NULL, NULL },
382 { "IncrementalBackupPool", CFG_TYPE_RES, ITEM(res_job.inc_pool), R_POOL, 0, NULL, NULL, NULL },
383 { "DifferentialBackupPool", CFG_TYPE_RES, ITEM(res_job.diff_pool), R_POOL, 0, NULL, NULL, NULL },
384 { "NextPool", CFG_TYPE_RES, ITEM(res_job.next_pool), R_POOL, 0, NULL, NULL, NULL },
385 { "Client", CFG_TYPE_RES, ITEM(res_job.client), R_CLIENT, 0, NULL, NULL, NULL },
386 { "FileSet", CFG_TYPE_RES, ITEM(res_job.fileset), R_FILESET, 0, NULL, NULL, NULL },
387 { "Schedule", CFG_TYPE_RES, ITEM(res_job.schedule), R_SCHEDULE, 0, NULL, NULL, NULL },
388 { "VerifyJob", CFG_TYPE_RES, ITEM(res_job.verify_job), R_JOB, CFG_ITEM_ALIAS, NULL, NULL, NULL },
389 { "JobToVerify", CFG_TYPE_RES, ITEM(res_job.verify_job), R_JOB, 0, NULL, NULL, NULL },
390 { "Catalog", CFG_TYPE_RES, ITEM(res_job.catalog), R_CATALOG, 0, NULL, "13.4.0-", NULL },
391 { "JobDefs", CFG_TYPE_RES, ITEM(res_job.jobdefs), R_JOBDEFS, 0, NULL, NULL, NULL },
392 { "Run", CFG_TYPE_ALIST_STR, ITEM(res_job.run_cmds), 0, 0, NULL, NULL, NULL },
393 /* Root of where to restore files */
394 { "Where", CFG_TYPE_DIR, ITEM(res_job.RestoreWhere), 0, 0, NULL, NULL, NULL },
395 { "RegexWhere", CFG_TYPE_STR, ITEM(res_job.RegexWhere), 0, 0, NULL, NULL, NULL },
396 { "StripPrefix", CFG_TYPE_STR, ITEM(res_job.strip_prefix), 0, 0, NULL, NULL, NULL },
397 { "AddPrefix", CFG_TYPE_STR, ITEM(res_job.add_prefix), 0, 0, NULL, NULL, NULL },
398 { "AddSuffix", CFG_TYPE_STR, ITEM(res_job.add_suffix), 0, 0, NULL, NULL, NULL },
399 /* Where to find bootstrap during restore */
400 { "Bootstrap", CFG_TYPE_DIR, ITEM(res_job.RestoreBootstrap), 0, 0, NULL, NULL, NULL },
401 /* Where to write bootstrap file during backup */
402 { "WriteBootstrap", CFG_TYPE_DIR, ITEM(res_job.WriteBootstrap), 0, 0, NULL, NULL, NULL },
403 { "WriteVerifyList", CFG_TYPE_DIR, ITEM(res_job.WriteVerifyList), 0, 0, NULL, NULL, NULL },
404 { "Replace", CFG_TYPE_REPLACE, ITEM(res_job.replace), 0, CFG_ITEM_DEFAULT, "Always", NULL, NULL },
405 { "MaximumBandwidth", CFG_TYPE_SPEED, ITEM(res_job.max_bandwidth), 0, 0, NULL, NULL, NULL },
406 { "MaxRunSchedTime", CFG_TYPE_TIME, ITEM(res_job.MaxRunSchedTime), 0, 0, NULL, NULL, NULL },
407 { "MaxRunTime", CFG_TYPE_TIME, ITEM(res_job.MaxRunTime), 0, 0, NULL, NULL, NULL },
408 { "FullMaxWaitTime", CFG_TYPE_TIME, ITEM(res_job.FullMaxRunTime), 0, CFG_ITEM_DEPRECATED, NULL, "-12.4.0", NULL },
409 { "IncrementalMaxWaitTime", CFG_TYPE_TIME, ITEM(res_job.IncMaxRunTime), 0, CFG_ITEM_DEPRECATED, NULL, "-12.4.0", NULL },
410 { "DifferentialMaxWaitTime", CFG_TYPE_TIME, ITEM(res_job.DiffMaxRunTime), 0, CFG_ITEM_DEPRECATED, NULL, "-12.4.0", NULL },
411 { "FullMaxRuntime", CFG_TYPE_TIME, ITEM(res_job.FullMaxRunTime), 0, 0, NULL, NULL, NULL },
412 { "IncrementalMaxRuntime", CFG_TYPE_TIME, ITEM(res_job.IncMaxRunTime), 0, 0, NULL, NULL, NULL },
413 { "DifferentialMaxRuntime", CFG_TYPE_TIME, ITEM(res_job.DiffMaxRunTime), 0, 0, NULL, NULL, NULL },
414 { "MaxWaitTime", CFG_TYPE_TIME, ITEM(res_job.MaxWaitTime), 0, 0, NULL, NULL, NULL },
415 { "MaxStartDelay", CFG_TYPE_TIME, ITEM(res_job.MaxStartDelay), 0, 0, NULL, NULL, NULL },
416 { "MaxFullInterval", CFG_TYPE_TIME, ITEM(res_job.MaxFullInterval), 0, 0, NULL, NULL, NULL },
417 { "MaxVirtualFullInterval", CFG_TYPE_TIME, ITEM(res_job.MaxVFullInterval), 0, 0, NULL, "14.4.0-", NULL },
418 { "MaxDiffInterval", CFG_TYPE_TIME, ITEM(res_job.MaxDiffInterval), 0, 0, NULL, NULL, NULL },
419 { "PrefixLinks", CFG_TYPE_BOOL, ITEM(res_job.PrefixLinks), 0, CFG_ITEM_DEFAULT, "false", NULL, NULL },
420 { "PruneJobs", CFG_TYPE_BOOL, ITEM(res_job.PruneJobs), 0, CFG_ITEM_DEFAULT, "false", NULL, NULL },
421 { "PruneFiles", CFG_TYPE_BOOL, ITEM(res_job.PruneFiles), 0, CFG_ITEM_DEFAULT, "false", NULL, NULL },
422 { "PruneVolumes", CFG_TYPE_BOOL, ITEM(res_job.PruneVolumes), 0, CFG_ITEM_DEFAULT, "false", NULL, NULL },
423 { "PurgeMigrationJob", CFG_TYPE_BOOL, ITEM(res_job.PurgeMigrateJob), 0, CFG_ITEM_DEFAULT, "false", NULL, NULL },
424 { "Enabled", CFG_TYPE_BOOL, ITEM(res_job.enabled), 0, CFG_ITEM_DEFAULT, "true", NULL,
425 "En- or disable this resource." },
426 { "SpoolAttributes", CFG_TYPE_BOOL, ITEM(res_job.SpoolAttributes), 0, CFG_ITEM_DEFAULT, "false", NULL, NULL },
427 { "SpoolData", CFG_TYPE_BOOL, ITEM(res_job.spool_data), 0, CFG_ITEM_DEFAULT, "false", NULL, NULL },
428 { "SpoolSize", CFG_TYPE_SIZE64, ITEM(res_job.spool_size), 0, 0, NULL, NULL, NULL },
429 { "RerunFailedLevels", CFG_TYPE_BOOL, ITEM(res_job.rerun_failed_levels), 0, CFG_ITEM_DEFAULT, "false", NULL, NULL },
430 { "PreferMountedVolumes", CFG_TYPE_BOOL, ITEM(res_job.PreferMountedVolumes), 0, CFG_ITEM_DEFAULT, "true", NULL, NULL },
431 { "RunBeforeJob", CFG_TYPE_SHRTRUNSCRIPT, ITEM(res_job.RunScripts), 0, 0, NULL, NULL, NULL },
432 { "RunAfterJob", CFG_TYPE_SHRTRUNSCRIPT, ITEM(res_job.RunScripts), 0, 0, NULL, NULL, NULL },
433 { "RunAfterFailedJob", CFG_TYPE_SHRTRUNSCRIPT, ITEM(res_job.RunScripts), 0, 0, NULL, NULL, NULL },
434 { "ClientRunBeforeJob", CFG_TYPE_SHRTRUNSCRIPT, ITEM(res_job.RunScripts), 0, 0, NULL, NULL, NULL },
435 { "ClientRunAfterJob", CFG_TYPE_SHRTRUNSCRIPT, ITEM(res_job.RunScripts), 0, 0, NULL, NULL, NULL },
436 { "MaximumConcurrentJobs", CFG_TYPE_PINT32, ITEM(res_job.MaxConcurrentJobs), 0, CFG_ITEM_DEFAULT, "1", NULL, NULL },
437 { "RescheduleOnError", CFG_TYPE_BOOL, ITEM(res_job.RescheduleOnError), 0, CFG_ITEM_DEFAULT, "false", NULL, NULL },
438 { "RescheduleInterval", CFG_TYPE_TIME, ITEM(res_job.RescheduleInterval), 0, CFG_ITEM_DEFAULT, "1800" /* 30 minutes */, NULL, NULL },
439 { "RescheduleTimes", CFG_TYPE_PINT32, ITEM(res_job.RescheduleTimes), 0, CFG_ITEM_DEFAULT, "5", NULL, NULL },
440 { "Priority", CFG_TYPE_PINT32, ITEM(res_job.Priority), 0, CFG_ITEM_DEFAULT, "10", NULL, NULL },
441 { "AllowMixedPriority", CFG_TYPE_BOOL, ITEM(res_job.allow_mixed_priority), 0, CFG_ITEM_DEFAULT, "false", NULL, NULL },
442 { "WritePartAfterJob", CFG_TYPE_BOOL, ITEM(res_job.write_part_after_job), 0, CFG_ITEM_DEPRECATED, NULL, "-12.4.0", NULL },
443 { "SelectionPattern", CFG_TYPE_STR, ITEM(res_job.selection_pattern), 0, 0, NULL, NULL, NULL },
444 { "RunScript", CFG_TYPE_RUNSCRIPT, ITEM(res_job.RunScripts), 0, CFG_ITEM_NO_EQUALS, NULL, NULL, NULL },
445 { "SelectionType", CFG_TYPE_MIGTYPE, ITEM(res_job.selection_type), 0, 0, NULL, NULL, NULL },
446 { "Accurate", CFG_TYPE_BOOL, ITEM(res_job.accurate), 0, CFG_ITEM_DEFAULT, "false", NULL, NULL },
447 { "AllowDuplicateJobs", CFG_TYPE_BOOL, ITEM(res_job.AllowDuplicateJobs), 0, CFG_ITEM_DEFAULT, "true", NULL, NULL },
448 { "AllowHigherDuplicates", CFG_TYPE_BOOL, ITEM(res_job.AllowHigherDuplicates), 0, CFG_ITEM_DEFAULT, "true", NULL, NULL },
449 { "CancelLowerLevelDuplicates", CFG_TYPE_BOOL, ITEM(res_job.CancelLowerLevelDuplicates), 0, CFG_ITEM_DEFAULT, "false", NULL, NULL },
450 { "CancelQueuedDuplicates", CFG_TYPE_BOOL, ITEM(res_job.CancelQueuedDuplicates), 0, CFG_ITEM_DEFAULT, "false", NULL, NULL },
451 { "CancelRunningDuplicates", CFG_TYPE_BOOL, ITEM(res_job.CancelRunningDuplicates), 0, CFG_ITEM_DEFAULT, "false", NULL, NULL },
452 { "SaveFileHistory", CFG_TYPE_BOOL, ITEM(res_job.SaveFileHist), 0, CFG_ITEM_DEFAULT, "true", "14.2.0-", NULL },
453 { "FileHistorySize", CFG_TYPE_SIZE64, ITEM(res_job.FileHistSize), 0, CFG_ITEM_DEFAULT, "10000000", "15.2.4-", NULL },
454 { "PluginOptions", CFG_TYPE_ALIST_STR, ITEM(res_job.FdPluginOptions), 0, CFG_ITEM_DEPRECATED | CFG_ITEM_ALIAS, NULL, "-12.4.0", NULL },
455 { "FdPluginOptions", CFG_TYPE_ALIST_STR, ITEM(res_job.FdPluginOptions), 0, 0, NULL, NULL, NULL },
456 { "SdPluginOptions", CFG_TYPE_ALIST_STR, ITEM(res_job.SdPluginOptions), 0, 0, NULL, NULL, NULL },
457 { "DirPluginOptions", CFG_TYPE_ALIST_STR, ITEM(res_job.DirPluginOptions), 0, 0, NULL, NULL, NULL },
458 { "Base", CFG_TYPE_ALIST_RES, ITEM(res_job.base), R_JOB, 0, NULL, NULL, NULL },
459 { "MaxConcurrentCopies", CFG_TYPE_PINT32, ITEM(res_job.MaxConcurrentCopies), 0, CFG_ITEM_DEFAULT, "100", NULL, NULL },
460 /* Settings for always incremental */
461 { "AlwaysIncremental", CFG_TYPE_BOOL, ITEM(res_job.AlwaysIncremental), 0, CFG_ITEM_DEFAULT, "false", "16.2.4-",
462 "Enable/disable always incremental backup scheme." },
463 { "AlwaysIncrementalJobRetention", CFG_TYPE_TIME, ITEM(res_job.AlwaysIncrementalJobRetention), 0, CFG_ITEM_DEFAULT, "0", "16.2.4-",
464 "Backup Jobs older than the specified time duration will be merged into a new Virtual backup." },
465 { "AlwaysIncrementalKeepNumber", CFG_TYPE_PINT32, ITEM(res_job.AlwaysIncrementalKeepNumber), 0, CFG_ITEM_DEFAULT, "0", "16.2.4-",
466 "Guarantee that at least the specified number of Backup Jobs will persist, even if they are older than \"Always Incremental Job Retention\"."},
467 { "AlwaysIncrementalMaxFullAge", CFG_TYPE_TIME, ITEM(res_job.AlwaysIncrementalMaxFullAge), 0, 0, NULL, "16.2.4-",
468 "If \"AlwaysIncrementalMaxFullAge\" is set, during consolidations only incremental backups will be considered while the Full Backup remains to reduce the amount of data being consolidated. Only if the Full Backup is older than \"AlwaysIncrementalMaxFullAge\", the Full Backup will be part of the consolidation to avoid the Full Backup becoming too old ." },
469 { "MaxFullConsolidations", CFG_TYPE_PINT32, ITEM(res_job.MaxFullConsolidations), 0, CFG_ITEM_DEFAULT, "0", "16.2.4-",
470 "If \"AlwaysIncrementalMaxFullAge\" is configured, do not run more than \"MaxFullConsolidations\" consolidation jobs that include the Full backup."},
471 { NULL, 0, { 0 }, 0, 0, NULL, NULL, NULL }
472 };
473
474 /**
475 * FileSet resource
476 *
477 * name handler value code flags default_value
478 */
479 static ResourceItem fs_items[] = {
480 { "Name", CFG_TYPE_NAME, ITEM(res_fs.hdr.name), 0, CFG_ITEM_REQUIRED, NULL, NULL,
481 "The name of the resource." },
482 { "Description", CFG_TYPE_STR, ITEM(res_fs.hdr.desc), 0, 0, NULL, NULL, NULL },
483 { "Include", CFG_TYPE_INCEXC, { 0 }, 0, CFG_ITEM_NO_EQUALS, NULL, NULL, NULL },
484 { "Exclude", CFG_TYPE_INCEXC, { 0 }, 1, CFG_ITEM_NO_EQUALS, NULL, NULL, NULL },
485 { "IgnoreFileSetChanges", CFG_TYPE_BOOL, ITEM(res_fs.ignore_fs_changes), 0, CFG_ITEM_DEFAULT, "false", NULL, NULL },
486 { "EnableVSS", CFG_TYPE_BOOL, ITEM(res_fs.enable_vss), 0, CFG_ITEM_DEFAULT, "true", NULL, NULL },
487 { NULL, 0, { 0 }, 0, 0, NULL, NULL, NULL }
488 };
489
490 /**
491 * Schedule -- see run_conf.c
492 *
493 * name handler value code flags default_value
494 */
495 static ResourceItem sch_items[] = {
496 { "Name", CFG_TYPE_NAME, ITEM(res_sch.hdr.name), 0, CFG_ITEM_REQUIRED, NULL, NULL,
497 "The name of the resource." },
498 { "Description", CFG_TYPE_STR, ITEM(res_sch.hdr.desc), 0, 0, NULL, NULL, NULL },
499 { "Run", CFG_TYPE_RUN, ITEM(res_sch.run), 0, 0, NULL, NULL, NULL },
500 { "Enabled", CFG_TYPE_BOOL, ITEM(res_sch.enabled), 0, CFG_ITEM_DEFAULT, "true", NULL,
501 "En- or disable this resource." },
502 { NULL, 0, { 0 }, 0, 0, NULL, NULL, NULL }
503 };
504
505 /**
506 * Pool resource
507 *
508 * name handler value code flags default_value
509 */
510 static ResourceItem pool_items[] = {
511 { "Name", CFG_TYPE_NAME, ITEM(res_pool.hdr.name), 0, CFG_ITEM_REQUIRED, NULL, NULL,
512 "The name of the resource." },
513 { "Description", CFG_TYPE_STR, ITEM(res_pool.hdr.desc), 0, 0, NULL, NULL, NULL },
514 { "PoolType", CFG_TYPE_POOLTYPE, ITEM(res_pool.pool_type), 0, CFG_ITEM_DEFAULT, "Backup", NULL, NULL },
515 { "LabelFormat", CFG_TYPE_STRNAME, ITEM(res_pool.label_format), 0, 0, NULL, NULL, NULL },
516 { "LabelType", CFG_TYPE_LABEL, ITEM(res_pool.LabelType), 0, 0, NULL, NULL, NULL },
517 { "CleaningPrefix", CFG_TYPE_STRNAME, ITEM(res_pool.cleaning_prefix), 0, CFG_ITEM_DEFAULT, "CLN", NULL, NULL },
518 { "UseCatalog", CFG_TYPE_BOOL, ITEM(res_pool.use_catalog), 0, CFG_ITEM_DEFAULT, "true", NULL, NULL },
519 { "UseVolumeOnce", CFG_TYPE_BOOL, ITEM(res_pool.use_volume_once), 0, CFG_ITEM_DEPRECATED, NULL, "-12.4.0", NULL },
520 { "PurgeOldestVolume", CFG_TYPE_BOOL, ITEM(res_pool.purge_oldest_volume), 0, CFG_ITEM_DEFAULT, "false", NULL, NULL },
521 { "ActionOnPurge", CFG_TYPE_ACTIONONPURGE, ITEM(res_pool.action_on_purge), 0, 0, NULL, NULL, NULL },
522 { "RecycleOldestVolume", CFG_TYPE_BOOL, ITEM(res_pool.recycle_oldest_volume), 0, CFG_ITEM_DEFAULT, "false", NULL, NULL },
523 { "RecycleCurrentVolume", CFG_TYPE_BOOL, ITEM(res_pool.recycle_current_volume), 0, CFG_ITEM_DEFAULT, "false", NULL, NULL },
524 { "MaximumVolumes", CFG_TYPE_PINT32, ITEM(res_pool.max_volumes), 0, 0, NULL, NULL, NULL },
525 { "MaximumVolumeJobs", CFG_TYPE_PINT32, ITEM(res_pool.MaxVolJobs), 0, 0, NULL, NULL, NULL },
526 { "MaximumVolumeFiles", CFG_TYPE_PINT32, ITEM(res_pool.MaxVolFiles), 0, 0, NULL, NULL, NULL },
527 { "MaximumVolumeBytes", CFG_TYPE_SIZE64, ITEM(res_pool.MaxVolBytes), 0, 0, NULL, NULL, NULL },
528 { "CatalogFiles", CFG_TYPE_BOOL, ITEM(res_pool.catalog_files), 0, CFG_ITEM_DEFAULT, "true", NULL, NULL },
529 { "VolumeRetention", CFG_TYPE_TIME, ITEM(res_pool.VolRetention), 0, CFG_ITEM_DEFAULT, "31536000" /* 365 days */, NULL, NULL },
530 { "VolumeUseDuration", CFG_TYPE_TIME, ITEM(res_pool.VolUseDuration), 0, 0, NULL, NULL, NULL },
531 { "MigrationTime", CFG_TYPE_TIME, ITEM(res_pool.MigrationTime), 0, 0, NULL, NULL, NULL },
532 { "MigrationHighBytes", CFG_TYPE_SIZE64, ITEM(res_pool.MigrationHighBytes), 0, 0, NULL, NULL, NULL },
533 { "MigrationLowBytes", CFG_TYPE_SIZE64, ITEM(res_pool.MigrationLowBytes), 0, 0, NULL, NULL, NULL },
534 { "NextPool", CFG_TYPE_RES, ITEM(res_pool.NextPool), R_POOL, 0, NULL, NULL, NULL },
535 { "Storage", CFG_TYPE_ALIST_RES, ITEM(res_pool.storage), R_STORAGE, 0, NULL, NULL, NULL },
536 { "AutoPrune", CFG_TYPE_BOOL, ITEM(res_pool.AutoPrune), 0, CFG_ITEM_DEFAULT, "true", NULL, NULL },
537 { "Recycle", CFG_TYPE_BOOL, ITEM(res_pool.Recycle), 0, CFG_ITEM_DEFAULT, "true", NULL, NULL },
538 { "RecyclePool", CFG_TYPE_RES, ITEM(res_pool.RecyclePool), R_POOL, 0, NULL, NULL, NULL },
539 { "ScratchPool", CFG_TYPE_RES, ITEM(res_pool.ScratchPool), R_POOL, 0, NULL, NULL, NULL },
540 { "Catalog", CFG_TYPE_RES, ITEM(res_pool.catalog), R_CATALOG, 0, NULL, NULL, NULL },
541 { "FileRetention", CFG_TYPE_TIME, ITEM(res_pool.FileRetention), 0, 0, NULL, NULL, NULL },
542 { "JobRetention", CFG_TYPE_TIME, ITEM(res_pool.JobRetention), 0, 0, NULL, NULL, NULL },
543 { "MinimumBlockSize", CFG_TYPE_SIZE32, ITEM(res_pool.MinBlocksize), 0, 0, NULL, NULL, NULL },
544 { "MaximumBlockSize", CFG_TYPE_SIZE32, ITEM(res_pool.MaxBlocksize), 0, 0, NULL, "14.2.0-", NULL },
545 { NULL, 0, { 0 }, 0, 0, NULL, NULL, NULL }
546 };
547
548 /**
549 * Counter Resource
550 *
551 * name handler value code flags default_value
552 */
553 static ResourceItem counter_items[] = {
554 { "Name", CFG_TYPE_NAME, ITEM(res_counter.hdr.name), 0, CFG_ITEM_REQUIRED, NULL, NULL,
555 "The name of the resource." },
556 { "Description", CFG_TYPE_STR, ITEM(res_counter.hdr.desc), 0, 0, NULL, NULL, NULL },
557 { "Minimum", CFG_TYPE_INT32, ITEM(res_counter.MinValue), 0, CFG_ITEM_DEFAULT, "0", NULL, NULL },
558 { "Maximum", CFG_TYPE_PINT32, ITEM(res_counter.MaxValue), 0, CFG_ITEM_DEFAULT, "2147483647" /* INT32_MAX */, NULL, NULL },
559 { "WrapCounter", CFG_TYPE_RES, ITEM(res_counter.WrapCounter), R_COUNTER, 0, NULL, NULL, NULL },
560 { "Catalog", CFG_TYPE_RES, ITEM(res_counter.Catalog), R_CATALOG, 0, NULL, NULL, NULL },
561 { NULL, 0, { 0 }, 0, 0, NULL, NULL, NULL }
562 };
563
564 /**
565 * Message resource
566 */
567 #include "lib/msg_res.h"
568 #include "lib/json.h"
569
570 /**
571 * This is the master resource definition.
572 * It must have one item for each of the resources.
573 *
574 * NOTE!!! keep it in the same order as the R_codes
575 * or eliminate all resources[rindex].name
576 *
577 * name handler value code flags default_value
578 */
579 static ResourceTable resources[] = {
__anon96618ae60102()580 { "Director", dir_items, R_DIRECTOR, sizeof(DirectorResource), [] (void *res){ return new((DirectorResource *) res) DirectorResource(); } },
__anon96618ae60202()581 { "Client", cli_items, R_CLIENT, sizeof(ClientResource), [] (void *res){ return new((ClientResource*) res) ClientResource(); } },
582 { "JobDefs", job_items, R_JOBDEFS, sizeof(JobResource)},
583 { "Job", job_items, R_JOB, sizeof(JobResource) },
__anon96618ae60302()584 { "Storage", store_items, R_STORAGE, sizeof(StorageResource), [] (void *res){ return new((StorageResource *) res) StorageResource(); } },
585 { "Catalog", cat_items, R_CATALOG, sizeof(CatalogResource) },
586 { "Schedule", sch_items, R_SCHEDULE, sizeof(ScheduleResource) },
587 { "FileSet", fs_items, R_FILESET, sizeof(FilesetResource) },
588 { "Pool", pool_items, R_POOL, sizeof(PoolResource) },
589 { "Messages", msgs_items, R_MSGS, sizeof(MessagesResource) },
590 { "Counter", counter_items, R_COUNTER, sizeof(CounterResource) },
591 { "Profile", profile_items, R_PROFILE, sizeof(ProfileResource) },
__anon96618ae60402()592 { "Console", con_items, R_CONSOLE, sizeof(ConsoleResource), [] (void *res){ return new((ConsoleResource *) res) ConsoleResource(); } },
__anon96618ae60502()593 { "User", con_items, R_CONSOLE, sizeof(ConsoleResource), [] (void *res){ return new((ConsoleResource *) res) ConsoleResource(); } },
594 { "Device", NULL, R_DEVICE, sizeof(DeviceResource) }, /* info obtained from SD */
595 { NULL, NULL, 0, 0, nullptr }
596 };
597
598 /**
599 * Note, when this resource is used, we are inside a Job
600 * resource. We treat the RunScript like a sort of
601 * mini-resource within the Job resource. As such we
602 * don't use the UnionOfResources union because that contains
603 * a Job resource (and it would corrupt the Job resource)
604 * but use a global separate resource for holding the
605 * runscript data.
606 */
607 static RunScript res_runscript;
608
609 /**
610 * new RunScript items
611 * name handler value code flags default_value
612 */
613 static ResourceItem runscript_items[] = {
614 { "Command", CFG_TYPE_RUNSCRIPT_CMD, { (char **)&res_runscript }, SHELL_CMD, 0, NULL, NULL, NULL },
615 { "Console", CFG_TYPE_RUNSCRIPT_CMD, { (char **)&res_runscript }, CONSOLE_CMD, 0, NULL, NULL, NULL },
616 { "Target", CFG_TYPE_RUNSCRIPT_TARGET, { (char **)&res_runscript }, 0, 0, NULL, NULL, NULL },
617 { "RunsOnSuccess", CFG_TYPE_RUNSCRIPT_BOOL, { (char **)&res_runscript.on_success }, 0, 0, NULL, NULL, NULL },
618 { "RunsOnFailure", CFG_TYPE_RUNSCRIPT_BOOL, { (char **)&res_runscript.on_failure }, 0, 0, NULL, NULL, NULL },
619 { "FailJobOnError", CFG_TYPE_RUNSCRIPT_BOOL, { (char **)&res_runscript.fail_on_error }, 0, 0, NULL, NULL, NULL },
620 { "AbortJobOnError", CFG_TYPE_RUNSCRIPT_BOOL, { (char **)&res_runscript.fail_on_error }, 0, 0, NULL, NULL, NULL },
621 { "RunsWhen", CFG_TYPE_RUNSCRIPT_WHEN, { (char **)&res_runscript.when }, 0, 0, NULL, NULL, NULL },
622 { "RunsOnClient", CFG_TYPE_RUNSCRIPT_TARGET, { (char **)&res_runscript }, 0, 0, NULL, NULL, NULL }, /* TODO */
623 { NULL, 0, { 0 }, 0, 0, NULL, NULL, NULL }
624 };
625
626 /**
627 * The following arrays are referenced from else where and
628 * used for display to the user so the keyword are pretty
629 * printed with additional capitals. As the code uses
630 * strcasecmp anyhow this doesn't matter.
631 */
632
633 /**
634 * Keywords (RHS) permitted in Job Level records
635 *
636 * name level job_type
637 */
638 struct s_jl joblevels[] = {
639 { "Full", L_FULL, JT_BACKUP },
640 { "Base", L_BASE, JT_BACKUP },
641 { "Incremental", L_INCREMENTAL, JT_BACKUP },
642 { "Differential", L_DIFFERENTIAL, JT_BACKUP },
643 { "Since", L_SINCE, JT_BACKUP },
644 { "VirtualFull", L_VIRTUAL_FULL, JT_BACKUP },
645 { "Catalog", L_VERIFY_CATALOG, JT_VERIFY },
646 { "InitCatalog", L_VERIFY_INIT, JT_VERIFY },
647 { "VolumeToCatalog", L_VERIFY_VOLUME_TO_CATALOG, JT_VERIFY },
648 { "DiskToCatalog", L_VERIFY_DISK_TO_CATALOG, JT_VERIFY },
649 { "Data", L_VERIFY_DATA, JT_VERIFY },
650 { "Full", L_FULL, JT_COPY },
651 { "Incremental", L_INCREMENTAL, JT_COPY },
652 { "Differential", L_DIFFERENTIAL, JT_COPY },
653 { "Full", L_FULL, JT_MIGRATE },
654 { "Incremental", L_INCREMENTAL, JT_MIGRATE },
655 { "Differential", L_DIFFERENTIAL, JT_MIGRATE },
656 { " ", L_NONE, JT_ADMIN },
657 { " ", L_NONE, JT_ARCHIVE },
658 { " ", L_NONE, JT_RESTORE },
659 { " ", L_NONE, JT_CONSOLIDATE },
660 { NULL, 0, 0 }
661 };
662
663 /** Keywords (RHS) permitted in Job type records
664 *
665 * type_name job_type
666 */
667 struct s_jt jobtypes[] = {
668 { "Backup", JT_BACKUP },
669 { "Admin", JT_ADMIN },
670 { "Archive", JT_ARCHIVE },
671 { "Verify", JT_VERIFY },
672 { "Restore", JT_RESTORE },
673 { "Migrate",JT_MIGRATE },
674 { "Copy", JT_COPY },
675 { "Consolidate", JT_CONSOLIDATE },
676 { NULL, 0 }
677 };
678
679 /** Keywords (RHS) permitted in Protocol type records
680 *
681 * name token
682 */
683 static struct s_kw backupprotocols[] = {
684 { "Native", PT_NATIVE },
685 { "NDMP_BAREOS", PT_NDMP_BAREOS}, /* alias for PT_NDMP */
686 { "NDMP", PT_NDMP_BAREOS},
687 { "NDMP_NATIVE", PT_NDMP_NATIVE },
688 { NULL, 0 }
689 };
690
691 /** Keywords (RHS) permitted in AuthProtocol type records
692 *
693 * name token
694 */
695 static struct s_kw authprotocols[] = {
696 { "Native", APT_NATIVE },
697 { "NDMPV2", APT_NDMPV2 },
698 { "NDMPV3", APT_NDMPV3 },
699 { "NDMPV4", APT_NDMPV4 },
700 { NULL, 0 }
701 };
702
703 /**
704 * Keywords (RHS) permitted in Authentication type records
705 *
706 * name token
707 */
708 static struct s_kw authmethods[] = {
709 { "None", AT_NONE },
710 { "Clear", AT_CLEAR },
711 { "MD5", AT_MD5 },
712 { NULL, 0 }
713 };
714
715 /**
716 * Keywords (RHS) permitted in Selection type records
717 *
718 * type_name job_type
719 */
720 static struct s_jt migtypes[] = {
721 { "SmallestVolume", MT_SMALLEST_VOL },
722 { "OldestVolume", MT_OLDEST_VOL },
723 { "PoolOccupancy", MT_POOL_OCCUPANCY },
724 { "PoolTime", MT_POOL_TIME },
725 { "PoolUncopiedJobs", MT_POOL_UNCOPIED_JOBS },
726 { "Client", MT_CLIENT },
727 { "Volume", MT_VOLUME },
728 { "Job", MT_JOB },
729 { "SqlQuery", MT_SQLQUERY },
730 { NULL, 0 }
731 };
732
733 /**
734 * Keywords (RHS) permitted in Restore replace type records
735 *
736 * name token
737 */
738 struct s_kw ReplaceOptions[] = {
739 { "Always", REPLACE_ALWAYS },
740 { "IfNewer", REPLACE_IFNEWER },
741 { "IfOlder", REPLACE_IFOLDER },
742 { "Never", REPLACE_NEVER },
743 { NULL, 0 }
744 };
745
746 /**
747 * Keywords (RHS) permitted in ActionOnPurge type records
748 *
749 * name token
750 */
751 struct s_kw ActionOnPurgeOptions[] = {
752 { "None", ON_PURGE_NONE },
753 { "Truncate", ON_PURGE_TRUNCATE },
754 { NULL, 0 }
755 };
756
757 /**
758 * Keywords (RHS) permitted in Volume status type records
759 *
760 * token is set to zero for all items as this
761 * is not a mapping but a filter table.
762 *
763 * name token
764 */
765 struct s_kw VolumeStatus[] = {
766 { "Append", 0 },
767 { "Full", 0 },
768 { "Used", 0 },
769 { "Recycle", 0 },
770 { "Purged", 0 },
771 { "Cleaning", 0 },
772 { "Error", 0 },
773 { NULL, 0 }
774 };
775
776 /**
777 * Keywords (RHS) permitted in Pool type records
778 *
779 * token is set to zero for all items as this
780 * is not a mapping but a filter table.
781 *
782 * name token
783 */
784 struct s_kw PoolTypes[] = {
785 { "Backup", 0 },
786 { "Copy", 0 },
787 { "Cloned", 0 },
788 { "Archive", 0 },
789 { "Migration", 0 },
790 { "Scratch", 0 },
791 { NULL, 0 }
792 };
793
794 #ifdef HAVE_JANSSON
json_item(s_jl * item)795 json_t *json_item(s_jl *item)
796 {
797 json_t *json = json_object();
798
799 json_object_set_new(json, "level", json_integer(item->level));
800 json_object_set_new(json, "type", json_integer(item->job_type));
801
802 return json;
803 }
804
json_item(s_jt * item)805 json_t *json_item(s_jt *item)
806 {
807 json_t *json = json_object();
808
809 json_object_set_new(json, "type", json_integer(item->job_type));
810
811 return json;
812 }
813
json_datatype_header(const int type,const char * typeclass)814 json_t *json_datatype_header(const int type, const char *typeclass)
815 {
816 json_t *json = json_object();
817 const char *description = datatype_to_description(type);
818
819 json_object_set_new(json, "number", json_integer(type));
820
821 if (description) {
822 json_object_set_new(json, "description", json_string(description));
823 }
824
825 if (typeclass) {
826 json_object_set_new(json, "class", json_string(typeclass));
827 }
828
829 return json;
830 }
831
json_datatype(const int type)832 json_t *json_datatype(const int type)
833 {
834 return json_datatype_header(type, NULL);
835 }
836
json_datatype(const int type,s_kw items[])837 json_t *json_datatype(const int type, s_kw items[])
838 {
839 json_t *json = json_datatype_header(type, "keyword");
840 if (items) {
841 json_t *values = json_object();
842 for (int i = 0; items[i].name; i++) {
843 json_object_set_new(values, items[i].name, json_item(&items[i]));
844 }
845 json_object_set_new(json, "values", values);
846 }
847 return json;
848 }
849
json_datatype(const int type,s_jl items[])850 json_t *json_datatype(const int type, s_jl items[])
851 {
852 // FIXME: level_name keyword is not unique
853 json_t *json = json_datatype_header(type, "keyword");
854 if (items) {
855 json_t *values = json_object();
856 for (int i = 0; items[i].level_name; i++) {
857 json_object_set_new(values, items[i].level_name, json_item(&items[i]));
858 }
859 json_object_set_new(json, "values", values);
860 }
861 return json;
862 }
863
json_datatype(const int type,s_jt items[])864 json_t *json_datatype(const int type, s_jt items[])
865 {
866 json_t *json = json_datatype_header(type, "keyword");
867 if (items) {
868 json_t *values = json_object();
869 for (int i = 0; items[i].type_name; i++) {
870 json_object_set_new(values, items[i].type_name, json_item(&items[i]));
871 }
872 json_object_set_new(json, "values", values);
873 }
874 return json;
875 }
876
json_datatype(const int type,ResourceItem items[])877 json_t *json_datatype(const int type, ResourceItem items[])
878 {
879 json_t *json = json_datatype_header(type, "sub");
880 if (items) {
881 json_t *values = json_object();
882 for (int i = 0; items[i].name; i++) {
883 json_object_set_new(values, items[i].name, json_item(&items[i]));
884 }
885 json_object_set_new(json, "values", values);
886 }
887 return json;
888 }
889
890 /**
891 * Print configuration file schema in json format
892 */
PrintConfigSchemaJson(PoolMem & buffer)893 bool PrintConfigSchemaJson(PoolMem &buffer)
894 {
895 DatatypeName *datatype;
896 ResourceTable *resources = my_config->resources_;
897
898 InitializeJson();
899
900 json_t *json = json_object();
901 json_object_set_new(json, "format-version", json_integer(2));
902 json_object_set_new(json, "component", json_string("bareos-dir"));
903 json_object_set_new(json, "version", json_string(VERSION));
904
905 /*
906 * Resources
907 */
908 json_t *resource = json_object();
909 json_object_set(json, "resource", resource);
910 json_t *bareos_dir = json_object();
911 json_object_set(resource, "bareos-dir", bareos_dir);
912
913 for (int r = 0; resources[r].name; r++) {
914 ResourceTable resource = my_config->resources_[r];
915 json_object_set(bareos_dir, resource.name, json_items(resource.items));
916 }
917
918 /*
919 * Datatypes
920 */
921 json_t *json_datatype_obj = json_object();
922 json_object_set(json, "datatype", json_datatype_obj);
923
924 int d = 0;
925 while (get_datatype(d)->name != NULL) {
926 datatype = get_datatype(d);
927
928 switch (datatype->number) {
929 case CFG_TYPE_RUNSCRIPT:
930 json_object_set(json_datatype_obj, datatype_to_str(datatype->number), json_datatype(CFG_TYPE_RUNSCRIPT, runscript_items));
931 break;
932 case CFG_TYPE_INCEXC:
933 json_object_set(json_datatype_obj, datatype_to_str(datatype->number), json_incexc(CFG_TYPE_INCEXC));
934 break;
935 case CFG_TYPE_OPTIONS:
936 json_object_set(json_datatype_obj, datatype_to_str(datatype->number), json_options(CFG_TYPE_OPTIONS));
937 break;
938 case CFG_TYPE_PROTOCOLTYPE:
939 json_object_set(json_datatype_obj, datatype_to_str(datatype->number), json_datatype(CFG_TYPE_PROTOCOLTYPE, backupprotocols));
940 break;
941 case CFG_TYPE_AUTHPROTOCOLTYPE:
942 json_object_set(json_datatype_obj, datatype_to_str(datatype->number), json_datatype(CFG_TYPE_AUTHPROTOCOLTYPE, authprotocols));
943 break;
944 case CFG_TYPE_AUTHTYPE:
945 json_object_set(json_datatype_obj, datatype_to_str(datatype->number), json_datatype(CFG_TYPE_AUTHTYPE, authmethods));
946 break;
947 case CFG_TYPE_LEVEL:
948 json_object_set(json_datatype_obj, datatype_to_str(datatype->number), json_datatype(CFG_TYPE_LEVEL, joblevels));
949 break;
950 case CFG_TYPE_JOBTYPE:
951 json_object_set(json_datatype_obj, datatype_to_str(datatype->number), json_datatype(CFG_TYPE_JOBTYPE, jobtypes));
952 break;
953 case CFG_TYPE_MIGTYPE:
954 json_object_set(json_datatype_obj, datatype_to_str(datatype->number), json_datatype(CFG_TYPE_MIGTYPE, migtypes));
955 break;
956 case CFG_TYPE_REPLACE:
957 json_object_set(json_datatype_obj, datatype_to_str(datatype->number), json_datatype(CFG_TYPE_REPLACE, ReplaceOptions));
958 break;
959 case CFG_TYPE_ACTIONONPURGE:
960 json_object_set(json_datatype_obj, datatype_to_str(datatype->number), json_datatype(CFG_TYPE_ACTIONONPURGE, ActionOnPurgeOptions));
961 break;
962 case CFG_TYPE_POOLTYPE:
963 json_object_set(json_datatype_obj, datatype_to_str(datatype->number), json_datatype(CFG_TYPE_POOLTYPE, PoolTypes));
964 break;
965 case CFG_TYPE_RUN:
966 json_object_set(json_datatype_obj, datatype_to_str(datatype->number), json_datatype(CFG_TYPE_RUN, RunFields));
967 break;
968 default:
969 json_object_set(json_datatype_obj, datatype_to_str(datatype->number), json_datatype(datatype->number));
970 break;
971 }
972 d++;
973 }
974
975 /*
976 * following datatypes are ignored:
977 * - VolumeStatus: only used in ua_dotcmds, not a datatype
978 * - FS_option_kw: from inc_conf. Replaced by CFG_TYPE_OPTIONS", options_items.
979 * - FS_options: are they needed?
980 */
981
982 PmStrcat(buffer, json_dumps(json, JSON_INDENT(2)));
983 json_decref(json);
984
985 return true;
986 }
987 #else
PrintConfigSchemaJson(PoolMem & buffer)988 bool PrintConfigSchemaJson(PoolMem &buffer)
989 {
990 PmStrcat(buffer, "{ \"success\": false, \"message\": \"not available\" }");
991
992 return false;
993 }
994 #endif
995
CmdlineItem(PoolMem * buffer,ResourceItem * item)996 static inline bool CmdlineItem(PoolMem *buffer, ResourceItem *item)
997 {
998 PoolMem temp;
999 PoolMem key;
1000 const char *nomod = "";
1001 const char *mod_start = nomod;
1002 const char *mod_end = nomod;
1003
1004 if (item->flags & CFG_ITEM_ALIAS) {
1005 return false;
1006 }
1007
1008 if (item->flags & CFG_ITEM_DEPRECATED) {
1009 return false;
1010 }
1011
1012 if (item->flags & CFG_ITEM_NO_EQUALS) {
1013 /* TODO: currently not supported */
1014 return false;
1015 }
1016
1017 if (!(item->flags & CFG_ITEM_REQUIRED)) {
1018 mod_start = "[";
1019 mod_end = "]";
1020 }
1021
1022 /*
1023 * Tab completion only supports lower case keywords.
1024 */
1025 key.strcat(item->name);
1026 key.toLower();
1027
1028 temp.bsprintf(" %s%s=<%s>%s", mod_start, key.c_str(), datatype_to_str(item->type), mod_end);
1029 PmStrcat(buffer, temp.c_str());
1030
1031 return true;
1032 }
1033
CmdlineItems(PoolMem * buffer,ResourceItem items[])1034 static inline bool CmdlineItems(PoolMem *buffer, ResourceItem items[])
1035 {
1036 if (!items) {
1037 return false;
1038 }
1039
1040 for (int i = 0; items[i].name; i++) {
1041 CmdlineItem(buffer, &items[i]);
1042 }
1043
1044 return true;
1045 }
1046
1047 /**
1048 * Get the usage string for the console "configure" command.
1049 *
1050 * This will be all available resource directives.
1051 * They are formated in a way to be usable for command line completion.
1052 */
get_configure_usage_string()1053 const char *get_configure_usage_string()
1054 {
1055 PoolMem resourcename;
1056
1057 if (!configure_usage_string) {
1058 configure_usage_string = new PoolMem(PM_BSOCK);
1059 }
1060
1061 /*
1062 * Only fill the configure_usage_string once. The content is static.
1063 */
1064 if (configure_usage_string->strlen() == 0) {
1065 /*
1066 * subcommand: add
1067 */
1068 for (int r = 0; resources[r].name; r++) {
1069 /*
1070 * Only one Director is allowed.
1071 * If the resource have not items, there is no need to add it.
1072 */
1073 if ((resources[r].rcode != R_DIRECTOR) && (resources[r].items)) {
1074 configure_usage_string->strcat("add ");
1075 resourcename.strcpy(resources[r].name);
1076 resourcename.toLower();
1077 configure_usage_string->strcat(resourcename);
1078 CmdlineItems(configure_usage_string, resources[r].items);
1079 configure_usage_string->strcat(" |\n");
1080 }
1081 }
1082 /*
1083 * subcommand: export
1084 */
1085 configure_usage_string->strcat("export client=<client>");
1086 }
1087
1088 return configure_usage_string->c_str();
1089 }
1090
DestroyConfigureUsageString()1091 void DestroyConfigureUsageString()
1092 {
1093 if (configure_usage_string) {
1094 delete configure_usage_string;
1095 configure_usage_string = NULL;
1096 }
1097 }
1098
1099 /**
1100 * Propagate the settings from source BareosResource to dest BareosResource using the RES_ITEMS array.
1101 */
PropagateResource(ResourceItem * items,BareosResource * source,BareosResource * dest)1102 static void PropagateResource(ResourceItem *items, BareosResource *source, BareosResource *dest)
1103 {
1104 uint32_t offset;
1105
1106 for (int i = 0; items[i].name; i++) {
1107 if (!BitIsSet(i, dest->hdr.item_present) &&
1108 BitIsSet(i, source->hdr.item_present)) {
1109 offset = (char *)(items[i].value) - (char *)&res_all;
1110 switch (items[i].type) {
1111 case CFG_TYPE_STR:
1112 case CFG_TYPE_DIR: {
1113 char **def_svalue, **svalue;
1114
1115 /*
1116 * Handle strings and directory strings
1117 */
1118 def_svalue = (char **)((char *)(source) + offset);
1119 svalue = (char **)((char *)dest + offset);
1120 if (*svalue) {
1121 free(*svalue);
1122 }
1123 *svalue = bstrdup(*def_svalue);
1124 SetBit(i, dest->hdr.item_present);
1125 SetBit(i, dest->hdr.inherit_content);
1126 break;
1127 }
1128 case CFG_TYPE_RES: {
1129 char **def_svalue, **svalue;
1130
1131 /*
1132 * Handle resources
1133 */
1134 def_svalue = (char **)((char *)(source) + offset);
1135 svalue = (char **)((char *)dest + offset);
1136 if (*svalue) {
1137 Pmsg1(000, _("Hey something is wrong. p=0x%lu\n"), *svalue);
1138 }
1139 *svalue = *def_svalue;
1140 SetBit(i, dest->hdr.item_present);
1141 SetBit(i, dest->hdr.inherit_content);
1142 break;
1143 }
1144 case CFG_TYPE_ALIST_STR: {
1145 const char *str = nullptr;
1146 alist *orig_list, **new_list;
1147
1148 /*
1149 * Handle alist strings
1150 */
1151 orig_list = *(alist **)((char *)(source) + offset);
1152
1153 /*
1154 * See if there is anything on the list.
1155 */
1156 if (orig_list && orig_list->size()) {
1157 new_list = (alist **)((char *)(dest) + offset);
1158
1159 if (!*new_list) {
1160 *new_list = New(alist(10, owned_by_alist));
1161 }
1162
1163 foreach_alist(str, orig_list) {
1164 (*new_list)->append(bstrdup(str));
1165 }
1166
1167 SetBit(i, dest->hdr.item_present);
1168 SetBit(i, dest->hdr.inherit_content);
1169 }
1170 break;
1171 }
1172 case CFG_TYPE_ALIST_RES: {
1173 CommonResourceHeader *res = nullptr;
1174 alist *orig_list, **new_list;
1175
1176 /*
1177 * Handle alist resources
1178 */
1179 orig_list = *(alist **)((char *)(source) + offset);
1180
1181 /*
1182 * See if there is anything on the list.
1183 */
1184 if (orig_list && orig_list->size()) {
1185 new_list = (alist **)((char *)(dest) + offset);
1186
1187 if (!*new_list) {
1188 *new_list = New(alist(10, not_owned_by_alist));
1189 }
1190
1191 foreach_alist(res, orig_list) {
1192 (*new_list)->append(res);
1193 }
1194
1195 SetBit(i, dest->hdr.item_present);
1196 SetBit(i, dest->hdr.inherit_content);
1197 }
1198 break;
1199 }
1200 case CFG_TYPE_ACL: {
1201 const char *str = nullptr;
1202 alist *orig_list, **new_list;
1203
1204 /*
1205 * Handle ACL lists.
1206 */
1207 orig_list = ((alist **)((char *)(source) + offset))[items[i].code];
1208
1209 /*
1210 * See if there is anything on the list.
1211 */
1212 if (orig_list && orig_list->size()) {
1213 new_list = &(((alist **)((char *)(dest) + offset))[items[i].code]);
1214
1215 if (!*new_list) {
1216 *new_list = New(alist(10, owned_by_alist));
1217 }
1218
1219 foreach_alist(str, orig_list) {
1220 (*new_list)->append(bstrdup(str));
1221 }
1222
1223 SetBit(i, dest->hdr.item_present);
1224 SetBit(i, dest->hdr.inherit_content);
1225 }
1226 break;
1227 }
1228 case CFG_TYPE_BIT:
1229 case CFG_TYPE_PINT32:
1230 case CFG_TYPE_JOBTYPE:
1231 case CFG_TYPE_PROTOCOLTYPE:
1232 case CFG_TYPE_LEVEL:
1233 case CFG_TYPE_INT32:
1234 case CFG_TYPE_SIZE32:
1235 case CFG_TYPE_MIGTYPE:
1236 case CFG_TYPE_REPLACE: {
1237 uint32_t *def_ivalue, *ivalue;
1238
1239 /*
1240 * Handle integer fields
1241 * Note, our StoreBit does not handle bitmaped fields
1242 */
1243 def_ivalue = (uint32_t *)((char *)(source) + offset);
1244 ivalue = (uint32_t *)((char *)dest + offset);
1245 *ivalue = *def_ivalue;
1246 SetBit(i, dest->hdr.item_present);
1247 SetBit(i, dest->hdr.inherit_content);
1248 break;
1249 }
1250 case CFG_TYPE_TIME:
1251 case CFG_TYPE_SIZE64:
1252 case CFG_TYPE_INT64:
1253 case CFG_TYPE_SPEED: {
1254 int64_t *def_lvalue, *lvalue;
1255
1256 /*
1257 * Handle 64 bit integer fields
1258 */
1259 def_lvalue = (int64_t *)((char *)(source) + offset);
1260 lvalue = (int64_t *)((char *)dest + offset);
1261 *lvalue = *def_lvalue;
1262 SetBit(i, dest->hdr.item_present);
1263 SetBit(i, dest->hdr.inherit_content);
1264 break;
1265 }
1266 case CFG_TYPE_BOOL: {
1267 bool *def_bvalue, *bvalue;
1268
1269 /*
1270 * Handle bool fields
1271 */
1272 def_bvalue = (bool *)((char *)(source) + offset);
1273 bvalue = (bool *)((char *)dest + offset);
1274 *bvalue = *def_bvalue;
1275 SetBit(i, dest->hdr.item_present);
1276 SetBit(i, dest->hdr.inherit_content);
1277 break;
1278 }
1279 case CFG_TYPE_AUTOPASSWORD: {
1280 s_password *s_pwd, *d_pwd;
1281
1282 /*
1283 * Handle password fields
1284 */
1285 s_pwd = (s_password *)((char *)(source) + offset);
1286 d_pwd = (s_password *)((char *)(dest) + offset);
1287
1288 d_pwd->encoding = s_pwd->encoding;
1289 d_pwd->value = bstrdup(s_pwd->value);
1290 SetBit(i, dest->hdr.item_present);
1291 SetBit(i, dest->hdr.inherit_content);
1292 break;
1293 }
1294 default:
1295 Dmsg2(200, "Don't know how to propagate resource %s of configtype %d\n", items[i].name, items[i].type);
1296 break;
1297 }
1298 }
1299 }
1300 }
1301
1302
1303 /**
1304 * Ensure that all required items are present
1305 */
ValidateResource(int res_type,ResourceItem * items,BareosResource * res)1306 bool ValidateResource(int res_type, ResourceItem *items, BareosResource *res)
1307 {
1308 if (res_type == R_JOBDEFS) {
1309 /*
1310 * a jobdef don't have to be fully defined.
1311 */
1312 return true;
1313 } else if (res_type == R_JOB) {
1314 if (!((JobResource *)res)->validate()) {
1315 return false;
1316 }
1317 }
1318
1319 for (int i = 0; items[i].name; i++) {
1320 if (items[i].flags & CFG_ITEM_REQUIRED) {
1321 if (!BitIsSet(i, res->hdr.item_present)) {
1322 Jmsg(NULL, M_ERROR, 0,
1323 _("\"%s\" directive in %s \"%s\" resource is required, but not found.\n"),
1324 items[i].name, my_config->res_to_str(res_type), res->name());
1325 return false;
1326 }
1327 }
1328
1329 /*
1330 * If this triggers, take a look at lib/parse_conf.h
1331 */
1332 if (i >= MAX_RES_ITEMS) {
1333 Emsg1(M_ERROR, 0, _("Too many items in %s resource\n"), my_config->res_to_str(res_type));
1334 return false;
1335 }
1336 }
1337
1338 return true;
1339 }
1340
validate()1341 bool JobResource::validate()
1342 {
1343 /*
1344 * For Copy and Migrate we can have Jobs without a client or fileset.
1345 * As for a copy we use the original Job as a reference for the Read storage
1346 * we also don't need to check if there is an explicit storage definition in
1347 * either the Job or the Read pool.
1348 */
1349 switch (JobType) {
1350 case JT_COPY:
1351 case JT_MIGRATE:
1352 break;
1353 default:
1354 /*
1355 * All others must have a client and fileset.
1356 */
1357 if (!client) {
1358 Jmsg(NULL, M_ERROR, 0,
1359 _("\"client\" directive in Job \"%s\" resource is required, but not found.\n"), name());
1360 return false;
1361 }
1362
1363 if (!fileset) {
1364 Jmsg(NULL, M_ERROR, 0,
1365 _("\"fileset\" directive in Job \"%s\" resource is required, but not found.\n"), name());
1366 return false;
1367 }
1368
1369 if (!storage && (!pool || !pool->storage)) {
1370 Jmsg(NULL, M_ERROR, 0, _("No storage specified in Job \"%s\" nor in Pool.\n"), name());
1371 return false;
1372 }
1373 break;
1374 }
1375
1376 return true;
1377 }
1378
display(POOLMEM * dst)1379 char *CatalogResource::display(POOLMEM *dst)
1380 {
1381 Mmsg(dst, "catalog=%s\ndb_name=%s\ndb_driver=%s\ndb_user=%s\n"
1382 "db_password=%s\ndb_address=%s\ndb_port=%i\n"
1383 "db_socket=%s\n",
1384 name(), NPRTB(db_name),
1385 NPRTB(db_driver), NPRTB(db_user), NPRTB(db_password.value),
1386 NPRTB(db_address), db_port, NPRTB(db_socket));
1387
1388 return dst;
1389 }
1390
PrintConfigRunscript(ResourceItem * item,PoolMem & cfg_str)1391 static inline void PrintConfigRunscript(ResourceItem *item, PoolMem &cfg_str)
1392 {
1393 PoolMem temp;
1394 RunScript *runscript = nullptr;
1395 alist *list;
1396
1397 list = *item->alistvalue;
1398 if (Bstrcasecmp(item->name, "runscript")) {
1399 if (list != NULL) {
1400 foreach_alist(runscript, list) {
1401 PoolMem esc;
1402
1403 EscapeString(esc, runscript->command, strlen(runscript->command));
1404
1405 /*
1406 * Don't print runscript when its inherited from a JobDef.
1407 */
1408 if (runscript->from_jobdef) {
1409 continue;
1410 }
1411
1412 /*
1413 * Check if runscript must be written as short runscript
1414 */
1415 if (runscript->short_form) {
1416 if (runscript->when == SCRIPT_Before && /* runbeforejob */
1417 (bstrcmp(runscript->target, ""))) {
1418 Mmsg(temp, "run before job = \"%s\"\n", esc.c_str());
1419 } else if (runscript->when == SCRIPT_After && /* runafterjob */
1420 runscript->on_success &&
1421 !runscript->on_failure &&
1422 !runscript->fail_on_error &&
1423 bstrcmp(runscript->target, "")) {
1424 Mmsg(temp, "run after job = \"%s\"\n", esc.c_str());
1425 } else if (runscript->when == SCRIPT_After && /* client run after job */
1426 runscript->on_success &&
1427 !runscript->on_failure &&
1428 !runscript->fail_on_error &&
1429 !bstrcmp(runscript->target, "")) {
1430 Mmsg(temp, "client run after job = \"%s\"\n", esc.c_str());
1431 } else if (runscript->when == SCRIPT_Before && /* client run before job */
1432 !bstrcmp(runscript->target, "")) {
1433 Mmsg(temp, "client run before job = \"%s\"\n", esc.c_str());
1434 } else if (runscript->when == SCRIPT_After && /* run after failed job */
1435 runscript->on_failure &&
1436 !runscript->on_success &&
1437 !runscript->fail_on_error &&
1438 bstrcmp(runscript->target, "")) {
1439 Mmsg(temp, "run after failed job = \"%s\"\n", esc.c_str());
1440 }
1441 IndentConfigItem(cfg_str, 1, temp.c_str());
1442 } else {
1443 Mmsg(temp, "runscript {\n");
1444 IndentConfigItem(cfg_str, 1, temp.c_str());
1445
1446 char *cmdstring = (char *)"command"; /* '|' */
1447 if (runscript->cmd_type == '@') {
1448 cmdstring = (char *)"console";
1449 }
1450
1451 Mmsg(temp, "%s = \"%s\"\n", cmdstring, esc.c_str());
1452 IndentConfigItem(cfg_str, 2, temp.c_str());
1453
1454 /*
1455 * Default: never
1456 */
1457 char *when = (char *)"never";
1458 switch (runscript->when) {
1459 case SCRIPT_Before:
1460 when = (char *)"before";
1461 break;
1462 case SCRIPT_After:
1463 when = (char *)"after";
1464 break;
1465 case SCRIPT_AfterVSS:
1466 when = (char *)"aftervss";
1467 break;
1468 case SCRIPT_Any:
1469 when = (char *)"always";
1470 break;
1471 }
1472
1473 if (!Bstrcasecmp(when, "never")) { /* suppress default value */
1474 Mmsg(temp, "runswhen = %s\n", when);
1475 IndentConfigItem(cfg_str, 2, temp.c_str());
1476 }
1477
1478 /*
1479 * Default: fail_on_error = true
1480 */
1481 char *fail_on_error = (char *)"Yes";
1482 if (!runscript->fail_on_error){
1483 fail_on_error = (char *)"No";
1484 Mmsg(temp, "failonerror = %s\n", fail_on_error);
1485 IndentConfigItem(cfg_str, 2, temp.c_str());
1486 }
1487
1488 /*
1489 * Default: on_success = true
1490 */
1491 char *run_on_success = (char *)"Yes";
1492 if (!runscript->on_success){
1493 run_on_success = (char *)"No";
1494 Mmsg(temp, "runsonsuccess = %s\n", run_on_success);
1495 IndentConfigItem(cfg_str, 2, temp.c_str());
1496 }
1497
1498 /*
1499 * Default: on_failure = false
1500 */
1501 char *run_on_failure = (char *)"No";
1502 if (runscript->on_failure) {
1503 run_on_failure = (char *)"Yes";
1504 Mmsg(temp, "runsonfailure = %s\n", run_on_failure);
1505 IndentConfigItem(cfg_str, 2, temp.c_str());
1506 }
1507
1508 /* level is not implemented
1509 Dmsg1(200, " level = %d\n", runscript->level);
1510 */
1511
1512 /*
1513 * Default: runsonclient = yes
1514 */
1515 char *runsonclient = (char *)"Yes";
1516 if (bstrcmp(runscript->target, "")) {
1517 runsonclient = (char *)"No";
1518 Mmsg(temp, "runsonclient = %s\n", runsonclient);
1519 IndentConfigItem(cfg_str, 2, temp.c_str());
1520 }
1521
1522 IndentConfigItem(cfg_str, 1, "}\n");
1523 }
1524 }
1525 } /* foreach runscript */
1526 }
1527 }
1528
PrintConfigRun(ResourceItem * item,PoolMem & cfg_str)1529 static inline void PrintConfigRun(ResourceItem *item, PoolMem &cfg_str)
1530 {
1531 PoolMem temp;
1532 RunResource *run;
1533 bool all_set;
1534 int i, nr_items;
1535 int interval_start;
1536 char *weekdays[] = {
1537 (char *)"Sun",
1538 (char *)"Mon",
1539 (char *)"Tue",
1540 (char *)"Wed",
1541 (char *)"Thu",
1542 (char *)"Fri",
1543 (char *)"Sat"
1544 };
1545 char *months[] = {
1546 (char *)"Jan",
1547 (char *)"Feb",
1548 (char *)"Mar",
1549 (char *)"Apr",
1550 (char *)"May",
1551 (char *)"Jun",
1552 (char *)"Jul",
1553 (char *)"Aug",
1554 (char *)"Sep",
1555 (char *)"Oct",
1556 (char *)"Nov",
1557 (char *)"Dec"
1558 };
1559 char *ordinals[] = {
1560 (char *)"1st",
1561 (char *)"2nd",
1562 (char *)"3rd",
1563 (char *)"4th",
1564 (char *)"5th"
1565 };
1566
1567 run = (RunResource *)*(item->value);
1568 if (run != NULL) {
1569 while (run) {
1570 PoolMem run_str; /* holds the complete run= ... line */
1571 PoolMem interval; /* is one entry of day/month/week etc. */
1572
1573 IndentConfigItem(cfg_str, 1, "run = ");
1574
1575 /*
1576 * Overrides
1577 */
1578 if (run->pool) {
1579 Mmsg(temp, "pool=\"%s\" ", run->pool->name());
1580 PmStrcat(run_str, temp.c_str());
1581 }
1582
1583 if (run->full_pool) {
1584 Mmsg(temp, "fullpool=\"%s\" ", run->full_pool->name());
1585 PmStrcat(run_str, temp.c_str());
1586 }
1587
1588 if (run->vfull_pool) {
1589 Mmsg(temp, "virtualfullpool=\"%s\" ", run->vfull_pool->name());
1590 PmStrcat(run_str, temp.c_str());
1591 }
1592
1593 if (run->inc_pool) {
1594 Mmsg(temp, "incrementalpool=\"%s\" ", run->inc_pool->name());
1595 PmStrcat(run_str, temp.c_str());
1596 }
1597
1598 if (run->diff_pool) {
1599 Mmsg(temp, "differentialpool=\"%s\" ", run->diff_pool->name());
1600 PmStrcat(run_str, temp.c_str());
1601 }
1602
1603 if (run->next_pool) {
1604 Mmsg(temp, "nextpool=\"%s\" ", run->next_pool->name());
1605 PmStrcat(run_str, temp.c_str());
1606 }
1607
1608 if (run->level) {
1609 for (int j = 0; joblevels[j].level_name; j++) {
1610 if (joblevels[j].level == run->level) {
1611 PmStrcat(run_str, joblevels[j].level_name);
1612 PmStrcat(run_str, " ");
1613 break;
1614 }
1615 }
1616 }
1617
1618 if (run->storage) {
1619 Mmsg(temp, "storage=\"%s\" ", run->storage->name());
1620 PmStrcat(run_str, temp.c_str());
1621 }
1622
1623 if (run->msgs) {
1624 Mmsg(temp, "messages=\"%s\" ", run->msgs->name());
1625 PmStrcat(run_str, temp.c_str());
1626 }
1627
1628 if (run->Priority && run->Priority != 10) {
1629 Mmsg(temp, "priority=%d ", run->Priority);
1630 PmStrcat(run_str, temp.c_str());
1631 }
1632
1633 if (run->MaxRunSchedTime) {
1634 Mmsg(temp, "maxrunschedtime=%d ", run->MaxRunSchedTime);
1635 PmStrcat(run_str, temp.c_str());
1636 }
1637
1638 if (run->accurate) {
1639 /*
1640 * TODO: You cannot distinct if accurate was not set or if it was set to no
1641 * maybe we need an additional variable like "accurate_set".
1642 */
1643 Mmsg(temp, "accurate=\"%s\" ","yes");
1644 PmStrcat(run_str, temp.c_str());
1645 }
1646
1647 /*
1648 * Now the time specification
1649 */
1650
1651 /*
1652 * run->mday , output is just the number comma separated
1653 */
1654 PmStrcpy(temp, "");
1655
1656 /*
1657 * First see if not all bits are set.
1658 */
1659 all_set = true;
1660 nr_items = 31;
1661 for (i = 0; i < nr_items; i++) {
1662 if (!BitIsSet(i, run->mday)) {
1663 all_set = false;
1664 }
1665 }
1666
1667 if (!all_set) {
1668 interval_start = -1;
1669
1670 for (i = 0; i < nr_items; i++) {
1671 if (BitIsSet(i, run->mday)) {
1672 if (interval_start == -1) { /* bit is set and we are not in an interval */
1673 interval_start = i; /* start an interval */
1674 Dmsg1(200, "starting interval at %d\n", i + 1);
1675 Mmsg(interval, ",%d", i + 1);
1676 PmStrcat(temp, interval.c_str());
1677 }
1678 }
1679
1680 if (!BitIsSet(i, run->mday)) {
1681 if (interval_start != -1) { /* bit is unset and we are in an interval */
1682 if ((i - interval_start) > 1) {
1683 Dmsg2(200, "found end of interval from %d to %d\n", interval_start + 1, i);
1684 Mmsg(interval, "-%d", i);
1685 PmStrcat(temp, interval.c_str());
1686 }
1687 interval_start = -1; /* end the interval */
1688 }
1689 }
1690 }
1691
1692 /*
1693 * See if we are still in an interval and the last bit is also set then the interval stretches to the last item.
1694 */
1695 i = nr_items - 1;
1696 if (interval_start != -1 && BitIsSet(i, run->mday)) {
1697 if ((i - interval_start) > 1) {
1698 Dmsg2(200, "found end of interval from %d to %d\n", interval_start + 1, i + 1);
1699 Mmsg(interval, "-%d", i + 1);
1700 PmStrcat(temp, interval.c_str());
1701 }
1702 }
1703
1704 PmStrcat(temp, " ");
1705 PmStrcat(run_str, temp.c_str() + 1); /* jump over first comma*/
1706 }
1707
1708 /*
1709 * run->wom output is 1st, 2nd... 5th comma separated
1710 * first, second, third... is also allowed
1711 * but we ignore that for now
1712 */
1713 all_set = true;
1714 nr_items = 5;
1715 for (i = 0; i < nr_items; i++) {
1716 if (!BitIsSet(i, run->wom)) {
1717 all_set = false;
1718 }
1719 }
1720
1721 if (!all_set) {
1722 interval_start = -1;
1723
1724 PmStrcpy(temp, "");
1725 for (i = 0; i < nr_items; i++) {
1726 if (BitIsSet(i, run->wom)) {
1727 if (interval_start == -1) { /* bit is set and we are not in an interval */
1728 interval_start = i; /* start an interval */
1729 Dmsg1(200, "starting interval at %s\n", ordinals[i]);
1730 Mmsg(interval, ",%s", ordinals[i]);
1731 PmStrcat(temp, interval.c_str());
1732 }
1733 }
1734
1735 if (!BitIsSet(i, run->wom)) {
1736 if (interval_start != -1) { /* bit is unset and we are in an interval */
1737 if ((i - interval_start) > 1) {
1738 Dmsg2(200, "found end of interval from %s to %s\n", ordinals[interval_start], ordinals[i - 1]);
1739 Mmsg(interval, "-%s", ordinals[i - 1]);
1740 PmStrcat(temp, interval.c_str());
1741 }
1742 interval_start = -1; /* end the interval */
1743 }
1744 }
1745 }
1746
1747 /*
1748 * See if we are still in an interval and the last bit is also set then the interval stretches to the last item.
1749 */
1750 i = nr_items - 1;
1751 if (interval_start != -1 && BitIsSet(i, run->wom)) {
1752 if ((i - interval_start) > 1) {
1753 Dmsg2(200, "found end of interval from %s to %s\n", ordinals[interval_start], ordinals[i]);
1754 Mmsg(interval, "-%s", ordinals[i]);
1755 PmStrcat(temp, interval.c_str());
1756 }
1757 }
1758
1759 PmStrcat(temp, " ");
1760 PmStrcat(run_str, temp.c_str() + 1); /* jump over first comma*/
1761 }
1762
1763 /*
1764 * run->wday output is Sun, Mon, ..., Sat comma separated
1765 */
1766 all_set = true;
1767 nr_items = 7;
1768 for (i = 0; i < nr_items; i++) {
1769 if (!BitIsSet(i, run->wday)) {
1770 all_set = false;
1771 }
1772 }
1773
1774 if (!all_set) {
1775 interval_start = -1;
1776
1777 PmStrcpy(temp, "");
1778 for (i = 0; i < nr_items; i++) {
1779 if (BitIsSet(i, run->wday)) {
1780 if (interval_start == -1) { /* bit is set and we are not in an interval */
1781 interval_start = i; /* start an interval */
1782 Dmsg1(200, "starting interval at %s\n", weekdays[i]);
1783 Mmsg(interval, ",%s", weekdays[i]);
1784 PmStrcat(temp, interval.c_str());
1785 }
1786 }
1787
1788 if (!BitIsSet(i, run->wday)) {
1789 if (interval_start != -1) { /* bit is unset and we are in an interval */
1790 if ((i - interval_start) > 1) {
1791 Dmsg2(200, "found end of interval from %s to %s\n", weekdays[interval_start], weekdays[i - 1]);
1792 Mmsg(interval, "-%s", weekdays[i - 1]);
1793 PmStrcat(temp, interval.c_str());
1794 }
1795 interval_start = -1; /* end the interval */
1796 }
1797 }
1798 }
1799
1800 /*
1801 * See if we are still in an interval and the last bit is also set then the interval stretches to the last item.
1802 */
1803 i = nr_items - 1;
1804 if (interval_start != -1 && BitIsSet(i, run->wday)) {
1805 if ((i - interval_start) > 1) {
1806 Dmsg2(200, "found end of interval from %s to %s\n", weekdays[interval_start], weekdays[i]);
1807 Mmsg(interval, "-%s", weekdays[i]);
1808 PmStrcat(temp, interval.c_str());
1809 }
1810 }
1811
1812 PmStrcat(temp, " ");
1813 PmStrcat(run_str, temp.c_str() + 1); /* jump over first comma*/
1814 }
1815
1816 /*
1817 * run->month output is Jan, Feb, ..., Dec comma separated
1818 */
1819 all_set = true;
1820 nr_items = 12;
1821 for (i = 0; i < nr_items; i++) {
1822 if (!BitIsSet(i, run->month)) {
1823 all_set = false;
1824 }
1825 }
1826
1827 if (!all_set) {
1828 interval_start = -1;
1829
1830 PmStrcpy(temp, "");
1831 for (i = 0; i < nr_items; i++) {
1832 if (BitIsSet(i, run->month)) {
1833 if (interval_start == -1) { /* bit is set and we are not in an interval */
1834 interval_start = i; /* start an interval */
1835 Dmsg1(200, "starting interval at %s\n", months[i]);
1836 Mmsg(interval, ",%s", months[i]);
1837 PmStrcat(temp, interval.c_str());
1838 }
1839 }
1840
1841 if (!BitIsSet(i, run->month)) {
1842 if (interval_start != -1) { /* bit is unset and we are in an interval */
1843 if ((i - interval_start) > 1) {
1844 Dmsg2(200, "found end of interval from %s to %s\n", months[interval_start], months[i - 1]);
1845 Mmsg(interval, "-%s", months[i - 1]);
1846 PmStrcat(temp, interval.c_str());
1847 }
1848 interval_start = -1; /* end the interval */
1849 }
1850 }
1851 }
1852
1853 /*
1854 * See if we are still in an interval and the last bit is also set then the interval stretches to the last item.
1855 */
1856 i = nr_items - 1;
1857 if (interval_start != -1 && BitIsSet(i, run->month)) {
1858 if ((i - interval_start) > 1) {
1859 Dmsg2(200, "found end of interval from %s to %s\n", months[interval_start], months[i]);
1860 Mmsg(interval, "-%s", months[i]);
1861 PmStrcat(temp, interval.c_str());
1862 }
1863 }
1864
1865 PmStrcat(temp, " ");
1866 PmStrcat(run_str, temp.c_str() + 1); /* jump over first comma*/
1867 }
1868
1869 /*
1870 * run->woy output is w00 - w53, comma separated
1871 */
1872 all_set = true;
1873 nr_items = 54;
1874 for (i = 0; i < nr_items; i++) {
1875 if (!BitIsSet(i, run->woy)) {
1876 all_set = false;
1877 }
1878 }
1879
1880 if (!all_set) {
1881 interval_start = -1;
1882
1883 PmStrcpy(temp, "");
1884 for (i = 0; i < nr_items; i++) {
1885 if (BitIsSet(i, run->woy)) {
1886 if (interval_start == -1) { /* bit is set and we are not in an interval */
1887 interval_start = i; /* start an interval */
1888 Dmsg1(200, "starting interval at w%02d\n", i);
1889 Mmsg(interval, ",w%02d", i);
1890 PmStrcat(temp, interval.c_str());
1891 }
1892 }
1893
1894 if (!BitIsSet(i, run->woy)) {
1895 if (interval_start != -1) { /* bit is unset and we are in an interval */
1896 if ((i - interval_start) > 1) {
1897 Dmsg2(200, "found end of interval from w%02d to w%02d\n", interval_start, i - 1);
1898 Mmsg(interval, "-w%02d", i - 1);
1899 PmStrcat(temp, interval.c_str());
1900 }
1901 interval_start = -1; /* end the interval */
1902 }
1903 }
1904 }
1905
1906 /*
1907 * See if we are still in an interval and the last bit is also set then the interval stretches to the last item.
1908 */
1909 i = nr_items - 1;
1910 if (interval_start != -1 && BitIsSet(i, run->woy)) {
1911 if ((i - interval_start) > 1) {
1912 Dmsg2(200, "found end of interval from w%02d to w%02d\n", interval_start, i);
1913 Mmsg(interval, "-w%02d", i);
1914 PmStrcat(temp, interval.c_str());
1915 }
1916 }
1917
1918 PmStrcat(temp, " ");
1919 PmStrcat(run_str, temp.c_str() + 1); /* jump over first comma*/
1920 }
1921
1922 /*
1923 * run->hour output is HH:MM for hour and minute though its a bitfield.
1924 * only "hourly" sets all bits.
1925 */
1926 PmStrcpy(temp, "");
1927 for (i = 0; i < 24; i++) {
1928 if BitIsSet(i, run->hour) {
1929 Mmsg(temp, "at %02d:%02d\n", i, run->minute);
1930 PmStrcat(run_str, temp.c_str());
1931 }
1932 }
1933
1934 /*
1935 * run->minute output is smply the minute in HH:MM
1936 */
1937 PmStrcat(cfg_str, run_str.c_str());
1938
1939 run = run->next;
1940 } /* loop over runs */
1941 }
1942 }
1943
PrintConfig(PoolMem & buff,bool hide_sensitive_data,bool verbose)1944 bool FilesetResource::PrintConfig(PoolMem &buff, bool hide_sensitive_data, bool verbose)
1945 {
1946 PoolMem cfg_str;
1947 PoolMem temp;
1948 const char *p;
1949
1950 Dmsg0(200,"FilesetResource::PrintConfig\n");
1951
1952 Mmsg(temp, "FileSet {\n");
1953 PmStrcat(cfg_str, temp.c_str());
1954
1955 Mmsg(temp, "Name = \"%s\"\n", this->name());
1956 IndentConfigItem(cfg_str, 1, temp.c_str());
1957
1958 if (this->hdr.desc != NULL ) {
1959 Mmsg(temp, "Description = \"%s\"\n", this->hdr.desc);
1960 IndentConfigItem(cfg_str, 1, temp.c_str());
1961 }
1962
1963 if (num_includes) {
1964 /*
1965 * Loop over all exclude blocks.
1966 */
1967 for (int i = 0; i < num_includes; i++) {
1968 IncludeExcludeItem *incexe = include_items[i];
1969
1970 IndentConfigItem(cfg_str, 1, "Include {\n");
1971
1972 /*
1973 * Start options block
1974 */
1975 if (incexe->num_opts > 0) {
1976 for (int j = 0; j < incexe->num_opts; j++) {
1977 FileOptions *fo = incexe->opts_list[j];
1978
1979 IndentConfigItem(cfg_str, 2, "Options {\n");
1980 for (p = &fo->opts[0]; *p; p++) {
1981 switch (*p) {
1982 case '0': /* no option */
1983 break;
1984 case 'a': /* alway replace */
1985 IndentConfigItem(cfg_str, 3, "Replace = Always\n");
1986 break;
1987 case 'C': /* */
1988 IndentConfigItem(cfg_str, 3, "Accurate = ");
1989 p++; /* skip C */
1990 for (; *p && *p != ':'; p++) {
1991 Mmsg(temp, "%c", *p);
1992 PmStrcat(cfg_str, temp.c_str());
1993 }
1994 PmStrcat(cfg_str, "\n");
1995 break;
1996 case 'c':
1997 IndentConfigItem(cfg_str, 3, "CheckFileChanges = Yes\n");
1998 break;
1999 case 'd':
2000 switch(*(p + 1)) {
2001 case '1':
2002 IndentConfigItem(cfg_str, 3, "Shadowing = LocalWarn\n");
2003 p++;
2004 break;
2005 case '2':
2006 IndentConfigItem(cfg_str, 3, "Shadowing = LocalRemove\n");
2007 p++;
2008 break;
2009 case '3':
2010 IndentConfigItem(cfg_str, 3, "Shadowing = GlobalWarn\n");
2011 p++;
2012 break;
2013 case '4':
2014 IndentConfigItem(cfg_str, 3, "Shadowing = GlobalRemove\n");
2015 p++;
2016 break;
2017 }
2018 break;
2019 case 'e':
2020 IndentConfigItem(cfg_str, 3, "Exclude = Yes\n");
2021 break;
2022 case 'f':
2023 IndentConfigItem(cfg_str, 3, "OneFS = No\n");
2024 break;
2025 case 'h': /* no recursion */
2026 IndentConfigItem(cfg_str, 3, "Recurse = No\n");
2027 break;
2028 case 'H': /* no hard link handling */
2029 IndentConfigItem(cfg_str, 3, "Hardlinks = No\n");
2030 break;
2031 case 'i':
2032 IndentConfigItem(cfg_str, 3, "IgnoreCase = Yes\n");
2033 break;
2034 case 'J': /* Base Job */
2035 IndentConfigItem(cfg_str, 3, "BaseJob = ");
2036 p++; /* skip J */
2037 for (; *p && *p != ':'; p++) {
2038 Mmsg(temp, "%c", *p);
2039 PmStrcat(cfg_str, temp.c_str());
2040 }
2041 PmStrcat(cfg_str, "\n");
2042 break;
2043 case 'M': /* MD5 */
2044 IndentConfigItem(cfg_str, 3, "Signature = MD5\n");
2045 break;
2046 case 'n':
2047 IndentConfigItem(cfg_str, 3, "Replace = Never\n");
2048 break;
2049 case 'p': /* use portable data format */
2050 IndentConfigItem(cfg_str, 3, "Portable = Yes\n");
2051 break;
2052 case 'P': /* strip path */
2053 IndentConfigItem(cfg_str, 3, "Strip = ");
2054 p++; /* skip P */
2055 for (; *p && *p != ':'; p++) {
2056 Mmsg(temp, "%c", *p);
2057 PmStrcat(cfg_str, temp.c_str());
2058 }
2059 PmStrcat(cfg_str, "\n");
2060 break;
2061 case 'R': /* Resource forks and Finder Info */
2062 IndentConfigItem(cfg_str, 3, "HFSPlusSupport = Yes\n");
2063 break;
2064 case 'r': /* read fifo */
2065 IndentConfigItem(cfg_str, 3, "ReadFifo = Yes\n");
2066 break;
2067 case 'S':
2068 switch(*(p + 1)) {
2069 #ifdef HAVE_SHA2
2070 case '2':
2071 IndentConfigItem(cfg_str, 3, "Signature = SHA256\n");
2072 p++;
2073 break;
2074 case '3':
2075 IndentConfigItem(cfg_str, 3, "Signature = SHA512\n");
2076 p++;
2077 break;
2078 #endif
2079 default:
2080 IndentConfigItem(cfg_str, 3, "Signature = SHA1\n");
2081 break;
2082 }
2083 break;
2084 case 's':
2085 IndentConfigItem(cfg_str, 3, "Sparse = Yes\n");
2086 break;
2087 case 'm':
2088 IndentConfigItem(cfg_str, 3, "MtimeOnly = Yes\n");
2089 break;
2090 case 'k':
2091 IndentConfigItem(cfg_str, 3, "KeepAtime = Yes\n");
2092 break;
2093 case 'K':
2094 IndentConfigItem(cfg_str, 3, "NoAtime = Yes\n");
2095 break;
2096 case 'A':
2097 IndentConfigItem(cfg_str, 3, "AclSupport = Yes\n");
2098 break;
2099 case 'V': /* verify options */
2100 IndentConfigItem(cfg_str, 3, "Verify = ");
2101 p++; /* skip V */
2102 for (; *p && *p != ':'; p++) {
2103 Mmsg(temp, "%c", *p);
2104 PmStrcat(cfg_str, temp.c_str());
2105 }
2106 PmStrcat(cfg_str, "\n");
2107 break;
2108 case 'w':
2109 IndentConfigItem(cfg_str, 3, "Replace = IfNewer\n");
2110 break;
2111 case 'W':
2112 IndentConfigItem(cfg_str, 3, "EnhancedWild = Yes\n");
2113 break;
2114 case 'z': /* size */
2115 IndentConfigItem(cfg_str, 3, "Size = ");
2116 p++; /* skip z */
2117 for (; *p && *p != ':'; p++) {
2118 Mmsg(temp, "%c", *p);
2119 PmStrcat(cfg_str, temp.c_str());
2120 }
2121 PmStrcat(cfg_str, "\n");
2122 break;
2123 case 'Z': /* compression */
2124 IndentConfigItem(cfg_str, 3, "Compression = ");
2125 p++; /* skip Z */
2126 switch (*p) {
2127 case '0':
2128 case '1':
2129 case '2':
2130 case '3':
2131 case '4':
2132 case '5':
2133 case '6':
2134 case '7':
2135 case '8':
2136 case '9':
2137 Mmsg(temp, "GZIP%c\n", *p);
2138 PmStrcat(cfg_str, temp.c_str());
2139 break;
2140 case 'o':
2141 Mmsg(temp, "LZO\n");
2142 PmStrcat(cfg_str, temp.c_str());
2143 break;
2144 case 'f':
2145 p++; /* skip f */
2146 switch (*p) {
2147 case 'f':
2148 Mmsg(temp, "LZFAST\n");
2149 PmStrcat(cfg_str, temp.c_str());
2150 break;
2151 case '4':
2152 Mmsg(temp, "LZ4\n");
2153 PmStrcat(cfg_str, temp.c_str());
2154 break;
2155 case 'h':
2156 Mmsg(temp, "LZ4HC\n");
2157 PmStrcat(cfg_str, temp.c_str());
2158 break;
2159 default:
2160 Emsg1(M_ERROR, 0, _("Unknown compression include/exclude option: %c\n"), *p);
2161 break;
2162 }
2163 break;
2164 default:
2165 Emsg1(M_ERROR, 0, _("Unknown compression include/exclude option: %c\n"), *p);
2166 break;
2167 }
2168 break;
2169 case 'X':
2170 IndentConfigItem(cfg_str, 3, "XattrSupport = Yes\n");
2171 break;
2172 case 'x':
2173 IndentConfigItem(cfg_str, 3, "AutoExclude = No\n");
2174 break;
2175 default:
2176 Emsg1(M_ERROR, 0, _("Unknown include/exclude option: %c\n"), *p);
2177 break;
2178 }
2179 }
2180
2181 for (int k = 0; k < fo->regex.size(); k++) {
2182 Mmsg(temp, "Regex = \"%s\"\n", fo->regex.get(k));
2183 IndentConfigItem(cfg_str, 3, temp.c_str());
2184 }
2185
2186 for (int k = 0; k < fo->regexdir.size(); k++) {
2187 Mmsg(temp, "Regex Dir = \"%s\"\n", fo->regexdir.get(k));
2188 IndentConfigItem(cfg_str, 3, temp.c_str());
2189 }
2190
2191 for (int k = 0; k < fo->regexfile.size(); k++) {
2192 Mmsg(temp, "Regex File = \"%s\"\n", fo->regexfile.get(k));
2193 IndentConfigItem(cfg_str, 3, temp.c_str());
2194 }
2195
2196 for (int k = 0; k < fo->wild.size(); k++) {
2197 Mmsg(temp, "Wild = \"%s\"\n", fo->wild.get(k));
2198 IndentConfigItem(cfg_str, 3, temp.c_str());
2199 }
2200
2201 for (int k = 0; k < fo->wilddir.size(); k++) {
2202 Mmsg(temp, "Wild Dir = \"%s\"\n", fo->wilddir.get(k));
2203 IndentConfigItem(cfg_str, 3, temp.c_str());
2204 }
2205
2206 for (int k = 0; k < fo->wildfile.size(); k++) {
2207 Mmsg(temp, "Wild File = \"%s\"\n", fo->wildfile.get(k));
2208 IndentConfigItem(cfg_str, 3, temp.c_str());
2209 }
2210
2211 /*
2212 * Wildbase is WildFile not containing a / or \\
2213 * see void StoreWild() in inc_conf.c
2214 * so we need to translate it back to a Wild File entry
2215 */
2216 for (int k = 0; k < fo->wildbase.size(); k++) {
2217 Mmsg(temp, "Wild File = \"%s\"\n", fo->wildbase.get(k));
2218 IndentConfigItem(cfg_str, 3, temp.c_str());
2219 }
2220
2221 for (int k = 0; k < fo->base.size(); k++) {
2222 Mmsg(temp, "Base = \"%s\"\n", fo->base.get(k));
2223 IndentConfigItem(cfg_str, 3, temp.c_str());
2224 }
2225
2226 for (int k = 0; k < fo->fstype.size(); k++) {
2227 Mmsg(temp, "Fs Type = \"%s\"\n", fo->fstype.get(k));
2228 IndentConfigItem(cfg_str, 3, temp.c_str());
2229 }
2230
2231 for (int k = 0; k < fo->Drivetype.size(); k++) {
2232 Mmsg(temp, "Drive Type = \"%s\"\n", fo->Drivetype.get(k));
2233 IndentConfigItem(cfg_str, 3, temp.c_str());
2234 }
2235
2236 for (int k = 0; k < fo->meta.size(); k++) {
2237 Mmsg(temp, "Meta = \"%s\"\n", fo->meta.get(k));
2238 IndentConfigItem(cfg_str, 3, temp.c_str());
2239 }
2240
2241 if (fo->plugin) {
2242 Mmsg(temp, "Plugin = \"%s\"\n", fo->plugin);
2243 IndentConfigItem(cfg_str, 3, temp.c_str());
2244 }
2245
2246 if (fo->reader) {
2247 Mmsg(temp, "Reader = \"%s\"\n", fo->reader);
2248 IndentConfigItem(cfg_str, 3, temp.c_str());
2249 }
2250
2251 if (fo->writer) {
2252 Mmsg(temp, "Writer = \"%s\"\n", fo->writer);
2253 IndentConfigItem(cfg_str, 3, temp.c_str());
2254 }
2255
2256 IndentConfigItem(cfg_str, 2, "}\n");
2257 }
2258 } /* end options block */
2259
2260 /*
2261 * File = entries.
2262 */
2263 if (incexe->name_list.size()) {
2264 char *entry;
2265 PoolMem esc;
2266
2267 for (int l = 0; l < incexe->name_list.size(); l++) {
2268 entry = (char *)incexe->name_list.get(l);
2269 EscapeString(esc, entry, strlen(entry));
2270 Mmsg(temp, "File = \"%s\"\n", esc.c_str());
2271 IndentConfigItem(cfg_str, 2, temp.c_str());
2272 }
2273 }
2274
2275 /*
2276 * Plugin = entries.
2277 */
2278 if (incexe->plugin_list.size()) {
2279 char *entry;
2280 PoolMem esc;
2281
2282 for (int l = 0; l < incexe->plugin_list.size(); l++) {
2283 entry = (char *)incexe->plugin_list.get(l);
2284 EscapeString(esc, entry, strlen(entry));
2285 Mmsg(temp, "Plugin = \"%s\"\n", esc.c_str());
2286 IndentConfigItem(cfg_str, 2, temp.c_str());
2287 }
2288 }
2289
2290 /*
2291 * Exclude Dir Containing = entry.
2292 */
2293 if (incexe->ignoredir.size()) {
2294 for (int l = 0; l < incexe->ignoredir.size(); l++) {
2295 Mmsg(temp, "Exclude Dir Containing = \"%s\"\n", incexe->ignoredir.get(l));
2296 IndentConfigItem(cfg_str, 2, temp.c_str());
2297 }
2298 }
2299
2300 IndentConfigItem(cfg_str, 1, "}\n");
2301
2302 /*
2303 * End Include block
2304 */
2305 } /* loop over all include blocks */
2306 }
2307
2308 if (num_excludes) {
2309 /*
2310 * Loop over all exclude blocks.
2311 */
2312 for (int j = 0; j < num_excludes; j++) {
2313 IncludeExcludeItem *incexe = exclude_items[j];
2314
2315 if (incexe->name_list.size()) {
2316 char *entry;
2317 PoolMem esc;
2318
2319 IndentConfigItem(cfg_str, 1, "Exclude {\n");
2320 for (int k = 0; k < incexe->name_list.size(); k++) {
2321 entry = (char *)incexe->name_list.get(k);
2322 EscapeString(esc, entry, strlen(entry));
2323 Mmsg(temp, "File = \"%s\"\n", esc.c_str());
2324 IndentConfigItem(cfg_str, 2, temp.c_str());
2325 }
2326
2327 IndentConfigItem(cfg_str, 1, "}\n");
2328 }
2329 } /* loop over all exclude blocks */
2330 }
2331
2332 PmStrcat(cfg_str, "}\n\n");
2333 PmStrcat(buff, cfg_str.c_str());
2334
2335 return true;
2336 }
2337
auth_protocol_to_str(uint32_t auth_protocol)2338 const char *auth_protocol_to_str(uint32_t auth_protocol)
2339 {
2340 for (int i = 0; authprotocols[i].name; i++) {
2341 if (authprotocols[i].token == auth_protocol) {
2342 return authprotocols[i].name;
2343 }
2344 }
2345
2346 return "Unknown";
2347 }
2348
level_to_str(int level)2349 const char *level_to_str(int level)
2350 {
2351 static char level_no[30];
2352 const char *str = level_no;
2353
2354 Bsnprintf(level_no, sizeof(level_no), "%c (%d)", level, level); /* default if not found */
2355 for (int i = 0; joblevels[i].level_name; i++) {
2356 if (level == (int)joblevels[i].level) {
2357 str = joblevels[i].level_name;
2358 break;
2359 }
2360 }
2361
2362 return str;
2363 }
2364
2365 /**
2366 * Free all the members of an IncludeExcludeItem structure
2367 */
FreeIncexe(IncludeExcludeItem * incexe)2368 static void FreeIncexe(IncludeExcludeItem *incexe)
2369 {
2370 incexe->name_list.destroy();
2371 incexe->plugin_list.destroy();
2372 for (int i = 0; i < incexe->num_opts; i++) {
2373 FileOptions *fopt = incexe->opts_list[i];
2374 fopt->regex.destroy();
2375 fopt->regexdir.destroy();
2376 fopt->regexfile.destroy();
2377 fopt->wild.destroy();
2378 fopt->wilddir.destroy();
2379 fopt->wildfile.destroy();
2380 fopt->wildbase.destroy();
2381 fopt->base.destroy();
2382 fopt->fstype.destroy();
2383 fopt->Drivetype.destroy();
2384 fopt->meta.destroy();
2385 if (fopt->plugin) {
2386 free(fopt->plugin);
2387 }
2388 if (fopt->reader) {
2389 free(fopt->reader);
2390 }
2391 if (fopt->writer) {
2392 free(fopt->writer);
2393 }
2394 free(fopt);
2395 }
2396 if (incexe->opts_list) {
2397 free(incexe->opts_list);
2398 }
2399 incexe->ignoredir.destroy();
2400 free(incexe);
2401 }
2402
UpdateResourcePointer(int type,ResourceItem * items)2403 static bool UpdateResourcePointer(int type, ResourceItem *items)
2404 {
2405 UnionOfResources *res;
2406 bool result = true;
2407
2408 switch (type) {
2409 case R_PROFILE:
2410 case R_CATALOG:
2411 case R_MSGS:
2412 case R_FILESET:
2413 case R_DEVICE:
2414 /*
2415 * Resources not containing a resource
2416 */
2417 break;
2418 case R_POOL:
2419 /*
2420 * Resources containing another resource or alist. First
2421 * look up the resource which contains another resource. It
2422 * was written during pass 1. Then stuff in the pointers to
2423 * the resources it contains, which were inserted this pass.
2424 * Finally, it will all be stored back.
2425 *
2426 * Find resource saved in pass 1
2427 */
2428 if (!(res = (UnionOfResources *)my_config->GetResWithName(R_POOL, res_all.res_pool.name()))) {
2429 Emsg1(M_ERROR, 0, _("Cannot find Pool resource %s\n"), res_all.res_pool.name());
2430 return false;
2431 } else {
2432 /*
2433 * Explicitly copy resource pointers from this pass (res_all)
2434 */
2435 res->res_pool.NextPool = res_all.res_pool.NextPool;
2436 res->res_pool.RecyclePool = res_all.res_pool.RecyclePool;
2437 res->res_pool.ScratchPool = res_all.res_pool.ScratchPool;
2438 res->res_pool.storage = res_all.res_pool.storage;
2439 if (res_all.res_pool.catalog || !res->res_pool.use_catalog) {
2440 res->res_pool.catalog = res_all.res_pool.catalog;
2441 }
2442 }
2443 break;
2444 case R_CONSOLE:
2445 if (!(res = (UnionOfResources *)my_config->GetResWithName(R_CONSOLE, res_all.res_con.name()))) {
2446 Emsg1(M_ERROR, 0, _("Cannot find Console resource %s\n"), res_all.res_con.name());
2447 return false;
2448 } else {
2449 res->res_con.tls_cert_.allowed_certificate_common_names_ =
2450 res_all.res_con.tls_cert_.allowed_certificate_common_names_;
2451 res->res_con.profiles = res_all.res_con.profiles;
2452 }
2453 break;
2454 case R_DIRECTOR:
2455 if (!(res = (UnionOfResources *)my_config->GetResWithName(R_DIRECTOR, res_all.res_dir.name()))) {
2456 Emsg1(M_ERROR, 0, _("Cannot find Director resource %s\n"), res_all.res_dir.name());
2457 return false;
2458 } else {
2459 res->res_dir.plugin_names = res_all.res_dir.plugin_names;
2460 res->res_dir.messages = res_all.res_dir.messages;
2461 res->res_dir.backend_directories = res_all.res_dir.backend_directories;
2462 res->res_dir.tls_cert_.allowed_certificate_common_names_ =
2463 res_all.res_dir.tls_cert_.allowed_certificate_common_names_;
2464 }
2465 break;
2466 case R_STORAGE:
2467 if (!(res = (UnionOfResources *)my_config->GetResWithName(type, res_all.res_store.name()))) {
2468 Emsg1(M_ERROR, 0, _("Cannot find Storage resource %s\n"), res_all.res_dir.name());
2469 return false;
2470 } else {
2471 int status;
2472
2473 res->res_store.paired_storage = res_all.res_store.paired_storage;
2474 res->res_store.tls_cert_.allowed_certificate_common_names_ =
2475 res_all.res_store.tls_cert_.allowed_certificate_common_names_;
2476
2477 /*
2478 * We must explicitly copy the device alist pointer
2479 */
2480 res->res_store.device = res_all.res_store.device;
2481
2482 res->res_store.rss = (runtime_storage_status_t *)malloc(sizeof(runtime_storage_status_t));
2483 memset(res->res_store.rss, 0, sizeof(runtime_storage_status_t));
2484 if ((status = pthread_mutex_init(&res->res_store.rss->changer_lock, NULL)) != 0) {
2485 BErrNo be;
2486
2487 Emsg1(M_ERROR_TERM, 0, _("pthread_mutex_init: ERR=%s\n"), be.bstrerror(status));
2488 }
2489 if ((status = pthread_mutex_init(&res->res_store.rss->ndmp_deviceinfo_lock, NULL)) != 0) {
2490 BErrNo be;
2491
2492 Emsg1(M_ERROR_TERM, 0, _("pthread_mutex_init: ERR=%s\n"), be.bstrerror(status));
2493 }
2494
2495 }
2496 break;
2497 case R_JOBDEFS:
2498 case R_JOB:
2499 if (!(res = (UnionOfResources *)my_config->GetResWithName(type, res_all.res_job.name()))) {
2500 Emsg1(M_ERROR, 0, _("Cannot find Job resource %s\n"), res_all.res_job.name());
2501 return false;
2502 } else {
2503 res->res_job.messages = res_all.res_job.messages;
2504 res->res_job.schedule = res_all.res_job.schedule;
2505 res->res_job.client = res_all.res_job.client;
2506 res->res_job.fileset = res_all.res_job.fileset;
2507 res->res_job.storage = res_all.res_job.storage;
2508 res->res_job.catalog = res_all.res_job.catalog;
2509 res->res_job.FdPluginOptions = res_all.res_job.FdPluginOptions;
2510 res->res_job.SdPluginOptions = res_all.res_job.SdPluginOptions;
2511 res->res_job.DirPluginOptions = res_all.res_job.DirPluginOptions;
2512 res->res_job.base = res_all.res_job.base;
2513 res->res_job.pool = res_all.res_job.pool;
2514 res->res_job.full_pool = res_all.res_job.full_pool;
2515 res->res_job.vfull_pool = res_all.res_job.vfull_pool;
2516 res->res_job.inc_pool = res_all.res_job.inc_pool;
2517 res->res_job.diff_pool = res_all.res_job.diff_pool;
2518 res->res_job.next_pool = res_all.res_job.next_pool;
2519 res->res_job.verify_job = res_all.res_job.verify_job;
2520 res->res_job.jobdefs = res_all.res_job.jobdefs;
2521 res->res_job.run_cmds = res_all.res_job.run_cmds;
2522 res->res_job.RunScripts = res_all.res_job.RunScripts;
2523
2524 /*
2525 * TODO: JobDefs where/regexwhere doesn't work well (but this is not very useful)
2526 * We have to SetBit(index, res_all.hdr.item_present); or something like that
2527 *
2528 * We take RegexWhere before all other options
2529 */
2530 if (!res->res_job.RegexWhere &&
2531 (res->res_job.strip_prefix ||
2532 res->res_job.add_suffix ||
2533 res->res_job.add_prefix)) {
2534 int len = BregexpGetBuildWhereSize(res->res_job.strip_prefix,
2535 res->res_job.add_prefix,
2536 res->res_job.add_suffix);
2537 res->res_job.RegexWhere = (char *) bmalloc (len * sizeof(char));
2538 bregexp_build_where(res->res_job.RegexWhere, len,
2539 res->res_job.strip_prefix,
2540 res->res_job.add_prefix,
2541 res->res_job.add_suffix);
2542 /*
2543 * TODO: test bregexp
2544 */
2545 }
2546
2547 if (res->res_job.RegexWhere && res->res_job.RestoreWhere) {
2548 free(res->res_job.RestoreWhere);
2549 res->res_job.RestoreWhere = NULL;
2550 }
2551
2552 if (type == R_JOB) {
2553 res->res_job.rjs = (runtime_job_status_t *)malloc(sizeof(runtime_job_status_t));
2554 memset(res->res_job.rjs, 0, sizeof(runtime_job_status_t));
2555 }
2556 }
2557 break;
2558 case R_COUNTER:
2559 if (!(res = (UnionOfResources *)my_config->GetResWithName(R_COUNTER, res_all.res_counter.name()))) {
2560 Emsg1(M_ERROR, 0, _("Cannot find Counter resource %s\n"), res_all.res_counter.name());
2561 return false;
2562 } else {
2563 res->res_counter.Catalog = res_all.res_counter.Catalog;
2564 res->res_counter.WrapCounter = res_all.res_counter.WrapCounter;
2565 }
2566 break;
2567 case R_CLIENT:
2568 if (!(res = (UnionOfResources *)my_config->GetResWithName(R_CLIENT, res_all.res_client.name()))) {
2569 Emsg1(M_ERROR, 0, _("Cannot find Client resource %s\n"), res_all.res_client.name());
2570 return false;
2571 } else {
2572 if (res_all.res_client.catalog) {
2573 res->res_client.catalog = res_all.res_client.catalog;
2574 } else {
2575 /*
2576 * No catalog overwrite given use the first catalog definition.
2577 */
2578 res->res_client.catalog = (CatalogResource *)my_config->GetNextRes(R_CATALOG, NULL);
2579 }
2580 res->res_client.tls_cert_.allowed_certificate_common_names_ =
2581 res_all.res_client.tls_cert_.allowed_certificate_common_names_;
2582
2583 res->res_client.rcs = (runtime_client_status_t *)malloc(sizeof(runtime_client_status_t));
2584 memset(res->res_client.rcs, 0, sizeof(runtime_client_status_t));
2585 }
2586 break;
2587 case R_SCHEDULE:
2588 /*
2589 * Schedule is a bit different in that it contains a RunResource record
2590 * chain which isn't a "named" resource. This chain was linked
2591 * in by run_conf.c during pass 2, so here we jam the pointer
2592 * into the Schedule resource.
2593 */
2594 if (!(res = (UnionOfResources *)my_config->GetResWithName(R_SCHEDULE, res_all.res_client.name()))) {
2595 Emsg1(M_ERROR, 0, _("Cannot find Schedule resource %s\n"), res_all.res_client.name());
2596 return false;
2597 } else {
2598 res->res_sch.run = res_all.res_sch.run;
2599 }
2600 break;
2601 default:
2602 Emsg1(M_ERROR, 0, _("Unknown resource type %d in SaveResource.\n"), type);
2603 result = false;
2604 break;
2605 }
2606
2607 /*
2608 * Note, the resource name was already saved during pass 1,
2609 * so here, we can just release it.
2610 */
2611 if (res_all.res_dir.hdr.name) {
2612 free(res_all.res_dir.hdr.name);
2613 res_all.res_dir.hdr.name = NULL;
2614 }
2615
2616 if (res_all.res_dir.hdr.desc) {
2617 free(res_all.res_dir.hdr.desc);
2618 res_all.res_dir.hdr.desc = NULL;
2619 }
2620
2621 return result;
2622 }
2623
PropagateJobdefs(int res_type,JobResource * res)2624 bool PropagateJobdefs(int res_type, JobResource *res)
2625 {
2626 JobResource *jobdefs = NULL;
2627
2628 if (!res->jobdefs) {
2629 return true;
2630 }
2631
2632 /*
2633 * Don't allow the JobDefs pointing to itself.
2634 */
2635 if (res->jobdefs == res) {
2636 return false;
2637 }
2638
2639 if (res_type == R_JOB) {
2640 jobdefs = res->jobdefs;
2641
2642 /*
2643 * Handle RunScripts alists specifically
2644 */
2645 if (jobdefs->RunScripts) {
2646 RunScript *rs = nullptr, *elt;
2647
2648 if (!res->RunScripts) {
2649 res->RunScripts = New(alist(10, not_owned_by_alist));
2650 }
2651
2652 foreach_alist(rs, jobdefs->RunScripts) {
2653 elt = copy_runscript(rs);
2654 elt->from_jobdef = true;
2655 res->RunScripts->append(elt); /* we have to free it */
2656 }
2657 }
2658 }
2659
2660 /*
2661 * Transfer default items from JobDefs Resource
2662 */
2663 PropagateResource(job_items, res->jobdefs, res);
2664
2665 return true;
2666 }
2667
2668 /**
2669 * Populate Job Defaults (e.g. JobDefs)
2670 */
populate_jobdefs()2671 static inline bool populate_jobdefs()
2672 {
2673 JobResource *job, *jobdefs;
2674 bool retval = true;
2675
2676 /*
2677 * Propagate the content of a JobDefs to another.
2678 */
2679 foreach_res(jobdefs, R_JOBDEFS) {
2680 PropagateJobdefs(R_JOBDEFS, jobdefs);
2681 }
2682
2683 /*
2684 * Propagate the content of the JobDefs to the actual Job.
2685 */
2686 foreach_res(job, R_JOB) {
2687 PropagateJobdefs(R_JOB, job);
2688
2689 /*
2690 * Ensure that all required items are present
2691 */
2692 if (!ValidateResource(R_JOB, job_items, job)) {
2693 retval = false;
2694 goto bail_out;
2695 }
2696
2697 } /* End loop over Job res */
2698
2699 bail_out:
2700 return retval;
2701 }
2702
PopulateDefs()2703 bool PopulateDefs()
2704 {
2705 return populate_jobdefs();
2706 }
2707
StorePooltype(LEX * lc,ResourceItem * item,int index,int pass)2708 static void StorePooltype(LEX *lc, ResourceItem *item, int index, int pass)
2709 {
2710 int i;
2711
2712 LexGetToken(lc, BCT_NAME);
2713 if (pass == 1) {
2714 for (i = 0; PoolTypes[i].name; i++) {
2715 if (Bstrcasecmp(lc->str, PoolTypes[i].name)) {
2716 /*
2717 * If a default was set free it first.
2718 */
2719 if (*(item->value)) {
2720 free(*(item->value));
2721 }
2722 *(item->value) = bstrdup(PoolTypes[i].name);
2723 i = 0;
2724 break;
2725 }
2726 }
2727
2728 if (i != 0) {
2729 scan_err1(lc, _("Expected a Pool Type option, got: %s"), lc->str);
2730 }
2731 }
2732
2733 ScanToEol(lc);
2734 SetBit(index, res_all.hdr.item_present);
2735 ClearBit(index, res_all.hdr.inherit_content);
2736 }
2737
StoreActiononpurge(LEX * lc,ResourceItem * item,int index,int pass)2738 static void StoreActiononpurge(LEX *lc, ResourceItem *item, int index, int pass)
2739 {
2740 int i;
2741 uint32_t *destination = item->ui32value;
2742
2743 LexGetToken(lc, BCT_NAME);
2744 /*
2745 * Store the type both in pass 1 and pass 2
2746 * Scan ActionOnPurge options
2747 */
2748 for (i = 0; ActionOnPurgeOptions[i].name; i++) {
2749 if (Bstrcasecmp(lc->str, ActionOnPurgeOptions[i].name)) {
2750 *destination = (*destination) | ActionOnPurgeOptions[i].token;
2751 i = 0;
2752 break;
2753 }
2754 }
2755
2756 if (i != 0) {
2757 scan_err1(lc, _("Expected an Action On Purge option, got: %s"), lc->str);
2758 }
2759
2760 ScanToEol(lc);
2761 SetBit(index, res_all.hdr.item_present);
2762 ClearBit(index, res_all.hdr.inherit_content);
2763 }
2764
2765 /**
2766 * Store Device. Note, the resource is created upon the
2767 * first reference. The details of the resource are obtained
2768 * later from the SD.
2769 */
StoreDevice(LEX * lc,ResourceItem * item,int index,int pass)2770 static void StoreDevice(LEX *lc, ResourceItem *item, int index, int pass)
2771 {
2772 UnionOfResources *res;
2773 int rindex = R_DEVICE - R_FIRST;
2774 bool found = false;
2775
2776 if (pass == 1) {
2777 LexGetToken(lc, BCT_NAME);
2778 if (!res_head[rindex]) {
2779 res = (UnionOfResources *)malloc(resources[rindex].size);
2780 memset(res, 0, resources[rindex].size);
2781 res->res_dev.hdr.name = bstrdup(lc->str);
2782 res_head[rindex] = (CommonResourceHeader *)res; /* store first entry */
2783 Dmsg3(900, "Inserting first %s res: %s index=%d\n", my_config->res_to_str(R_DEVICE), res->res_dir.name(),
2784 rindex);
2785 } else {
2786 CommonResourceHeader *next;
2787 /*
2788 * See if it is already defined
2789 */
2790 for (next = res_head[rindex]; next->next; next = next->next) {
2791 if (bstrcmp(next->name, lc->str)) {
2792 found = true;
2793 break;
2794 }
2795 }
2796 if (!found) {
2797 res = (UnionOfResources *)malloc(resources[rindex].size);
2798 memset(res, 0, resources[rindex].size);
2799 res->res_dev.hdr.name = bstrdup(lc->str);
2800 next->next = (CommonResourceHeader *)res;
2801 Dmsg4(900, "Inserting %s res: %s index=%d pass=%d\n", my_config->res_to_str(R_DEVICE),
2802 res->res_dir.name(), rindex, pass);
2803 }
2804 }
2805
2806 ScanToEol(lc);
2807 SetBit(index, res_all.hdr.item_present);
2808 ClearBit(index, res_all.hdr.inherit_content);
2809 } else {
2810 my_config->StoreResource(CFG_TYPE_ALIST_RES, lc, item, index, pass);
2811 }
2812 }
2813
2814 /**
2815 * Store Migration/Copy type
2816 */
StoreMigtype(LEX * lc,ResourceItem * item,int index,int pass)2817 static void StoreMigtype(LEX *lc, ResourceItem *item, int index, int pass)
2818 {
2819 int i;
2820
2821 LexGetToken(lc, BCT_NAME);
2822 /*
2823 * Store the type both in pass 1 and pass 2
2824 */
2825 for (i = 0; migtypes[i].type_name; i++) {
2826 if (Bstrcasecmp(lc->str, migtypes[i].type_name)) {
2827 *(item->ui32value) = migtypes[i].job_type;
2828 i = 0;
2829 break;
2830 }
2831 }
2832
2833 if (i != 0) {
2834 scan_err1(lc, _("Expected a Migration Job Type keyword, got: %s"), lc->str);
2835 }
2836
2837 ScanToEol(lc);
2838 SetBit(index, res_all.hdr.item_present);
2839 ClearBit(index, res_all.hdr.inherit_content);
2840 }
2841
2842 /**
2843 * Store JobType (backup, verify, restore)
2844 */
StoreJobtype(LEX * lc,ResourceItem * item,int index,int pass)2845 static void StoreJobtype(LEX *lc, ResourceItem *item, int index, int pass)
2846 {
2847 int i;
2848
2849 LexGetToken(lc, BCT_NAME);
2850 /*
2851 * Store the type both in pass 1 and pass 2
2852 */
2853 for (i = 0; jobtypes[i].type_name; i++) {
2854 if (Bstrcasecmp(lc->str, jobtypes[i].type_name)) {
2855 *(item->ui32value) = jobtypes[i].job_type;
2856 i = 0;
2857 break;
2858 }
2859 }
2860
2861 if (i != 0) {
2862 scan_err1(lc, _("Expected a Job Type keyword, got: %s"), lc->str);
2863 }
2864
2865 ScanToEol(lc);
2866 SetBit(index, res_all.hdr.item_present);
2867 ClearBit(index, res_all.hdr.inherit_content);
2868 }
2869
2870 /**
2871 * Store Protocol (Native, NDMP/NDMP_BAREOS, NDMP_NATIVE)
2872 */
StoreProtocoltype(LEX * lc,ResourceItem * item,int index,int pass)2873 static void StoreProtocoltype(LEX *lc, ResourceItem *item, int index, int pass)
2874 {
2875 int i;
2876
2877 LexGetToken(lc, BCT_NAME);
2878 /*
2879 * Store the type both in pass 1 and pass 2
2880 */
2881 for (i = 0; backupprotocols[i].name; i++) {
2882 if (Bstrcasecmp(lc->str, backupprotocols[i].name)) {
2883 *(item->ui32value) = backupprotocols[i].token;
2884 i = 0;
2885 break;
2886 }
2887 }
2888
2889 if (i != 0) {
2890 scan_err1(lc, _("Expected a Protocol Type keyword, got: %s"), lc->str);
2891 }
2892
2893 ScanToEol(lc);
2894 SetBit(index, res_all.hdr.item_present);
2895 ClearBit(index, res_all.hdr.inherit_content);
2896 }
2897
StoreReplace(LEX * lc,ResourceItem * item,int index,int pass)2898 static void StoreReplace(LEX *lc, ResourceItem *item, int index, int pass)
2899 {
2900 int i;
2901
2902 LexGetToken(lc, BCT_NAME);
2903 /*
2904 * Scan Replacement options
2905 */
2906 for (i = 0; ReplaceOptions[i].name; i++) {
2907 if (Bstrcasecmp(lc->str, ReplaceOptions[i].name)) {
2908 *(item->ui32value) = ReplaceOptions[i].token;
2909 i = 0;
2910 break;
2911 }
2912 }
2913
2914 if (i != 0) {
2915 scan_err1(lc, _("Expected a Restore replacement option, got: %s"), lc->str);
2916 }
2917
2918 ScanToEol(lc);
2919 SetBit(index, res_all.hdr.item_present);
2920 ClearBit(index, res_all.hdr.inherit_content);
2921 }
2922
2923 /**
2924 * Store Auth Protocol (Native, NDMPv2, NDMPv3, NDMPv4)
2925 */
StoreAuthprotocoltype(LEX * lc,ResourceItem * item,int index,int pass)2926 static void StoreAuthprotocoltype(LEX *lc, ResourceItem *item, int index, int pass)
2927 {
2928 int i;
2929
2930 LexGetToken(lc, BCT_NAME);
2931 /*
2932 * Store the type both in pass 1 and pass 2
2933 */
2934 for (i = 0; authprotocols[i].name; i++) {
2935 if (Bstrcasecmp(lc->str, authprotocols[i].name)) {
2936 *(item->ui32value) = authprotocols[i].token;
2937 i = 0;
2938 break;
2939 }
2940 }
2941
2942 if (i != 0) {
2943 scan_err1(lc, _("Expected a Auth Protocol Type keyword, got: %s"), lc->str);
2944 }
2945 ScanToEol(lc);
2946 SetBit(index, res_all.hdr.item_present);
2947 ClearBit(index, res_all.hdr.inherit_content);
2948 }
2949
2950 /**
2951 * Store authentication type (Mostly for NDMP like clear or MD5).
2952 */
StoreAuthtype(LEX * lc,ResourceItem * item,int index,int pass)2953 static void StoreAuthtype(LEX *lc, ResourceItem *item, int index, int pass)
2954 {
2955 int i;
2956
2957 LexGetToken(lc, BCT_NAME);
2958 /*
2959 * Store the type both in pass 1 and pass 2
2960 */
2961 for (i = 0; authmethods[i].name; i++) {
2962 if (Bstrcasecmp(lc->str, authmethods[i].name)) {
2963 *(item->ui32value) = authmethods[i].token;
2964 i = 0;
2965 break;
2966 }
2967 }
2968
2969 if (i != 0) {
2970 scan_err1(lc, _("Expected a Authentication Type keyword, got: %s"), lc->str);
2971 }
2972
2973 ScanToEol(lc);
2974 SetBit(index, res_all.hdr.item_present);
2975 ClearBit(index, res_all.hdr.inherit_content);
2976 }
2977
2978 /**
2979 * Store Job Level (Full, Incremental, ...)
2980 */
StoreLevel(LEX * lc,ResourceItem * item,int index,int pass)2981 static void StoreLevel(LEX *lc, ResourceItem *item, int index, int pass)
2982 {
2983 int i;
2984
2985 LexGetToken(lc, BCT_NAME);
2986 /*
2987 * Store the level pass 2 so that type is defined
2988 */
2989 for (i = 0; joblevels[i].level_name; i++) {
2990 if (Bstrcasecmp(lc->str, joblevels[i].level_name)) {
2991 *(item->ui32value) = joblevels[i].level;
2992 i = 0;
2993 break;
2994 }
2995 }
2996
2997 if (i != 0) {
2998 scan_err1(lc, _("Expected a Job Level keyword, got: %s"), lc->str);
2999 }
3000
3001 ScanToEol(lc);
3002 SetBit(index, res_all.hdr.item_present);
3003 ClearBit(index, res_all.hdr.inherit_content);
3004 }
3005
3006 /**
3007 * Store password either clear if for NDMP and catalog or MD5 hashed for native.
3008 */
StoreAutopassword(LEX * lc,ResourceItem * item,int index,int pass)3009 static void StoreAutopassword(LEX *lc, ResourceItem *item, int index, int pass)
3010 {
3011 switch (res_all.hdr.rcode) {
3012 case R_DIRECTOR:
3013 /*
3014 * As we need to store both clear and MD5 hashed within the same
3015 * resource class we use the item->code as a hint default is 0
3016 * and for clear we need a code of 1.
3017 */
3018 switch (item->code) {
3019 case 1:
3020 my_config->StoreResource(CFG_TYPE_CLEARPASSWORD, lc, item, index, pass);
3021 break;
3022 default:
3023 my_config->StoreResource(CFG_TYPE_MD5PASSWORD, lc, item, index, pass);
3024 break;
3025 }
3026 break;
3027 case R_CLIENT:
3028 switch (res_all.res_client.Protocol) {
3029 case APT_NDMPV2:
3030 case APT_NDMPV3:
3031 case APT_NDMPV4:
3032 my_config->StoreResource(CFG_TYPE_CLEARPASSWORD, lc, item, index, pass);
3033 break;
3034 default:
3035 my_config->StoreResource(CFG_TYPE_MD5PASSWORD, lc, item, index, pass);
3036 break;
3037 }
3038 break;
3039 case R_STORAGE:
3040 switch (res_all.res_store.Protocol) {
3041 case APT_NDMPV2:
3042 case APT_NDMPV3:
3043 case APT_NDMPV4:
3044 my_config->StoreResource(CFG_TYPE_CLEARPASSWORD, lc, item, index, pass);
3045 break;
3046 default:
3047 my_config->StoreResource(CFG_TYPE_MD5PASSWORD, lc, item, index, pass);
3048 break;
3049 }
3050 break;
3051 case R_CATALOG:
3052 my_config->StoreResource(CFG_TYPE_CLEARPASSWORD, lc, item, index, pass);
3053 break;
3054 default:
3055 my_config->StoreResource(CFG_TYPE_MD5PASSWORD, lc, item, index, pass);
3056 break;
3057 }
3058 }
3059
3060 /**
3061 * Store ACL (access control list)
3062 */
StoreAcl(LEX * lc,ResourceItem * item,int index,int pass)3063 static void StoreAcl(LEX *lc, ResourceItem *item, int index, int pass)
3064 {
3065 int token;
3066 alist *list;
3067
3068 if (pass == 1) {
3069 if (!item->alistvalue[item->code]) {
3070 item->alistvalue[item->code] = New(alist(10, owned_by_alist));
3071 Dmsg1(900, "Defined new ACL alist at %d\n", item->code);
3072 }
3073 }
3074 list = item->alistvalue[item->code];
3075
3076 for (;;) {
3077 LexGetToken(lc, BCT_STRING);
3078 if (pass == 1) {
3079 list->append(bstrdup(lc->str));
3080 Dmsg2(900, "Appended to %d %s\n", item->code, lc->str);
3081 }
3082 token = LexGetToken(lc, BCT_ALL);
3083 if (token == BCT_COMMA) {
3084 continue; /* get another ACL */
3085 }
3086 break;
3087 }
3088 SetBit(index, res_all.hdr.item_present);
3089 ClearBit(index, res_all.hdr.inherit_content);
3090 }
3091
3092 /**
3093 * Store Audit event.
3094 */
StoreAudit(LEX * lc,ResourceItem * item,int index,int pass)3095 static void StoreAudit(LEX *lc, ResourceItem *item, int index, int pass)
3096 {
3097 int token;
3098 alist *list;
3099
3100 if (pass == 1) {
3101 if (!*item->alistvalue) {
3102 *(item->alistvalue) = New(alist(10, owned_by_alist));
3103 }
3104 }
3105 list = *item->alistvalue;
3106
3107 for (;;) {
3108 LexGetToken(lc, BCT_STRING);
3109 if (pass == 1) {
3110 list->append(bstrdup(lc->str));
3111 }
3112 token = LexGetToken(lc, BCT_ALL);
3113 if (token == BCT_COMMA) {
3114 continue;
3115 }
3116 break;
3117 }
3118 SetBit(index, res_all.hdr.item_present);
3119 ClearBit(index, res_all.hdr.inherit_content);
3120 }
3121 /**
3122 * Store a runscript->when in a bit field
3123 */
StoreRunscriptWhen(LEX * lc,ResourceItem * item,int index,int pass)3124 static void StoreRunscriptWhen(LEX *lc, ResourceItem *item, int index, int pass)
3125 {
3126 LexGetToken(lc, BCT_NAME);
3127
3128 if (Bstrcasecmp(lc->str, "before")) {
3129 *(item->ui32value) = SCRIPT_Before;
3130 } else if (Bstrcasecmp(lc->str, "after")) {
3131 *(item->ui32value) = SCRIPT_After;
3132 } else if (Bstrcasecmp(lc->str, "aftervss")) {
3133 *(item->ui32value) = SCRIPT_AfterVSS;
3134 } else if (Bstrcasecmp(lc->str, "always")) {
3135 *(item->ui32value) = SCRIPT_Any;
3136 } else {
3137 scan_err2(lc, _("Expect %s, got: %s"), "Before, After, AfterVSS or Always", lc->str);
3138 }
3139 ScanToEol(lc);
3140 }
3141
3142 /**
3143 * Store a runscript->target
3144 */
StoreRunscriptTarget(LEX * lc,ResourceItem * item,int index,int pass)3145 static void StoreRunscriptTarget(LEX *lc, ResourceItem *item, int index, int pass)
3146 {
3147 LexGetToken(lc, BCT_STRING);
3148
3149 if (pass == 2) {
3150 if (bstrcmp(lc->str, "%c")) {
3151 ((RunScript *)item->value)->SetTarget(lc->str);
3152 } else if (Bstrcasecmp(lc->str, "yes")) {
3153 ((RunScript *)item->value)->SetTarget("%c");
3154 } else if (Bstrcasecmp(lc->str, "no")) {
3155 ((RunScript *)item->value)->SetTarget("");
3156 } else {
3157 CommonResourceHeader *res;
3158
3159 if (!(res = my_config->GetResWithName(R_CLIENT, lc->str))) {
3160 scan_err3(lc, _("Could not find config Resource %s referenced on line %d : %s\n"), lc->str,
3161 lc->line_no, lc->line);
3162 }
3163
3164 ((RunScript *)item->value)->SetTarget(lc->str);
3165 }
3166 }
3167 ScanToEol(lc);
3168 }
3169
3170 /**
3171 * Store a runscript->command as a string and runscript->cmd_type as a pointer
3172 */
StoreRunscriptCmd(LEX * lc,ResourceItem * item,int index,int pass)3173 static void StoreRunscriptCmd(LEX *lc, ResourceItem *item, int index, int pass)
3174 {
3175 LexGetToken(lc, BCT_STRING);
3176
3177 if (pass == 2) {
3178 Dmsg2(1, "runscript cmd=%s type=%c\n", lc->str, item->code);
3179 POOLMEM *c = GetPoolMemory(PM_FNAME);
3180 /*
3181 * Each runscript command takes 2 entries in commands list
3182 */
3183 PmStrcpy(c, lc->str);
3184 ((RunScript *)item->value)->commands->prepend(c); /* command line */
3185 ((RunScript *)item->value)->commands->prepend((void *)(intptr_t)item->code); /* command type */
3186 }
3187 ScanToEol(lc);
3188 }
3189
StoreShortRunscript(LEX * lc,ResourceItem * item,int index,int pass)3190 static void StoreShortRunscript(LEX *lc, ResourceItem *item, int index, int pass)
3191 {
3192 LexGetToken(lc, BCT_STRING);
3193 alist **runscripts = item->alistvalue;
3194
3195 if (pass == 2) {
3196 RunScript *script = NewRunscript();
3197 script->SetJobCodeCallback(job_code_callback_director);
3198
3199 script->SetCommand(lc->str);
3200 if (Bstrcasecmp(item->name, "runbeforejob")) {
3201 script->when = SCRIPT_Before;
3202 script->SetTarget("");
3203 } else if (Bstrcasecmp(item->name, "runafterjob")) {
3204 script->when = SCRIPT_After;
3205 script->on_success = true;
3206 script->on_failure = false;
3207 script->fail_on_error = false;
3208 script->SetTarget("");
3209 } else if (Bstrcasecmp(item->name, "clientrunafterjob")) {
3210 script->when = SCRIPT_After;
3211 script->on_success = true;
3212 script->on_failure = false;
3213 script->fail_on_error = false;
3214 script->SetTarget("%c");
3215 } else if (Bstrcasecmp(item->name, "clientrunbeforejob")) {
3216 script->when = SCRIPT_Before;
3217 script->SetTarget("%c");
3218 } else if (Bstrcasecmp(item->name, "runafterfailedjob")) {
3219 script->when = SCRIPT_After;
3220 script->on_failure = true;
3221 script->on_success = false;
3222 script->fail_on_error = false;
3223 script->SetTarget("");
3224 }
3225
3226 /*
3227 * Remember that the entry was configured in the short runscript form.
3228 */
3229 script->short_form = true;
3230
3231 if (!*runscripts) {
3232 *runscripts = New(alist(10, not_owned_by_alist));
3233 }
3234
3235 (*runscripts)->append(script);
3236 script->debug();
3237 }
3238
3239 ScanToEol(lc);
3240 }
3241
3242 /**
3243 * Store a bool in a bit field without modifing res_all.hdr
3244 * We can also add an option to StoreBool to skip res_all.hdr
3245 */
StoreRunscriptBool(LEX * lc,ResourceItem * item,int index,int pass)3246 static void StoreRunscriptBool(LEX *lc, ResourceItem *item, int index, int pass)
3247 {
3248 LexGetToken(lc, BCT_NAME);
3249 if (Bstrcasecmp(lc->str, "yes") || Bstrcasecmp(lc->str, "true")) {
3250 *(item->boolvalue) = true;
3251 } else if (Bstrcasecmp(lc->str, "no") || Bstrcasecmp(lc->str, "false")) {
3252 *(item->boolvalue) = false;
3253 } else {
3254 scan_err2(lc, _("Expect %s, got: %s"), "YES, NO, TRUE, or FALSE", lc->str); /* YES and NO must not be translated */
3255 }
3256 ScanToEol(lc);
3257 }
3258
3259 /**
3260 * Store RunScript info
3261 *
3262 * Note, when this routine is called, we are inside a Job
3263 * resource. We treat the RunScript like a sort of
3264 * mini-resource within the Job resource.
3265 */
StoreRunscript(LEX * lc,ResourceItem * item,int index,int pass)3266 static void StoreRunscript(LEX *lc, ResourceItem *item, int index, int pass)
3267 {
3268 char *c;
3269 int token, i, t;
3270 alist **runscripts = item->alistvalue;
3271
3272 Dmsg1(200, "StoreRunscript: begin StoreRunscript pass=%i\n", pass);
3273
3274 token = LexGetToken(lc, BCT_SKIP_EOL);
3275
3276 if (token != BCT_BOB) {
3277 scan_err1(lc, _("Expecting open brace. Got %s"), lc->str);
3278 }
3279 /*
3280 * Setting on_success, on_failure, fail_on_error
3281 */
3282 res_runscript.ResetDefault();
3283
3284 if (pass == 2) {
3285 res_runscript.commands = New(alist(10, not_owned_by_alist));
3286 }
3287
3288 while ((token = LexGetToken(lc, BCT_SKIP_EOL)) != BCT_EOF) {
3289 if (token == BCT_EOB) {
3290 break;
3291 }
3292
3293 if (token != BCT_IDENTIFIER) {
3294 scan_err1(lc, _("Expecting keyword, got: %s\n"), lc->str);
3295 }
3296
3297 for (i = 0; runscript_items[i].name; i++) {
3298 if (Bstrcasecmp(runscript_items[i].name, lc->str)) {
3299 token = LexGetToken(lc, BCT_SKIP_EOL);
3300 if (token != BCT_EQUALS) {
3301 scan_err1(lc, _("Expected an equals, got: %s"), lc->str);
3302 }
3303
3304 /*
3305 * Call item handler
3306 */
3307 switch (runscript_items[i].type) {
3308 case CFG_TYPE_RUNSCRIPT_CMD:
3309 StoreRunscriptCmd(lc, &runscript_items[i], i, pass);
3310 break;
3311 case CFG_TYPE_RUNSCRIPT_TARGET:
3312 StoreRunscriptTarget(lc, &runscript_items[i], i, pass);
3313 break;
3314 case CFG_TYPE_RUNSCRIPT_BOOL:
3315 StoreRunscriptBool(lc, &runscript_items[i], i, pass);
3316 break;
3317 case CFG_TYPE_RUNSCRIPT_WHEN:
3318 StoreRunscriptWhen(lc, &runscript_items[i], i, pass);
3319 break;
3320 default:
3321 break;
3322 }
3323 i = -1;
3324 break;
3325 }
3326 }
3327
3328 if (i >=0) {
3329 scan_err1(lc, _("Keyword %s not permitted in this resource"), lc->str);
3330 }
3331 }
3332
3333 if (pass == 2) {
3334 /*
3335 * Run on client by default
3336 */
3337 if (!res_runscript.target) {
3338 res_runscript.SetTarget("%c");
3339 }
3340 if (!*runscripts) {
3341 *runscripts = New(alist(10, not_owned_by_alist));
3342 }
3343 /*
3344 * commands list contains 2 values per command
3345 * - POOLMEM command string (ex: /bin/true)
3346 * - int command type (ex: SHELL_CMD)
3347 */
3348 res_runscript.SetJobCodeCallback(job_code_callback_director);
3349 while ((c = (char *)res_runscript.commands->pop()) != NULL) {
3350 t = (intptr_t)res_runscript.commands->pop();
3351 RunScript *script = NewRunscript();
3352 memcpy(script, &res_runscript, sizeof(RunScript));
3353 script->command = c;
3354 script->cmd_type = t;
3355 /*
3356 * target is taken from res_runscript,
3357 * each runscript object have a copy
3358 */
3359 script->target = NULL;
3360 script->SetTarget(res_runscript.target);
3361
3362 /*
3363 * Remember that the entry was configured in the short runscript form.
3364 */
3365 script->short_form = false;
3366
3367 (*runscripts)->append(script);
3368 script->debug();
3369 }
3370 delete res_runscript.commands;
3371 /*
3372 * setting on_success, on_failure... cleanup target field
3373 */
3374 res_runscript.ResetDefault(true);
3375 }
3376
3377 ScanToEol(lc);
3378 SetBit(index, res_all.hdr.item_present);
3379 ClearBit(index, res_all.hdr.inherit_content);
3380 }
3381
3382 /**
3383 * callback function for edit_job_codes
3384 * See ../lib/util.c, function edit_job_codes, for more remaining codes
3385 *
3386 * %f = Filesetname
3387 * %h = Client Address
3388 * %p = Poolname
3389 * %w = Write storage
3390 * %x = Spooling (yes/no)
3391 * %C = Cloning (yes/no)
3392 * %D = Director name
3393 * %V = Volume name(s) (Destination)
3394 */
job_code_callback_director(JobControlRecord * jcr,const char * param)3395 extern "C" char *job_code_callback_director(JobControlRecord *jcr, const char *param)
3396 {
3397 static char yes[] = "yes";
3398 static char no[] = "no";
3399
3400 switch (param[0]) {
3401 case 'f':
3402 if (jcr->res.fileset) {
3403 return jcr->res.fileset->name();
3404 }
3405 break;
3406 case 'h':
3407 if (jcr->res.client) {
3408 return jcr->res.client->address;
3409 }
3410 break;
3411 case 'p':
3412 if (jcr->res.pool) {
3413 return jcr->res.pool->name();
3414 }
3415 break;
3416 case 'w':
3417 if (jcr->res.write_storage) {
3418 return jcr->res.write_storage->name();
3419 }
3420 break;
3421 case 'x':
3422 return jcr->spool_data ? yes : no;
3423 case 'C':
3424 return jcr->cloned ? yes : no;
3425 case 'D':
3426 return my_name;
3427 case 'V':
3428 if (jcr) {
3429 /*
3430 * If this is a migration/copy we need the volume name from the mig_jcr.
3431 */
3432 if (jcr->mig_jcr) {
3433 jcr = jcr->mig_jcr;
3434 }
3435
3436 if (jcr->VolumeName) {
3437 return jcr->VolumeName;
3438 } else {
3439 return (char *)_("*None*");
3440 }
3441 } else {
3442 return (char *)_("*None*");
3443 }
3444 break;
3445 }
3446
3447 return NULL;
3448 }
3449
3450 /**
3451 * callback function for init_resource
3452 * See ../lib/parse_conf.c, function InitResource, for more generic handling.
3453 */
InitResourceCb(ResourceItem * item,int pass)3454 static void InitResourceCb(ResourceItem *item, int pass)
3455 {
3456 switch (pass) {
3457 case 1:
3458 switch (item->type) {
3459 case CFG_TYPE_REPLACE:
3460 for (int i = 0; ReplaceOptions[i].name; i++) {
3461 if (Bstrcasecmp(item->default_value, ReplaceOptions[i].name)) {
3462 *(item->ui32value) = ReplaceOptions[i].token;
3463 }
3464 }
3465 break;
3466 case CFG_TYPE_AUTHPROTOCOLTYPE:
3467 for (int i = 0; authprotocols[i].name; i++) {
3468 if (Bstrcasecmp(item->default_value, authprotocols[i].name)) {
3469 *(item->ui32value) = authprotocols[i].token;
3470 }
3471 }
3472 break;
3473 case CFG_TYPE_AUTHTYPE:
3474 for (int i = 0; authmethods[i].name; i++) {
3475 if (Bstrcasecmp(item->default_value, authmethods[i].name)) {
3476 *(item->ui32value) = authmethods[i].token;
3477 }
3478 }
3479 break;
3480 case CFG_TYPE_POOLTYPE:
3481 *(item->value) = bstrdup(item->default_value);
3482 break;
3483 default:
3484 break;
3485 }
3486 break;
3487 default:
3488 break;
3489 }
3490 }
3491
3492 /**
3493 * callback function for parse_config
3494 * See ../lib/parse_conf.c, function ParseConfig, for more generic handling.
3495 */
ParseConfigCb(LEX * lc,ResourceItem * item,int index,int pass)3496 static void ParseConfigCb(LEX *lc, ResourceItem *item, int index, int pass)
3497 {
3498 switch (item->type) {
3499 case CFG_TYPE_AUTOPASSWORD:
3500 StoreAutopassword(lc, item, index, pass);
3501 break;
3502 case CFG_TYPE_ACL:
3503 StoreAcl(lc, item, index, pass);
3504 break;
3505 case CFG_TYPE_AUDIT:
3506 StoreAudit(lc, item, index, pass);
3507 break;
3508 case CFG_TYPE_AUTHPROTOCOLTYPE:
3509 StoreAuthprotocoltype(lc, item, index, pass);
3510 break;
3511 case CFG_TYPE_AUTHTYPE:
3512 StoreAuthtype(lc, item, index, pass);
3513 break;
3514 case CFG_TYPE_DEVICE:
3515 StoreDevice(lc, item, index, pass);
3516 break;
3517 case CFG_TYPE_JOBTYPE:
3518 StoreJobtype(lc, item, index, pass);
3519 break;
3520 case CFG_TYPE_PROTOCOLTYPE:
3521 StoreProtocoltype(lc, item, index, pass);
3522 break;
3523 case CFG_TYPE_LEVEL:
3524 StoreLevel(lc, item, index, pass);
3525 break;
3526 case CFG_TYPE_REPLACE:
3527 StoreReplace(lc, item, index, pass);
3528 break;
3529 case CFG_TYPE_SHRTRUNSCRIPT:
3530 StoreShortRunscript(lc, item, index, pass);
3531 break;
3532 case CFG_TYPE_RUNSCRIPT:
3533 StoreRunscript(lc, item, index, pass);
3534 break;
3535 case CFG_TYPE_MIGTYPE:
3536 StoreMigtype(lc, item, index, pass);
3537 break;
3538 case CFG_TYPE_INCEXC:
3539 StoreInc(lc, item, index, pass);
3540 break;
3541 case CFG_TYPE_RUN:
3542 StoreRun(lc, item, index, pass);
3543 break;
3544 case CFG_TYPE_ACTIONONPURGE:
3545 StoreActiononpurge(lc, item, index, pass);
3546 break;
3547 case CFG_TYPE_POOLTYPE:
3548 StorePooltype(lc, item, index, pass);
3549 break;
3550 default:
3551 break;
3552 }
3553 }
3554
3555 /**
3556 * callback function for print_config
3557 * See ../lib/res.c, function BareosResource::PrintConfig, for more generic handling.
3558 */
PrintConfigCb(ResourceItem * items,int i,PoolMem & cfg_str,bool hide_sensitive_data,bool inherited)3559 static void PrintConfigCb(ResourceItem *items, int i, PoolMem &cfg_str, bool hide_sensitive_data, bool inherited)
3560 {
3561 PoolMem temp;
3562
3563 switch (items[i].type) {
3564 case CFG_TYPE_DEVICE: {
3565 /*
3566 * Each member of the list is comma-separated
3567 */
3568 int cnt = 0;
3569 CommonResourceHeader *res = nullptr;
3570 alist *list;
3571 PoolMem res_names;
3572
3573 list = *(items[i].alistvalue);
3574 if (list != NULL) {
3575 Mmsg(temp, "%s = ", items[i].name);
3576 IndentConfigItem(cfg_str, 1, temp.c_str(), inherited);
3577
3578 PmStrcpy(res_names, "");
3579 foreach_alist(res, list) {
3580 if (cnt) {
3581 Mmsg(temp, ",\"%s\"", res->name);
3582 } else {
3583 Mmsg(temp, "\"%s\"", res->name);
3584 }
3585 PmStrcat(res_names, temp.c_str());
3586 cnt++;
3587 }
3588
3589 PmStrcat(cfg_str, res_names.c_str());
3590 PmStrcat(cfg_str, "\n");
3591 }
3592 break;
3593 }
3594 case CFG_TYPE_RUNSCRIPT:
3595 Dmsg0(200, "CFG_TYPE_RUNSCRIPT\n");
3596 PrintConfigRunscript(&items[i], cfg_str);
3597 break;
3598 case CFG_TYPE_SHRTRUNSCRIPT:
3599 /*
3600 * We don't get here as this type is converted to a CFG_TYPE_RUNSCRIPT when parsed
3601 */
3602 break;
3603 case CFG_TYPE_ACL: {
3604 int cnt = 0;
3605 char *value = nullptr;
3606 alist *list;
3607 PoolMem acl;
3608
3609 list = items[i].alistvalue[items[i].code];
3610 if (list != NULL) {
3611 Mmsg(temp, "%s = ", items[i].name);
3612 IndentConfigItem(cfg_str, 1, temp.c_str(), inherited);
3613 foreach_alist(value, list) {
3614 if (cnt) {
3615 Mmsg(temp, ",\"%s\"", value);
3616 } else {
3617 Mmsg(temp, "\"%s\"", value);
3618 }
3619 PmStrcat(acl, temp.c_str());
3620 cnt++;
3621 }
3622
3623 PmStrcat(cfg_str, acl.c_str());
3624 PmStrcat(cfg_str, "\n");
3625 }
3626 break;
3627 }
3628 case CFG_TYPE_RUN:
3629 PrintConfigRun(&items[i], cfg_str);
3630 break;
3631 case CFG_TYPE_JOBTYPE: {
3632 int32_t jobtype = *(items[i].ui32value);
3633
3634 if (jobtype) {
3635 for (int j = 0; jobtypes[j].type_name; j++) {
3636 if (jobtypes[j].job_type == jobtype) {
3637 Mmsg(temp, "%s = %s\n", items[i].name, jobtypes[j].type_name);
3638 IndentConfigItem(cfg_str, 1, temp.c_str(), inherited);
3639 break;
3640 }
3641 }
3642 }
3643 break;
3644 }
3645 case CFG_TYPE_PROTOCOLTYPE: {
3646 uint32_t protocol = *(items[i].ui32value);
3647
3648 if (protocol) {
3649 for (int j = 0; backupprotocols[j].name; j++) {
3650 if (backupprotocols[j].token == protocol) {
3651 /*
3652 * Suppress printing default value.
3653 */
3654 if (items[i].flags & CFG_ITEM_DEFAULT) {
3655 if (Bstrcasecmp(items[i].default_value, backupprotocols[j].name)) {
3656 break;
3657 }
3658 }
3659
3660 Mmsg(temp, "%s = %s\n", items[i].name, backupprotocols[j].name);
3661 IndentConfigItem(cfg_str, 1, temp.c_str(), inherited);
3662 break;
3663 }
3664 }
3665 }
3666 break;
3667 }
3668 case CFG_TYPE_MIGTYPE: {
3669 int32_t migtype = *(items[i].ui32value);
3670
3671 if (migtype) {
3672 for (int j = 0; migtypes[j].type_name; j++) {
3673 if (migtypes[j].job_type == migtype) {
3674 Mmsg(temp, "%s = %s\n", items[i].name, migtypes[j].type_name);
3675 IndentConfigItem(cfg_str, 1, temp.c_str(), inherited);
3676 break;
3677 }
3678 }
3679 }
3680 break;
3681 }
3682 case CFG_TYPE_REPLACE: {
3683 uint32_t replace = *(items[i].ui32value);
3684
3685 if (replace) {
3686 for (int j = 0; ReplaceOptions[j].name; j++) {
3687 if (ReplaceOptions[j].token == replace) {
3688 /*
3689 * Supress printing default value.
3690 */
3691 if (items[i].flags & CFG_ITEM_DEFAULT) {
3692 if (Bstrcasecmp(items[i].default_value, ReplaceOptions[j].name)) {
3693 break;
3694 }
3695 }
3696
3697 Mmsg(temp, "%s = %s\n", items[i].name, ReplaceOptions[j].name);
3698 IndentConfigItem(cfg_str, 1, temp.c_str(), inherited);
3699 break;
3700 }
3701 }
3702 }
3703 break;
3704 }
3705 case CFG_TYPE_LEVEL: {
3706 uint32_t level = *(items[i].ui32value);
3707
3708 if (level) {
3709 for (int j = 0; joblevels[j].level_name; j++) {
3710 if (joblevels[j].level == level) {
3711 Mmsg(temp, "%s = %s\n", items[i].name, joblevels[j].level_name);
3712 IndentConfigItem(cfg_str, 1, temp.c_str(), inherited);
3713 break;
3714 }
3715 }
3716 }
3717 break;
3718 }
3719 case CFG_TYPE_ACTIONONPURGE: {
3720 uint32_t action = *(items[i].ui32value);
3721
3722 if (action) {
3723 for (int j = 0; ActionOnPurgeOptions[j].name; j++) {
3724 if (ActionOnPurgeOptions[j].token == action) {
3725 Mmsg(temp, "%s = %s\n", items[i].name, ActionOnPurgeOptions[j].name);
3726 IndentConfigItem(cfg_str, 1, temp.c_str(), inherited);
3727 break;
3728 }
3729 }
3730 }
3731 break;
3732 }
3733 case CFG_TYPE_AUTHPROTOCOLTYPE: {
3734 uint32_t authprotocol = *(items[i].ui32value);
3735
3736 if (authprotocol) {
3737 for (int j = 0; authprotocols[j].name; j++) {
3738 if (authprotocols[j].token == authprotocol) {
3739 Mmsg(temp, "%s = %s\n", items[i].name, authprotocols[j].name);
3740 IndentConfigItem(cfg_str, 1, temp.c_str(), inherited);
3741 break;
3742 }
3743 }
3744 }
3745 break;
3746 }
3747 case CFG_TYPE_AUTHTYPE: {
3748 uint32_t authtype = *(items[i].ui32value);
3749
3750 if (authtype) {
3751 for (int j = 0; authmethods[j].name; j++) {
3752 if (authprotocols[j].token == authtype) {
3753 Mmsg(temp, "%s = %s\n", items[i].name, authmethods[j].name);
3754 IndentConfigItem(cfg_str, 1, temp.c_str(), inherited);
3755 break;
3756 }
3757 }
3758 }
3759 break;
3760 }
3761 case CFG_TYPE_AUDIT: {
3762 /*
3763 * Each member of the list is comma-separated
3764 */
3765 int cnt = 0;
3766 char *audit_event = nullptr;
3767 alist *list;
3768 PoolMem audit_events;
3769
3770 list = *(items[i].alistvalue);
3771 if (list != NULL) {
3772 Mmsg(temp, "%s = ", items[i].name);
3773 IndentConfigItem(cfg_str, 1, temp.c_str(), inherited);
3774
3775 PmStrcpy(audit_events, "");
3776 foreach_alist(audit_event, list) {
3777 if (cnt) {
3778 Mmsg(temp, ",\"%s\"", audit_event);
3779 } else {
3780 Mmsg(temp, "\"%s\"", audit_event);
3781 }
3782 PmStrcat(audit_events, temp.c_str());
3783 cnt++;
3784 }
3785
3786 PmStrcat(cfg_str, audit_events.c_str());
3787 PmStrcat(cfg_str, "\n");
3788 }
3789 break;
3790 }
3791 case CFG_TYPE_POOLTYPE:
3792 Mmsg(temp, "%s = %s\n", items[i].name, *(items[i].value));
3793 IndentConfigItem(cfg_str, 1, temp.c_str());
3794 break;
3795 default:
3796 Dmsg2(200, "%s is UNSUPPORTED TYPE: %d\n", items[i].name, items[i].type);
3797 break;
3798 }
3799 }
3800
ResetAllClientConnectionHandshakeModes(ConfigurationParser & my_config)3801 static void ResetAllClientConnectionHandshakeModes(ConfigurationParser &my_config)
3802 {
3803 CommonResourceHeader *header = nullptr;
3804 header = my_config.GetNextRes(R_CLIENT, header);
3805 while(header) {
3806 ClientResource *client = reinterpret_cast<ClientResource*>(header);
3807 if (client) {
3808 client->connection_successful_handshake_ = ClientConnectionHandshakeMode::kUndefined;
3809 }
3810 header = my_config.GetNextRes(R_CLIENT, header);
3811 };
3812 }
3813
ConfigReadyCallback(ConfigurationParser & my_config)3814 static void ConfigReadyCallback(ConfigurationParser &my_config)
3815 {
3816 CreateAndAddUserAgentConsoleResource(my_config);
3817
3818 std::map<int, std::string> map{
3819 {R_DIRECTOR, "R_DIRECTOR"}, {R_CLIENT, "R_CLIENT"}, {R_JOBDEFS, "R_JOBDEFS"},
3820 {R_JOB, "R_JOB"}, {R_STORAGE, "R_STORAGE"}, {R_CATALOG, "R_CATALOG"},
3821 {R_SCHEDULE, "R_SCHEDULE"}, {R_FILESET, "R_FILESET"}, {R_POOL, "R_POOL"},
3822 {R_MSGS, "R_MSGS"}, {R_COUNTER, "R_COUNTER"}, {R_PROFILE, "R_PROFILE"},
3823 {R_CONSOLE, "R_CONSOLE"}, {R_DEVICE, "R_DEVICE"}};
3824 my_config.InitializeQualifiedResourceNameTypeConverter(map);
3825
3826 ResetAllClientConnectionHandshakeModes(my_config);
3827 }
3828
AddResourceCopyToEndOfChain(UnionOfResources * res_to_add,int type)3829 static bool AddResourceCopyToEndOfChain(UnionOfResources *res_to_add, int type)
3830 {
3831 int rindex = type - R_FIRST;
3832 UnionOfResources *res = (UnionOfResources *)malloc(resources[rindex].size);
3833 memcpy(res, res_to_add, resources[rindex].size);
3834 if (!res_head[rindex]) {
3835 res_head[rindex] = (CommonResourceHeader *)res; /* store first entry */
3836 Dmsg3(900, "Inserting first %s res: %s index=%d\n", my_config->res_to_str(type), res->res_dir.name(),
3837 rindex);
3838 } else {
3839 CommonResourceHeader *next, *last;
3840 if (!res->res_dir.name()) {
3841 Emsg1(M_ERROR, 0, _("Name item is required in %s resource, but not found.\n"), resources[rindex].name);
3842 return false;
3843 }
3844 /*
3845 * Add new res to end of chain
3846 */
3847 for (last = next = res_head[rindex]; next; next = next->next) {
3848 last = next;
3849 if (bstrcmp(next->name, res->res_dir.name())) {
3850 Emsg2(M_ERROR, 0, _("Attempt to define second %s resource named \"%s\" is not permitted.\n"),
3851 resources[rindex].name, res->res_dir.name());
3852 return false;
3853 }
3854 }
3855 last->next = (CommonResourceHeader *)res;
3856 Dmsg3(900, _("Inserting %s res: %s index=%d\n"), my_config->res_to_str(type), res->res_dir.name(),rindex);
3857 }
3858 return true;
3859 }
3860
3861 /*
3862 * Create a special Console named "*UserAgent*" with
3863 * root console password so that incoming console
3864 * connections can be handled in unique way
3865 *
3866 */
CreateAndAddUserAgentConsoleResource(ConfigurationParser & my_config)3867 static void CreateAndAddUserAgentConsoleResource(ConfigurationParser &my_config)
3868 {
3869 DirectorResource *dir_resource = (DirectorResource *)my_config.GetNextRes(R_DIRECTOR, NULL);
3870 if (!dir_resource) { return; }
3871
3872 ConsoleResource console;
3873 memset(&console, 0, sizeof(console));
3874 console.password_.encoding = dir_resource->password_.encoding;
3875 console.password_.value = bstrdup(dir_resource->password_.value);
3876 console.tls_enable_ = true;
3877 console.hdr.name = bstrdup("*UserAgent*");
3878 console.hdr.desc = bstrdup("root console definition");
3879 console.hdr.rcode = 1013;
3880 console.hdr.refcnt = 1;
3881
3882 AddResourceCopyToEndOfChain((UnionOfResources *)&console, R_CONSOLE);
3883 }
3884
InitDirConfig(const char * configfile,int exit_code)3885 ConfigurationParser *InitDirConfig(const char *configfile, int exit_code)
3886 {
3887 ConfigurationParser *config =
3888 new ConfigurationParser(configfile, nullptr, nullptr, InitResourceCb, ParseConfigCb, PrintConfigCb,
3889 exit_code, (void *)&res_all, res_all_size, R_FIRST, R_LAST, resources, res_head,
3890 default_config_filename.c_str(), "bareos-dir.d", ConfigReadyCallback,
3891 SaveResource, DumpResource, FreeResource);
3892 if (config) { config->r_own_ = R_DIRECTOR; }
3893 return config;
3894 }
3895
3896
3897 /**
3898 * Dump contents of resource
3899 */
DumpResource(int type,CommonResourceHeader * ures,void sendit (void * sock,const char * fmt,...),void * sock,bool hide_sensitive_data,bool verbose)3900 static void DumpResource(int type,
3901 CommonResourceHeader *ures,
3902 void sendit(void *sock, const char *fmt, ...),
3903 void *sock,
3904 bool hide_sensitive_data,
3905 bool verbose)
3906 {
3907 PoolMem buf;
3908 bool recurse = true;
3909 UnionOfResources *res = (UnionOfResources *)ures;
3910 UaContext *ua = (UaContext *)sock;
3911
3912 if (!res) {
3913 sendit(sock, _("No %s resource defined\n"), my_config->res_to_str(type));
3914 return;
3915 }
3916
3917 if (type < 0) { /* no recursion */
3918 type = -type;
3919 recurse = false;
3920 }
3921
3922 if (ua && !ua->IsResAllowed(ures)) { goto bail_out; }
3923
3924 switch (type) {
3925 case R_DIRECTOR:
3926 res->res_dir.PrintConfig(buf, *my_config, hide_sensitive_data, verbose);
3927 sendit(sock, "%s", buf.c_str());
3928 break;
3929 case R_PROFILE:
3930 res->res_profile.PrintConfig(buf, *my_config, hide_sensitive_data, verbose);
3931 sendit(sock, "%s", buf.c_str());
3932 break;
3933 case R_CONSOLE:
3934 res->res_con.PrintConfig(buf, *my_config, hide_sensitive_data, verbose);
3935 sendit(sock, "%s", buf.c_str());
3936 break;
3937 case R_COUNTER:
3938 res->res_counter.PrintConfig(buf, *my_config, hide_sensitive_data, verbose);
3939 sendit(sock, "%s", buf.c_str());
3940 break;
3941 case R_CLIENT:
3942 res->res_client.PrintConfig(buf, *my_config, hide_sensitive_data, verbose);
3943 sendit(sock, "%s", buf.c_str());
3944 break;
3945 case R_DEVICE:
3946 res->res_dev.PrintConfig(buf, *my_config, hide_sensitive_data, verbose);
3947 sendit(sock, "%s", buf.c_str());
3948 break;
3949 case R_STORAGE:
3950 res->res_store.PrintConfig(buf, *my_config, hide_sensitive_data, verbose);
3951 sendit(sock, "%s", buf.c_str());
3952 break;
3953 case R_CATALOG:
3954 res->res_cat.PrintConfig(buf, *my_config, hide_sensitive_data, verbose);
3955 sendit(sock, "%s", buf.c_str());
3956 break;
3957 case R_JOBDEFS:
3958 case R_JOB:
3959 res->res_job.PrintConfig(buf, *my_config, hide_sensitive_data, verbose);
3960 sendit(sock, "%s", buf.c_str());
3961 break;
3962 case R_FILESET:
3963 res->res_fs.PrintConfig(buf, hide_sensitive_data, verbose);
3964 sendit(sock, "%s", buf.c_str());
3965 break;
3966 case R_SCHEDULE:
3967 res->res_sch.PrintConfig(buf, *my_config, hide_sensitive_data, verbose);
3968 sendit(sock, "%s", buf.c_str());
3969 break;
3970 case R_POOL:
3971 res->res_pool.PrintConfig(buf, *my_config, hide_sensitive_data, verbose);
3972 sendit(sock, "%s", buf.c_str());
3973 break;
3974 case R_MSGS:
3975 res->res_msgs.PrintConfig(buf, hide_sensitive_data, verbose);
3976 sendit(sock, "%s", buf.c_str());
3977 break;
3978 default:
3979 sendit(sock, _("Unknown resource type %d in DumpResource.\n"), type);
3980 break;
3981 }
3982
3983 bail_out:
3984 if (recurse && res->res_dir.hdr.next) {
3985 my_config->DumpResourceCb_(type, res->res_dir.hdr.next, sendit, sock, hide_sensitive_data, verbose);
3986 }
3987 }
3988
3989 /**
3990 * Free memory of resource -- called when daemon terminates.
3991 * NB, we don't need to worry about freeing any references
3992 * to other resources as they will be freed when that
3993 * resource chain is traversed. Mainly we worry about freeing
3994 * allocated strings (names).
3995 */
FreeResource(CommonResourceHeader * sres,int type)3996 static void FreeResource(CommonResourceHeader *sres, int type)
3997 {
3998 int num;
3999 CommonResourceHeader *nres; /* next resource if linked */
4000 UnionOfResources *res = (UnionOfResources *)sres;
4001
4002 if (!res) return;
4003
4004 /*
4005 * Common stuff -- free the resource name and description
4006 */
4007 nres = (CommonResourceHeader *)res->res_dir.hdr.next;
4008 if (res->res_dir.hdr.name) { free(res->res_dir.hdr.name); }
4009 if (res->res_dir.hdr.desc) { free(res->res_dir.hdr.desc); }
4010
4011 switch (type) {
4012 case R_DIRECTOR:
4013 if (res->res_dir.working_directory) { free(res->res_dir.working_directory); }
4014 if (res->res_dir.scripts_directory) { free(res->res_dir.scripts_directory); }
4015 if (res->res_dir.plugin_directory) { free(res->res_dir.plugin_directory); }
4016 if (res->res_dir.plugin_names) { delete res->res_dir.plugin_names; }
4017 if (res->res_dir.pid_directory) { free(res->res_dir.pid_directory); }
4018 if (res->res_dir.subsys_directory) { free(res->res_dir.subsys_directory); }
4019 if (res->res_dir.backend_directories) { delete res->res_dir.backend_directories; }
4020 if (res->res_dir.password_.value) { free(res->res_dir.password_.value); }
4021 if (res->res_dir.query_file) { free(res->res_dir.query_file); }
4022 if (res->res_dir.DIRaddrs) { FreeAddresses(res->res_dir.DIRaddrs); }
4023 if (res->res_dir.DIRsrc_addr) { FreeAddresses(res->res_dir.DIRsrc_addr); }
4024 if (res->res_dir.verid) { free(res->res_dir.verid); }
4025 if (res->res_dir.keyencrkey.value) { free(res->res_dir.keyencrkey.value); }
4026 if (res->res_dir.audit_events) { delete res->res_dir.audit_events; }
4027 if (res->res_dir.secure_erase_cmdline) { free(res->res_dir.secure_erase_cmdline); }
4028 if (res->res_dir.log_timestamp_format) { free(res->res_dir.log_timestamp_format); }
4029 if (res->res_dir.tls_cert_.allowed_certificate_common_names_) {
4030 res->res_dir.tls_cert_.allowed_certificate_common_names_->destroy();
4031 free(res->res_dir.tls_cert_.allowed_certificate_common_names_);
4032 }
4033 if (res->res_dir.tls_cert_.ca_certfile_) { delete res->res_dir.tls_cert_.ca_certfile_; }
4034 if (res->res_dir.tls_cert_.ca_certdir_) { delete res->res_dir.tls_cert_.ca_certdir_; }
4035 if (res->res_dir.tls_cert_.crlfile_) { delete res->res_dir.tls_cert_.crlfile_; }
4036 if (res->res_dir.tls_cert_.certfile_) { delete res->res_dir.tls_cert_.certfile_; }
4037 if (res->res_dir.tls_cert_.keyfile_) { delete res->res_dir.tls_cert_.keyfile_; }
4038 if (res->res_dir.cipherlist_) { delete res->res_dir.cipherlist_; }
4039 if (res->res_dir.tls_cert_.dhfile_) { delete res->res_dir.tls_cert_.dhfile_; }
4040 if (res->res_dir.tls_cert_.pem_message_) { delete res->res_dir.tls_cert_.pem_message_; }
4041 break;
4042 case R_DEVICE:
4043 case R_COUNTER:
4044 break;
4045 case R_PROFILE:
4046 for (int i = 0; i < Num_ACL; i++) {
4047 if (res->res_profile.ACL_lists[i]) {
4048 delete res->res_profile.ACL_lists[i];
4049 res->res_profile.ACL_lists[i] = NULL;
4050 }
4051 }
4052 break;
4053 case R_CONSOLE:
4054 if (res->res_con.password_.value) { free(res->res_con.password_.value); }
4055 if (res->res_con.profiles) { delete res->res_con.profiles; }
4056 for (int i = 0; i < Num_ACL; i++) {
4057 if (res->res_con.ACL_lists[i]) {
4058 delete res->res_con.ACL_lists[i];
4059 res->res_con.ACL_lists[i] = NULL;
4060 }
4061 }
4062 if (res->res_con.tls_cert_.allowed_certificate_common_names_) {
4063 res->res_con.tls_cert_.allowed_certificate_common_names_->destroy();
4064 free(res->res_con.tls_cert_.allowed_certificate_common_names_);
4065 }
4066 if (res->res_con.tls_cert_.ca_certfile_) { delete res->res_con.tls_cert_.ca_certfile_; }
4067 if (res->res_con.tls_cert_.ca_certdir_) { delete res->res_con.tls_cert_.ca_certdir_; }
4068 if (res->res_con.tls_cert_.crlfile_) { delete res->res_con.tls_cert_.crlfile_; }
4069 if (res->res_con.tls_cert_.certfile_) { delete res->res_con.tls_cert_.certfile_; }
4070 if (res->res_con.tls_cert_.keyfile_) { delete res->res_con.tls_cert_.keyfile_; }
4071 if (res->res_con.cipherlist_) { delete res->res_con.cipherlist_; }
4072 if (res->res_con.tls_cert_.dhfile_) { delete res->res_con.tls_cert_.dhfile_; }
4073 if (res->res_con.tls_cert_.pem_message_) { delete res->res_con.tls_cert_.pem_message_; }
4074 break;
4075 case R_CLIENT:
4076 if (res->res_client.address) { free(res->res_client.address); }
4077 if (res->res_client.lanaddress) { free(res->res_client.lanaddress); }
4078 if (res->res_client.username) { free(res->res_client.username); }
4079 if (res->res_client.password_.value) { free(res->res_client.password_.value); }
4080 if (res->res_client.rcs) { free(res->res_client.rcs); }
4081 if (res->res_client.tls_cert_.allowed_certificate_common_names_) {
4082 res->res_client.tls_cert_.allowed_certificate_common_names_->destroy();
4083 free(res->res_client.tls_cert_.allowed_certificate_common_names_);
4084 }
4085 if (res->res_client.tls_cert_.ca_certfile_) { delete res->res_client.tls_cert_.ca_certfile_; }
4086 if (res->res_client.tls_cert_.ca_certdir_) { delete res->res_client.tls_cert_.ca_certdir_; }
4087 if (res->res_client.tls_cert_.crlfile_) { delete res->res_client.tls_cert_.crlfile_; }
4088 if (res->res_client.tls_cert_.certfile_) { delete res->res_client.tls_cert_.certfile_; }
4089 if (res->res_client.tls_cert_.keyfile_) { delete res->res_client.tls_cert_.keyfile_; }
4090 if (res->res_client.cipherlist_) { delete res->res_client.cipherlist_; }
4091 if (res->res_client.tls_cert_.dhfile_) { delete res->res_client.tls_cert_.dhfile_; }
4092 if (res->res_client.tls_cert_.pem_message_) { delete res->res_client.tls_cert_.pem_message_; }
4093 break;
4094 case R_STORAGE:
4095 if (res->res_store.address) { free(res->res_store.address); }
4096 if (res->res_store.lanaddress) { free(res->res_store.lanaddress); }
4097 if (res->res_store.username) { free(res->res_store.username); }
4098 if (res->res_store.password_.value) { free(res->res_store.password_.value); }
4099 if (res->res_store.media_type) { free(res->res_store.media_type); }
4100 if (res->res_store.ndmp_changer_device) { free(res->res_store.ndmp_changer_device); }
4101 if (res->res_store.device) { delete res->res_store.device; }
4102 if (res->res_store.rss) {
4103 if (res->res_store.rss->vol_list) {
4104 if (res->res_store.rss->vol_list->contents) {
4105 vol_list_t *vl;
4106
4107 foreach_dlist (vl, res->res_store.rss->vol_list->contents) {
4108 if (vl->VolName) { free(vl->VolName); }
4109 }
4110 res->res_store.rss->vol_list->contents->destroy();
4111 delete res->res_store.rss->vol_list->contents;
4112 }
4113 free(res->res_store.rss->vol_list);
4114 }
4115 pthread_mutex_destroy(&res->res_store.rss->changer_lock);
4116 pthread_mutex_destroy(&res->res_store.rss->ndmp_deviceinfo_lock);
4117 free(res->res_store.rss);
4118 }
4119 if (res->res_store.tls_cert_.allowed_certificate_common_names_) {
4120 res->res_store.tls_cert_.allowed_certificate_common_names_->destroy();
4121 free(res->res_store.tls_cert_.allowed_certificate_common_names_);
4122 }
4123 if (res->res_store.tls_cert_.ca_certfile_) { delete res->res_store.tls_cert_.ca_certfile_; }
4124 if (res->res_store.tls_cert_.ca_certdir_) { delete res->res_store.tls_cert_.ca_certdir_; }
4125 if (res->res_store.tls_cert_.crlfile_) { delete res->res_store.tls_cert_.crlfile_; }
4126 if (res->res_store.tls_cert_.certfile_) { delete res->res_store.tls_cert_.certfile_; }
4127 if (res->res_store.tls_cert_.keyfile_) { delete res->res_store.tls_cert_.keyfile_; }
4128 if (res->res_store.cipherlist_) { delete res->res_store.cipherlist_; }
4129 if (res->res_store.tls_cert_.dhfile_) { delete res->res_store.tls_cert_.dhfile_; }
4130 if (res->res_store.tls_cert_.pem_message_) { delete res->res_store.tls_cert_.pem_message_; }
4131 break;
4132 case R_CATALOG:
4133 if (res->res_cat.db_address) { free(res->res_cat.db_address); }
4134 if (res->res_cat.db_socket) { free(res->res_cat.db_socket); }
4135 if (res->res_cat.db_user) { free(res->res_cat.db_user); }
4136 if (res->res_cat.db_name) { free(res->res_cat.db_name); }
4137 if (res->res_cat.db_driver) { free(res->res_cat.db_driver); }
4138 if (res->res_cat.db_password.value) { free(res->res_cat.db_password.value); }
4139 break;
4140 case R_FILESET:
4141 if ((num = res->res_fs.num_includes)) {
4142 while (--num >= 0) { FreeIncexe(res->res_fs.include_items[num]); }
4143 free(res->res_fs.include_items);
4144 }
4145 res->res_fs.num_includes = 0;
4146 if ((num = res->res_fs.num_excludes)) {
4147 while (--num >= 0) { FreeIncexe(res->res_fs.exclude_items[num]); }
4148 free(res->res_fs.exclude_items);
4149 }
4150 res->res_fs.num_excludes = 0;
4151 break;
4152 case R_POOL:
4153 if (res->res_pool.pool_type) { free(res->res_pool.pool_type); }
4154 if (res->res_pool.label_format) { free(res->res_pool.label_format); }
4155 if (res->res_pool.cleaning_prefix) { free(res->res_pool.cleaning_prefix); }
4156 if (res->res_pool.storage) { delete res->res_pool.storage; }
4157 break;
4158 case R_SCHEDULE:
4159 if (res->res_sch.run) {
4160 RunResource *nrun, *next;
4161 nrun = res->res_sch.run;
4162 while (nrun) {
4163 next = nrun->next;
4164 free(nrun);
4165 nrun = next;
4166 }
4167 }
4168 break;
4169 case R_JOBDEFS:
4170 case R_JOB:
4171 if (res->res_job.backup_format) { free(res->res_job.backup_format); }
4172 if (res->res_job.RestoreWhere) { free(res->res_job.RestoreWhere); }
4173 if (res->res_job.RegexWhere) { free(res->res_job.RegexWhere); }
4174 if (res->res_job.strip_prefix) { free(res->res_job.strip_prefix); }
4175 if (res->res_job.add_prefix) { free(res->res_job.add_prefix); }
4176 if (res->res_job.add_suffix) { free(res->res_job.add_suffix); }
4177 if (res->res_job.RestoreBootstrap) { free(res->res_job.RestoreBootstrap); }
4178 if (res->res_job.WriteBootstrap) { free(res->res_job.WriteBootstrap); }
4179 if (res->res_job.WriteVerifyList) { free(res->res_job.WriteVerifyList); }
4180 if (res->res_job.selection_pattern) { free(res->res_job.selection_pattern); }
4181 if (res->res_job.run_cmds) { delete res->res_job.run_cmds; }
4182 if (res->res_job.storage) { delete res->res_job.storage; }
4183 if (res->res_job.FdPluginOptions) { delete res->res_job.FdPluginOptions; }
4184 if (res->res_job.SdPluginOptions) { delete res->res_job.SdPluginOptions; }
4185 if (res->res_job.DirPluginOptions) { delete res->res_job.DirPluginOptions; }
4186 if (res->res_job.base) { delete res->res_job.base; }
4187 if (res->res_job.RunScripts) {
4188 FreeRunscripts(res->res_job.RunScripts);
4189 delete res->res_job.RunScripts;
4190 }
4191 if (res->res_job.rjs) { free(res->res_job.rjs); }
4192 break;
4193 case R_MSGS:
4194 if (res->res_msgs.mail_cmd) { free(res->res_msgs.mail_cmd); }
4195 if (res->res_msgs.operator_cmd) { free(res->res_msgs.operator_cmd); }
4196 if (res->res_msgs.timestamp_format) { free(res->res_msgs.timestamp_format); }
4197 FreeMsgsRes((MessagesResource *)res); /* free message resource */
4198 res = NULL;
4199 break;
4200 default:
4201 printf(_("Unknown resource type %d in FreeResource.\n"), type);
4202 }
4203 /*
4204 * Common stuff again -- free the resource, recurse to next one
4205 */
4206 if (res) { free(res); }
4207 if (nres) { my_config->FreeResourceCb_(nres, type); }
4208 }
4209
4210 /**
4211 * Save the new resource by chaining it into the head list for
4212 * the resource. If this is pass 2, we update any resource
4213 * pointers because they may not have been defined until
4214 * later in pass 1.
4215 */
SaveResource(int type,ResourceItem * items,int pass)4216 static bool SaveResource(int type, ResourceItem *items, int pass)
4217 {
4218 int rindex = type - R_FIRST;
4219
4220 switch (type) {
4221 case R_JOBDEFS:
4222 break;
4223 case R_JOB:
4224 /*
4225 * Check Job requirements after applying JobDefs
4226 * Ensure that the name item is present however.
4227 */
4228 if (items[0].flags & CFG_ITEM_REQUIRED) {
4229 if (!BitIsSet(0, res_all.res_dir.hdr.item_present)) {
4230 Emsg2(M_ERROR, 0, _("%s item is required in %s resource, but not found.\n"), items[0].name,
4231 resources[rindex].name);
4232 return false;
4233 }
4234 }
4235 break;
4236 default:
4237 /*
4238 * Ensure that all required items are present
4239 */
4240 if (!ValidateResource(type, items, &res_all.res_dir)) { return false; }
4241 }
4242
4243 /*
4244 * During pass 2 in each "store" routine, we looked up pointers
4245 * to all the resources referenced in the current resource, now we
4246 * must copy their addresses from the static record to the allocated
4247 * record.
4248 */
4249 if (pass == 2) { return UpdateResourcePointer(type, items); }
4250
4251 if (!AddResourceCopyToEndOfChain(&res_all, type)) { return false; }
4252 return true;
4253 }
4254
4255 } /* namespace directordaemon */
4256