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