]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/stored/reserve.c
- Add VolumePurged method to Python JobEvents class. Fixes
[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    Dmsg1(100, "<dird: %s", dir->msg);
307    jcr->dirstore = New(alist(10, not_owned_by_alist));
308    do {
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          ok = sscanf(dir->msg, use_device, dev_name.c_str()) == 1;
332          if (!ok) {
333             break;
334          }
335          unbash_spaces(dev_name);
336          store->device->append(bstrdup(dev_name.c_str()));
337       }
338    }  while (ok && bnet_recv(dir) >= 0);
339
340 #ifdef DEVELOPER
341    /* This loop is debug code and can be removed */
342    /* ***FIXME**** remove after 1.38 release */
343    char *device_name;
344    foreach_alist(store, jcr->dirstore) {
345       Dmsg4(100, "Storage=%s media_type=%s pool=%s pool_type=%s\n", 
346          store->name, store->media_type, store->pool_name, 
347          store->pool_type);
348       foreach_alist(device_name, store->device) {
349          Dmsg1(100, "   Device=%s\n", device_name);
350       }
351    }
352 #endif
353
354    /*                    
355     * At this point, we have a list of all the Director's Storage
356     *  resources indicated for this Job, which include Pool, PoolType,
357     *  storage name, and Media type.     
358     * Then for each of the Storage resources, we have a list of
359     *  device names that were given.
360     *
361     * Wiffle through them and find one that can do the backup.
362     */
363    if (ok) {
364       /*
365        * First look for an exact match of Volume name as the
366        *  tape may already be mounted.
367        */
368       rctx.do_not_wait = true;
369       rctx.exact_match = true;
370       if ((ok = find_suitable_device_for_job(jcr, rctx))) {
371          goto done;
372       }
373       rctx.exact_match = false;
374
375       /* Now search if an unused autochanger slot is available */
376       rctx.available_autochanger = true;
377       if ((ok = find_suitable_device_for_job(jcr, rctx))) {
378          goto done;
379       }
380       rctx.available_autochanger = false;
381
382
383       /*
384        * Make up to two passes. The first with PreferMountedVols possibly
385        *   set to true.  In that case, we look only for an available 
386        *   drive with something mounted. If that fails, then we
387        *   do a second pass with PerferMountedVols set false.
388        */
389       rctx.PreferMountedVols = jcr->PreferMountedVols;
390       if (!rctx.PreferMountedVols) {
391          rctx.do_not_wait = false;
392       }
393       if ((ok = find_suitable_device_for_job(jcr, rctx))) {
394          goto done;
395       }
396       if (rctx.PreferMountedVols) {
397          rctx.PreferMountedVols = false;
398          rctx.do_not_wait = false;
399          if ((ok = find_suitable_device_for_job(jcr, rctx))) {
400             goto done;
401          }
402       }
403       if (verbose) {
404          unbash_spaces(dir->msg);
405          pm_strcpy(jcr->errmsg, dir->msg);
406          Jmsg(jcr, M_INFO, 0, _("Failed command: %s\n"), jcr->errmsg);
407       }
408       Jmsg(jcr, M_FATAL, 0, _("\n"
409          "     Device \"%s\" with MediaType \"%s\" requested by DIR not found in SD Device resources.\n"),
410            dev_name.c_str(), media_type.c_str());
411       bnet_fsend(dir, NO_device, dev_name.c_str());
412 #ifdef implemented
413       for (error=(char*)rctx->errors.first(); error;
414            error=(char*)rctx->errors.next()) {
415          Jmsg(jcr, M_INFO, 0, "%s", error);
416       }
417 #endif
418       Dmsg1(100, ">dird: %s", dir->msg);
419    } else {
420       unbash_spaces(dir->msg);
421       pm_strcpy(jcr->errmsg, dir->msg);
422       if (verbose) {
423          Jmsg(jcr, M_INFO, 0, _("Failed command: %s\n"), jcr->errmsg);
424       }
425       bnet_fsend(dir, BAD_use, jcr->errmsg);
426       Dmsg1(100, ">dird: %s", dir->msg);
427    }
428
429 done:
430    foreach_alist(store, jcr->dirstore) {
431       delete store->device;
432       delete store;
433    }
434    delete jcr->dirstore;
435 #ifdef implemented
436    for (error=(char*)rctx->errors.first(); error;
437         error=(char*)rctx->errors.next()) {
438       free(error);
439    }
440 #endif
441    return ok;
442 }
443
444
445 /*
446  * Search for a device suitable for this job.
447  */
448 bool find_suitable_device_for_job(JCR *jcr, RCTX &rctx)
449 {
450    bool first = true;
451    bool ok;
452    DCR *dcr = NULL;
453    DIRSTORE *store;
454    char *device_name;
455
456    init_jcr_device_wait_timers(jcr);
457    for ( ;; ) {
458       int can_wait = false;
459       ok = false;
460       P(search_lock);
461       foreach_alist(store, jcr->dirstore) {
462          rctx.store = store;
463          foreach_alist(device_name, store->device) {
464             int stat;
465             rctx.device_name = device_name;
466             stat = search_res_for_device(rctx); 
467             if (stat == 1) {             /* found available device */
468                ok = true;
469                break;
470             } else if (stat == 0) {      /* device busy */
471                can_wait = true;
472             }
473             /* otherwise error */
474 //             rctx->errors.push(bstrdup(jcr->errmsg));
475          }
476          if (ok) {
477             break;
478          }
479       }
480       V(search_lock);
481       /*
482        * We did not find a suitable device, so
483        *  if there is some device for which we can wait, then
484        *  wait and try again until the wait time expires
485        */
486       if (rctx.do_not_wait || !can_wait || !wait_for_device(jcr, first)) {
487          break;
488       }
489       first = false;                  /* first wait complete */
490
491 #ifdef implemented
492       for (error=(char*)rctx->errors.first(); error;
493            error=(char*)rctx->errors.next()) {
494          free(error);
495       }
496 #endif
497    }
498    if (dcr) {
499       free_dcr(dcr);
500    }
501    return ok;
502 }
503
504 /*
505  * Search for a particular storage device with particular storage
506  *  characteristics (MediaType).
507  */
508 static int search_res_for_device(RCTX &rctx) 
509 {
510    AUTOCHANGER *changer;
511    BSOCK *dir = rctx.jcr->dir_bsock;
512    bool ok;
513    int stat;
514
515    Dmsg1(100, "Search res for %s\n", rctx.device_name);
516    if (!rctx.available_autochanger) {
517       foreach_res(rctx.device, R_DEVICE) {
518          Dmsg1(100, "Try res=%s\n", rctx.device->hdr.name);
519          /* Find resource, and make sure we were able to open it */
520          if (fnmatch(rctx.device_name, rctx.device->hdr.name, 0) == 0) {
521             stat = reserve_device(rctx);
522             if (stat != 1) {
523                return stat;
524             }
525             Dmsg1(220, "Got: %s", dir->msg);
526             bash_spaces(rctx.device_name);
527             ok = bnet_fsend(dir, OK_device, rctx.device_name);
528             Dmsg1(100, ">dird dev: %s", dir->msg);
529             return ok ? 1 : -1;
530          }
531       }
532    }
533    foreach_res(changer, R_AUTOCHANGER) {
534       Dmsg1(100, "Try changer res=%s\n", changer->hdr.name);
535       /* Find resource, and make sure we were able to open it */
536       if (fnmatch(rctx.device_name, changer->hdr.name, 0) == 0) {
537          /* Try each device in this AutoChanger */
538          foreach_alist(rctx.device, changer->device) {
539             Dmsg1(100, "Try changer device %s\n", rctx.device->hdr.name);
540             stat = reserve_device(rctx);
541             if (stat == -1) {            /* hard error */
542                return -1;
543             }
544             if (stat == 0) {             /* must wait, try next one */
545                continue;
546             }
547             POOL_MEM dev_name;
548             Dmsg1(100, "Device %s opened.\n", rctx.device_name);
549             pm_strcpy(dev_name, rctx.device->hdr.name);
550             bash_spaces(dev_name);
551             ok = bnet_fsend(dir, OK_device, dev_name.c_str());  /* Return real device name */
552             Dmsg1(100, ">dird changer: %s", dir->msg);
553             return ok ? 1 : -1;
554          }
555       }
556    }
557    return 0;                    /* nothing found */
558 }
559
560 /*
561  *  Try to reserve a specific device.
562  *
563  *  Returns: 1 -- OK, have DCR
564  *           0 -- must wait
565  *          -1 -- fatal error
566  */
567 static int reserve_device(RCTX &rctx)
568 {
569    bool ok;
570    DCR *dcr;
571    const int name_len = MAX_NAME_LENGTH;
572
573    /* Make sure MediaType is OK */
574    if (strcmp(rctx.device->media_type, rctx.store->media_type) != 0) {
575       return -1;
576    }
577
578    if (!rctx.device->dev) {
579       rctx.device->dev = init_dev(rctx.jcr, rctx.device);
580    }
581    if (!rctx.device->dev) {
582       if (rctx.device->changer_res) {
583         Jmsg(rctx.jcr, M_WARNING, 0, _("\n"
584            "     Device \"%s\" in changer \"%s\" requested by DIR could not be opened or does not exist.\n"),
585              rctx.device->hdr.name, rctx.device_name);
586       } else {
587          Jmsg(rctx.jcr, M_WARNING, 0, _("\n"
588             "     Device \"%s\" requested by DIR could not be opened or does not exist.\n"),
589               rctx.device_name);
590       }
591       return -1;  /* no use waiting */
592    }  
593    Dmsg1(100, "Found device %s\n", rctx.device->hdr.name);
594    dcr = new_dcr(rctx.jcr, rctx.device->dev);
595    if (!dcr) {
596       BSOCK *dir = rctx.jcr->dir_bsock;
597       bnet_fsend(dir, _("3926 Could not get dcr for device: %s\n"), rctx.device_name);
598       Dmsg1(100, ">dird: %s", dir->msg);
599       return -1;
600    }
601    rctx.jcr->dcr = dcr;
602    bstrncpy(dcr->pool_name, rctx.store->pool_name, name_len);
603    bstrncpy(dcr->pool_type, rctx.store->pool_type, name_len);
604    bstrncpy(dcr->media_type, rctx.store->media_type, name_len);
605    bstrncpy(dcr->dev_name, rctx.device_name, name_len);
606    if (rctx.store->append == SD_APPEND) {
607       if (rctx.exact_match && !rctx.have_volume) {
608          dcr->any_volume = true;
609          if (dir_find_next_appendable_volume(dcr)) {
610             Dmsg1(200, "Looking for Volume=%s\n", dcr->VolumeName);
611             bstrncpy(rctx.VolumeName, dcr->VolumeName, sizeof(rctx.VolumeName));
612             rctx.have_volume = true;
613          } else {
614             Dmsg0(200, "No next volume found\n");
615             rctx.VolumeName[0] = 0;
616         }
617       }
618       ok = reserve_device_for_append(dcr, rctx);
619       Dmsg3(200, "dev_name=%s mediatype=%s ok=%d\n", dcr->dev_name, dcr->media_type, ok);
620    } else {
621       ok = reserve_device_for_read(dcr);
622    }
623    if (!ok) {
624       free_dcr(rctx.jcr->dcr);
625       return 0;
626    }
627    return 1;
628 }
629
630 /*
631  * We "reserve" the drive by setting the ST_READ bit. No one else
632  *  should touch the drive until that is cleared.
633  *  This allows the DIR to "reserve" the device before actually
634  *  starting the job. 
635  */
636 static bool reserve_device_for_read(DCR *dcr)
637 {
638    DEVICE *dev = dcr->dev;
639    JCR *jcr = dcr->jcr;
640    bool ok = false;
641
642    ASSERT(dcr);
643
644    dev->block(BST_DOING_ACQUIRE);
645
646    if (is_device_unmounted(dev)) {             
647       Dmsg1(200, "Device %s is BLOCKED due to user unmount.\n", dev->print_name());
648       Mmsg(jcr->errmsg, _("Device %s is BLOCKED due to user unmount.\n"),
649            dev->print_name());
650       goto bail_out;
651    }
652
653    if (dev->is_busy()) {
654       Dmsg4(200, "Device %s is busy ST_READ=%d num_writers=%d reserved=%d.\n", dev->print_name(),
655          dev->state & ST_READ?1:0, dev->num_writers, dev->reserved_device);
656       Mmsg1(jcr->errmsg, _("Device %s is busy.\n"),
657             dev->print_name());
658       goto bail_out;
659    }
660
661    dev->clear_append();
662    dev->set_read();
663    ok = true;
664
665 bail_out:
666    dev->unblock();
667    return ok;
668 }
669
670
671 /*
672  * We reserve the device for appending by incrementing the 
673  *  reserved_device. We do virtually all the same work that
674  *  is done in acquire_device_for_append(), but we do
675  *  not attempt to mount the device. This routine allows
676  *  the DIR to reserve multiple devices before *really* 
677  *  starting the job. It also permits the SD to refuse 
678  *  certain devices (not up, ...).
679  *
680  * Note, in reserving a device, if the device is for the
681  *  same pool and the same pool type, then it is acceptable.
682  *  The Media Type has already been checked. If we are
683  *  the first tor reserve the device, we put the pool
684  *  name and pool type in the device record.
685  */
686 static bool reserve_device_for_append(DCR *dcr, RCTX &rctx)
687 {
688    JCR *jcr = dcr->jcr;
689    DEVICE *dev = dcr->dev;
690    bool ok = false;
691
692    ASSERT(dcr);
693
694    dev->block(BST_DOING_ACQUIRE);
695
696    if (dev->can_read()) {
697       Mmsg1(jcr->errmsg, _("Device %s is busy reading.\n"), dev->print_name());
698       Dmsg1(100, "%s", jcr->errmsg);
699       goto bail_out;
700    }
701
702    if (is_device_unmounted(dev)) {
703       Mmsg(jcr->errmsg, _("Device %s is BLOCKED due to user unmount.\n"), dev->print_name());
704       Dmsg1(100, "%s", jcr->errmsg);
705       goto bail_out;
706    }
707
708    Dmsg1(190, "reserve_append device is %s\n", dev->is_tape()?"tape":"disk");
709
710    if (can_reserve_drive(dcr, rctx) != 1) {
711       Dmsg1(100, "%s", jcr->errmsg);
712       goto bail_out;
713    }
714
715    dev->reserved_device++;
716    Dmsg1(200, "Inc reserve=%d\n", dev->reserved_device);
717    dcr->reserved_device = true;
718    ok = true;
719
720 bail_out:
721    dev->unblock();
722    return ok;
723 }
724
725 /*
726  * Returns: 1 if drive can be reserved
727  *          0 if we should wait
728  *         -1 on error
729  */
730 static int can_reserve_drive(DCR *dcr, RCTX &rctx) 
731 {
732    DEVICE *dev = dcr->dev;
733    JCR *jcr = dcr->jcr;
734
735    /* Check for prefer mounted volumes */
736    if (rctx.PreferMountedVols && !dev->VolHdr.VolumeName[0] && dev->is_tape()) {
737       Mmsg0(jcr->errmsg, _("Want mounted Volume, drive is empty\n"));
738       Dmsg0(200, "want mounted -- no vol\n");
739       return 0;                 /* No volume mounted */
740    }
741
742    /* Check for exact Volume name match */
743    if (rctx.exact_match && rctx.have_volume &&
744        strcmp(dev->VolHdr.VolumeName, rctx.VolumeName) != 0) {
745       Mmsg2(jcr->errmsg, _("Not exact match have=%s want=%s\n"),
746             dev->VolHdr.VolumeName, rctx.VolumeName);
747       Dmsg2(200, "Not exact match have=%s want=%s\n",
748             dev->VolHdr.VolumeName, rctx.VolumeName);
749       return 0;
750    }
751
752    /* Check for unused autochanger drive */
753    if (rctx.available_autochanger && dev->num_writers == 0 &&
754        dev->VolHdr.VolumeName[0] == 0) {
755       /* Device is available but not yet reserved, reserve it for us */
756       bstrncpy(dev->pool_name, dcr->pool_name, sizeof(dev->pool_name));
757       bstrncpy(dev->pool_type, dcr->pool_type, sizeof(dev->pool_type));
758       return 1;                       /* reserve drive */
759    }
760
761    /*
762     * Handle the case that there are no writers
763     */
764    if (dev->num_writers == 0) {
765       /* Now check if there are any reservations on the drive */
766       if (dev->reserved_device) {           
767          /* Now check if we want the same Pool and pool type */
768          if (strcmp(dev->pool_name, dcr->pool_name) == 0 &&
769              strcmp(dev->pool_type, dcr->pool_type) == 0) {
770             /* OK, compatible device */
771             Dmsg0(200, "got dev: num_writers=0, reserved, pool matches\n");
772             return 1;
773          } else {
774             /* Drive not suitable for us */
775             Mmsg2(jcr->errmsg, _("Drive busy wrong pool: num_writers=0, reserved, pool=%s wanted=%s\n"),
776                dev->pool_name, dcr->pool_name);
777             Dmsg2(200, "busy: num_writers=0, reserved, pool=%s wanted=%s\n",
778                dev->pool_name, dcr->pool_name);
779             return 0;                 /* wait */
780          }
781       } else if (dev->can_append()) {
782          /* Device in append mode, check if changing pool */
783          if (strcmp(dev->pool_name, dcr->pool_name) == 0 &&
784              strcmp(dev->pool_type, dcr->pool_type) == 0) {
785             Dmsg0(200, "got dev: num_writers=0, can_append, pool matches\n");
786             /* OK, compatible device */
787             return 1;
788          } else {
789             /* Changing pool, unload old tape if any in drive */
790             Dmsg0(200, "got dev: num_writers=0, reserved, pool change\n");
791             unload_autochanger(dcr, 0);
792          }
793       }
794       /* Device is available but not yet reserved, reserve it for us */
795       bstrncpy(dev->pool_name, dcr->pool_name, sizeof(dev->pool_name));
796       bstrncpy(dev->pool_type, dcr->pool_type, sizeof(dev->pool_type));
797       return 1;                       /* reserve drive */
798    }
799
800    /*
801     * Check if the device is in append mode with writers (i.e.
802     *  available if pool is the same).
803     */
804    if (dev->can_append() || dev->num_writers > 0) {
805       Dmsg0(190, "device already in append.\n");
806       /* Yes, now check if we want the same Pool and pool type */
807       if (strcmp(dev->pool_name, dcr->pool_name) == 0 &&
808           strcmp(dev->pool_type, dcr->pool_type) == 0) {
809          Dmsg0(200, "got dev: num_writers>=0, can_append, pool matches\n");
810          /* OK, compatible device */
811          return 1;
812       } else {
813          /* Drive not suitable for us */
814          Mmsg(jcr->errmsg, _("Wanted Pool \"%s\", but device %s is using Pool \"%s\" .\n"), 
815                  dcr->pool_name, dev->print_name(), dev->pool_name);
816          Dmsg2(200, "busy: num_writers>0, can_append, pool=%s wanted=%s\n",
817             dev->pool_name, dcr->pool_name);
818          return 0;                    /* wait */
819       }
820    } else {
821       Pmsg0(000, _("Logic error!!!! Should not get here.\n"));
822       Jmsg0(jcr, M_FATAL, 0, _("Logic error!!!! Should not get here.\n"));
823       return -1;                      /* error, should not get here */
824    }
825
826    return 0;
827 }