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