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