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