]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/stored/reserve.c
- Return HARDEOF status from bnet_recv() if bsock NULL rather
[bacula/bacula] / bacula / src / stored / reserve.c
1 /*
2  *   Drive reservation functions for Storage Daemon
3  *
4  *   Kern Sibbald, MM
5  *
6  *   Split from job.c and acquire.c June 2005
7  *
8  *   Version $Id$
9  *
10  */
11 /*
12    Copyright (C) 2000-2005 Kern Sibbald
13
14    This program is free software; you can redistribute it and/or
15    modify it under the terms of the GNU General Public License
16    version 2 as amended with additional clauses defined in the
17    file LICENSE in the main source directory.
18
19    This program is distributed in the hope that it will be useful,
20    but WITHOUT ANY WARRANTY; without even the implied warranty of
21    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 
22    the file LICENSE for additional details.
23
24  */
25
26 #include "bacula.h"
27 #include "stored.h"
28
29 /*
30  *   Use Device command from Director
31  *   He tells is what Device Name to use, the Media Type,
32  *      the Pool Name, and the Pool Type.
33  *
34  *    Ensure that the device exists and is opened, then store
35  *      the media and pool info in the JCR.  This class is used
36  *      only temporarily in this file.
37  */
38 class DIRSTORE {
39 public:
40    alist *device;
41    bool append;
42    char name[MAX_NAME_LENGTH];
43    char media_type[MAX_NAME_LENGTH];
44    char pool_name[MAX_NAME_LENGTH];
45    char pool_type[MAX_NAME_LENGTH];
46 };
47
48 /* Reserve context */
49 class RCTX {
50 public:
51    alist *errors;
52    JCR *jcr;
53    char *device_name;
54    DIRSTORE *store;
55    DEVRES   *device;
56    bool PreferMountedVols;
57    bool exact_match;
58    bool have_volume;
59    bool do_not_wait;
60    bool available_autochanger;
61    char VolumeName[MAX_NAME_LENGTH];
62 };
63
64 static dlist *vol_list = NULL;
65 static pthread_mutex_t vol_list_lock = PTHREAD_MUTEX_INITIALIZER;
66 static pthread_mutex_t search_lock = PTHREAD_MUTEX_INITIALIZER;
67
68 /* Forward referenced functions */
69 static int can_reserve_drive(DCR *dcr, RCTX &rctx);
70 static int search_res_for_device(RCTX &rctx);
71 static int reserve_device(RCTX &rctx);
72 static bool reserve_device_for_read(DCR *dcr);
73 static bool reserve_device_for_append(DCR *dcr, RCTX &rctx);
74 static bool use_storage_cmd(JCR *jcr);
75 bool find_suitable_device_for_job(JCR *jcr, RCTX &rctx);
76
77 /* Requests from the Director daemon */
78 static char use_storage[]  = "use storage=%127s media_type=%127s "
79    "pool_name=%127s pool_type=%127s append=%d copy=%d stripe=%d\n";
80 static char use_device[]  = "use device=%127s\n";
81
82 /* Responses sent to Director daemon */
83 static char OK_device[] = "3000 OK use device device=%s\n";
84 static char NO_device[] = "3924 Device \"%s\" not in SD Device resources.\n";
85 static char BAD_use[]   = "3913 Bad use command: %s\n";
86
87 bool use_cmd(JCR *jcr) 
88 {
89    /*
90     * Get the device, media, and pool information
91     */
92    if (!use_storage_cmd(jcr)) {
93       set_jcr_job_status(jcr, JS_ErrorTerminated);
94       memset(jcr->sd_auth_key, 0, strlen(jcr->sd_auth_key));
95       return false;
96    }
97    return true;
98 }
99
100 static int my_compare(void *item1, void *item2)
101 {
102    return strcmp(((VOLRES *)item1)->vol_name, ((VOLRES *)item2)->vol_name);
103 }
104
105
106 /*
107  * Put a new Volume entry in the Volume list. This
108  *  effectively reserves the volume so that it will
109  *  not be mounted again.
110  *
111  *  Return: VOLRES entry on success
112  *          NULL if the Volume is already in the list
113  */
114 VOLRES *new_volume(DCR *dcr, const char *VolumeName)
115 {
116    VOLRES *vol, *nvol;
117
118    Dmsg1(400, "new_volume %s\n", VolumeName);
119    P(vol_list_lock);
120    if (dcr->dev) {
121 again:
122       foreach_dlist(vol, vol_list) {
123          if (vol && vol->dev == dcr->dev) {
124             vol_list->remove(vol);
125             if (vol->vol_name) {
126                free(vol->vol_name);
127             }
128             free(vol);
129             goto again;
130          }
131       }
132    }
133    vol = (VOLRES *)malloc(sizeof(VOLRES));
134    memset(vol, 0, sizeof(VOLRES));
135    vol->vol_name = bstrdup(VolumeName);
136    vol->dev = dcr->dev;
137    vol->dcr = dcr;
138    nvol = (VOLRES *)vol_list->binary_insert(vol, my_compare);
139    if (nvol != vol) {
140       free(vol->vol_name);
141       free(vol);
142       vol = NULL;
143       if (dcr->dev) {
144          nvol->dev = dcr->dev;
145       }
146    }
147    V(vol_list_lock);
148    return vol;
149 }
150
151 /*
152  * Search for a Volume name in the Volume list.
153  *
154  *  Returns: VOLRES entry on success
155  *           NULL if the Volume is not in the list
156  */
157 VOLRES *find_volume(const char *VolumeName)
158 {
159    VOLRES vol, *fvol;
160    P(vol_list_lock);
161    vol.vol_name = bstrdup(VolumeName);
162    fvol = (VOLRES *)vol_list->binary_search(&vol, my_compare);
163    free(vol.vol_name);
164    V(vol_list_lock);
165    return fvol;
166 }
167
168 /*  
169  * Free a Volume from the Volume list
170  *
171  *  Returns: true if the Volume found and removed from the list
172  *           false if the Volume is not in the list
173  */
174 bool free_volume(DEVICE *dev)
175 {
176    VOLRES vol, *fvol;
177
178   P(vol_list_lock);
179    if (dev->VolHdr.VolumeName[0] == 0) {
180       /*
181        * Our device has no VolumeName listed, but
182        *  search the list for any Volume attached to
183        *  this device and remove it.
184        */
185       foreach_dlist(fvol, vol_list) {
186          if (fvol && fvol->dev == dev) {
187             vol_list->remove(fvol);
188             if (fvol->vol_name) {
189                free(fvol->vol_name);
190             }
191             free(fvol);
192             break;
193          }
194       }
195       goto bail_out;
196    }
197    Dmsg1(400, "free_volume %s\n", dev->VolHdr.VolumeName);
198    vol.vol_name = bstrdup(dev->VolHdr.VolumeName);
199    fvol = (VOLRES *)vol_list->binary_search(&vol, my_compare);
200    if (fvol) {
201       vol_list->remove(fvol);
202       free(fvol->vol_name);
203       free(fvol);
204    }
205    free(vol.vol_name);
206    dev->VolHdr.VolumeName[0] = 0;
207 bail_out:
208    V(vol_list_lock);
209    return fvol != NULL;
210 }
211
212 /* Free volume reserved by this dcr but not attached to a dev */
213 void free_unused_volume(DCR *dcr)
214 {
215    VOLRES *vol;
216    P(vol_list_lock);
217    for (vol=(VOLRES *)vol_list->first(); vol; vol=(VOLRES *)vol_list->next(vol)) {
218       if (vol->dcr == dcr && (vol->dev == NULL || 
219           strcmp(vol->vol_name, vol->dev->VolHdr.VolumeName) != 0)) {
220          vol_list->remove(vol);
221          free(vol->vol_name);
222          free(vol);
223          break;
224       }
225    }
226    V(vol_list_lock);
227 }
228
229 /*
230  * List Volumes -- this should be moved to status.c
231  */
232 void list_volumes(BSOCK *user)  
233 {
234    VOLRES *vol;
235    for (vol=(VOLRES *)vol_list->first(); vol; vol=(VOLRES *)vol_list->next(vol)) {
236       if (vol->dev) {
237          bnet_fsend(user, "%s on device %s\n", vol->vol_name, vol->dev->print_name());
238       } else {
239          bnet_fsend(user, "%s\n", vol->vol_name);
240       }
241    }
242 }
243       
244 /* Create the Volume list */
245 void create_volume_list()
246 {
247    VOLRES *dummy = NULL;
248    if (vol_list == NULL) {
249       vol_list = New(dlist(dummy, &dummy->link));
250    }
251 }
252
253 /* Release all Volumes from the list */
254 void free_volume_list()
255 {
256    VOLRES *vol;
257    if (!vol_list) {
258       return;
259    }
260    for (vol=(VOLRES *)vol_list->first(); vol; vol=(VOLRES *)vol_list->next(vol)) {
261       Dmsg3(000, "Unreleased Volume=%s dcr=0x%x dev=0x%x\n", vol->vol_name,
262          vol->dcr, vol->dev);
263    }
264    delete vol_list;
265    vol_list = NULL;
266 }
267
268 bool is_volume_in_use(DCR *dcr)
269 {
270    VOLRES *vol = find_volume(dcr->VolumeName);
271    if (!vol) {
272       return false;                   /* vol not in list */
273    }
274    if (!vol->dev) {                   /* vol not attached to device */
275       return false;
276    }
277    if (dcr->dev == vol->dev) {        /* same device OK */
278       return false;
279    }
280    if (!vol->dev->is_busy()) {
281       return false;
282    }
283    return true;
284 }
285
286
287 static bool use_storage_cmd(JCR *jcr)
288 {
289    POOL_MEM store_name, dev_name, media_type, pool_name, pool_type;
290    BSOCK *dir = jcr->dir_bsock;
291    int append;
292    bool ok;       
293    int Copy, Stripe;
294    DIRSTORE *store;
295    RCTX rctx;
296 #ifdef implemented
297    char *error;
298 #endif
299
300    memset(&rctx, 0, sizeof(RCTX));
301    rctx.jcr = jcr;
302    /*
303     * If there are multiple devices, the director sends us
304     *   use_device for each device that it wants to use.
305     */
306    jcr->dirstore = New(alist(10, not_owned_by_alist));
307    do {
308       Dmsg1(100, "<dird: %s", dir->msg);
309       ok = sscanf(dir->msg, use_storage, store_name.c_str(), 
310                   media_type.c_str(), pool_name.c_str(), 
311                   pool_type.c_str(), &append, &Copy, &Stripe) == 7;
312       if (!ok) {
313          break;
314       }
315       unbash_spaces(store_name);
316       unbash_spaces(media_type);
317       unbash_spaces(pool_name);
318       unbash_spaces(pool_type);
319       store = new DIRSTORE;
320       jcr->dirstore->append(store);
321       memset(store, 0, sizeof(DIRSTORE));
322       store->device = New(alist(10));
323       bstrncpy(store->name, store_name, sizeof(store->name));
324       bstrncpy(store->media_type, media_type, sizeof(store->media_type));
325       bstrncpy(store->pool_name, pool_name, sizeof(store->pool_name));
326       bstrncpy(store->pool_type, pool_type, sizeof(store->pool_type));
327       store->append = append;
328
329       /* Now get all devices */
330       while (bnet_recv(dir) >= 0) {
331          Dmsg1(100, "<dird device: %s", dir->msg);
332          ok = sscanf(dir->msg, use_device, dev_name.c_str()) == 1;
333          if (!ok) {
334             break;
335          }
336          unbash_spaces(dev_name);
337          store->device->append(bstrdup(dev_name.c_str()));
338       }
339    }  while (ok && bnet_recv(dir) >= 0);
340
341 #ifdef DEVELOPER
342    /* This loop is debug code and can be removed */
343    /* ***FIXME**** remove after 1.38 release */
344    char *device_name;
345    foreach_alist(store, jcr->dirstore) {
346       Dmsg4(100, "Storage=%s media_type=%s pool=%s pool_type=%s\n", 
347          store->name, store->media_type, store->pool_name, 
348          store->pool_type);
349       foreach_alist(device_name, store->device) {
350          Dmsg1(100, "   Device=%s\n", device_name);
351       }
352    }
353 #endif
354
355    /*                    
356     * At this point, we have a list of all the Director's Storage
357     *  resources indicated for this Job, which include Pool, PoolType,
358     *  storage name, and Media type.     
359     * Then for each of the Storage resources, we have a list of
360     *  device names that were given.
361     *
362     * Wiffle through them and find one that can do the backup.
363     */
364    if (ok) {
365       /*
366        * First look for an exact match of Volume name as the
367        *  tape may already be mounted.
368        */
369       rctx.do_not_wait = true;
370       rctx.exact_match = true;
371       if ((ok = find_suitable_device_for_job(jcr, rctx))) {
372          goto done;
373       }
374       rctx.exact_match = false;
375
376       /* Now search if an unused autochanger slot is available */
377       rctx.available_autochanger = true;
378       if ((ok = find_suitable_device_for_job(jcr, rctx))) {
379          goto done;
380       }
381       rctx.available_autochanger = false;
382
383
384       /*
385        * Make up to two passes. The first with PreferMountedVols possibly
386        *   set to true.  In that case, we look only for an available 
387        *   drive with something mounted. If that fails, then we
388        *   do a second pass with PerferMountedVols set false.
389        */
390       rctx.PreferMountedVols = jcr->PreferMountedVols;
391       if (!rctx.PreferMountedVols) {
392          rctx.do_not_wait = false;
393       }
394       if ((ok = find_suitable_device_for_job(jcr, rctx))) {
395          goto done;
396       }
397       if (rctx.PreferMountedVols) {
398          rctx.PreferMountedVols = false;
399          rctx.do_not_wait = false;
400          if ((ok = find_suitable_device_for_job(jcr, rctx))) {
401             goto done;
402          }
403       }
404       if (verbose) {
405          unbash_spaces(dir->msg);
406          pm_strcpy(jcr->errmsg, dir->msg);
407          Jmsg(jcr, M_INFO, 0, _("Failed command: %s\n"), jcr->errmsg);
408       }
409       Jmsg(jcr, M_FATAL, 0, _("\n"
410          "     Device \"%s\" with MediaType \"%s\" requested by DIR not found in SD Device resources.\n"),
411            dev_name.c_str(), media_type.c_str());
412       bnet_fsend(dir, NO_device, dev_name.c_str());
413 #ifdef implemented
414       for (error=(char*)rctx->errors.first(); error;
415            error=(char*)rctx->errors.next()) {
416          Jmsg(jcr, M_INFO, 0, "%s", error);
417       }
418 #endif
419       Dmsg1(100, ">dird: %s", dir->msg);
420    } else {
421       unbash_spaces(dir->msg);
422       pm_strcpy(jcr->errmsg, dir->msg);
423       if (verbose) {
424          Jmsg(jcr, M_INFO, 0, _("Failed command: %s\n"), jcr->errmsg);
425       }
426       bnet_fsend(dir, BAD_use, jcr->errmsg);
427       Dmsg1(100, ">dird: %s", dir->msg);
428    }
429
430 done:
431    foreach_alist(store, jcr->dirstore) {
432       delete store->device;
433       delete store;
434    }
435    delete jcr->dirstore;
436 #ifdef implemented
437    for (error=(char*)rctx->errors.first(); error;
438         error=(char*)rctx->errors.next()) {
439       free(error);
440    }
441 #endif
442    return ok;
443 }
444
445
446 /*
447  * Search for a device suitable for this job.
448  */
449 bool find_suitable_device_for_job(JCR *jcr, RCTX &rctx)
450 {
451    bool first = true;
452    bool ok;
453    DCR *dcr = NULL;
454    DIRSTORE *store;
455    char *device_name;
456
457    init_jcr_device_wait_timers(jcr);
458    for ( ;; ) {
459       int can_wait = false;
460       ok = false;
461       P(search_lock);
462       foreach_alist(store, jcr->dirstore) {
463          rctx.store = store;
464          foreach_alist(device_name, store->device) {
465             int stat;
466             rctx.device_name = device_name;
467             stat = search_res_for_device(rctx); 
468             if (stat == 1) {             /* found available device */
469                ok = true;
470                break;
471             } else if (stat == 0) {      /* device busy */
472                can_wait = true;
473             }
474             /* otherwise error */
475 //             rctx->errors.push(bstrdup(jcr->errmsg));
476          }
477          if (ok) {
478             break;
479          }
480       }
481       V(search_lock);
482       /*
483        * We did not find a suitable device, so
484        *  if there is some device for which we can wait, then
485        *  wait and try again until the wait time expires
486        */
487       if (rctx.do_not_wait || !can_wait || !wait_for_device(jcr, first)) {
488          break;
489       }
490       first = false;                  /* first wait complete */
491
492 #ifdef implemented
493       for (error=(char*)rctx->errors.first(); error;
494            error=(char*)rctx->errors.next()) {
495          free(error);
496       }
497 #endif
498    }
499    if (dcr) {
500       free_dcr(dcr);
501    }
502    return ok;
503 }
504
505 /*
506  * Search for a particular storage device with particular storage
507  *  characteristics (MediaType).
508  */
509 static int search_res_for_device(RCTX &rctx) 
510 {
511    AUTOCHANGER *changer;
512    BSOCK *dir = rctx.jcr->dir_bsock;
513    bool ok;
514    int stat;
515
516    Dmsg1(100, "Search res for %s\n", rctx.device_name);
517    if (!rctx.available_autochanger) {
518       foreach_res(rctx.device, R_DEVICE) {
519          Dmsg1(100, "Try res=%s\n", rctx.device->hdr.name);
520          /* Find resource, and make sure we were able to open it */
521          if (fnmatch(rctx.device_name, rctx.device->hdr.name, 0) == 0) {
522             stat = reserve_device(rctx);
523             if (stat != 1) {
524                return stat;
525             }
526             Dmsg1(220, "Got: %s", dir->msg);
527             bash_spaces(rctx.device_name);
528             ok = bnet_fsend(dir, OK_device, rctx.device_name);
529             Dmsg1(100, ">dird dev: %s", dir->msg);
530             return ok ? 1 : -1;
531          }
532       }
533    }
534    foreach_res(changer, R_AUTOCHANGER) {
535       Dmsg1(100, "Try changer res=%s\n", changer->hdr.name);
536       /* Find resource, and make sure we were able to open it */
537       if (fnmatch(rctx.device_name, changer->hdr.name, 0) == 0) {
538          /* Try each device in this AutoChanger */
539          foreach_alist(rctx.device, changer->device) {
540             Dmsg1(100, "Try changer device %s\n", rctx.device->hdr.name);
541             stat = reserve_device(rctx);
542             if (stat == -1) {            /* hard error */
543                return -1;
544             }
545             if (stat == 0) {             /* must wait, try next one */
546                continue;
547             }
548             POOL_MEM dev_name;
549             Dmsg1(100, "Device %s opened.\n", rctx.device_name);
550             pm_strcpy(dev_name, rctx.device->hdr.name);
551             bash_spaces(dev_name);
552             ok = bnet_fsend(dir, OK_device, dev_name.c_str());  /* Return real device name */
553             Dmsg1(100, ">dird changer: %s", dir->msg);
554             return ok ? 1 : -1;
555          }
556       }
557    }
558    return 0;                    /* nothing found */
559 }
560
561 /*
562  *  Try to reserve a specific device.
563  *
564  *  Returns: 1 -- OK, have DCR
565  *           0 -- must wait
566  *          -1 -- fatal error
567  */
568 static int reserve_device(RCTX &rctx)
569 {
570    bool ok;
571    DCR *dcr;
572    const int name_len = MAX_NAME_LENGTH;
573
574    /* Make sure MediaType is OK */
575    if (strcmp(rctx.device->media_type, rctx.store->media_type) != 0) {
576       return -1;
577    }
578
579    if (!rctx.device->dev) {
580       rctx.device->dev = init_dev(rctx.jcr, rctx.device);
581    }
582    if (!rctx.device->dev) {
583       if (rctx.device->changer_res) {
584         Jmsg(rctx.jcr, M_WARNING, 0, _("\n"
585            "     Device \"%s\" in changer \"%s\" requested by DIR could not be opened or does not exist.\n"),
586              rctx.device->hdr.name, rctx.device_name);
587       } else {
588          Jmsg(rctx.jcr, M_WARNING, 0, _("\n"
589             "     Device \"%s\" requested by DIR could not be opened or does not exist.\n"),
590               rctx.device_name);
591       }
592       return -1;  /* no use waiting */
593    }  
594    Dmsg1(100, "Found device %s\n", rctx.device->hdr.name);
595    dcr = new_dcr(rctx.jcr, rctx.device->dev);
596    if (!dcr) {
597       BSOCK *dir = rctx.jcr->dir_bsock;
598       bnet_fsend(dir, _("3926 Could not get dcr for device: %s\n"), rctx.device_name);
599       Dmsg1(100, ">dird: %s", dir->msg);
600       return -1;
601    }
602    rctx.jcr->dcr = dcr;
603    bstrncpy(dcr->pool_name, rctx.store->pool_name, name_len);
604    bstrncpy(dcr->pool_type, rctx.store->pool_type, name_len);
605    bstrncpy(dcr->media_type, rctx.store->media_type, name_len);
606    bstrncpy(dcr->dev_name, rctx.device_name, name_len);
607    if (rctx.store->append == SD_APPEND) {
608       if (rctx.exact_match && !rctx.have_volume) {
609          dcr->any_volume = true;
610          if (dir_find_next_appendable_volume(dcr)) {
611             Dmsg1(200, "Looking for Volume=%s\n", dcr->VolumeName);
612             bstrncpy(rctx.VolumeName, dcr->VolumeName, sizeof(rctx.VolumeName));
613             rctx.have_volume = true;
614          } else {
615             Dmsg0(200, "No next volume found\n");
616             rctx.VolumeName[0] = 0;
617         }
618       }
619       ok = reserve_device_for_append(dcr, rctx);
620       Dmsg3(200, "dev_name=%s mediatype=%s ok=%d\n", dcr->dev_name, dcr->media_type, ok);
621    } else {
622       ok = reserve_device_for_read(dcr);
623    }
624    if (!ok) {
625       free_dcr(rctx.jcr->dcr);
626       return 0;
627    }
628    return 1;
629 }
630
631 /*
632  * We "reserve" the drive by setting the ST_READ bit. No one else
633  *  should touch the drive until that is cleared.
634  *  This allows the DIR to "reserve" the device before actually
635  *  starting the job. 
636  */
637 static bool reserve_device_for_read(DCR *dcr)
638 {
639    DEVICE *dev = dcr->dev;
640    JCR *jcr = dcr->jcr;
641    bool ok = false;
642
643    ASSERT(dcr);
644
645    dev->block(BST_DOING_ACQUIRE);
646
647    if (is_device_unmounted(dev)) {             
648       Dmsg1(200, "Device %s is BLOCKED due to user unmount.\n", dev->print_name());
649       Mmsg(jcr->errmsg, _("Device %s is BLOCKED due to user unmount.\n"),
650            dev->print_name());
651       goto bail_out;
652    }
653
654    if (dev->is_busy()) {
655       Dmsg4(200, "Device %s is busy ST_READ=%d num_writers=%d reserved=%d.\n", dev->print_name(),
656          dev->state & ST_READ?1:0, dev->num_writers, dev->reserved_device);
657       Mmsg1(jcr->errmsg, _("Device %s is busy.\n"),
658             dev->print_name());
659       goto bail_out;
660    }
661
662    dev->clear_append();
663    dev->set_read();
664    ok = true;
665
666 bail_out:
667    dev->unblock();
668    return ok;
669 }
670
671
672 /*
673  * We reserve the device for appending by incrementing the 
674  *  reserved_device. We do virtually all the same work that
675  *  is done in acquire_device_for_append(), but we do
676  *  not attempt to mount the device. This routine allows
677  *  the DIR to reserve multiple devices before *really* 
678  *  starting the job. It also permits the SD to refuse 
679  *  certain devices (not up, ...).
680  *
681  * Note, in reserving a device, if the device is for the
682  *  same pool and the same pool type, then it is acceptable.
683  *  The Media Type has already been checked. If we are
684  *  the first tor reserve the device, we put the pool
685  *  name and pool type in the device record.
686  */
687 static bool reserve_device_for_append(DCR *dcr, RCTX &rctx)
688 {
689    JCR *jcr = dcr->jcr;
690    DEVICE *dev = dcr->dev;
691    bool ok = false;
692
693    ASSERT(dcr);
694
695    dev->block(BST_DOING_ACQUIRE);
696
697    if (dev->can_read()) {
698       Mmsg1(jcr->errmsg, _("Device %s is busy reading.\n"), dev->print_name());
699       Dmsg1(100, "%s", jcr->errmsg);
700       goto bail_out;
701    }
702
703    if (is_device_unmounted(dev)) {
704       Mmsg(jcr->errmsg, _("Device %s is BLOCKED due to user unmount.\n"), dev->print_name());
705       Dmsg1(100, "%s", jcr->errmsg);
706       goto bail_out;
707    }
708
709    Dmsg1(190, "reserve_append device is %s\n", dev->is_tape()?"tape":"disk");
710
711    if (can_reserve_drive(dcr, rctx) != 1) {
712       Dmsg1(100, "%s", jcr->errmsg);
713       goto bail_out;
714    }
715
716    dev->reserved_device++;
717    Dmsg1(200, "Inc reserve=%d\n", dev->reserved_device);
718    dcr->reserved_device = true;
719    ok = true;
720
721 bail_out:
722    dev->unblock();
723    return ok;
724 }
725
726 /*
727  * Returns: 1 if drive can be reserved
728  *          0 if we should wait
729  *         -1 on error
730  */
731 static int can_reserve_drive(DCR *dcr, RCTX &rctx) 
732 {
733    DEVICE *dev = dcr->dev;
734    JCR *jcr = dcr->jcr;
735
736    /* Check for prefer mounted volumes */
737    if (rctx.PreferMountedVols && !dev->VolHdr.VolumeName[0] && dev->is_tape()) {
738       Mmsg0(jcr->errmsg, _("Want mounted Volume, drive is empty\n"));
739       Dmsg0(200, "want mounted -- no vol\n");
740       return 0;                 /* No volume mounted */
741    }
742
743    /* Check for exact Volume name match */
744    if (rctx.exact_match && rctx.have_volume &&
745        strcmp(dev->VolHdr.VolumeName, rctx.VolumeName) != 0) {
746       Mmsg2(jcr->errmsg, _("Not exact match have=%s want=%s\n"),
747             dev->VolHdr.VolumeName, rctx.VolumeName);
748       Dmsg2(200, "Not exact match have=%s want=%s\n",
749             dev->VolHdr.VolumeName, rctx.VolumeName);
750       return 0;
751    }
752
753    /* Check for unused autochanger drive */
754    if (rctx.available_autochanger && dev->num_writers == 0 &&
755        dev->VolHdr.VolumeName[0] == 0) {
756       /* Device is available but not yet reserved, reserve it for us */
757       bstrncpy(dev->pool_name, dcr->pool_name, sizeof(dev->pool_name));
758       bstrncpy(dev->pool_type, dcr->pool_type, sizeof(dev->pool_type));
759       return 1;                       /* reserve drive */
760    }
761
762    /*
763     * Handle the case that there are no writers
764     */
765    if (dev->num_writers == 0) {
766       /* Now check if there are any reservations on the drive */
767       if (dev->reserved_device) {           
768          /* Now check if we want the same Pool and pool type */
769          if (strcmp(dev->pool_name, dcr->pool_name) == 0 &&
770              strcmp(dev->pool_type, dcr->pool_type) == 0) {
771             /* OK, compatible device */
772             Dmsg0(200, "got dev: num_writers=0, reserved, pool matches\n");
773             return 1;
774          } else {
775             /* Drive not suitable for us */
776             Mmsg2(jcr->errmsg, _("Drive busy wrong pool: num_writers=0, reserved, pool=%s wanted=%s\n"),
777                dev->pool_name, dcr->pool_name);
778             Dmsg2(200, "busy: num_writers=0, reserved, pool=%s wanted=%s\n",
779                dev->pool_name, dcr->pool_name);
780             return 0;                 /* wait */
781          }
782       } else if (dev->can_append()) {
783          /* Device in append mode, check if changing pool */
784          if (strcmp(dev->pool_name, dcr->pool_name) == 0 &&
785              strcmp(dev->pool_type, dcr->pool_type) == 0) {
786             Dmsg0(200, "got dev: num_writers=0, can_append, pool matches\n");
787             /* OK, compatible device */
788             return 1;
789          } else {
790             /* Changing pool, unload old tape if any in drive */
791             Dmsg0(200, "got dev: num_writers=0, reserved, pool change\n");
792             unload_autochanger(dcr, 0);
793          }
794       }
795       /* Device is available but not yet reserved, reserve it for us */
796       bstrncpy(dev->pool_name, dcr->pool_name, sizeof(dev->pool_name));
797       bstrncpy(dev->pool_type, dcr->pool_type, sizeof(dev->pool_type));
798       return 1;                       /* reserve drive */
799    }
800
801    /*
802     * Check if the device is in append mode with writers (i.e.
803     *  available if pool is the same).
804     */
805    if (dev->can_append() || dev->num_writers > 0) {
806       Dmsg0(190, "device already in append.\n");
807       /* Yes, now check if we want the same Pool and pool type */
808       if (strcmp(dev->pool_name, dcr->pool_name) == 0 &&
809           strcmp(dev->pool_type, dcr->pool_type) == 0) {
810          Dmsg0(200, "got dev: num_writers>=0, can_append, pool matches\n");
811          /* OK, compatible device */
812          return 1;
813       } else {
814          /* Drive not suitable for us */
815          Mmsg(jcr->errmsg, _("Wanted Pool \"%s\", but device %s is using Pool \"%s\" .\n"), 
816                  dcr->pool_name, dev->print_name(), dev->pool_name);
817          Dmsg2(200, "busy: num_writers>0, can_append, pool=%s wanted=%s\n",
818             dev->pool_name, dcr->pool_name);
819          return 0;                    /* wait */
820       }
821    } else {
822       Pmsg0(000, _("Logic error!!!! Should not get here.\n"));
823       Jmsg0(jcr, M_FATAL, 0, _("Logic error!!!! Should not get here.\n"));
824       return -1;                      /* error, should not get here */
825    }
826
827    return 0;
828 }