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