1 /*
2 BAREOS® - Backup Archiving REcovery Open Sourced
3
4 Copyright (C) 2000-2012 Free Software Foundation Europe e.V.
5 Copyright (C) 2011-2016 Planets Communications B.V.
6 Copyright (C) 2013-2019 Bareos GmbH & Co. KG
7
8 This program is Free Software; you can redistribute it and/or
9 modify it under the terms of version three of the GNU Affero General Public
10 License as published by the Free Software Foundation and included
11 in the file LICENSE.
12
13 This program is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Affero General Public License for more details.
17
18 You should have received a copy of the GNU Affero General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
21 02110-1301, USA.
22 */
23 /*
24 * Kern Sibbald, September MM
25 */
26 /**
27 * @file
28 * BAREOS Director -- User Agent database handling.
29 */
30
31 #include "include/bareos.h"
32 #include "dird.h"
33 #include "dird/jcr_private.h"
34 #include "dird/ua_db.h"
35 #include "cats/sql_pooling.h"
36 #include "dird/ua_select.h"
37
38 namespace directordaemon {
39
40 /* Imported subroutines */
41
42 /**
43 * This call explicitly checks for a catalog=catalog-name and
44 * if given, opens that catalog. It also checks for
45 * client=client-name and if found, opens the catalog
46 * corresponding to that client. If we still don't
47 * have a catalog, look for a Job keyword and get the
48 * catalog from its client record.
49 */
OpenClientDb(UaContext * ua,bool use_private)50 bool OpenClientDb(UaContext* ua, bool use_private)
51 {
52 int i;
53 CatalogResource* catalog;
54 ClientResource* client;
55 JobResource* job;
56
57 /*
58 * Try for catalog keyword
59 */
60 i = FindArgWithValue(ua, NT_("catalog"));
61 if (i >= 0) {
62 catalog = ua->GetCatalogResWithName(ua->argv[i]);
63 if (catalog) {
64 if (ua->catalog && ua->catalog != catalog) { CloseDb(ua); }
65 ua->catalog = catalog;
66 return OpenDb(ua, use_private);
67 }
68 }
69
70 /*
71 * Try for client keyword
72 */
73 i = FindArgWithValue(ua, NT_("client"));
74 if (i >= 0) {
75 client = ua->GetClientResWithName(ua->argv[i]);
76 if (client) {
77 catalog = client->catalog;
78 if (ua->catalog && ua->catalog != catalog) { CloseDb(ua); }
79 if (!ua->AclAccessOk(Catalog_ACL, catalog->resource_name_, true)) {
80 ua->ErrorMsg(_("No authorization for Catalog \"%s\"\n"),
81 catalog->resource_name_);
82 return false;
83 }
84 ua->catalog = catalog;
85 return OpenDb(ua, use_private);
86 }
87 }
88
89 /*
90 * Try for Job keyword
91 */
92 i = FindArgWithValue(ua, NT_("job"));
93 if (i >= 0) {
94 job = ua->GetJobResWithName(ua->argv[i]);
95 if (job && job->client) {
96 catalog = job->client->catalog;
97 if (ua->catalog && ua->catalog != catalog) { CloseDb(ua); }
98 if (!ua->AclAccessOk(Catalog_ACL, catalog->resource_name_, true)) {
99 ua->ErrorMsg(_("No authorization for Catalog \"%s\"\n"),
100 catalog->resource_name_);
101 return false;
102 }
103 ua->catalog = catalog;
104 return OpenDb(ua, use_private);
105 }
106 }
107
108 return OpenDb(ua, use_private);
109 }
110
111 /**
112 * Open the catalog database.
113 */
OpenDb(UaContext * ua,bool use_private)114 bool OpenDb(UaContext* ua, bool use_private)
115 {
116 bool mult_db_conn;
117
118 /*
119 * See if we need to do any work at all.
120 * Point the current used db e.g. ua->db to the correct database connection.
121 */
122 if (use_private) {
123 if (ua->private_db) {
124 ua->db = ua->private_db;
125 return true;
126 }
127 } else if (ua->shared_db) {
128 ua->db = ua->shared_db;
129 return true;
130 }
131
132 /*
133 * Select the right catalog to use.
134 */
135 if (!ua->catalog) {
136 ua->catalog = get_catalog_resource(ua);
137 if (!ua->catalog) {
138 ua->ErrorMsg(_("Could not find a Catalog resource\n"));
139 return false;
140 }
141 }
142
143 /*
144 * Some modules like bvfs need their own private catalog connection
145 */
146 mult_db_conn = ua->catalog->mult_db_connections;
147 if (use_private) { mult_db_conn = true; }
148
149 ua->jcr->impl->res.catalog = ua->catalog;
150 Dmsg0(100, "UA Open database\n");
151 ua->db = DbSqlGetPooledConnection(
152 ua->jcr, ua->catalog->db_driver, ua->catalog->db_name,
153 ua->catalog->db_user, ua->catalog->db_password.value,
154 ua->catalog->db_address, ua->catalog->db_port, ua->catalog->db_socket,
155 mult_db_conn, ua->catalog->disable_batch_insert,
156 ua->catalog->try_reconnect, ua->catalog->exit_on_fatal, use_private);
157 if (ua->db == NULL) {
158 ua->ErrorMsg(_("Could not open catalog database \"%s\".\n"),
159 ua->catalog->db_name);
160 return false;
161 }
162 ua->jcr->db = ua->db;
163
164 /*
165 * Save the new database connection under the right label e.g. shared or
166 * private.
167 */
168 if (use_private) {
169 ua->private_db = ua->db;
170 } else {
171 ua->shared_db = ua->db;
172 }
173
174 if (!ua->api && !ua->runscript) {
175 ua->SendMsg(_("Using Catalog \"%s\"\n"), ua->catalog->resource_name_);
176 }
177
178 Dmsg1(150, "DB %s opened\n", ua->catalog->db_name);
179 return true;
180 }
181
CloseDb(UaContext * ua)182 void CloseDb(UaContext* ua)
183 {
184 if (ua->jcr) { ua->jcr->db = NULL; }
185
186 if (ua->shared_db) {
187 DbSqlClosePooledConnection(ua->jcr, ua->shared_db);
188 ua->shared_db = NULL;
189 }
190
191 if (ua->private_db) {
192 DbSqlClosePooledConnection(ua->jcr, ua->private_db);
193 ua->private_db = NULL;
194 }
195 }
196
197 /**
198 * Create a pool record from a given Pool resource
199 *
200 * Returns: -1 on error
201 * 0 record already exists
202 * 1 record created
203 */
CreatePool(JobControlRecord * jcr,BareosDb * db,PoolResource * pool,e_pool_op op)204 int CreatePool(JobControlRecord* jcr,
205 BareosDb* db,
206 PoolResource* pool,
207 e_pool_op op)
208 {
209 PoolDbRecord pr;
210
211 bstrncpy(pr.Name, pool->resource_name_, sizeof(pr.Name));
212
213 if (db->GetPoolRecord(jcr, &pr)) {
214 /*
215 * Pool Exists
216 */
217 if (op == POOL_OP_UPDATE) { /* update request */
218 SetPooldbrFromPoolres(&pr, pool, op);
219 SetPooldbrReferences(jcr, db, &pr, pool);
220 db->UpdatePoolRecord(jcr, &pr);
221 }
222 return 0; /* exists */
223 }
224
225 SetPooldbrFromPoolres(&pr, pool, op);
226 SetPooldbrReferences(jcr, db, &pr, pool);
227
228 if (!db->CreatePoolRecord(jcr, &pr)) { return -1; /* error */ }
229 return 1;
230 }
231
232 /**
233 * This is a common routine used to stuff the Pool DB record defaults
234 * into the Media DB record just before creating a media (Volume) record.
235 */
SetPoolDbrDefaultsInMediaDbr(MediaDbRecord * mr,PoolDbRecord * pr)236 void SetPoolDbrDefaultsInMediaDbr(MediaDbRecord* mr, PoolDbRecord* pr)
237 {
238 mr->PoolId = pr->PoolId;
239 bstrncpy(mr->VolStatus, NT_("Append"), sizeof(mr->VolStatus));
240 mr->Recycle = pr->Recycle;
241 mr->VolRetention = pr->VolRetention;
242 mr->VolUseDuration = pr->VolUseDuration;
243 mr->ActionOnPurge = pr->ActionOnPurge;
244 mr->RecyclePoolId = pr->RecyclePoolId;
245 mr->MaxVolJobs = pr->MaxVolJobs;
246 mr->MaxVolFiles = pr->MaxVolFiles;
247 mr->MaxVolBytes = pr->MaxVolBytes;
248 mr->LabelType = pr->LabelType;
249 mr->MinBlocksize = pr->MinBlocksize;
250 mr->MaxBlocksize = pr->MaxBlocksize;
251 mr->Enabled = VOL_ENABLED;
252 }
253
254 /**
255 * Set PoolDbRecord.RecyclePoolId and PoolDbRecord.ScratchPoolId from Pool
256 * resource works with set_pooldbr_from_poolres
257 */
SetPooldbrReferences(JobControlRecord * jcr,BareosDb * db,PoolDbRecord * pr,PoolResource * pool)258 bool SetPooldbrReferences(JobControlRecord* jcr,
259 BareosDb* db,
260 PoolDbRecord* pr,
261 PoolResource* pool)
262 {
263 bool ret = true;
264
265 if (pool->RecyclePool) {
266 PoolDbRecord rpool;
267
268 bstrncpy(rpool.Name, pool->RecyclePool->resource_name_, sizeof(rpool.Name));
269 if (db->GetPoolRecord(jcr, &rpool)) {
270 pr->RecyclePoolId = rpool.PoolId;
271 } else {
272 Jmsg(jcr, M_WARNING, 0,
273 _("Can't set %s RecyclePool to %s, %s is not in database.\n"
274 "Try to update it with 'update pool=%s'\n"),
275 pool->resource_name_, rpool.Name, rpool.Name, pool->resource_name_);
276
277 ret = false;
278 }
279 } else { /* no RecyclePool used, set it to 0 */
280 pr->RecyclePoolId = 0;
281 }
282
283 if (pool->ScratchPool) {
284 PoolDbRecord rpool;
285
286 bstrncpy(rpool.Name, pool->ScratchPool->resource_name_, sizeof(rpool.Name));
287 if (db->GetPoolRecord(jcr, &rpool)) {
288 pr->ScratchPoolId = rpool.PoolId;
289 } else {
290 Jmsg(jcr, M_WARNING, 0,
291 _("Can't set %s ScratchPool to %s, %s is not in database.\n"
292 "Try to update it with 'update pool=%s'\n"),
293 pool->resource_name_, rpool.Name, rpool.Name, pool->resource_name_);
294 ret = false;
295 }
296 } else { /* no ScratchPool used, set it to 0 */
297 pr->ScratchPoolId = 0;
298 }
299
300 return ret;
301 }
302
303 /**
304 * This is a common routine to create or update a
305 * Pool DB base record from a Pool Resource. We handle
306 * the setting of MaxVols and NumVols slightly differently
307 * depending on if we are creating the Pool or we are
308 * simply bringing it into agreement with the resource (update).
309 *
310 * Caution : RecyclePoolId isn't setup in this function.
311 * You can use set_pooldbr_recyclepoolid();
312 */
SetPooldbrFromPoolres(PoolDbRecord * pr,PoolResource * pool,e_pool_op op)313 void SetPooldbrFromPoolres(PoolDbRecord* pr, PoolResource* pool, e_pool_op op)
314 {
315 bstrncpy(pr->PoolType, pool->pool_type, sizeof(pr->PoolType));
316 if (op == POOL_OP_CREATE) {
317 pr->MaxVols = pool->max_volumes;
318 pr->NumVols = 0;
319 } else {
320 /*
321 * Update pool
322 */
323 if (pr->MaxVols != pool->max_volumes) { pr->MaxVols = pool->max_volumes; }
324 if (pr->MaxVols != 0 && pr->MaxVols < pr->NumVols) {
325 pr->MaxVols = pr->NumVols;
326 }
327 }
328 pr->LabelType = pool->LabelType;
329 pr->UseOnce = pool->use_volume_once;
330 pr->UseCatalog = pool->use_catalog;
331 pr->Recycle = pool->Recycle;
332 pr->VolRetention = pool->VolRetention;
333 pr->VolUseDuration = pool->VolUseDuration;
334 pr->MaxVolJobs = pool->MaxVolJobs;
335 pr->MaxVolFiles = pool->MaxVolFiles;
336 pr->MaxVolBytes = pool->MaxVolBytes;
337 pr->AutoPrune = pool->AutoPrune;
338 pr->ActionOnPurge = pool->action_on_purge;
339 pr->ActionOnPurge = pool->action_on_purge;
340 pr->MinBlocksize = pool->MinBlocksize;
341 pr->MaxBlocksize = pool->MaxBlocksize;
342 pr->Recycle = pool->Recycle;
343 if (pool->label_format) {
344 bstrncpy(pr->LabelFormat, pool->label_format, sizeof(pr->LabelFormat));
345 } else {
346 bstrncpy(pr->LabelFormat, "*", sizeof(pr->LabelFormat)); /* none */
347 }
348 }
349
350 /**
351 * set/update Pool.RecyclePoolId and Pool.ScratchPoolId in Catalog
352 */
UpdatePoolReferences(JobControlRecord * jcr,BareosDb * db,PoolResource * pool)353 int UpdatePoolReferences(JobControlRecord* jcr,
354 BareosDb* db,
355 PoolResource* pool)
356 {
357 PoolDbRecord pr;
358
359 if (!pool->RecyclePool && !pool->ScratchPool) { return true; }
360 bstrncpy(pr.Name, pool->resource_name_, sizeof(pr.Name));
361
362 if (!db->GetPoolRecord(jcr, &pr)) { return -1; /* not exists in database */ }
363
364 SetPooldbrFromPoolres(&pr, pool, POOL_OP_UPDATE);
365
366 if (!SetPooldbrReferences(jcr, db, &pr, pool)) { return -1; /* error */ }
367
368 if (!db->UpdatePoolRecord(jcr, &pr)) { return -1; /* error */ }
369 return true;
370 }
371 } /* namespace directordaemon */
372