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