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 * Split from ua_cmds.c March 2005
25 * Kern Sibbald, September MM
26 */
27 /**
28 * @file
29 * Update command processing
30 */
31
32 #include "include/bareos.h"
33 #include "dird.h"
34 #include "dird/jcr_private.h"
35 #include "dird/next_vol.h"
36 #include "dird/sd_cmds.h"
37 #include "dird/storage.h"
38 #include "dird/ua_db.h"
39 #include "dird/ua_input.h"
40 #include "dird/ua_select.h"
41 #include "lib/edit.h"
42 #include "lib/util.h"
43
44 namespace directordaemon {
45
46 /* Forward referenced functions */
47 static bool UpdateVolume(UaContext* ua);
48 static bool UpdatePool(UaContext* ua);
49 static bool UpdateJob(UaContext* ua);
50 static bool UpdateStats(UaContext* ua);
51 static void UpdateSlots(UaContext* ua);
52
53 /**
54 * Update a Pool Record in the database.
55 * It is always updated from the Resource record.
56 *
57 * update volume pool=<pool-name> volume=<volume-name>
58 * changes pool info for volume
59 * update pool=<pool-name>
60 * updates pool from Pool resource
61 * update slots[=..] [scan]
62 * updates autochanger slots
63 * update jobid[=..] ...
64 * update job information
65 * update stats [days=...]
66 * updates long term statistics
67 */
UpdateCmd(UaContext * ua,const char * cmd)68 bool UpdateCmd(UaContext* ua, const char* cmd)
69 {
70 static const char* kw[] = {NT_("media"), /* 0 */
71 NT_("volume"), /* 1 */
72 NT_("pool"), /* 2 */
73 NT_("slots"), /* 3 */
74 NT_("slot"), /* 4 */
75 NT_("jobid"), /* 5 */
76 NT_("stats"), /* 6 */
77 NULL};
78
79 if (!OpenClientDb(ua)) { return true; }
80
81 switch (FindArgKeyword(ua, kw)) {
82 case 0:
83 case 1:
84 UpdateVolume(ua);
85 return true;
86 case 2:
87 UpdatePool(ua);
88 return true;
89 case 3:
90 case 4:
91 UpdateSlots(ua);
92 return true;
93 case 5:
94 UpdateJob(ua);
95 return true;
96 case 6:
97 UpdateStats(ua);
98 return true;
99 default:
100 break;
101 }
102
103 StartPrompt(ua, _("Update choice:\n"));
104 AddPrompt(ua, _("Volume parameters"));
105 AddPrompt(ua, _("Pool from resource"));
106 AddPrompt(ua, _("Slots from autochanger"));
107 AddPrompt(ua, _("Long term statistics"));
108 switch (
109 DoPrompt(ua, _("item"), _("Choose catalog item to update"), NULL, 0)) {
110 case 0:
111 UpdateVolume(ua);
112 break;
113 case 1:
114 UpdatePool(ua);
115 break;
116 case 2:
117 UpdateSlots(ua);
118 break;
119 case 3:
120 UpdateStats(ua);
121 break;
122 default:
123 break;
124 }
125 return true;
126 }
127
UpdateVolstatus(UaContext * ua,const char * val,MediaDbRecord * mr)128 static void UpdateVolstatus(UaContext* ua, const char* val, MediaDbRecord* mr)
129 {
130 PoolMem query(PM_MESSAGE);
131 const char* kw[] = {NT_("Append"), NT_("Archive"),
132 NT_("Disabled"), NT_("Full"),
133 NT_("Used"), NT_("Cleaning"),
134 NT_("Recycle"), NT_("Read-Only"),
135 NT_("Error"), NULL};
136 bool found = false;
137 int i;
138
139 for (i = 0; kw[i]; i++) {
140 if (Bstrcasecmp(val, kw[i])) {
141 found = true;
142 break;
143 }
144 }
145 if (!found) {
146 ua->ErrorMsg(_("Invalid VolStatus specified: %s\n"), val);
147 } else {
148 char ed1[50];
149 bstrncpy(mr->VolStatus, kw[i], sizeof(mr->VolStatus));
150 Mmsg(query, "UPDATE Media SET VolStatus='%s' WHERE MediaId=%s",
151 mr->VolStatus, edit_int64(mr->MediaId, ed1));
152 if (!ua->db->SqlQuery(query.c_str())) {
153 ua->ErrorMsg("%s", ua->db->strerror());
154 } else {
155 ua->InfoMsg(_("New Volume status is: %s\n"), mr->VolStatus);
156 }
157 }
158 }
159
UpdateVolretention(UaContext * ua,char * val,MediaDbRecord * mr)160 static void UpdateVolretention(UaContext* ua, char* val, MediaDbRecord* mr)
161 {
162 char ed1[150], ed2[50];
163 PoolMem query(PM_MESSAGE);
164
165 if (!DurationToUtime(val, &mr->VolRetention)) {
166 ua->ErrorMsg(_("Invalid retention period specified: %s\n"), val);
167 return;
168 }
169 Mmsg(query, "UPDATE Media SET VolRetention=%s WHERE MediaId=%s",
170 edit_uint64(mr->VolRetention, ed1), edit_int64(mr->MediaId, ed2));
171 if (!ua->db->SqlQuery(query.c_str())) {
172 ua->ErrorMsg("%s", ua->db->strerror());
173 } else {
174 ua->InfoMsg(_("New retention period is: %s\n"),
175 edit_utime(mr->VolRetention, ed1, sizeof(ed1)));
176 }
177 }
178
UpdateVoluseduration(UaContext * ua,char * val,MediaDbRecord * mr)179 static void UpdateVoluseduration(UaContext* ua, char* val, MediaDbRecord* mr)
180 {
181 char ed1[150], ed2[50];
182 PoolMem query(PM_MESSAGE);
183
184 if (!DurationToUtime(val, &mr->VolUseDuration)) {
185 ua->ErrorMsg(_("Invalid use duration specified: %s\n"), val);
186 return;
187 }
188 Mmsg(query, "UPDATE Media SET VolUseDuration=%s WHERE MediaId=%s",
189 edit_uint64(mr->VolUseDuration, ed1), edit_int64(mr->MediaId, ed2));
190 if (!ua->db->SqlQuery(query.c_str())) {
191 ua->ErrorMsg("%s", ua->db->strerror());
192 } else {
193 ua->InfoMsg(_("New use duration is: %s\n"),
194 edit_utime(mr->VolUseDuration, ed1, sizeof(ed1)));
195 }
196 }
197
UpdateVolmaxjobs(UaContext * ua,char * val,MediaDbRecord * mr)198 static void UpdateVolmaxjobs(UaContext* ua, char* val, MediaDbRecord* mr)
199 {
200 PoolMem query(PM_MESSAGE);
201 char ed1[50];
202
203 Mmsg(query, "UPDATE Media SET MaxVolJobs=%s WHERE MediaId=%s", val,
204 edit_int64(mr->MediaId, ed1));
205 if (!ua->db->SqlQuery(query.c_str())) {
206 ua->ErrorMsg("%s", ua->db->strerror());
207 } else {
208 ua->InfoMsg(_("New max jobs is: %s\n"), val);
209 }
210 }
211
UpdateVolmaxfiles(UaContext * ua,char * val,MediaDbRecord * mr)212 static void UpdateVolmaxfiles(UaContext* ua, char* val, MediaDbRecord* mr)
213 {
214 PoolMem query(PM_MESSAGE);
215 char ed1[50];
216
217 Mmsg(query, "UPDATE Media SET MaxVolFiles=%s WHERE MediaId=%s", val,
218 edit_int64(mr->MediaId, ed1));
219 if (!ua->db->SqlQuery(query.c_str())) {
220 ua->ErrorMsg("%s", ua->db->strerror());
221 } else {
222 ua->InfoMsg(_("New max files is: %s\n"), val);
223 }
224 }
225
UpdateVolmaxbytes(UaContext * ua,char * val,MediaDbRecord * mr)226 static void UpdateVolmaxbytes(UaContext* ua, char* val, MediaDbRecord* mr)
227 {
228 uint64_t maxbytes;
229 char ed1[50], ed2[50];
230 PoolMem query(PM_MESSAGE);
231
232 if (!size_to_uint64(val, &maxbytes)) {
233 ua->ErrorMsg(_("Invalid max. bytes specification: %s\n"), val);
234 return;
235 }
236 Mmsg(query, "UPDATE Media SET MaxVolBytes=%s WHERE MediaId=%s",
237 edit_uint64(maxbytes, ed1), edit_int64(mr->MediaId, ed2));
238 if (!ua->db->SqlQuery(query.c_str())) {
239 ua->ErrorMsg("%s", ua->db->strerror());
240 } else {
241 ua->InfoMsg(_("New Max bytes is: %s\n"), edit_uint64(maxbytes, ed1));
242 }
243 }
244
UpdateVolrecycle(UaContext * ua,char * val,MediaDbRecord * mr)245 static void UpdateVolrecycle(UaContext* ua, char* val, MediaDbRecord* mr)
246 {
247 bool recycle;
248 char ed1[50];
249 PoolMem query(PM_MESSAGE);
250
251 if (!IsYesno(val, &recycle)) {
252 ua->ErrorMsg(_("Invalid value. It must be yes or no.\n"));
253 return;
254 }
255
256 Mmsg(query, "UPDATE Media SET Recycle=%d WHERE MediaId=%s", recycle ? 1 : 0,
257 edit_int64(mr->MediaId, ed1));
258
259 if (!ua->db->SqlQuery(query.c_str())) {
260 ua->ErrorMsg("%s", ua->db->strerror());
261 } else {
262 ua->InfoMsg(_("New Recycle flag is: %s\n"), recycle ? _("yes") : _("no"));
263 }
264 }
265
UpdateVolinchanger(UaContext * ua,char * val,MediaDbRecord * mr)266 static void UpdateVolinchanger(UaContext* ua, char* val, MediaDbRecord* mr)
267 {
268 char ed1[50];
269 bool InChanger;
270 PoolMem query(PM_MESSAGE);
271
272 if (!IsYesno(val, &InChanger)) {
273 ua->ErrorMsg(_("Invalid value. It must be yes or no.\n"));
274 return;
275 }
276
277 Mmsg(query, "UPDATE Media SET InChanger=%d WHERE MediaId=%s",
278 InChanger ? 1 : 0, edit_int64(mr->MediaId, ed1));
279
280 if (!ua->db->SqlQuery(query.c_str())) {
281 ua->ErrorMsg("%s", ua->db->strerror());
282 } else {
283 ua->InfoMsg(_("New InChanger flag is: %s\n"),
284 InChanger ? _("yes") : _("no"));
285 }
286 }
287
UpdateVolslot(UaContext * ua,char * val,MediaDbRecord * mr)288 static void UpdateVolslot(UaContext* ua, char* val, MediaDbRecord* mr)
289 {
290 PoolDbRecord pr;
291
292 pr.PoolId = mr->PoolId;
293 if (!ua->db->GetPoolRecord(ua->jcr, &pr)) {
294 ua->ErrorMsg("%s", ua->db->strerror());
295 return;
296 }
297 mr->Slot = atoi(val);
298 if (pr.MaxVols > 0 && mr->Slot > (int)pr.MaxVols) {
299 ua->ErrorMsg(_("Invalid slot, it must be between 0 and MaxVols=%d\n"),
300 pr.MaxVols);
301 return;
302 }
303 /*
304 * Make sure to use db_update... rather than doing this directly,
305 * so that any Slot is handled correctly.
306 */
307 SetStorageidInMr(NULL, mr);
308 if (!ua->db->UpdateMediaRecord(ua->jcr, mr)) {
309 ua->ErrorMsg(_("Error updating media record Slot: ERR=%s"),
310 ua->db->strerror());
311 } else {
312 ua->InfoMsg(_("New Slot is: %d\n"), mr->Slot);
313 }
314 }
315
316 /**
317 * Modify the Pool in which this Volume is located
318 */
UpdateVolPool(UaContext * ua,char * val,MediaDbRecord * mr,PoolDbRecord * opr)319 void UpdateVolPool(UaContext* ua,
320 char* val,
321 MediaDbRecord* mr,
322 PoolDbRecord* opr)
323 {
324 PoolDbRecord pr;
325 PoolMem query(PM_MESSAGE);
326 char ed1[50], ed2[50];
327
328 bstrncpy(pr.Name, val, sizeof(pr.Name));
329 if (!GetPoolDbr(ua, &pr)) { return; }
330 mr->PoolId = pr.PoolId; /* set new PoolId */
331
332 DbLock(ua->db);
333 Mmsg(query, "UPDATE Media SET PoolId=%s WHERE MediaId=%s",
334 edit_int64(mr->PoolId, ed1), edit_int64(mr->MediaId, ed2));
335 if (!ua->db->SqlQuery(query.c_str())) {
336 ua->ErrorMsg("%s", ua->db->strerror());
337 } else {
338 ua->InfoMsg(_("New Pool is: %s\n"), pr.Name);
339 opr->NumVols--;
340 if (!ua->db->UpdatePoolRecord(ua->jcr, opr)) {
341 ua->ErrorMsg("%s", ua->db->strerror());
342 }
343 pr.NumVols++;
344 if (!ua->db->UpdatePoolRecord(ua->jcr, &pr)) {
345 ua->ErrorMsg("%s", ua->db->strerror());
346 }
347 }
348 DbUnlock(ua->db);
349 }
350
351 /**
352 * Modify the RecyclePool of a Volume
353 */
UpdateVolRecyclepool(UaContext * ua,char * val,MediaDbRecord * mr)354 void UpdateVolRecyclepool(UaContext* ua, char* val, MediaDbRecord* mr)
355 {
356 PoolDbRecord pr;
357 PoolMem query(PM_MESSAGE);
358 char ed1[50], ed2[50];
359 const char* poolname;
360
361 if (val && *val) { /* update volume recyclepool="Scratch" */
362 /*
363 * If a pool name is given, look up the PoolId
364 */
365 bstrncpy(pr.Name, val, sizeof(pr.Name));
366 if (!GetPoolDbr(ua, &pr, NT_("recyclepool"))) { return; }
367 mr->RecyclePoolId = pr.PoolId; /* get the PoolId */
368 poolname = pr.Name;
369 } else { /* update volume recyclepool="" */
370 /*
371 * If no pool name is given, set the PoolId to 0 (the default)
372 */
373 mr->RecyclePoolId = 0;
374 poolname = _("*None*");
375 }
376
377 DbLock(ua->db);
378 Mmsg(query, "UPDATE Media SET RecyclePoolId=%s WHERE MediaId=%s",
379 edit_int64(mr->RecyclePoolId, ed1), edit_int64(mr->MediaId, ed2));
380 if (!ua->db->SqlQuery(query.c_str())) {
381 ua->ErrorMsg("%s", ua->db->strerror());
382 } else {
383 ua->InfoMsg(_("New RecyclePool is: %s\n"), poolname);
384 }
385 DbUnlock(ua->db);
386 }
387
388 /**
389 * Modify the Storage in which this Volume is located
390 */
UpdateVolStorage(UaContext * ua,char * val,MediaDbRecord * mr)391 void UpdateVolStorage(UaContext* ua, char* val, MediaDbRecord* mr)
392 {
393 StorageDbRecord sr;
394 PoolMem query(PM_MESSAGE);
395 char ed1[50], ed2[50];
396
397 bstrncpy(sr.Name, val, sizeof(sr.Name));
398 if (!GetStorageDbr(ua, &sr)) { return; }
399 mr->StorageId = sr.StorageId; /* set new StorageId */
400
401 DbLock(ua->db);
402 Mmsg(query, "UPDATE Media SET StorageId=%s WHERE MediaId=%s",
403 edit_int64(mr->StorageId, ed1), edit_int64(mr->MediaId, ed2));
404 if (!ua->db->SqlQuery(query.c_str())) {
405 ua->ErrorMsg("%s", ua->db->strerror());
406 }
407
408 DbUnlock(ua->db);
409 }
410
411 /**
412 * Refresh the Volume information from the Pool record
413 */
UpdateVolFromPool(UaContext * ua,MediaDbRecord * mr)414 static void UpdateVolFromPool(UaContext* ua, MediaDbRecord* mr)
415 {
416 PoolDbRecord pr;
417
418 pr.PoolId = mr->PoolId;
419 if (!ua->db->GetPoolRecord(ua->jcr, &pr) ||
420 !ua->AclAccessOk(Pool_ACL, pr.Name, true)) {
421 return;
422 }
423 SetPoolDbrDefaultsInMediaDbr(mr, &pr);
424 if (!ua->db->UpdateMediaDefaults(ua->jcr, mr)) {
425 ua->ErrorMsg(_("Error updating Volume record: ERR=%s"), ua->db->strerror());
426 } else {
427 ua->InfoMsg(_("Volume defaults updated from \"%s\" Pool record.\n"),
428 pr.Name);
429 }
430 }
431
432 /**
433 * Refresh the Volume information from the Pool record for all Volumes
434 */
UpdateAllVolsFromPool(UaContext * ua,const char * pool_name)435 static void UpdateAllVolsFromPool(UaContext* ua, const char* pool_name)
436 {
437 PoolDbRecord pr;
438 MediaDbRecord mr;
439
440 bstrncpy(pr.Name, pool_name, sizeof(pr.Name));
441 if (!GetPoolDbr(ua, &pr)) { return; }
442 SetPoolDbrDefaultsInMediaDbr(&mr, &pr);
443 mr.PoolId = pr.PoolId;
444 if (!ua->db->UpdateMediaDefaults(ua->jcr, &mr)) {
445 ua->ErrorMsg(_("Error updating Volume records: ERR=%s"),
446 ua->db->strerror());
447 } else {
448 ua->InfoMsg(_("All Volume defaults updated from \"%s\" Pool record.\n"),
449 pr.Name);
450 }
451 }
452
UpdateAllVols(UaContext * ua)453 static void UpdateAllVols(UaContext* ua)
454 {
455 int i, num_pools;
456 uint32_t* ids;
457 PoolDbRecord pr;
458 MediaDbRecord mr;
459
460 if (!ua->db->GetPoolIds(ua->jcr, &num_pools, &ids)) {
461 ua->ErrorMsg(_("Error obtaining pool ids. ERR=%s\n"), ua->db->strerror());
462 return;
463 }
464
465 for (i = 0; i < num_pools; i++) {
466 pr.PoolId = ids[i];
467 if (!ua->db->GetPoolRecord(ua->jcr, &pr)) {
468 ua->WarningMsg(_("Updating all pools, but skipped PoolId=%d. ERR=%s\n"),
469 ua->db->strerror());
470 continue;
471 }
472
473 /*
474 * Check access to pool.
475 */
476 if (!ua->AclAccessOk(Pool_ACL, pr.Name, false)) { continue; }
477
478 SetPoolDbrDefaultsInMediaDbr(&mr, &pr);
479 mr.PoolId = pr.PoolId;
480
481 if (!ua->db->UpdateMediaDefaults(ua->jcr, &mr)) {
482 ua->ErrorMsg(_("Error updating Volume records: ERR=%s"),
483 ua->db->strerror());
484 } else {
485 ua->InfoMsg(_("All Volume defaults updated from \"%s\" Pool record.\n"),
486 pr.Name);
487 }
488 }
489
490 free(ids);
491 }
492
UpdateVolenabled(UaContext * ua,char * val,MediaDbRecord * mr)493 static void UpdateVolenabled(UaContext* ua, char* val, MediaDbRecord* mr)
494 {
495 mr->Enabled = GetEnabled(ua, val);
496 if (mr->Enabled < 0) { return; }
497 SetStorageidInMr(NULL, mr);
498 if (!ua->db->UpdateMediaRecord(ua->jcr, mr)) {
499 ua->ErrorMsg(_("Error updating media record Enabled: ERR=%s"),
500 ua->db->strerror());
501 } else {
502 ua->InfoMsg(_("New Enabled is: %d\n"), mr->Enabled);
503 }
504 }
505
UpdateVolActiononpurge(UaContext * ua,char * val,MediaDbRecord * mr)506 static void UpdateVolActiononpurge(UaContext* ua, char* val, MediaDbRecord* mr)
507 {
508 PoolMem ret;
509 if (Bstrcasecmp(val, "truncate")) {
510 mr->ActionOnPurge = ON_PURGE_TRUNCATE;
511 } else {
512 mr->ActionOnPurge = 0;
513 }
514
515 SetStorageidInMr(NULL, mr);
516 if (!ua->db->UpdateMediaRecord(ua->jcr, mr)) {
517 ua->ErrorMsg(_("Error updating media record ActionOnPurge: ERR=%s"),
518 ua->db->strerror());
519 } else {
520 ua->InfoMsg(_("New ActionOnPurge is: %s\n"),
521 action_on_purge_to_string(mr->ActionOnPurge, ret));
522 }
523 }
524
525 /**
526 * Update a media record -- allows you to change the
527 * Volume status. E.g. if you want BAREOS to stop
528 * writing on the volume, set it to anything other
529 * than Append.
530 */
UpdateVolume(UaContext * ua)531 static bool UpdateVolume(UaContext* ua)
532 {
533 PoolResource* pool;
534 POOLMEM* query;
535 PoolMem ret;
536 char buf[1000];
537 char ed1[130];
538 bool done = false;
539 int i;
540 const char* kw[] = {NT_("VolStatus"), /* 0 */
541 NT_("VolRetention"), /* 1 */
542 NT_("VolUse"), /* 2 */
543 NT_("MaxVolJobs"), /* 3 */
544 NT_("MaxVolFiles"), /* 4 */
545 NT_("MaxVolBytes"), /* 5 */
546 NT_("Recycle"), /* 6 */
547 NT_("InChanger"), /* 7 */
548 NT_("Slot"), /* 8 */
549 NT_("Pool"), /* 9 */
550 NT_("FromPool"), /* 10 */
551 NT_("AllFromPool"), /* 11 !!! see below !!! */
552 NT_("Enabled"), /* 12 */
553 NT_("RecyclePool"), /* 13 */
554 NT_("ActionOnPurge"), /* 14 */
555 NT_("Storage"), /* 15 */
556 NULL};
557
558 #define AllFromPool 11 /* keep this updated with above */
559
560 for (i = 0; kw[i]; i++) {
561 int j;
562 PoolDbRecord pr;
563 MediaDbRecord mr;
564
565 if ((j = FindArgWithValue(ua, kw[i])) > 0) {
566 /* If all from pool don't select a media record */
567 if (i != AllFromPool && !SelectMediaDbr(ua, &mr)) { return false; }
568 switch (i) {
569 case 0:
570 UpdateVolstatus(ua, ua->argv[j], &mr);
571 break;
572 case 1:
573 UpdateVolretention(ua, ua->argv[j], &mr);
574 break;
575 case 2:
576 UpdateVoluseduration(ua, ua->argv[j], &mr);
577 break;
578 case 3:
579 UpdateVolmaxjobs(ua, ua->argv[j], &mr);
580 break;
581 case 4:
582 UpdateVolmaxfiles(ua, ua->argv[j], &mr);
583 break;
584 case 5:
585 UpdateVolmaxbytes(ua, ua->argv[j], &mr);
586 break;
587 case 6:
588 UpdateVolrecycle(ua, ua->argv[j], &mr);
589 break;
590 case 7:
591 UpdateVolinchanger(ua, ua->argv[j], &mr);
592 break;
593 case 8:
594 UpdateVolslot(ua, ua->argv[j], &mr);
595 break;
596 case 9:
597 pr.PoolId = mr.PoolId;
598 if (!ua->db->GetPoolRecord(ua->jcr, &pr)) {
599 ua->ErrorMsg("%s", ua->db->strerror());
600 break;
601 }
602 UpdateVolPool(ua, ua->argv[j], &mr, &pr);
603 break;
604 case 10:
605 UpdateVolFromPool(ua, &mr);
606 return true;
607 case 11:
608 UpdateAllVolsFromPool(ua, ua->argv[j]);
609 return true;
610 case 12:
611 UpdateVolenabled(ua, ua->argv[j], &mr);
612 break;
613 case 13:
614 UpdateVolRecyclepool(ua, ua->argv[j], &mr);
615 break;
616 case 14:
617 UpdateVolActiononpurge(ua, ua->argv[j], &mr);
618 break;
619 case 15:
620 UpdateVolStorage(ua, ua->argv[j], &mr);
621 break;
622 }
623 done = true;
624 }
625 }
626
627 /* Allow user to simply update all volumes */
628 if (FindArg(ua, NT_("fromallpools")) > 0) {
629 UpdateAllVols(ua);
630 return true;
631 }
632
633 for (; !done;) {
634 PoolDbRecord pr;
635 MediaDbRecord mr;
636 StorageDbRecord sr;
637
638 StartPrompt(ua, _("Parameters to modify:\n"));
639 AddPrompt(ua, _("Volume Status")); /* 0 */
640 AddPrompt(ua, _("Volume Retention Period")); /* 1 */
641 AddPrompt(ua, _("Volume Use Duration")); /* 2 */
642 AddPrompt(ua, _("Maximum Volume Jobs")); /* 3 */
643 AddPrompt(ua, _("Maximum Volume Files")); /* 4 */
644 AddPrompt(ua, _("Maximum Volume Bytes")); /* 5 */
645 AddPrompt(ua, _("Recycle Flag")); /* 6 */
646 AddPrompt(ua, _("Slot")); /* 7 */
647 AddPrompt(ua, _("InChanger Flag")); /* 8 */
648 AddPrompt(ua, _("Volume Files")); /* 9 */
649 AddPrompt(ua, _("Pool")); /* 10 */
650 AddPrompt(ua, _("Volume from Pool")); /* 11 */
651 AddPrompt(ua, _("All Volumes from Pool")); /* 12 */
652 AddPrompt(ua, _("All Volumes from all Pools")); /* 13 */
653 AddPrompt(ua, _("Enabled")), /* 14 */
654 AddPrompt(ua, _("RecyclePool")), /* 15 */
655 AddPrompt(ua, _("Action On Purge")), /* 16 */
656 AddPrompt(ua, _("Storage")), /* 17 */
657 AddPrompt(ua, _("Done")); /* 18 */
658 i = DoPrompt(ua, "", _("Select parameter to modify"), NULL, 0);
659
660 /* For All Volumes, All Volumes from Pool, and Done, we don't need
661 * a Volume record */
662 if (i != 12 && i != 13 && i != 18) {
663 if (!SelectMediaDbr(ua, &mr)) { /* Get Volume record */
664 return false;
665 }
666 ua->InfoMsg(_("Updating Volume \"%s\"\n"), mr.VolumeName);
667 }
668 switch (i) {
669 case 0: /* Volume Status */
670 /* Modify Volume Status */
671 ua->InfoMsg(_("Current Volume status is: %s\n"), mr.VolStatus);
672 StartPrompt(ua, _("Possible Values are:\n"));
673 AddPrompt(ua, NT_("Append"));
674 AddPrompt(ua, NT_("Archive"));
675 AddPrompt(ua, NT_("Disabled"));
676 AddPrompt(ua, NT_("Full"));
677 AddPrompt(ua, NT_("Used"));
678 AddPrompt(ua, NT_("Cleaning"));
679 if (bstrcmp(mr.VolStatus, NT_("Purged"))) {
680 AddPrompt(ua, NT_("Recycle"));
681 }
682 AddPrompt(ua, NT_("Read-Only"));
683 if (DoPrompt(ua, "", _("Choose new Volume Status"), ua->cmd,
684 sizeof(mr.VolStatus)) < 0) {
685 return true;
686 }
687 UpdateVolstatus(ua, ua->cmd, &mr);
688 break;
689 case 1: /* Retention */
690 ua->InfoMsg(_("Current retention period is: %s\n"),
691 edit_utime(mr.VolRetention, ed1, sizeof(ed1)));
692 if (!GetCmd(ua, _("Enter Volume Retention period: "))) { return false; }
693 UpdateVolretention(ua, ua->cmd, &mr);
694 break;
695
696 case 2: /* Use Duration */
697 ua->InfoMsg(_("Current use duration is: %s\n"),
698 edit_utime(mr.VolUseDuration, ed1, sizeof(ed1)));
699 if (!GetCmd(ua, _("Enter Volume Use Duration: "))) { return false; }
700 UpdateVoluseduration(ua, ua->cmd, &mr);
701 break;
702
703 case 3: /* Max Jobs */
704 ua->InfoMsg(_("Current max jobs is: %u\n"), mr.MaxVolJobs);
705 if (!GetPint(ua, _("Enter new Maximum Jobs: "))) { return false; }
706 UpdateVolmaxjobs(ua, ua->cmd, &mr);
707 break;
708
709 case 4: /* Max Files */
710 ua->InfoMsg(_("Current max files is: %u\n"), mr.MaxVolFiles);
711 if (!GetPint(ua, _("Enter new Maximum Files: "))) { return false; }
712 UpdateVolmaxfiles(ua, ua->cmd, &mr);
713 break;
714
715 case 5: /* Max Bytes */
716 ua->InfoMsg(_("Current value is: %s\n"),
717 edit_uint64(mr.MaxVolBytes, ed1));
718 if (!GetCmd(ua, _("Enter new Maximum Bytes: "))) { return false; }
719 UpdateVolmaxbytes(ua, ua->cmd, &mr);
720 break;
721
722
723 case 6: /* Recycle */
724 ua->InfoMsg(_("Current recycle flag is: %s\n"),
725 (mr.Recycle == 1) ? _("yes") : _("no"));
726 if (!GetYesno(ua, _("Enter new Recycle status: "))) { return false; }
727 UpdateVolrecycle(ua, ua->cmd, &mr);
728 break;
729
730 case 7: /* Slot */
731 ua->InfoMsg(_("Current Slot is: %d\n"), mr.Slot);
732 if (!GetPint(ua, _("Enter new Slot: "))) { return false; }
733 UpdateVolslot(ua, ua->cmd, &mr);
734 break;
735
736 case 8: /* InChanger */
737 ua->InfoMsg(_("Current InChanger flag is: %d\n"), mr.InChanger);
738 Bsnprintf(buf, sizeof(buf),
739 _("Set InChanger flag for Volume \"%s\": yes/no: "),
740 mr.VolumeName);
741 if (!GetYesno(ua, buf)) { return false; }
742 mr.InChanger = ua->pint32_val;
743 /*
744 * Make sure to use db_update... rather than doing this directly,
745 * so that any Slot is handled correctly.
746 */
747 SetStorageidInMr(NULL, &mr);
748 if (!ua->db->UpdateMediaRecord(ua->jcr, &mr)) {
749 ua->ErrorMsg(_("Error updating media record Slot: ERR=%s"),
750 ua->db->strerror());
751 } else {
752 ua->InfoMsg(_("New InChanger flag is: %d\n"), mr.InChanger);
753 }
754 break;
755
756
757 case 9: /* Volume Files */
758 int32_t VolFiles;
759 ua->WarningMsg(
760 _("Warning changing Volume Files can result\n"
761 "in loss of data on your Volume\n\n"));
762 ua->InfoMsg(_("Current Volume Files is: %u\n"), mr.VolFiles);
763 if (!GetPint(ua, _("Enter new number of Files for Volume: "))) {
764 return false;
765 }
766 VolFiles = ua->pint32_val;
767 if (VolFiles != (int)(mr.VolFiles + 1)) {
768 ua->WarningMsg(
769 _("Normally, you should only increase Volume Files by one!\n"));
770 if (!GetYesno(ua, _("Increase Volume Files? (yes/no): ")) ||
771 !ua->pint32_val) {
772 break;
773 }
774 }
775 query = GetPoolMemory(PM_MESSAGE);
776 Mmsg(query, "UPDATE Media SET VolFiles=%u WHERE MediaId=%s", VolFiles,
777 edit_int64(mr.MediaId, ed1));
778 if (!ua->db->SqlQuery(query)) {
779 ua->ErrorMsg("%s", ua->db->strerror());
780 } else {
781 ua->InfoMsg(_("New Volume Files is: %u\n"), VolFiles);
782 }
783 FreePoolMemory(query);
784 break;
785
786 case 10: /* Volume's Pool */
787 pr.PoolId = mr.PoolId;
788 if (!ua->db->GetPoolRecord(ua->jcr, &pr)) {
789 ua->ErrorMsg("%s", ua->db->strerror());
790 return false;
791 }
792 ua->InfoMsg(_("Current Pool is: %s\n"), pr.Name);
793 if (!GetCmd(ua, _("Enter new Pool name: "))) { return false; }
794 UpdateVolPool(ua, ua->cmd, &mr, &pr);
795 return true;
796
797 case 11:
798 UpdateVolFromPool(ua, &mr);
799 return true;
800 case 12:
801 pool = select_pool_resource(ua);
802 if (pool) { UpdateAllVolsFromPool(ua, pool->resource_name_); }
803 return true;
804
805 case 13:
806 UpdateAllVols(ua);
807 return true;
808
809 case 14:
810 ua->InfoMsg(_("Current Enabled is: %d\n"), mr.Enabled);
811 if (!GetCmd(ua, _("Enter new Enabled: "))) { return false; }
812
813 UpdateVolenabled(ua, ua->cmd, &mr);
814 break;
815
816 case 15:
817 pr.PoolId = mr.RecyclePoolId;
818 if (ua->db->GetPoolRecord(ua->jcr, &pr)) {
819 ua->InfoMsg(_("Current RecyclePool is: %s\n"), pr.Name);
820 } else {
821 ua->InfoMsg(_("No current RecyclePool\n"));
822 }
823 if (!SelectPoolDbr(ua, &pr, NT_("recyclepool"))) { return false; }
824 UpdateVolRecyclepool(ua, pr.Name, &mr);
825 return true;
826
827 case 16:
828 PmStrcpy(ret, "");
829 ua->InfoMsg(_("Current ActionOnPurge is: %s\n"),
830 action_on_purge_to_string(mr.ActionOnPurge, ret));
831 if (!GetCmd(ua,
832 _("Enter new ActionOnPurge (one of: Truncate, None): "))) {
833 return false;
834 }
835
836 UpdateVolActiononpurge(ua, ua->cmd, &mr);
837 break;
838
839 case 17:
840 sr.StorageId = mr.StorageId;
841 if (ua->db->GetStorageRecord(ua->jcr, &sr)) {
842 ua->InfoMsg(_("Current Storage is: %s\n"), sr.Name);
843 } else {
844 ua->InfoMsg(_("Warning, could not find current Storage\n"));
845 }
846 if (!SelectStorageDbr(ua, &sr, NT_("storage"))) { return false; }
847 UpdateVolStorage(ua, sr.Name, &mr);
848 ua->InfoMsg(_("New Storage is: %s\n"), sr.Name);
849 return true;
850
851 default: /* Done or error */
852 ua->InfoMsg(_("Selection terminated.\n"));
853 return true;
854 }
855 }
856 return true;
857 }
858
859 /**
860 * Update long term statistics
861 */
UpdateStats(UaContext * ua)862 static bool UpdateStats(UaContext* ua)
863 {
864 int i = FindArgWithValue(ua, NT_("days"));
865 utime_t since = 0;
866
867 if (i >= 0) { since = ((int64_t)atoi(ua->argv[i]) * 24 * 60 * 60); }
868
869 int nb = ua->db->UpdateStats(ua->jcr, since);
870 ua->InfoMsg(_("Updating %i job(s).\n"), nb);
871
872 return true;
873 }
874
875 /**
876 * Update pool record -- pull info from current POOL resource
877 */
UpdatePool(UaContext * ua)878 static bool UpdatePool(UaContext* ua)
879 {
880 int id;
881 PoolDbRecord pr;
882 char ed1[50];
883 PoolResource* pool;
884 PoolMem query(PM_MESSAGE);
885
886 pool = get_pool_resource(ua);
887 if (!pool) { return false; }
888
889 bstrncpy(pr.Name, pool->resource_name_, sizeof(pr.Name));
890 if (!GetPoolDbr(ua, &pr)) { return false; }
891
892 SetPooldbrFromPoolres(&pr, pool, POOL_OP_UPDATE); /* update */
893 SetPooldbrReferences(ua->jcr, ua->db, &pr, pool);
894
895 id = ua->db->UpdatePoolRecord(ua->jcr, &pr);
896 if (id <= 0) {
897 ua->ErrorMsg(_("UpdatePoolRecord returned %d. ERR=%s\n"), id,
898 ua->db->strerror());
899 }
900 ua->db->FillQuery(query, BareosDb::SQL_QUERY::list_pool,
901 edit_int64(pr.PoolId, ed1));
902 ua->db->ListSqlQuery(ua->jcr, query.c_str(), ua->send, HORZ_LIST, true);
903 ua->InfoMsg(_("Pool DB record updated from resource.\n"));
904
905 return true;
906 }
907
908 /**
909 * Update a Job record -- allows to change the fields in a Job record.
910 */
UpdateJob(UaContext * ua)911 static bool UpdateJob(UaContext* ua)
912 {
913 int i;
914 char ed1[50], ed2[50], ed3[50], ed4[50];
915 PoolMem cmd(PM_MESSAGE);
916 JobDbRecord jr;
917 ClientDbRecord cr;
918 utime_t StartTime;
919 char* client_name = NULL;
920 char* job_name = NULL;
921 char* start_time = NULL;
922 char job_type = '\0';
923 DBId_t fileset_id = 0;
924 const char* kw[] = {NT_("starttime"), /* 0 */
925 NT_("client"), /* 1 */
926 NT_("filesetid"), /* 2 */
927 NT_("jobname"), /* 3 */
928 NT_("jobtype"), /* 4 */
929 NULL};
930
931 Dmsg1(200, "cmd=%s\n", ua->cmd);
932 i = FindArgWithValue(ua, NT_("jobid"));
933 if (i < 0) {
934 ua->ErrorMsg(_("Expect JobId keyword, not found.\n"));
935 return false;
936 }
937 jr.JobId = str_to_int64(ua->argv[i]);
938 if (!ua->db->GetJobRecord(ua->jcr, &jr)) {
939 ua->ErrorMsg("%s", ua->db->strerror());
940 return false;
941 }
942
943 for (i = 0; kw[i]; i++) {
944 int j;
945 if ((j = FindArgWithValue(ua, kw[i])) >= 0) {
946 switch (i) {
947 case 0: /* Start time */
948 start_time = ua->argv[j];
949 break;
950 case 1: /* Client name */
951 client_name = ua->argv[j];
952 break;
953 case 2: /* Fileset id */
954 fileset_id = str_to_uint64(ua->argv[j]);
955 break;
956 case 3: /* Job name */
957 job_name = ua->argv[j];
958 break;
959 case 4: /* Job Type */
960 job_type = ua->argv[j][0];
961 break;
962 }
963 }
964 }
965 if (!client_name && !start_time && !fileset_id && !job_name && !job_type) {
966 ua->ErrorMsg(_(
967 "Neither Client, StartTime, Filesetid, JobType nor Name specified.\n"));
968 return false;
969 }
970 if (client_name) {
971 if (!GetClientDbr(ua, &cr)) { return false; }
972 jr.ClientId = cr.ClientId;
973 }
974 if (fileset_id) { jr.FileSetId = fileset_id; }
975 if (job_name) { bstrncpy(jr.Name, job_name, MAX_NAME_LENGTH); }
976 if (job_type) { jr.JobType = job_type; }
977 if (start_time) {
978 utime_t delta_start;
979
980 StartTime = StrToUtime(start_time);
981 if (StartTime == 0) {
982 ua->ErrorMsg(_("Improper date format: %s\n"), ua->argv[i]);
983 return false;
984 }
985 delta_start = StartTime - jr.StartTime;
986 Dmsg3(200, "ST=%lld jr.ST=%lld delta=%lld\n", StartTime,
987 (utime_t)jr.StartTime, delta_start);
988 jr.StartTime = (time_t)StartTime;
989 jr.SchedTime += (time_t)delta_start;
990 jr.EndTime += (time_t)delta_start;
991 jr.JobTDate += delta_start;
992 /* Convert to DB times */
993 bstrutime(jr.cStartTime, sizeof(jr.cStartTime), jr.StartTime);
994 bstrutime(jr.cSchedTime, sizeof(jr.cSchedTime), jr.SchedTime);
995 bstrutime(jr.cEndTime, sizeof(jr.cEndTime), jr.EndTime);
996 }
997 Mmsg(cmd,
998 "UPDATE Job SET Name='%s', ClientId=%s,StartTime='%s',SchedTime='%s',"
999 "EndTime='%s',JobTDate=%s, FileSetId='%s', Type='%c' WHERE JobId=%s",
1000 jr.Name, edit_int64(jr.ClientId, ed1), jr.cStartTime, jr.cSchedTime,
1001 jr.cEndTime, edit_uint64(jr.JobTDate, ed2),
1002 edit_uint64(jr.FileSetId, ed3), jr.JobType, edit_int64(jr.JobId, ed4));
1003 if (!ua->db->SqlQuery(cmd.c_str())) {
1004 ua->ErrorMsg("%s", ua->db->strerror());
1005 return false;
1006 }
1007 return true;
1008 }
1009
1010 /**
1011 * Update Slots corresponding to Volumes in autochanger
1012 */
UpdateSlots(UaContext * ua)1013 static void UpdateSlots(UaContext* ua)
1014 {
1015 UnifiedStorageResource store;
1016 vol_list_t* vl;
1017 changer_vol_list_t* vol_list = NULL;
1018 MediaDbRecord mr;
1019 char* slot_list;
1020 bool scan;
1021 slot_number_t max_slots;
1022 drive_number_t drive = kInvalidDriveNumber;
1023 int Enabled = VOL_ENABLED;
1024 bool have_enabled;
1025 int i;
1026
1027
1028 if (!OpenClientDb(ua)) { return; }
1029 store.store = get_storage_resource(ua, true, true);
1030 if (!store.store) { return; }
1031 PmStrcpy(store.store_source, _("command line"));
1032 SetWstorage(ua->jcr, &store);
1033
1034 scan = FindArg(ua, NT_("scan")) >= 0;
1035 if (scan) { drive = GetStorageDrive(ua, store.store); }
1036 if ((i = FindArgWithValue(ua, NT_("Enabled"))) >= 0) {
1037 Enabled = GetEnabled(ua, ua->argv[i]);
1038 if (Enabled < 0) { return; }
1039 have_enabled = true;
1040 } else {
1041 have_enabled = false;
1042 }
1043
1044 max_slots = GetNumSlots(ua, ua->jcr->impl->res.write_storage);
1045 Dmsg1(100, "max_slots=%d\n", max_slots);
1046 if (max_slots <= 0) {
1047 ua->WarningMsg(_("No slots in changer to scan.\n"));
1048 return;
1049 }
1050
1051 slot_list = (char*)malloc(NbytesForBits(max_slots));
1052 ClearAllBits(max_slots, slot_list);
1053 if (!GetUserSlotList(ua, slot_list, "slots", max_slots)) {
1054 free(slot_list);
1055 return;
1056 }
1057
1058 vol_list = get_vol_list_from_storage(ua, store.store, false, scan, false);
1059 if (!vol_list) {
1060 ua->WarningMsg(_("No Volumes found to update, or no barcodes.\n"));
1061 goto bail_out;
1062 }
1063
1064 /*
1065 * First zap out any InChanger with StorageId=0
1066 */
1067 ua->db->SqlQuery("UPDATE Media SET InChanger=0 WHERE StorageId=0");
1068
1069 /*
1070 * Walk through the list updating the media records
1071 */
1072 foreach_dlist (vl, vol_list->contents) {
1073 if (vl->bareos_slot_number > max_slots) {
1074 ua->WarningMsg(_("Slot %d greater than max %d ignored.\n"),
1075 vl->bareos_slot_number, max_slots);
1076 continue;
1077 }
1078 /*
1079 * Check if user wants us to look at this slot
1080 */
1081 if (!BitIsSet(vl->bareos_slot_number - 1, slot_list)) {
1082 Dmsg1(100, "Skipping slot=%d\n", vl->bareos_slot_number);
1083 continue;
1084 }
1085 /*
1086 * If scanning, we read the label rather than the barcode
1087 */
1088 if (scan) {
1089 if (vl->VolName) {
1090 free(vl->VolName);
1091 vl->VolName = NULL;
1092 }
1093 vl->VolName = get_volume_name_from_SD(ua, vl->bareos_slot_number, drive);
1094 Dmsg2(100, "Got Vol=%s from SD for Slot=%d\n", vl->VolName,
1095 vl->bareos_slot_number);
1096 }
1097 ClearBit(vl->bareos_slot_number - 1, slot_list); /* clear Slot */
1098 SetStorageidInMr(store.store, &mr);
1099 mr.Slot = vl->bareos_slot_number;
1100 mr.InChanger = 1;
1101 mr.MediaId = 0; /* Get by VolumeName */
1102 if (vl->VolName) {
1103 bstrncpy(mr.VolumeName, vl->VolName, sizeof(mr.VolumeName));
1104 } else {
1105 mr.VolumeName[0] = 0;
1106 }
1107 SetStorageidInMr(store.store, &mr);
1108
1109 Dmsg4(100, "Before make unique: Vol=%s slot=%d inchanger=%d sid=%d\n",
1110 mr.VolumeName, mr.Slot, mr.InChanger, mr.StorageId);
1111 DbLock(ua->db);
1112 /*
1113 * Set InChanger to zero for this Slot
1114 */
1115 ua->db->MakeInchangerUnique(ua->jcr, &mr);
1116 DbUnlock(ua->db);
1117 Dmsg4(100, "After make unique: Vol=%s slot=%d inchanger=%d sid=%d\n",
1118 mr.VolumeName, mr.Slot, mr.InChanger, mr.StorageId);
1119
1120 if (!vl->VolName) {
1121 Dmsg1(100, "No VolName for Slot=%d setting InChanger to zero.\n",
1122 vl->bareos_slot_number);
1123 ua->InfoMsg(_("No VolName for Slot=%d InChanger set to zero.\n"),
1124 vl->bareos_slot_number);
1125 continue;
1126 }
1127
1128 DbLock(ua->db);
1129 Dmsg4(100, "Before get MR: Vol=%s slot=%d inchanger=%d sid=%d\n",
1130 mr.VolumeName, mr.Slot, mr.InChanger, mr.StorageId);
1131 if (ua->db->GetMediaRecord(ua->jcr, &mr)) {
1132 Dmsg4(100, "After get MR: Vol=%s slot=%d inchanger=%d sid=%d\n",
1133 mr.VolumeName, mr.Slot, mr.InChanger, mr.StorageId);
1134 /*
1135 * If Slot, Inchanger, and StorageId have changed, update the Media record
1136 */
1137 if (mr.Slot != vl->bareos_slot_number || !mr.InChanger ||
1138 mr.StorageId != store.store->StorageId) {
1139 mr.Slot = vl->bareos_slot_number;
1140 mr.InChanger = 1;
1141 if (have_enabled) { mr.Enabled = Enabled; }
1142 SetStorageidInMr(store.store, &mr);
1143 if (!ua->db->UpdateMediaRecord(ua->jcr, &mr)) {
1144 ua->ErrorMsg("%s", ua->db->strerror());
1145 } else {
1146 ua->InfoMsg(_("Catalog record for Volume \"%s\" updated to reference "
1147 "slot %d.\n"),
1148 mr.VolumeName, mr.Slot);
1149 }
1150 } else {
1151 ua->InfoMsg(_("Catalog record for Volume \"%s\" is up to date.\n"),
1152 mr.VolumeName);
1153 }
1154 } else {
1155 ua->WarningMsg(_("Volume \"%s\" not found in catalog. Slot=%d InChanger "
1156 "set to zero.\n"),
1157 mr.VolumeName, vl->bareos_slot_number);
1158 }
1159 DbUnlock(ua->db);
1160 }
1161 {
1162 MediaDbRecord mr;
1163 mr.InChanger = 1;
1164 SetStorageidInMr(store.store, &mr);
1165
1166 /*
1167 * Any slot not visited gets it Inchanger flag reset.
1168 */
1169 DbLock(ua->db);
1170 for (i = 1; i <= max_slots; i++) {
1171 if (BitIsSet(i - 1, slot_list)) {
1172 /*
1173 * Set InChanger to zero for this Slot
1174 */
1175 mr.Slot = i;
1176 ua->db->MakeInchangerUnique(ua->jcr, &mr);
1177 }
1178 }
1179 DbUnlock(ua->db);
1180 }
1181 bail_out:
1182 if (vol_list) { StorageReleaseVolList(store.store, vol_list); }
1183 free(slot_list);
1184 CloseSdBsock(ua);
1185
1186 return;
1187 }
1188
1189 /**
1190 * Update Slots corresponding to Volumes in autochanger.
1191 * We only update any new volume location of slots marked in
1192 * the given slot_list. If you want to do funky stuff
1193 * run an "update slots" with the options you want. This
1194 * is a simple function which syncs the info from the
1195 * vol_list to the database for each slot marked in
1196 * the slot_list.
1197 *
1198 * The vol_list passed here needs to be from an "autochanger listall" cmd.
1199 */
UpdateSlotsFromVolList(UaContext * ua,StorageResource * store,changer_vol_list_t * vol_list,char * slot_list)1200 void UpdateSlotsFromVolList(UaContext* ua,
1201 StorageResource* store,
1202 changer_vol_list_t* vol_list,
1203 char* slot_list)
1204 {
1205 vol_list_t* vl;
1206
1207 if (!OpenClientDb(ua)) { return; }
1208
1209 /*
1210 * Walk through the list updating the media records
1211 */
1212 foreach_dlist (vl, vol_list->contents) {
1213 /*
1214 * We are only interested in normal slots.
1215 */
1216 switch (vl->slot_type) {
1217 case slot_type_t::kSlotTypeStorage:
1218 break;
1219 default:
1220 continue;
1221 }
1222
1223 /*
1224 * Only update entries of slots marked in the slot_list.
1225 */
1226 if (!BitIsSet(vl->bareos_slot_number - 1, slot_list)) { continue; }
1227
1228 /*
1229 * Set InChanger to zero for this Slot
1230 */
1231 MediaDbRecord mr;
1232 mr.Slot = vl->bareos_slot_number;
1233 mr.InChanger = 1;
1234 mr.MediaId = 0; /* Get by VolumeName */
1235 if (vl->VolName) {
1236 bstrncpy(mr.VolumeName, vl->VolName, sizeof(mr.VolumeName));
1237 } else {
1238 mr.VolumeName[0] = 0;
1239 }
1240 SetStorageidInMr(store, &mr);
1241
1242 Dmsg4(100, "Before make unique: Vol=%s slot=%d inchanger=%d sid=%d\n",
1243 mr.VolumeName, mr.Slot, mr.InChanger, mr.StorageId);
1244 DbLock(ua->db);
1245
1246 /*
1247 * Set InChanger to zero for this Slot
1248 */
1249 ua->db->MakeInchangerUnique(ua->jcr, &mr);
1250
1251 DbUnlock(ua->db);
1252 Dmsg4(100, "After make unique: Vol=%s slot=%d inchanger=%d sid=%d\n",
1253 mr.VolumeName, mr.Slot, mr.InChanger, mr.StorageId);
1254
1255 /*
1256 * See if there is anything in the slot.
1257 */
1258 switch (vl->slot_status) {
1259 case slot_status_t::kSlotStatusFull:
1260 if (!vl->VolName) {
1261 Dmsg1(100, "No VolName for Slot=%d setting InChanger to zero.\n",
1262 vl->bareos_slot_number);
1263 continue;
1264 }
1265 break;
1266 default:
1267 continue;
1268 }
1269
1270 /*
1271 * There is something in the slot and it has a VolumeName so we can check
1272 * the database and perform an update if needed.
1273 */
1274 DbLock(ua->db);
1275 Dmsg4(100, "Before get MR: Vol=%s slot=%d inchanger=%d sid=%d\n",
1276 mr.VolumeName, mr.Slot, mr.InChanger, mr.StorageId);
1277 if (ua->db->GetMediaRecord(ua->jcr, &mr)) {
1278 Dmsg4(100, "After get MR: Vol=%s slot=%d inchanger=%d sid=%d\n",
1279 mr.VolumeName, mr.Slot, mr.InChanger, mr.StorageId);
1280 /* If Slot, Inchanger, and StorageId have changed, update the Media record
1281 */
1282 if (mr.Slot != vl->bareos_slot_number || !mr.InChanger ||
1283 mr.StorageId != store->StorageId) {
1284 mr.Slot = vl->bareos_slot_number;
1285 mr.InChanger = 1;
1286 SetStorageidInMr(store, &mr);
1287 if (!ua->db->UpdateMediaRecord(ua->jcr, &mr)) {
1288 ua->ErrorMsg("%s", ua->db->strerror());
1289 }
1290 }
1291 } else {
1292 ua->WarningMsg(_("Volume \"%s\" not found in catalog. Slot=%d InChanger "
1293 "set to zero.\n"),
1294 mr.VolumeName, vl->bareos_slot_number);
1295 }
1296 DbUnlock(ua->db);
1297 }
1298 return;
1299 }
1300
1301 /**
1302 * Set the inchanger flag to zero for each slot marked in
1303 * the given slot_list.
1304 *
1305 * The vol_list passed here needs to be from an "autochanger listall" cmd.
1306 */
UpdateInchangerForExport(UaContext * ua,StorageResource * store,changer_vol_list_t * vol_list,char * slot_list)1307 void UpdateInchangerForExport(UaContext* ua,
1308 StorageResource* store,
1309 changer_vol_list_t* vol_list,
1310 char* slot_list)
1311 {
1312 vol_list_t* vl;
1313
1314 if (!OpenClientDb(ua)) { return; }
1315
1316 /*
1317 * Walk through the list updating the media records
1318 */
1319 foreach_dlist (vl, vol_list->contents) {
1320 /*
1321 * We are only interested in normal slots.
1322 */
1323 switch (vl->slot_type) {
1324 case slot_type_t::kSlotTypeStorage:
1325 break;
1326 default:
1327 continue;
1328 }
1329
1330 /*
1331 * Only update entries of slots marked in the slot_list.
1332 */
1333 if (!BitIsSet(vl->bareos_slot_number - 1, slot_list)) { continue; }
1334
1335 /*
1336 * Set InChanger to zero for this Slot
1337 */
1338 MediaDbRecord mr;
1339 mr.Slot = vl->bareos_slot_number;
1340 mr.InChanger = 1;
1341 mr.MediaId = 0; /* Get by VolumeName */
1342 if (vl->VolName) {
1343 bstrncpy(mr.VolumeName, vl->VolName, sizeof(mr.VolumeName));
1344 } else {
1345 mr.VolumeName[0] = 0;
1346 }
1347 SetStorageidInMr(store, &mr);
1348
1349 Dmsg4(100, "Before make unique: Vol=%s slot=%d inchanger=%d sid=%d\n",
1350 mr.VolumeName, mr.Slot, mr.InChanger, mr.StorageId);
1351 DbLock(ua->db);
1352
1353 /*
1354 * Set InChanger to zero for this Slot
1355 */
1356 ua->db->MakeInchangerUnique(ua->jcr, &mr);
1357
1358 DbUnlock(ua->db);
1359 Dmsg4(100, "After make unique: Vol=%s slot=%d inchanger=%d sid=%d\n",
1360 mr.VolumeName, mr.Slot, mr.InChanger, mr.StorageId);
1361 }
1362 return;
1363 }
1364 } /* namespace directordaemon */
1365