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