]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/stored/autochanger.c
kes Re-enable code to remember last volume mounted on a non-tape
[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 may 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    /* Virtual disk autochanger */
337    if (dcr->device->changer_command[0] == 0) {
338       return true;
339    }
340
341    if (loaded < 0) {
342       loaded = get_autochanger_loaded_slot(dcr);
343    }
344
345    if (loaded > 0) {
346       POOL_MEM results(PM_MESSAGE);
347       POOLMEM *changer = get_pool_memory(PM_FNAME);
348       lock_changer(dcr);
349       Jmsg(jcr, M_INFO, 0,
350            _("3307 Issuing autochanger \"unload slot %d, drive %d\" command.\n"),
351            loaded, dev->drive_index);
352       slot = dcr->VolCatInfo.Slot;
353       dcr->VolCatInfo.Slot = loaded;
354       changer = edit_device_codes(dcr, changer, 
355                    dcr->device->changer_command, "unload");
356       dev->close();
357       Dmsg1(100, "Run program=%s\n", changer);
358       *results.c_str() = 0;
359       int stat = run_program_full_output(changer, timeout, results.c_str());
360       dcr->VolCatInfo.Slot = slot;
361       if (stat != 0) {
362          berrno be;
363          be.set_errno(stat);
364          Jmsg(jcr, M_INFO, 0, _("3995 Bad autochanger \"unload slot %d, drive %d\": "
365               "ERR=%s\nResults=%s\n"),
366                  loaded, dev->drive_index, be.bstrerror(), results.c_str());
367          ok = false;
368          dev->Slot = -1;           /* unknown */
369       } else {
370          dev->Slot = 0;            /* nothing loaded */
371       }
372       free_volume(dev);            /* Free any volume associated with this drive */
373       free_pool_memory(changer);
374       unlock_changer(dcr);
375    }
376    return ok;
377 }
378
379 /*
380  * Unload the slot if mounted in a different drive
381  */
382 static bool unload_other_drive(DCR *dcr, int slot)
383 {
384    DEVICE *dev = NULL;
385    DEVICE *save_dev;
386    JCR *jcr = dcr->jcr;
387    int save_slot;
388    uint32_t timeout = dcr->device->max_changer_wait;
389    bool ok = true;
390    AUTOCHANGER *changer = dcr->dev->device->changer_res;
391    DEVRES *device;
392    bool found = false;
393    int retries = 0;                /* wait for device retries */
394
395    if (!changer) {
396       return false;
397    }
398    if (changer->device->size() == 1) {
399       return true;
400    }
401
402    foreach_alist(device, changer->device) {
403       if (device->dev && device->dev->Slot == slot) {
404          found = true;
405          dev = device->dev;
406          break;
407       }
408    }
409    if (!found) {
410       return true;
411    }
412
413    /* The Volume we want is on another device. */
414    if (dev->is_busy()) {
415       Dmsg4(100, "Vol %s for dev=%s in use dev=%s slot=%d\n",
416            dcr->VolumeName, dcr->dev->print_name(),
417            dev->print_name(), slot);
418    }   
419    for (int i=0; i < 3; i++) {
420       if (dev->is_busy()) {
421          wait_for_device(dcr->jcr, retries);
422          continue;
423       }
424       break;
425    }
426    dev->dlock();
427    if (dev->is_busy()) {
428       Jmsg(jcr, M_WARNING, 0, _("Volume \"%s\" is in use by device %s\n"),
429            dcr->VolumeName, dev->print_name());
430       Dmsg4(100, "Vol %s for dev=%s is busy dev=%s slot=%d\n",
431            dcr->VolumeName, dcr->dev->print_name(), dev->print_name(), slot);
432       Dmsg2(100, "num_writ=%d reserv=%d\n", dev->num_writers, dev->reserved_device);
433       dev->dunlock();
434       return false;
435    }
436
437    POOLMEM *changer_cmd = get_pool_memory(PM_FNAME);
438    POOL_MEM results(PM_MESSAGE);
439    lock_changer(dcr);
440    Jmsg(jcr, M_INFO, 0,
441         _("3307 Issuing autochanger \"unload slot %d, drive %d\" command.\n"),
442         slot, dev->drive_index);
443
444    Dmsg2(100, "Issuing autochanger \"unload slot %d, drive %d\" command.\n",
445         slot, dev->drive_index);
446
447    save_dev = dcr->dev;
448    dcr->dev = dev;
449    save_slot = dcr->VolCatInfo.Slot;
450    dcr->VolCatInfo.Slot = slot;
451    changer_cmd = edit_device_codes(dcr, changer_cmd, 
452                 dcr->device->changer_command, "unload");
453    dev->close();
454    Dmsg2(200, "close dev=%s reserve=%d\n", dev->print_name(), 
455       dev->reserved_device);
456    Dmsg1(100, "Run program=%s\n", changer_cmd);
457    int stat = run_program_full_output(changer_cmd, timeout, results.c_str());
458    dcr->VolCatInfo.Slot = save_slot;
459    dcr->dev = save_dev;
460    if (stat != 0) {
461       berrno be;
462       be.set_errno(stat);
463       Jmsg(jcr, M_INFO, 0, _("3995 Bad autochanger \"unload slot %d, drive %d\": ERR=%s.\n"),
464               slot, dev->drive_index, be.bstrerror());
465
466       Dmsg3(100, "Bad autochanger \"unload slot %d, drive %d\": ERR=%s.\n",
467               slot, dev->drive_index, be.bstrerror());
468       ok = false;
469       dev->Slot = -1;          /* unknown */
470    } else {
471       dev->Slot = 0;           /* nothing loaded */
472       Dmsg0(100, "Slot unloaded\n");
473    }
474    free_volume(dev);               /* Free any volume associated with this drive */
475    unlock_changer(dcr);
476    dev->dunlock();
477    free_pool_memory(changer_cmd);
478    return ok;
479 }
480
481
482
483 /*
484  * List the Volumes that are in the autoloader possibly
485  *   with their barcodes.
486  *   We assume that it is always the Console that is calling us.
487  */
488 bool autochanger_cmd(DCR *dcr, BSOCK *dir, const char *cmd)  
489 {
490    DEVICE *dev = dcr->dev;
491    uint32_t timeout = dcr->device->max_changer_wait;
492    POOLMEM *changer;
493    BPIPE *bpipe;
494    int len = sizeof_pool_memory(dir->msg) - 1;
495    bool ok = false;
496    int stat;
497
498    if (!dev->is_autochanger() || !dcr->device->changer_name ||
499        !dcr->device->changer_command) {
500       if (strcmp(cmd, "drives") == 0) {
501          dir->fsend("drives=1\n");
502       }
503       dir->fsend(_("3993 Device %s not an autochanger device.\n"),
504          dev->print_name());
505       return false;
506    }
507
508    if (strcmp(cmd, "drives") == 0) {
509       AUTOCHANGER *changer_res = dcr->device->changer_res;
510       int drives = 1;
511       if (changer_res) {
512          drives = changer_res->device->size();
513       }
514       dir->fsend("drives=%d\n", drives);
515       Dmsg1(100, "drives=%d\n", drives);
516       return true;
517    }
518
519    changer = get_pool_memory(PM_FNAME);
520    lock_changer(dcr);
521    /* Now issue the command */
522    changer = edit_device_codes(dcr, changer, 
523                  dcr->device->changer_command, cmd);
524    dir->fsend(_("3306 Issuing autochanger \"%s\" command.\n"), cmd);
525    bpipe = open_bpipe(changer, timeout, "r");
526    if (!bpipe) {
527       dir->fsend(_("3996 Open bpipe failed.\n"));
528       goto bail_out;
529    }
530    if (strcmp(cmd, "list") == 0) {
531       /* Get output from changer */
532       while (fgets(dir->msg, len, bpipe->rfd)) {
533          dir->msglen = strlen(dir->msg);
534          Dmsg1(100, "<stored: %s\n", dir->msg);
535          bnet_send(dir);
536       }
537    } else if (strcmp(cmd, "slots") == 0 ) {
538       char buf[100], *p;
539       /* For slots command, read a single line */
540       buf[0] = 0;
541       fgets(buf, sizeof(buf)-1, bpipe->rfd);
542       buf[sizeof(buf)-1] = 0;
543       /* Strip any leading space in front of # of slots */
544       for (p=buf; B_ISSPACE(*p); p++)
545         { }
546       dir->fsend("slots=%s", p);
547       Dmsg1(100, "<stored: %s", dir->msg);
548    } 
549                  
550    stat = close_bpipe(bpipe);
551    if (stat != 0) {
552       berrno be;
553       be.set_errno(stat);
554       dir->fsend(_("Autochanger error: ERR=%s\n"), be.bstrerror());
555    }
556    bnet_sig(dir, BNET_EOD);
557    ok = true;
558
559 bail_out:
560    unlock_changer(dcr);
561    free_pool_memory(changer);
562    return true;
563 }
564
565
566 /*
567  * Edit codes into ChangerCommand
568  *  %% = %
569  *  %a = archive device name
570  *  %c = changer device name
571  *  %d = changer drive index
572  *  %f = Client's name
573  *  %j = Job name
574  *  %o = command
575  *  %s = Slot base 0
576  *  %S = Slot base 1
577  *  %v = Volume name
578  *
579  *
580  *  omsg = edited output message
581  *  imsg = input string containing edit codes (%x)
582  *  cmd = command string (load, unload, ...)
583  *
584  */
585 char *edit_device_codes(DCR *dcr, char *omsg, const char *imsg, const char *cmd)
586 {
587    const char *p;
588    const char *str;
589    char add[20];
590
591    *omsg = 0;
592    Dmsg1(1800, "edit_device_codes: %s\n", imsg);
593    for (p=imsg; *p; p++) {
594       if (*p == '%') {
595          switch (*++p) {
596          case '%':
597             str = "%";
598             break;
599          case 'a':
600             str = dcr->dev->archive_name();
601             break;
602          case 'c':
603             str = NPRT(dcr->device->changer_name);
604             break;
605          case 'd':
606             sprintf(add, "%d", dcr->dev->drive_index);
607             str = add;
608             break;
609          case 'o':
610             str = NPRT(cmd);
611             break;
612          case 's':
613             sprintf(add, "%d", dcr->VolCatInfo.Slot - 1);
614             str = add;
615             break;
616          case 'S':
617             sprintf(add, "%d", dcr->VolCatInfo.Slot);
618             str = add;
619             break;
620          case 'j':                    /* Job name */
621             str = dcr->jcr->Job;
622             break;
623          case 'v':
624             str = NPRT(dcr->VolumeName);
625             break;
626          case 'f':
627             str = NPRT(dcr->jcr->client_name);
628             break;
629
630          default:
631             add[0] = '%';
632             add[1] = *p;
633             add[2] = 0;
634             str = add;
635             break;
636          }
637       } else {
638          add[0] = *p;
639          add[1] = 0;
640          str = add;
641       }
642       Dmsg1(1900, "add_str %s\n", str);
643       pm_strcat(&omsg, (char *)str);
644       Dmsg1(1800, "omsg=%s\n", omsg);
645    }
646    Dmsg1(800, "omsg=%s\n", omsg);
647    return omsg;
648 }