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