]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/dird/ua_update.c
03Dec05
[bacula/bacula] / bacula / src / dird / ua_update.c
1 /*
2  *
3  *   Bacula Director -- Update command processing
4  *     Split from ua_cmds.c March 2005
5  *
6  *     Kern Sibbald, September MM
7  *
8  *   Version $Id$
9  */
10 /*
11    Copyright (C) 2000-2005 Kern Sibbald
12
13    This program is free software; you can redistribute it and/or
14    modify it under the terms of the GNU General Public License
15    version 2 as amended with additional clauses defined in the
16    file LICENSE in the main source directory.
17
18    This program is distributed in the hope that it will be useful,
19    but WITHOUT ANY WARRANTY; without even the implied warranty of
20    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 
21    the file LICENSE for additional details.
22
23  */
24
25 #include "bacula.h"
26 #include "dird.h"
27
28 /* External variables */
29 extern char *list_pool;               /* in sql_cmds.c */
30
31 /* Imported functions */
32 void set_pooldbr_from_poolres(POOL_DBR *pr, POOL *pool, e_pool_op op);
33 int update_slots(UAContext *ua);
34
35
36 /* Forward referenced functions */
37 static int update_volume(UAContext *ua);
38 static int update_pool(UAContext *ua);
39
40 /*
41  * Update a Pool Record in the database.
42  *  It is always updated from the Resource record.
43  *
44  *    update pool=<pool-name>
45  *         updates pool from Pool resource
46  *    update media pool=<pool-name> volume=<volume-name>
47  *         changes pool info for volume
48  *    update slots [scan=...]
49  *         updates autochanger slots
50  */
51 int update_cmd(UAContext *ua, const char *cmd)
52 {
53    static const char *kw[] = {
54       N_("media"),  /* 0 */
55       N_("volume"), /* 1 */
56       N_("pool"),   /* 2 */
57       N_("slots"),  /* 3 */
58       NULL};
59
60    if (!open_db(ua)) {
61       return 1;
62    }
63
64    switch (find_arg_keyword(ua, kw)) {
65    case 0:
66    case 1:
67       update_volume(ua);
68       return 1;
69    case 2:
70       update_pool(ua);
71       return 1;
72    case 3:
73       update_slots(ua);
74       return 1;
75    default:
76       break;
77    }
78
79    start_prompt(ua, _("Update choice:\n"));
80    add_prompt(ua, _("Volume parameters"));
81    add_prompt(ua, _("Pool from resource"));
82    add_prompt(ua, _("Slots from autochanger"));
83    switch (do_prompt(ua, _("item"), _("Choose catalog item to update"), NULL, 0)) {
84    case 0:
85       update_volume(ua);
86       break;
87    case 1:
88       update_pool(ua);
89       break;
90    case 2:
91       update_slots(ua);
92       break;
93    default:
94       break;
95    }
96    return 1;
97 }
98
99 static void update_volstatus(UAContext *ua, const char *val, MEDIA_DBR *mr)
100 {
101    POOL_MEM query(PM_MESSAGE);
102    const char *kw[] = {
103       N_("Append"),
104       N_("Archive"),
105       N_("Disabled"),
106       N_("Full"),
107       N_("Used"),
108       N_("Cleaning"),
109       N_("Recycle"),
110       N_("Read-Only"),
111       NULL};
112    bool found = false;
113    int i;
114
115    for (i=0; kw[i]; i++) {
116       if (strcasecmp(val, kw[i]) == 0) {
117          found = true;
118          break;
119       }
120    }
121    if (!found) {
122       bsendmsg(ua, _("Invalid VolStatus specified: %s\n"), val);
123    } else {
124       char ed1[50];
125       bstrncpy(mr->VolStatus, kw[i], sizeof(mr->VolStatus));
126       Mmsg(query, "UPDATE Media SET VolStatus='%s' WHERE MediaId=%s",
127          mr->VolStatus, edit_int64(mr->MediaId,ed1));
128       if (!db_sql_query(ua->db, query.c_str(), NULL, NULL)) {
129          bsendmsg(ua, "%s", db_strerror(ua->db));
130       } else {
131          bsendmsg(ua, _("New Volume status is: %s\n"), mr->VolStatus);
132       }
133    }
134 }
135
136 static void update_volretention(UAContext *ua, char *val, MEDIA_DBR *mr)
137 {
138    char ed1[150], ed2[50];
139    POOL_MEM query(PM_MESSAGE);
140    if (!duration_to_utime(val, &mr->VolRetention)) {
141       bsendmsg(ua, _("Invalid retention period specified: %s\n"), val);
142       return;
143    }
144    Mmsg(query, "UPDATE Media SET VolRetention=%s WHERE MediaId=%s",
145       edit_uint64(mr->VolRetention, ed1), edit_int64(mr->MediaId,ed2));
146    if (!db_sql_query(ua->db, query.c_str(), NULL, NULL)) {
147       bsendmsg(ua, "%s", db_strerror(ua->db));
148    } else {
149       bsendmsg(ua, _("New retention period is: %s\n"),
150          edit_utime(mr->VolRetention, ed1, sizeof(ed1)));
151    }
152 }
153
154 static void update_voluseduration(UAContext *ua, char *val, MEDIA_DBR *mr)
155 {
156    char ed1[150], ed2[50];
157    POOL_MEM query(PM_MESSAGE);
158
159    if (!duration_to_utime(val, &mr->VolUseDuration)) {
160       bsendmsg(ua, _("Invalid use duration specified: %s\n"), val);
161       return;
162    }
163    Mmsg(query, "UPDATE Media SET VolUseDuration=%s WHERE MediaId=%s",
164       edit_uint64(mr->VolUseDuration, ed1), edit_int64(mr->MediaId,ed2));
165    if (!db_sql_query(ua->db, query.c_str(), NULL, NULL)) {
166       bsendmsg(ua, "%s", db_strerror(ua->db));
167    } else {
168       bsendmsg(ua, _("New use duration is: %s\n"),
169          edit_utime(mr->VolUseDuration, ed1, sizeof(ed1)));
170    }
171 }
172
173 static void update_volmaxjobs(UAContext *ua, char *val, MEDIA_DBR *mr)
174 {
175    POOLMEM *query = get_pool_memory(PM_MESSAGE);
176    char ed1[50];
177    Mmsg(query, "UPDATE Media SET MaxVolJobs=%s WHERE MediaId=%s",
178       val, edit_int64(mr->MediaId,ed1));
179    if (!db_sql_query(ua->db, query, NULL, NULL)) {
180       bsendmsg(ua, "%s", db_strerror(ua->db));
181    } else {
182       bsendmsg(ua, _("New max jobs is: %s\n"), val);
183    }
184    free_pool_memory(query);
185 }
186
187 static void update_volmaxfiles(UAContext *ua, char *val, MEDIA_DBR *mr)
188 {
189    POOLMEM *query = get_pool_memory(PM_MESSAGE);
190    char ed1[50];
191    Mmsg(query, "UPDATE Media SET MaxVolFiles=%s WHERE MediaId=%s",
192       val, edit_int64(mr->MediaId, ed1));
193    if (!db_sql_query(ua->db, query, NULL, NULL)) {
194       bsendmsg(ua, "%s", db_strerror(ua->db));
195    } else {
196       bsendmsg(ua, _("New max files is: %s\n"), val);
197    }
198    free_pool_memory(query);
199 }
200
201 static void update_volmaxbytes(UAContext *ua, char *val, MEDIA_DBR *mr)
202 {
203    uint64_t maxbytes;
204    char ed1[50], ed2[50];
205    POOLMEM *query;
206
207    if (!size_to_uint64(val, strlen(val), &maxbytes)) {
208       bsendmsg(ua, _("Invalid max. bytes specification: %s\n"), val);
209       return;
210    }
211    query = get_pool_memory(PM_MESSAGE);
212    Mmsg(query, "UPDATE Media SET MaxVolBytes=%s WHERE MediaId=%s",
213       edit_uint64(maxbytes, ed1), edit_int64(mr->MediaId, ed2));
214    if (!db_sql_query(ua->db, query, NULL, NULL)) {
215       bsendmsg(ua, "%s", db_strerror(ua->db));
216    } else {
217       bsendmsg(ua, _("New Max bytes is: %s\n"), edit_uint64(maxbytes, ed1));
218    }
219    free_pool_memory(query);
220 }
221
222 static void update_volrecycle(UAContext *ua, char *val, MEDIA_DBR *mr)
223 {
224    int recycle;
225    char ed1[50];
226    POOLMEM *query;
227    if (strcasecmp(val, _("yes")) == 0) {
228       recycle = 1;
229    } else if (strcasecmp(val, _("no")) == 0) {
230       recycle = 0;
231    } else {
232       bsendmsg(ua, _("Invalid value. It must by yes or no.\n"));
233       return;
234    }
235    query = get_pool_memory(PM_MESSAGE);
236    Mmsg(query, "UPDATE Media SET Recycle=%d WHERE MediaId=%s",
237       recycle, edit_int64(mr->MediaId, ed1));
238    if (!db_sql_query(ua->db, query, NULL, NULL)) {
239       bsendmsg(ua, "%s", db_strerror(ua->db));
240    } else {
241       bsendmsg(ua, _("New Recycle flag is: %s\n"),
242          mr->Recycle==1?_("yes"):_("no"));
243    }
244    free_pool_memory(query);
245 }
246
247 /* Modify the Pool in which this Volume is located */
248 static void update_vol_pool(UAContext *ua, char *val, MEDIA_DBR *mr, POOL_DBR *opr)
249 {
250    POOL_DBR pr;
251    POOLMEM *query;
252    char ed1[50], ed2[50];
253
254    memset(&pr, 0, sizeof(pr));
255    bstrncpy(pr.Name, val, sizeof(pr.Name));
256    if (!get_pool_dbr(ua, &pr)) {
257       return;
258    }
259    mr->PoolId = pr.PoolId;            /* set new PoolId */
260    /*
261     */
262    query = get_pool_memory(PM_MESSAGE);
263    db_lock(ua->db);
264    Mmsg(query, "UPDATE Media SET PoolId=%s WHERE MediaId=%s",
265       edit_int64(mr->PoolId, ed1),
266       edit_int64(mr->MediaId, ed2));
267    if (!db_sql_query(ua->db, query, NULL, NULL)) {
268       bsendmsg(ua, "%s", db_strerror(ua->db));
269    } else {
270       bsendmsg(ua, _("New Pool is: %s\n"), pr.Name);
271       opr->NumVols--;
272       if (!db_update_pool_record(ua->jcr, ua->db, opr)) {
273          bsendmsg(ua, "%s", db_strerror(ua->db));
274       }
275       pr.NumVols++;
276       if (!db_update_pool_record(ua->jcr, ua->db, &pr)) {
277          bsendmsg(ua, "%s", db_strerror(ua->db));
278       }
279    }
280    db_unlock(ua->db);
281    free_pool_memory(query);
282 }
283
284 /*
285  * Refresh the Volume information from the Pool record
286  */
287 static void update_vol_from_pool(UAContext *ua, MEDIA_DBR *mr)
288 {
289    POOL_DBR pr;
290
291    memset(&pr, 0, sizeof(pr));
292    pr.PoolId = mr->PoolId;
293    if (!db_get_pool_record(ua->jcr, ua->db, &pr) ||
294        !acl_access_ok(ua, Pool_ACL, pr.Name)) {
295       return;
296    }
297    set_pool_dbr_defaults_in_media_dbr(mr, &pr);
298    if (!db_update_media_defaults(ua->jcr, ua->db, mr)) {
299       bsendmsg(ua, _("Error updating Volume record: ERR=%s"), db_strerror(ua->db));
300    } else {
301       bsendmsg(ua, _("Volume defaults updated from \"%s\" Pool record.\n"),
302          pr.Name);
303    }
304 }
305
306 /*
307  * Refresh the Volume information from the Pool record
308  *   for all Volumes
309  */
310 static void update_all_vols_from_pool(UAContext *ua)
311 {
312    POOL_DBR pr;
313    MEDIA_DBR mr;
314
315    memset(&pr, 0, sizeof(pr));
316    memset(&mr, 0, sizeof(mr));
317    if (!get_pool_dbr(ua, &pr)) {
318       return;
319    }
320    set_pool_dbr_defaults_in_media_dbr(&mr, &pr);
321    mr.PoolId = pr.PoolId;
322    if (!db_update_media_defaults(ua->jcr, ua->db, &mr)) {
323       bsendmsg(ua, _("Error updating Volume records: ERR=%s"), db_strerror(ua->db));
324    } else {
325       bsendmsg(ua, _("All Volume defaults updated from Pool record.\n"));
326    }
327 }
328
329
330 /*
331  * Update a media record -- allows you to change the
332  *  Volume status. E.g. if you want Bacula to stop
333  *  writing on the volume, set it to anything other
334  *  than Append.
335  */
336 static int update_volume(UAContext *ua)
337 {
338    MEDIA_DBR mr;
339    POOL_DBR pr;
340    POOLMEM *query;
341    char ed1[130];
342    bool done = false;
343    const char *kw[] = {
344       _("VolStatus"),                /* 0 */
345       _("VolRetention"),             /* 1 */
346       _("VolUse"),                   /* 2 */
347       _("MaxVolJobs"),               /* 3 */
348       _("MaxVolFiles"),              /* 4 */
349       _("MaxVolBytes"),              /* 5 */
350       _("Recycle"),                  /* 6 */
351       _("Pool"),                     /* 7 */
352       _("FromPool"),                 /* 8 */
353       _("AllFromPool"),              /* 9 */
354       NULL };
355
356    for (int i=0; kw[i]; i++) {
357       int j;
358       POOL_DBR pr;
359       if ((j=find_arg_with_value(ua, kw[i])) > 0) {
360          if (i != 9 && !select_media_dbr(ua, &mr)) {
361             return 0;
362          }
363          switch (i) {
364          case 0:
365             update_volstatus(ua, ua->argv[j], &mr);
366             break;
367          case 1:
368             update_volretention(ua, ua->argv[j], &mr);
369             break;
370          case 2:
371             update_voluseduration(ua, ua->argv[j], &mr);
372             break;
373          case 3:
374             update_volmaxjobs(ua, ua->argv[j], &mr);
375             break;
376          case 4:
377             update_volmaxfiles(ua, ua->argv[j], &mr);
378             break;
379          case 5:
380             update_volmaxbytes(ua, ua->argv[j], &mr);
381             break;
382          case 6:
383             update_volrecycle(ua, ua->argv[j], &mr);
384             break;
385          case 7:
386             memset(&pr, 0, sizeof(POOL_DBR));
387             pr.PoolId = mr.PoolId;
388             if (!db_get_pool_record(ua->jcr, ua->db, &pr)) {
389                bsendmsg(ua, "%s", db_strerror(ua->db));
390                break;
391             }
392             update_vol_pool(ua, ua->argv[j], &mr, &pr);
393             break;
394          case 8:
395             update_vol_from_pool(ua, &mr);
396             return 1;
397          case 9:
398             update_all_vols_from_pool(ua);
399             return 1;
400          }
401          done = true;
402       }
403    }
404
405    for ( ; !done; ) {
406       if (!select_media_dbr(ua, &mr)) {
407          return 0;
408       }
409       bsendmsg(ua, _("Updating Volume \"%s\"\n"), mr.VolumeName);
410       start_prompt(ua, _("Parameters to modify:\n"));
411       add_prompt(ua, _("Volume Status"));
412       add_prompt(ua, _("Volume Retention Period"));
413       add_prompt(ua, _("Volume Use Duration"));
414       add_prompt(ua, _("Maximum Volume Jobs"));
415       add_prompt(ua, _("Maximum Volume Files"));
416       add_prompt(ua, _("Maximum Volume Bytes"));
417       add_prompt(ua, _("Recycle Flag"));
418       add_prompt(ua, _("Slot"));
419       add_prompt(ua, _("InChanger Flag"));
420       add_prompt(ua, _("Volume Files"));
421       add_prompt(ua, _("Pool"));
422       add_prompt(ua, _("Volume from Pool"));
423       add_prompt(ua, _("All Volumes from Pool"));
424       add_prompt(ua, _("Done"));
425       switch (do_prompt(ua, "", _("Select parameter to modify"), NULL, 0)) {
426       case 0:                         /* Volume Status */
427          /* Modify Volume Status */
428          bsendmsg(ua, _("Current Volume status is: %s\n"), mr.VolStatus);
429          start_prompt(ua, _("Possible Values are:\n"));
430          add_prompt(ua, N_("Append")); 
431          add_prompt(ua, N_("Archive"));
432          add_prompt(ua, N_("Disabled"));
433          add_prompt(ua, N_("Full"));
434          add_prompt(ua, N_("Used"));
435          add_prompt(ua, N_("Cleaning"));
436          if (strcmp(mr.VolStatus, N_("Purged")) == 0) {
437             add_prompt(ua, N_("Recycle"));
438          }
439          add_prompt(ua, N_("Read-Only"));
440          if (do_prompt(ua, "", _("Choose new Volume Status"), ua->cmd, sizeof(mr.VolStatus)) < 0) {
441             return 1;
442          }
443          update_volstatus(ua, ua->cmd, &mr);
444          break;
445       case 1:                         /* Retention */
446          bsendmsg(ua, _("Current retention period is: %s\n"),
447             edit_utime(mr.VolRetention, ed1, sizeof(ed1)));
448          if (!get_cmd(ua, _("Enter Volume Retention period: "))) {
449             return 0;
450          }
451          update_volretention(ua, ua->cmd, &mr);
452          break;
453
454       case 2:                         /* Use Duration */
455          bsendmsg(ua, _("Current use duration is: %s\n"),
456             edit_utime(mr.VolUseDuration, ed1, sizeof(ed1)));
457          if (!get_cmd(ua, _("Enter Volume Use Duration: "))) {
458             return 0;
459          }
460          update_voluseduration(ua, ua->cmd, &mr);
461          break;
462
463       case 3:                         /* Max Jobs */
464          bsendmsg(ua, _("Current max jobs is: %u\n"), mr.MaxVolJobs);
465          if (!get_pint(ua, _("Enter new Maximum Jobs: "))) {
466             return 0;
467          }
468          update_volmaxjobs(ua, ua->cmd, &mr);
469          break;
470
471       case 4:                         /* Max Files */
472          bsendmsg(ua, _("Current max files is: %u\n"), mr.MaxVolFiles);
473          if (!get_pint(ua, _("Enter new Maximum Files: "))) {
474             return 0;
475          }
476          update_volmaxfiles(ua, ua->cmd, &mr);
477          break;
478
479       case 5:                         /* Max Bytes */
480          bsendmsg(ua, _("Current value is: %s\n"), edit_uint64(mr.MaxVolBytes, ed1));
481          if (!get_cmd(ua, _("Enter new Maximum Bytes: "))) {
482             return 0;
483          }
484          update_volmaxbytes(ua, ua->cmd, &mr);
485          break;
486
487
488       case 6:                         /* Recycle */
489          bsendmsg(ua, _("Current recycle flag is: %s\n"),
490             mr.Recycle==1?_("yes"):_("no"));
491          if (!get_yesno(ua, _("Enter new Recycle status: "))) {
492             return 0;
493          }
494          update_volrecycle(ua, ua->cmd, &mr);
495          break;
496
497       case 7:                         /* Slot */
498          int Slot;
499
500          memset(&pr, 0, sizeof(POOL_DBR));
501          pr.PoolId = mr.PoolId;
502          if (!db_get_pool_record(ua->jcr, ua->db, &pr)) {
503             bsendmsg(ua, "%s", db_strerror(ua->db));
504             return 0;
505          }
506          bsendmsg(ua, _("Current Slot is: %d\n"), mr.Slot);
507          if (!get_pint(ua, _("Enter new Slot: "))) {
508             return 0;
509          }
510          Slot = ua->pint32_val;
511          if (pr.MaxVols > 0 && Slot > (int)pr.MaxVols) {
512             bsendmsg(ua, _("Invalid slot, it must be between 0 and %d\n"),
513                pr.MaxVols);
514             break;
515          }
516          mr.Slot = Slot;
517          /*
518           * Make sure to use db_update... rather than doing this directly,
519           *   so that any Slot is handled correctly.
520           */
521          if (!db_update_media_record(ua->jcr, ua->db, &mr)) {
522             bsendmsg(ua, _("Error updating media record Slot: ERR=%s"), db_strerror(ua->db));
523          } else {
524             bsendmsg(ua, _("New Slot is: %d\n"), mr.Slot);
525          }
526          break;
527
528       case 8:                         /* InChanger */
529          bsendmsg(ua, _("Current InChanger flag is: %d\n"), mr.InChanger);
530          if (!get_yesno(ua, _("Set InChanger flag? yes/no: "))) {
531             return 0;
532          }
533          mr.InChanger = ua->pint32_val;
534          /*
535           * Make sure to use db_update... rather than doing this directly,
536           *   so that any Slot is handled correctly.
537           */
538          if (!db_update_media_record(ua->jcr, ua->db, &mr)) {
539             bsendmsg(ua, _("Error updating media record Slot: ERR=%s"), db_strerror(ua->db));
540          } else {
541             bsendmsg(ua, _("New InChanger flag is: %d\n"), mr.InChanger);
542          }
543          break;
544
545
546       case 9:                         /* Volume Files */
547          int32_t VolFiles;
548          bsendmsg(ua, _("Warning changing Volume Files can result\n"
549                         "in loss of data on your Volume\n\n"));
550          bsendmsg(ua, _("Current Volume Files is: %u\n"), mr.VolFiles);
551          if (!get_pint(ua, _("Enter new number of Files for Volume: "))) {
552             return 0;
553          }
554          VolFiles = ua->pint32_val;
555          if (VolFiles != (int)(mr.VolFiles + 1)) {
556             bsendmsg(ua, _("Normally, you should only increase Volume Files by one!\n"));
557             if (!get_yesno(ua, _("Continue? (yes/no): ")) || ua->pint32_val == 0) {
558                break;
559             }
560          }
561          query = get_pool_memory(PM_MESSAGE);
562          Mmsg(query, "UPDATE Media SET VolFiles=%u WHERE MediaId=%s",
563             VolFiles, edit_int64(mr.MediaId, ed1));
564          if (!db_sql_query(ua->db, query, NULL, NULL)) {
565             bsendmsg(ua, "%s", db_strerror(ua->db));
566          } else {
567             bsendmsg(ua, _("New Volume Files is: %u\n"), VolFiles);
568          }
569          free_pool_memory(query);
570          break;
571
572       case 10:                        /* Volume's Pool */
573          memset(&pr, 0, sizeof(POOL_DBR));
574          pr.PoolId = mr.PoolId;
575          if (!db_get_pool_record(ua->jcr, ua->db, &pr)) {
576             bsendmsg(ua, "%s", db_strerror(ua->db));
577             return 0;
578          }
579          bsendmsg(ua, _("Current Pool is: %s\n"), pr.Name);
580          if (!get_cmd(ua, _("Enter new Pool name: "))) {
581             return 0;
582          }
583          update_vol_pool(ua, ua->cmd, &mr, &pr);
584          return 1;
585
586       case 11:
587          update_vol_from_pool(ua, &mr);
588          return 1;
589       case 12:
590          update_all_vols_from_pool(ua);
591          return 1;
592       default:                        /* Done or error */
593          bsendmsg(ua, _("Selection terminated.\n"));
594          return 1;
595       }
596    }
597    return 1;
598 }
599
600 /*
601  * Update pool record -- pull info from current POOL resource
602  */
603 static int update_pool(UAContext *ua)
604 {
605    POOL_DBR  pr;
606    int id;
607    POOL *pool;
608    POOLMEM *query;
609    char ed1[50];
610
611    pool = get_pool_resource(ua);
612    if (!pool) {
613       return 0;
614    }
615
616    memset(&pr, 0, sizeof(pr));
617    bstrncpy(pr.Name, pool->hdr.name, sizeof(pr.Name));
618    if (!get_pool_dbr(ua, &pr)) {
619       return 0;
620    }
621
622    set_pooldbr_from_poolres(&pr, pool, POOL_OP_UPDATE); /* update */
623
624    id = db_update_pool_record(ua->jcr, ua->db, &pr);
625    if (id <= 0) {
626       bsendmsg(ua, _("db_update_pool_record returned %d. ERR=%s\n"),
627          id, db_strerror(ua->db));
628    }
629    query = get_pool_memory(PM_MESSAGE);
630    Mmsg(query, list_pool, edit_int64(pr.PoolId, ed1));
631    db_list_sql_query(ua->jcr, ua->db, query, prtit, ua, 1, HORZ_LIST);
632    free_pool_memory(query);
633    bsendmsg(ua, _("Pool DB record updated from resource.\n"));
634    return 1;
635 }