]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/stored/autochanger.c
kes Tweak some code in ua_update.c to use POOL_MEM instead of POOLMEM.
[bacula/bacula] / bacula / src / stored / autochanger.c
1 /*
2    Bacula® - The Network Backup Solution
3
4    Copyright (C) 2002-2007 Free Software Foundation Europe e.V.
5
6    The main author of Bacula is Kern Sibbald, with contributions from
7    many others, a complete list can be found in the file AUTHORS.
8    This program is Free Software; you can redistribute it and/or
9    modify it under the terms of version two of the GNU 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    General Public License for more details.
17
18    You should have received a copy of the GNU 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    Bacula® is a registered trademark of John Walker.
24    The licensor of Bacula is the Free Software Foundation Europe
25    (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich,
26    Switzerland, email:ftf@fsfeurope.org.
27 */
28 /*
29  *
30  *  Routines for handling the autochanger.
31  *
32  *   Kern Sibbald, August MMII
33  *                            
34  *   Version $Id$
35  */
36
37 #include "bacula.h"                   /* pull in global headers */
38 #include "stored.h"                   /* pull in Storage Deamon headers */
39
40 /* Forward referenced functions */
41 static void lock_changer(DCR *dcr);
42 static void unlock_changer(DCR *dcr);
43 static bool unload_other_drive(DCR *dcr, int slot);
44
45 /* Init all the autochanger resources found */
46 bool init_autochangers()
47 {
48    bool OK = true;
49    AUTOCHANGER *changer;
50    /* Ensure that the media_type for each device is the same */
51    foreach_res(changer, R_AUTOCHANGER) {
52       DEVRES *device;
53       foreach_alist(device, changer->device) {
54          /*
55           * If the device does not have a changer name or changer command
56           *   defined, used the one from the Autochanger resource 
57           */
58          if (!device->changer_name && changer->changer_name) {
59             device->changer_name = bstrdup(changer->changer_name);
60          }
61          if (!device->changer_command && changer->changer_command) {
62             device->changer_command = bstrdup(changer->changer_command);
63          }
64          if (!device->changer_name) {
65             Jmsg(NULL, M_ERROR, 0, 
66                _("No Changer Name given for device %s. Cannot continue.\n"),
67                device->hdr.name);
68             OK = false;
69          }   
70          if (!device->changer_command) {
71             Jmsg(NULL, M_ERROR, 0, 
72                _("No Changer Command given for device %s. Cannot continue.\n"),
73                device->hdr.name);
74             OK = false;
75          }   
76
77 #ifdef xxx_needed
78          if (media_type == NULL) {
79             media_type = device->media_type;     /* get Media Type of first device */
80             continue;
81          }     
82          /* Ensure that other devices Media Types are the same */
83          if (strcmp(media_type, device->media_type) != 0) {
84             Jmsg(NULL, M_ERROR, 0, 
85                _("Media Type not the same for all devices in changer %s. Cannot continue.\n"),
86                changer->hdr.name);
87             OK = false;
88             continue;
89          }
90 #endif
91       }
92    }
93    return OK;
94 }
95
96
97 /*
98  * Called here to do an autoload using the autochanger, if
99  *  configured, and if a Slot has been defined for this Volume.
100  *  On success this routine loads the indicated tape, but the
101  *  label is not read, so it must be verified.
102  *
103  *  Note if dir is not NULL, it is the console requesting the
104  *   autoload for labeling, so we respond directly to the
105  *   dir bsock.
106  *
107  *  Returns: 1 on success
108  *           0 on failure (no changer available)
109  *          -1 on error on autochanger
110  */
111 int autoload_device(DCR *dcr, int writing, BSOCK *dir)
112 {
113    JCR *jcr = dcr->jcr;
114    DEVICE *dev = dcr->dev;
115    int slot;
116    int drive = dev->drive_index;
117    int rtn_stat = -1;                 /* error status */
118    POOLMEM *changer;
119
120    if (!dev->is_autochanger()) {
121       Dmsg1(200, "Device %s is not an autochanger\n", dev->print_name());
122       return 0;
123    }
124
125    /* An empty ChangerCommand => virtual disk autochanger */
126    if (dcr->device->changer_command && dcr->device->changer_command[0] == 0) {
127       return 1;                       /* nothing to load */
128    }
129
130    slot = dcr->VolCatInfo.InChanger ? dcr->VolCatInfo.Slot : 0;
131    /*
132     * Handle autoloaders here.  If we cannot autoload it, we
133     *  will return 0 so that the sysop will be asked to load it.
134     */
135    if (writing && slot <= 0) {
136       if (dir) {
137          return 0;                    /* For user, bail out right now */
138       }
139       if (dir_find_next_appendable_volume(dcr)) {
140          slot = dcr->VolCatInfo.InChanger ? dcr->VolCatInfo.Slot : 0;
141       } else {
142          slot = 0;
143       }
144    }
145    Dmsg1(400, "Want changer slot=%d\n", slot);
146
147    changer = get_pool_memory(PM_FNAME);
148    if (slot <= 0) {
149       Jmsg(jcr, M_INFO, 0, _("Invalid slot=%d defined in catalog for Volume \"%s\" "
150            "on %s. Manual load my be required.\n"), slot, dcr->VolCatInfo.VolCatName,
151            dev->print_name());
152       rtn_stat = 0;
153    } else if (!dcr->device->changer_name) {
154       Jmsg(jcr, M_INFO, 0, _("No \"Changer Device\" for %s. Manual load of Volume may be required.\n"),
155            dev->print_name());
156       rtn_stat = 0;
157   } else if (!dcr->device->changer_command) {
158       Jmsg(jcr, M_INFO, 0, _("No \"Changer Command\" for %s. Manual load of Volume may be requird.\n"),
159            dev->print_name());
160       rtn_stat = 0;
161   } else {
162       /* Attempt to load the Volume */
163
164       uint32_t timeout = dcr->device->max_changer_wait;
165       int loaded, status;
166
167       loaded = get_autochanger_loaded_slot(dcr);
168
169       if (loaded != slot) {
170          POOL_MEM results(PM_MESSAGE);
171
172          /* Unload anything in our drive */
173          if (!unload_autochanger(dcr, loaded)) {
174             goto bail_out;
175          }
176             
177          /* Make sure desired slot is unloaded */
178          if (!unload_other_drive(dcr, slot)) {
179             goto bail_out;
180          }
181
182          /*
183           * Load the desired cassette
184           */
185          lock_changer(dcr);
186          Dmsg1(100, "Doing changer load slot %d\n", slot);
187          Jmsg(jcr, M_INFO, 0,
188               _("3304 Issuing autochanger \"load slot %d, drive %d\" command.\n"),
189               slot, drive);
190          dcr->VolCatInfo.Slot = slot;    /* slot to be loaded */
191          changer = edit_device_codes(dcr, changer, dcr->device->changer_command, "load");
192          dev->close();
193          Dmsg1(200, "Run program=%s\n", changer);
194          status = run_program_full_output(changer, timeout, results.c_str());
195          if (status == 0) {
196             Jmsg(jcr, M_INFO, 0, _("3305 Autochanger \"load slot %d, drive %d\", status is OK.\n"),
197                     slot, drive);
198             Dmsg2(100, "load slot %d, drive %d, status is OK.\n", slot, drive);
199             dev->Slot = slot;         /* set currently loaded slot */
200          } else {
201             berrno be;
202             be.set_errno(status);
203             Dmsg3(100, "load slot %d, drive %d, bad stats=%s.\n", slot, drive,
204                be.bstrerror());
205             Jmsg(jcr, M_FATAL, 0, _("3992 Bad autochanger \"load slot %d, drive %d\": "
206                  "ERR=%s.\nResults=%s\n"),
207                     slot, drive, be.bstrerror(), results.c_str());
208             rtn_stat = -1;            /* hard error */
209             dev->Slot = -1;           /* mark unknown */
210          }
211          Dmsg2(100, "load slot %d status=%d\n", slot, status);
212          unlock_changer(dcr);
213       } else {
214          status = 0;                  /* we got what we want */
215          dev->Slot = slot;            /* set currently loaded slot */
216       }
217       Dmsg1(100, "After changer, status=%d\n", status);
218       if (status == 0) {              /* did we succeed? */
219          rtn_stat = 1;                /* tape loaded by changer */
220       }
221    }
222    free_pool_memory(changer);
223    return rtn_stat;
224
225 bail_out:
226    free_pool_memory(changer);
227    return -1;
228
229 }
230
231 /*
232  * Returns: -1 if error from changer command
233  *          slot otherwise
234  *  Note, this is safe to do without releasing the drive
235  *   since it does not attempt load/unload a slot.
236  */
237 int get_autochanger_loaded_slot(DCR *dcr)
238 {
239    JCR *jcr = dcr->jcr;
240    DEVICE *dev = dcr->dev;
241    int status, loaded;
242    uint32_t timeout = dcr->device->max_changer_wait;
243    int drive = dcr->dev->drive_index;
244    POOL_MEM results(PM_MESSAGE);
245    POOLMEM *changer;
246
247    if (!dev->is_autochanger()) {
248       return -1;
249    }
250    if (!dcr->device->changer_command) {
251       Jmsg(jcr, M_FATAL, 0, _("3992 Missing Changer command.\n"));
252       return -1;
253    }
254    if (dev->Slot > 0) {
255       return dev->Slot;
256    }
257    /* Virtual disk autochanger */
258    if (dcr->device->changer_command[0] == 0) {
259       return 1;
260    }
261
262    /* Find out what is loaded, zero means device is unloaded */
263    changer = get_pool_memory(PM_FNAME);
264    lock_changer(dcr);
265    Jmsg(jcr, M_INFO, 0, _("3301 Issuing autochanger \"loaded? drive %d\" command.\n"),
266         drive);
267    changer = edit_device_codes(dcr, changer, dcr->device->changer_command, "loaded");
268    *results.c_str() = 0;
269    Dmsg1(100, "Run program=%s\n", changer);
270    status = run_program_full_output(changer, timeout, results.c_str());
271    Dmsg3(100, "run_prog: %s stat=%d result=%s", changer, status, results.c_str());
272    if (status == 0) {
273       loaded = str_to_int32(results.c_str());
274       if (loaded > 0) {
275          Jmsg(jcr, M_INFO, 0, _("3302 Autochanger \"loaded? drive %d\", result is Slot %d.\n"),
276               drive, loaded);
277          dev->Slot = loaded;
278       } else {
279          Jmsg(jcr, M_INFO, 0, _("3302 Autochanger \"loaded? drive %d\", result: nothing loaded.\n"),
280               drive);
281          dev->Slot = -1;    /* unknown */
282       }
283    } else {
284       berrno be;
285       be.set_errno(status);
286       Jmsg(jcr, M_INFO, 0, _("3991 Bad autochanger \"loaded? drive %d\" command: "
287            "ERR=%s.\nResults=%s\n"), drive, be.bstrerror(), results.c_str());
288       loaded = -1;              /* force unload */
289    }
290    unlock_changer(dcr);
291    free_pool_memory(changer);
292    return loaded;
293 }
294
295 static void lock_changer(DCR *dcr)
296 {
297    AUTOCHANGER *changer_res = dcr->device->changer_res;
298    if (changer_res) {
299       Dmsg1(200, "Locking changer %s\n", changer_res->hdr.name);
300       P(changer_res->changer_mutex);  /* Lock changer script */
301    }
302 }
303
304 static void unlock_changer(DCR *dcr)
305 {
306    AUTOCHANGER *changer_res = dcr->device->changer_res;
307    if (changer_res) {
308       Dmsg1(200, "Unlocking changer %s\n", changer_res->hdr.name);
309       V(changer_res->changer_mutex);  /* Unlock changer script */
310    }
311 }
312
313 /*
314  * Unload the volume, if any, in this drive
315  *  On entry: loaded == 0 -- nothing to do
316  *            loaded  < 0 -- check if anything to do
317  *            loaded  > 0 -- load slot == loaded
318  */
319 bool unload_autochanger(DCR *dcr, int loaded)
320 {
321    DEVICE *dev = dcr->dev;
322    JCR *jcr = dcr->jcr;
323    int slot;
324    uint32_t timeout = dcr->device->max_changer_wait;
325    bool ok = true;
326
327    if (loaded == 0) {
328       return true;
329    }
330
331    if (!dev->is_autochanger() || !dcr->device->changer_name ||
332        !dcr->device->changer_command) {
333       return false;
334    }
335
336    if (loaded < 0) {
337       loaded = get_autochanger_loaded_slot(dcr);
338    }
339
340    if (loaded > 0) {
341       POOL_MEM results(PM_MESSAGE);
342       POOLMEM *changer = get_pool_memory(PM_FNAME);
343       lock_changer(dcr);
344       Jmsg(jcr, M_INFO, 0,
345            _("3307 Issuing autochanger \"unload slot %d, drive %d\" command.\n"),
346            loaded, dev->drive_index);
347       slot = dcr->VolCatInfo.Slot;
348       dcr->VolCatInfo.Slot = loaded;
349       changer = edit_device_codes(dcr, changer, 
350                    dcr->device->changer_command, "unload");
351       dev->close();
352       Dmsg1(100, "Run program=%s\n", changer);
353       *results.c_str() = 0;
354       int stat = run_program_full_output(changer, timeout, results.c_str());
355       dcr->VolCatInfo.Slot = slot;
356       if (stat != 0) {
357          berrno be;
358          be.set_errno(stat);
359          Jmsg(jcr, M_INFO, 0, _("3995 Bad autochanger \"unload slot %d, drive %d\": "
360               "ERR=%s\nResults=%s\n"),
361                  loaded, dev->drive_index, be.bstrerror(), results.c_str());
362          ok = false;
363          dev->Slot = -1;           /* unknown */
364       } else {
365          dev->Slot = 0;            /* nothing loaded */
366       }
367       free_volume(dev);            /* Free any volume associated with this drive */
368       free_pool_memory(changer);
369       unlock_changer(dcr);
370    }
371    return ok;
372 }
373
374 /*
375  * Unload the slot if mounted in a different drive
376  */
377 static bool unload_other_drive(DCR *dcr, int slot)
378 {
379    DEVICE *dev = NULL;
380    DEVICE *save_dev;
381    JCR *jcr = dcr->jcr;
382    int save_slot;
383    uint32_t timeout = dcr->device->max_changer_wait;
384    bool ok = true;
385    AUTOCHANGER *changer = dcr->dev->device->changer_res;
386    DEVRES *device;
387    bool found = false;
388    int retries = 0;                /* wait for device retries */
389
390    if (!changer) {
391       return false;
392    }
393    if (changer->device->size() == 1) {
394       return true;
395    }
396
397    foreach_alist(device, changer->device) {
398       if (device->dev && device->dev->Slot == slot) {
399          found = true;
400          dev = device->dev;
401          break;
402       }
403    }
404    if (!found) {
405       return true;
406    }
407
408    /* The Volume we want is on another device. */
409    if (dev->is_busy()) {
410       Dmsg4(100, "Vol %s for dev=%s in use dev=%s slot=%d\n",
411            dcr->VolumeName, dcr->dev->print_name(),
412            dev->print_name(), slot);
413    }   
414    for (int i=0; i < 3; i++) {
415       if (dev->is_busy()) {
416          wait_for_device(dcr->jcr, retries);
417          continue;
418       }
419       break;
420    }
421    dev->dlock();
422    if (dev->is_busy()) {
423       Jmsg(jcr, M_WARNING, 0, _("Volume \"%s\" is in use by device %s\n"),
424            dcr->VolumeName, dev->print_name());
425       Dmsg4(100, "Vol %s for dev=%s is busy dev=%s slot=%d\n",
426            dcr->VolumeName, dcr->dev->print_name(), dev->print_name(), slot);
427       Dmsg2(100, "num_writ=%d reserv=%d\n", dev->num_writers, dev->reserved_device);
428       dev->dunlock();
429       return false;
430    }
431
432    POOLMEM *changer_cmd = get_pool_memory(PM_FNAME);
433    POOL_MEM results(PM_MESSAGE);
434    lock_changer(dcr);
435    Jmsg(jcr, M_INFO, 0,
436         _("3307 Issuing autochanger \"unload slot %d, drive %d\" command.\n"),
437         slot, dev->drive_index);
438
439    Dmsg2(100, "Issuing autochanger \"unload slot %d, drive %d\" command.\n",
440         slot, dev->drive_index);
441
442    save_dev = dcr->dev;
443    dcr->dev = dev;
444    save_slot = dcr->VolCatInfo.Slot;
445    dcr->VolCatInfo.Slot = slot;
446    changer_cmd = edit_device_codes(dcr, changer_cmd, 
447                 dcr->device->changer_command, "unload");
448    dev->close();
449    Dmsg2(200, "close dev=%s reserve=%d\n", dev->print_name(), 
450       dev->reserved_device);
451    Dmsg1(100, "Run program=%s\n", changer_cmd);
452    int stat = run_program_full_output(changer_cmd, timeout, results.c_str());
453    dcr->VolCatInfo.Slot = save_slot;
454    dcr->dev = save_dev;
455    if (stat != 0) {
456       berrno be;
457       be.set_errno(stat);
458       Jmsg(jcr, M_INFO, 0, _("3995 Bad autochanger \"unload slot %d, drive %d\": ERR=%s.\n"),
459               slot, dev->drive_index, be.bstrerror());
460
461       Dmsg3(100, "Bad autochanger \"unload slot %d, drive %d\": ERR=%s.\n",
462               slot, dev->drive_index, be.bstrerror());
463       ok = false;
464       dev->Slot = -1;          /* unknown */
465    } else {
466       dev->Slot = 0;           /* nothing loaded */
467       Dmsg0(100, "Slot unloaded\n");
468    }
469    free_volume(dev);               /* Free any volume associated with this drive */
470    unlock_changer(dcr);
471    dev->dunlock();
472    free_pool_memory(changer_cmd);
473    return ok;
474 }
475
476
477
478 /*
479  * List the Volumes that are in the autoloader possibly
480  *   with their barcodes.
481  *   We assume that it is always the Console that is calling us.
482  */
483 bool autochanger_cmd(DCR *dcr, BSOCK *dir, const char *cmd)  
484 {
485    DEVICE *dev = dcr->dev;
486    uint32_t timeout = dcr->device->max_changer_wait;
487    POOLMEM *changer;
488    BPIPE *bpipe;
489    int len = sizeof_pool_memory(dir->msg) - 1;
490    bool ok = false;
491    int stat;
492
493    if (!dev->is_autochanger() || !dcr->device->changer_name ||
494        !dcr->device->changer_command) {
495       if (strcmp(cmd, "drives") == 0) {
496          bnet_fsend(dir, "drives=1\n");
497       }
498       bnet_fsend(dir, _("3993 Device %s not an autochanger device.\n"),
499          dev->print_name());
500       return false;
501    }
502
503    if (strcmp(cmd, "drives") == 0) {
504       AUTOCHANGER *changer_res = dcr->device->changer_res;
505       int drives = 1;
506       if (changer_res) {
507          drives = changer_res->device->size();
508       }
509       bnet_fsend(dir, "drives=%d\n", drives);
510       Dmsg1(100, "drives=%d\n", drives);
511       return true;
512    }
513
514    changer = get_pool_memory(PM_FNAME);
515    lock_changer(dcr);
516    /* Now issue the command */
517    changer = edit_device_codes(dcr, changer, 
518                  dcr->device->changer_command, cmd);
519    bnet_fsend(dir, _("3306 Issuing autochanger \"%s\" command.\n"), cmd);
520    bpipe = open_bpipe(changer, timeout, "r");
521    if (!bpipe) {
522       bnet_fsend(dir, _("3996 Open bpipe failed.\n"));
523       goto bail_out;
524    }
525    if (strcmp(cmd, "list") == 0) {
526       /* Get output from changer */
527       while (fgets(dir->msg, len, bpipe->rfd)) {
528          dir->msglen = strlen(dir->msg);
529          Dmsg1(100, "<stored: %s\n", dir->msg);
530          bnet_send(dir);
531       }
532    } else if (strcmp(cmd, "slots") == 0 ) {
533       char buf[100], *p;
534       /* For slots command, read a single line */
535       buf[0] = 0;
536       fgets(buf, sizeof(buf)-1, bpipe->rfd);
537       buf[sizeof(buf)-1] = 0;
538       /* Strip any leading space in front of # of slots */
539       for (p=buf; B_ISSPACE(*p); p++)
540         { }
541       bnet_fsend(dir, "slots=%s", p);
542       Dmsg1(100, "<stored: %s", dir->msg);
543    } 
544                  
545    stat = close_bpipe(bpipe);
546    if (stat != 0) {
547       berrno be;
548       be.set_errno(stat);
549       bnet_fsend(dir, _("Autochanger error: ERR=%s\n"), be.bstrerror());
550    }
551    bnet_sig(dir, BNET_EOD);
552    ok = true;
553
554 bail_out:
555    unlock_changer(dcr);
556    free_pool_memory(changer);
557    return true;
558 }
559
560
561 /*
562  * Edit codes into ChangerCommand
563  *  %% = %
564  *  %a = archive device name
565  *  %c = changer device name
566  *  %d = changer drive index
567  *  %f = Client's name
568  *  %j = Job name
569  *  %o = command
570  *  %s = Slot base 0
571  *  %S = Slot base 1
572  *  %v = Volume name
573  *
574  *
575  *  omsg = edited output message
576  *  imsg = input string containing edit codes (%x)
577  *  cmd = command string (load, unload, ...)
578  *
579  */
580 char *edit_device_codes(DCR *dcr, char *omsg, const char *imsg, const char *cmd)
581 {
582    const char *p;
583    const char *str;
584    char add[20];
585
586    *omsg = 0;
587    Dmsg1(1800, "edit_device_codes: %s\n", imsg);
588    for (p=imsg; *p; p++) {
589       if (*p == '%') {
590          switch (*++p) {
591          case '%':
592             str = "%";
593             break;
594          case 'a':
595             str = dcr->dev->archive_name();
596             break;
597          case 'c':
598             str = NPRT(dcr->device->changer_name);
599             break;
600          case 'd':
601             sprintf(add, "%d", dcr->dev->drive_index);
602             str = add;
603             break;
604          case 'o':
605             str = NPRT(cmd);
606             break;
607          case 's':
608             sprintf(add, "%d", dcr->VolCatInfo.Slot - 1);
609             str = add;
610             break;
611          case 'S':
612             sprintf(add, "%d", dcr->VolCatInfo.Slot);
613             str = add;
614             break;
615          case 'j':                    /* Job name */
616             str = dcr->jcr->Job;
617             break;
618          case 'v':
619             str = NPRT(dcr->VolumeName);
620             break;
621          case 'f':
622             str = NPRT(dcr->jcr->client_name);
623             break;
624
625          default:
626             add[0] = '%';
627             add[1] = *p;
628             add[2] = 0;
629             str = add;
630             break;
631          }
632       } else {
633          add[0] = *p;
634          add[1] = 0;
635          str = add;
636       }
637       Dmsg1(1900, "add_str %s\n", str);
638       pm_strcat(&omsg, (char *)str);
639       Dmsg1(1800, "omsg=%s\n", omsg);
640    }
641    Dmsg1(800, "omsg=%s\n", omsg);
642    return omsg;
643 }