]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/stored/reserve.c
bea00ddda18e6b5d021b205c93bbd43afd14b7be
[bacula/bacula] / bacula / src / stored / reserve.c
1 /*
2    Bacula® - The Network Backup Solution
3
4    Copyright (C) 2000-2007 Free Software Foundation Europe e.V.
5
6    The main author of Bacula is Kern Sibbald, with contributions from
7    many others, a complete list can be found in the file AUTHORS.
8    This program is Free Software; you can redistribute it and/or
9    modify it under the terms of version two of the GNU General Public
10    License as published by the Free Software Foundation plus additions
11    that are listed in the file LICENSE.
12
13    This program is distributed in the hope that it will be useful, but
14    WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16    General Public License for more details.
17
18    You should have received a copy of the GNU General Public License
19    along with this program; if not, write to the Free Software
20    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
21    02110-1301, USA.
22
23    Bacula® is a registered trademark of John Walker.
24    The licensor of Bacula is the Free Software Foundation Europe
25    (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich,
26    Switzerland, email:ftf@fsfeurope.org.
27 */
28 /*
29  *   Drive reservation functions for Storage Daemon
30  *
31  *   Kern Sibbald, MM
32  *
33  *   Split from job.c and acquire.c June 2005
34  *
35  *   Version $Id$
36  *
37  */
38
39 #include "bacula.h"
40 #include "stored.h"
41
42 static dlist *vol_list = NULL;
43 static pthread_mutex_t vol_list_lock = PTHREAD_MUTEX_INITIALIZER;
44
45 /* Forward referenced functions */
46 static int can_reserve_drive(DCR *dcr, RCTX &rctx);
47 static int reserve_device(RCTX &rctx);
48 static bool reserve_device_for_read(DCR *dcr);
49 static bool reserve_device_for_append(DCR *dcr, RCTX &rctx);
50 static bool use_storage_cmd(JCR *jcr);
51 static void queue_reserve_message(JCR *jcr);
52
53 /* Requests from the Director daemon */
54 static char use_storage[]  = "use storage=%127s media_type=%127s "
55    "pool_name=%127s pool_type=%127s append=%d copy=%d stripe=%d\n";
56 static char use_device[]  = "use device=%127s\n";
57
58 /* Responses sent to Director daemon */
59 static char OK_device[] = "3000 OK use device device=%s\n";
60 static char NO_device[] = "3924 Device \"%s\" not in SD Device resources.\n";
61 static char BAD_use[]   = "3913 Bad use command: %s\n";
62
63 bool use_cmd(JCR *jcr) 
64 {
65    /*
66     * Get the device, media, and pool information
67     */
68    if (!use_storage_cmd(jcr)) {
69       set_jcr_job_status(jcr, JS_ErrorTerminated);
70       memset(jcr->sd_auth_key, 0, strlen(jcr->sd_auth_key));
71       return false;
72    }
73    return true;
74 }
75
76 static int my_compare(void *item1, void *item2)
77 {
78    return strcmp(((VOLRES *)item1)->vol_name, ((VOLRES *)item2)->vol_name);
79 }
80
81 static brwlock_t reservation_lock;
82
83 void init_reservations_lock()
84 {
85    int errstat;
86    if ((errstat=rwl_init(&reservation_lock)) != 0) {
87       berrno be;
88       Emsg1(M_ABORT, 0, _("Unable to initialize reservation lock. ERR=%s\n"),
89             be.strerror(errstat));
90    }
91
92 }
93
94 void term_reservations_lock()
95 {
96    rwl_destroy(&reservation_lock);
97 }
98
99 int reservations_lock_count = 0;
100
101 /* This applies to a drive and to Volumes */
102 void _lock_reservations()
103 {
104    int errstat;
105    reservations_lock_count++;
106    if ((errstat=rwl_writelock(&reservation_lock)) != 0) {
107       berrno be;
108       Emsg2(M_ABORT, 0, "rwl_writelock failure. stat=%d: ERR=%s\n",
109            errstat, be.strerror(errstat));
110    }
111 }
112
113 void _unlock_reservations()
114 {
115    int errstat;
116    reservations_lock_count--;
117    if ((errstat=rwl_writeunlock(&reservation_lock)) != 0) {
118       berrno be;
119       Emsg2(M_ABORT, 0, "rwl_writeunlock failure. stat=%d: ERR=%s\n",
120            errstat, be.strerror(errstat));
121    }
122 }
123
124 /*
125  * List Volumes -- this should be moved to status.c
126  */
127 enum {
128    debug_lock = true,
129    debug_nolock = false
130 };
131
132 static void debug_list_volumes(const char *imsg, bool do_lock)
133 {
134    VOLRES *vol;
135    POOL_MEM msg(PM_MESSAGE);
136    int count = 0;
137    DEVICE *dev = NULL;
138
139    if (do_lock) P(vol_list_lock);
140    for (vol=(VOLRES *)vol_list->first(); vol; vol=(VOLRES *)vol_list->next(vol)) {
141       if (vol->dev) {
142          Mmsg(msg, "List from %s: %s at %p on device %s\n", imsg, 
143               vol->vol_name, vol->vol_name, vol->dev->print_name());
144       } else {
145          Mmsg(msg, "List from %s: %s at %p no dev\n", imsg, vol->vol_name, vol->vol_name);
146       }
147       Dmsg1(100, "%s", msg.c_str());
148       count++;
149    }
150
151    for (vol=(VOLRES *)vol_list->first(); vol; vol=(VOLRES *)vol_list->next(vol)) {
152       if (vol->dev == dev) {
153          Dmsg0(000, "Two Volumes on same device.\n");
154          ASSERT(0);
155          dev = vol->dev;
156       }
157    }
158
159    Dmsg2(100, "List from %s: %d volumes\n", imsg, count);
160    if (do_lock) V(vol_list_lock);
161 }
162
163
164 /*
165  * List Volumes -- this should be moved to status.c
166  */
167 void list_volumes(void sendit(const char *msg, int len, void *sarg), void *arg)
168 {
169    VOLRES *vol;
170    POOL_MEM msg(PM_MESSAGE);
171    int len;
172
173    P(vol_list_lock);
174    for (vol=(VOLRES *)vol_list->first(); vol; vol=(VOLRES *)vol_list->next(vol)) {
175       if (vol->dev) {
176          len = Mmsg(msg, "%s on device %s\n", vol->vol_name, vol->dev->print_name());
177          sendit(msg.c_str(), len, arg);
178       } else {
179          len = Mmsg(msg, "%s no dev\n", vol->vol_name);
180          sendit(msg.c_str(), len, arg);
181       }
182    }
183    V(vol_list_lock);
184 }
185
186 /*
187  * Create a Volume item to put in the Volume list
188  *   Ensure that the device points to it.
189  */
190 static VOLRES *new_vol_item(DCR *dcr, const char *VolumeName)
191 {
192    VOLRES *vol;
193    vol = (VOLRES *)malloc(sizeof(VOLRES));
194    memset(vol, 0, sizeof(VOLRES));
195    vol->vol_name = bstrdup(VolumeName);
196    vol->dev = dcr->dev;
197    Dmsg4(100, "New Vol=%s at %p dev=%s JobId=%u\n", VolumeName, vol->vol_name,
198          vol->dev->print_name(), (int)dcr->jcr->JobId);
199    return vol;
200 }
201
202 static void free_vol_item(VOLRES *vol)
203 {
204    free(vol->vol_name);
205    if (vol->dev) {
206       vol->dev->vol = NULL;
207    }
208    free(vol);
209 }
210
211
212 /*
213  * Put a new Volume entry in the Volume list. This
214  *  effectively reserves the volume so that it will
215  *  not be mounted again.
216  *
217  * If the device has any current volume associated with it,
218  *  and it is a different Volume, and the device is not busy,
219  *  we release the old Volume item and insert the new one.
220  * 
221  * It is assumed that the device is free and locked so that
222  *  we can change the device structure.
223  *
224  * Some details of the Volume list handling:
225  *
226  *  1. The Volume list entry must be attached to the drive (rather than 
227  *       attached to a job as it currently is. I.e. the drive that "owns" 
228  *       the volume (reserved, in use, mounted)
229  *       must point to the volume (still to be maintained in a list).
230  *
231  *  2. The Volume is entered in the list when a drive is reserved.  
232  *
233  *  3. When a drive is in use, the device code must appropriately update the
234  *      volume name as it changes (currently the list is static -- an entry is
235  *      removed when the Volume is no longer reserved, in use or mounted).  
236  *      The new code must keep the same list entry as long as the drive
237  *       has any volume associated with it but the volume name in the list
238  *       must be updated when the drive has a different volume mounted.
239  *
240  *  4. A job that has reserved a volume, can un-reserve the volume, and if the 
241  *      volume is not mounted, and not reserved, and not in use, it will be
242  *      removed from the list.
243  *
244  *  5. If a job wants to reserve a drive with a different Volume from the one on
245  *      the drive, it can re-use the drive for the new Volume.
246  *
247  *  6. If a job wants a Volume that is in a different drive, it can either use the
248  *      other drive or take the volume, only if the other drive is not in use or
249  *      not reserved.
250  *
251  *  One nice aspect of this is that the reserve use count and the writer use count 
252  *  already exist and are correctly programmed and will need no changes -- use 
253  *  counts are always very tricky.
254  *
255  *  The old code had a concept of "reserving" a Volume, but it needs to be changed 
256  *  to reserving and using a drive.  A volume is must be attached to (owned by) a 
257  *  drive and can move from drive to drive or be unused given certain specific 
258  *  conditions of the drive.  The key is that the drive must "own" the Volume.  
259  *  The old code has the job (dcr) owning the volume (more or less).  The job is 
260  *  to change the insertion and removal of the volumes from the list to be based 
261  *  on the drive rather than the job.  The new logic described above needs to be 
262  *  reviewed a couple more times for completeness and correctness.  Then I can 
263  *  program it.
264
265  *
266  *  Return: VOLRES entry on success
267  *          NULL volume busy on another drive
268  */
269 VOLRES *reserve_volume(DCR *dcr, const char *VolumeName)
270 {
271    VOLRES *vol, *nvol;
272    DEVICE *dev = dcr->dev;
273
274    ASSERT(dev != NULL);
275
276    Dmsg1(100, "reserve_volume %s\n", VolumeName);
277    /* 
278     * We lock the reservations system here to ensure
279     *  when adding a new volume that no newly scheduled
280     *  job can reserve it.
281     */
282    P(vol_list_lock);
283    debug_list_volumes("begin reserve_volume", debug_nolock);
284    /* 
285     * First, remove any old volume attached to this device as it
286     *  is no longer used.
287     */
288    if (dev->vol) {
289       vol = dev->vol;
290       /*
291        * Make sure we don't remove the current volume we are inserting
292        *  because it was probably inserted by another job.
293        */
294       if (strcmp(vol->vol_name, VolumeName) == 0) {
295          goto get_out;                  /* Volume already on this device */
296       } else {
297          Dmsg3(100, "reserve_vol free vol=%s at %p JobId=%u\n", vol->vol_name,
298                vol->vol_name, (int)dcr->jcr->JobId);
299          debug_list_volumes("reserve_vol free", debug_nolock);
300          vol_list->remove(vol);
301          free_vol_item(vol);
302       }
303    }
304
305    /* Create a new Volume entry */
306    nvol = new_vol_item(dcr, VolumeName);
307
308    /*
309     * Now try to insert the new Volume
310     */
311    vol = (VOLRES *)vol_list->binary_insert(nvol, my_compare);
312    if (vol != nvol) {
313       Dmsg2(100, "Found vol=%s dev-same=%d\n", vol->vol_name, dev==vol->dev);
314       /*
315        * At this point, a Volume with this name already is in the list,
316        *   so we simply release our new Volume entry. Note, this should
317        *   only happen if we are moving the volume from one drive to another.
318        */
319       Dmsg3(100, "reserve_vol free-tmp vol=%s at %p JobId=%u\n", vol->vol_name,
320             vol->vol_name, (int)dcr->jcr->JobId);
321       /*
322        * Clear dev pointer so that free_vol_item() doesn't 
323        *  take away our volume. 
324        */
325       nvol->dev = NULL;                   /* don't zap dev entry */
326       free_vol_item(nvol);
327
328       /* Check if we are trying to use the Volume on a different drive */
329       if (dev != vol->dev) {
330          /* Caller wants to switch Volume to another device */
331          if (!vol->dev->is_busy()) {
332             /* OK to move it -- I'm not sure this will work */
333             Dmsg3(100, "==== Swap vol=%s from dev=%s to %s\n", VolumeName,
334                vol->dev->print_name(), dev->print_name());
335             vol->dev->vol = NULL;         /* take vol from old drive */
336             vol->dev->VolHdr.VolumeName[0] = 0;
337             vol->dev = dev;               /* point vol at new drive */
338             dev->vol = vol;               /* point dev at vol */
339             dev->VolHdr.VolumeName[0] = 0;
340          } else {
341             Dmsg3(100, "Volume busy could not swap vol=%s from dev=%s to %s\n", VolumeName,
342                vol->dev->print_name(), dev->print_name());
343             vol = NULL;                /* device busy */
344          }
345       }
346    }
347    dev->vol = vol;
348
349 get_out:
350    debug_list_volumes("end new volume", debug_nolock);
351    V(vol_list_lock);
352    return vol;
353 }
354
355 /*
356  * Search for a Volume name in the Volume list.
357  *
358  *  Returns: VOLRES entry on success
359  *           NULL if the Volume is not in the list
360  */
361 VOLRES *find_volume(const char *VolumeName)
362 {
363    VOLRES vol, *fvol;
364    /* Do not lock reservations here */
365    P(vol_list_lock);
366    vol.vol_name = bstrdup(VolumeName);
367    fvol = (VOLRES *)vol_list->binary_search(&vol, my_compare);
368    free(vol.vol_name);
369    Dmsg2(100, "find_vol=%s found=%d\n", VolumeName, fvol!=NULL);
370    debug_list_volumes("find_volume", debug_nolock);
371    V(vol_list_lock);
372    return fvol;
373 }
374
375 /* 
376  * Remove any reservation from a drive and tell the system
377  *  that the volume is unused at least by us.
378  */
379 void unreserve_device(DCR *dcr)
380 {
381    DEVICE *dev = dcr->dev;
382    dev->dlock();
383    if (dcr->reserved_device) {
384       dcr->reserved_device = false;
385       dev->reserved_device--;
386       Dmsg2(100, "Dec reserve=%d dev=%s\n", dev->reserved_device, dev->print_name());
387       dcr->reserved_device = false;
388       /* If we set read mode in reserving, remove it */
389       if (dev->can_read()) {
390          dev->clear_read();
391       }
392       if (dev->num_writers < 0) {
393          Jmsg1(dcr->jcr, M_ERROR, 0, _("Hey! num_writers=%d!!!!\n"), dev->num_writers);
394          dev->num_writers = 0;
395       }
396    }
397
398    volume_unused(dcr);
399    dev->dunlock();
400 }
401
402 /*  
403  * Free a Volume from the Volume list if it is no longer used
404  *
405  *  Returns: true if the Volume found and removed from the list
406  *           false if the Volume is not in the list or is in use
407  */
408 bool volume_unused(DCR *dcr)
409 {
410    DEVICE *dev = dcr->dev;
411
412    if (dev->vol == NULL) {
413       Dmsg1(100, " unreserve_volume: no vol on %s\n", dev->print_name());
414       debug_list_volumes("null return unreserve_volume", debug_lock);
415       return false;
416    }
417
418    if (dev->is_busy()) {
419       Dmsg1(100, "unreserve_volume: dev is busy %s\n", dev->print_name());
420       debug_list_volumes("dev busy return unreserve_volume", debug_lock);
421       return false;
422    }
423
424    return free_volume(dev);
425 }
426
427 /*
428  * Unconditionally release the volume
429  */
430 bool free_volume(DEVICE *dev)
431 {
432    VOLRES *vol;
433
434    if (dev->vol == NULL) {
435       Dmsg1(100, "No vol on dev %s\n", dev->print_name());
436       return false;
437    }
438    P(vol_list_lock);
439    vol = dev->vol;
440    dev->vol = NULL;
441    Dmsg1(100, "free_volume %s\n", vol->vol_name);
442    vol_list->remove(vol);
443    Dmsg3(100, "free_volume %s at %p dev=%s\n", vol->vol_name, vol->vol_name,
444          dev->print_name());
445    free_vol_item(vol);
446    debug_list_volumes("free_volume", debug_nolock);
447    V(vol_list_lock);
448    return vol != NULL;
449 }
450
451       
452 /* Create the Volume list */
453 void create_volume_list()
454 {
455    VOLRES *dummy = NULL;
456    if (vol_list == NULL) {
457       vol_list = New(dlist(dummy, &dummy->link));
458    }
459 }
460
461 /* Release all Volumes from the list */
462 void free_volume_list()
463 {
464    VOLRES *vol;
465    if (!vol_list) {
466       return;
467    }
468    P(vol_list_lock);
469    for (vol=(VOLRES *)vol_list->first(); vol; vol=(VOLRES *)vol_list->next(vol)) {
470       Dmsg2(100, "Unreleased Volume=%s dev=%p\n", vol->vol_name, vol->dev);
471       free(vol->vol_name);
472       vol->vol_name = NULL;
473    }
474    delete vol_list;
475    vol_list = NULL;
476    V(vol_list_lock);
477 }
478
479 bool is_volume_in_use(DCR *dcr)
480 {
481    VOLRES *vol = find_volume(dcr->VolumeName);
482    if (!vol) {
483       Dmsg1(100, "Vol=%s not in use.\n", dcr->VolumeName);
484       return false;                   /* vol not in list */
485    }
486    ASSERT(vol->dev != NULL);
487
488    if (dcr->dev == vol->dev) {        /* same device OK */
489       Dmsg1(100, "Vol=%s on same dev.\n", dcr->VolumeName);
490       return false;
491    }
492    if (!vol->dev->is_busy()) {
493       Dmsg2(100, "Vol=%s dev=%s not busy.\n", dcr->VolumeName, vol->dev->print_name());
494       return false;
495    }
496    Dmsg2(100, "Vol=%s used by %s.\n", dcr->VolumeName, vol->dev->print_name());
497    return true;
498 }
499
500
501 /*
502  * We get the following type of information:
503  *
504  * use storage=xxx media_type=yyy pool_name=xxx pool_type=yyy append=1 copy=0 strip=0
505  *  use device=zzz
506  *  use device=aaa
507  *  use device=bbb
508  * use storage=xxx media_type=yyy pool_name=xxx pool_type=yyy append=0 copy=0 strip=0
509  *  use device=bbb
510  *
511  */
512 static bool use_storage_cmd(JCR *jcr)
513 {
514    POOL_MEM store_name, dev_name, media_type, pool_name, pool_type;
515    BSOCK *dir = jcr->dir_bsock;
516    int append;
517    bool ok;       
518    int Copy, Stripe;
519    DIRSTORE *store;
520    RCTX rctx;
521    char *msg;
522    alist *msgs;
523    alist *dirstore;
524
525    memset(&rctx, 0, sizeof(RCTX));
526    rctx.jcr = jcr;
527    /*
528     * If there are multiple devices, the director sends us
529     *   use_device for each device that it wants to use.
530     */
531    dirstore = New(alist(10, not_owned_by_alist));
532 // Dmsg2(000, "dirstore=%p JobId=%u\n", dirstore, jcr->JobId);
533    msgs = jcr->reserve_msgs = New(alist(10, not_owned_by_alist));  
534    do {
535       Dmsg1(100, "<dird: %s", dir->msg);
536       ok = sscanf(dir->msg, use_storage, store_name.c_str(), 
537                   media_type.c_str(), pool_name.c_str(), 
538                   pool_type.c_str(), &append, &Copy, &Stripe) == 7;
539       if (!ok) {
540          break;
541       }
542       if (append) {
543          jcr->write_store = dirstore;
544       } else {
545          jcr->read_store = dirstore;
546       }
547       rctx.append = append;
548       unbash_spaces(store_name);
549       unbash_spaces(media_type);
550       unbash_spaces(pool_name);
551       unbash_spaces(pool_type);
552       store = new DIRSTORE;
553       dirstore->append(store);
554       memset(store, 0, sizeof(DIRSTORE));
555       store->device = New(alist(10));
556       bstrncpy(store->name, store_name, sizeof(store->name));
557       bstrncpy(store->media_type, media_type, sizeof(store->media_type));
558       bstrncpy(store->pool_name, pool_name, sizeof(store->pool_name));
559       bstrncpy(store->pool_type, pool_type, sizeof(store->pool_type));
560       store->append = append;
561
562       /* Now get all devices */
563       while (dir->recv() >= 0) {
564          Dmsg1(100, "<dird device: %s", dir->msg);
565          ok = sscanf(dir->msg, use_device, dev_name.c_str()) == 1;
566          if (!ok) {
567             break;
568          }
569          unbash_spaces(dev_name);
570          store->device->append(bstrdup(dev_name.c_str()));
571       }
572    }  while (ok && dir->recv() >= 0);
573
574 #ifdef DEVELOPER
575    /* This loop is debug code and can be removed */
576    /* ***FIXME**** remove after 1.38 release */
577    char *device_name;
578    foreach_alist(store, dirstore) {
579       Dmsg5(110, "Storage=%s media_type=%s pool=%s pool_type=%s append=%d\n", 
580          store->name, store->media_type, store->pool_name, 
581          store->pool_type, store->append);
582       foreach_alist(device_name, store->device) {
583          Dmsg1(110, "   Device=%s\n", device_name);
584       }
585    }
586 #endif
587
588    init_jcr_device_wait_timers(jcr);
589    /*                    
590     * At this point, we have a list of all the Director's Storage
591     *  resources indicated for this Job, which include Pool, PoolType,
592     *  storage name, and Media type.     
593     * Then for each of the Storage resources, we have a list of
594     *  device names that were given.
595     *
596     * Wiffle through them and find one that can do the backup.
597     */
598    if (ok) {
599       bool first = true;           /* print wait message once */
600       bool fail = false;
601       rctx.notify_dir = true;
602       lock_reservations();
603       for ( ; !fail && !job_canceled(jcr); ) {
604          while ((msg = (char *)msgs->pop())) {
605             free(msg);
606          }
607          rctx.suitable_device = false;
608          rctx.have_volume = false;
609          rctx.VolumeName[0] = 0;
610          rctx.any_drive = false;
611          if (!jcr->PreferMountedVols) {
612             /* Look for unused drives in autochangers */
613             rctx.num_writers = 20000000;   /* start with impossible number */
614             rctx.low_use_drive = NULL;
615             rctx.PreferMountedVols = false;                
616             rctx.exact_match = false;
617             rctx.autochanger_only = true;
618             Dmsg5(110, "PrefMnt=%d exact=%d suitable=%d chgronly=%d any=%d\n",
619                rctx.PreferMountedVols, rctx.exact_match, rctx.suitable_device,
620                rctx.autochanger_only, rctx.any_drive);
621             if ((ok = find_suitable_device_for_job(jcr, rctx))) {
622                break;
623             }
624             /* Look through all drives possibly for low_use drive */
625             if (rctx.low_use_drive) {
626                rctx.try_low_use_drive = true;
627                if ((ok = find_suitable_device_for_job(jcr, rctx))) {
628                   break;
629                }
630                rctx.try_low_use_drive = false;
631             }
632             rctx.autochanger_only = false;
633             Dmsg5(110, "PrefMnt=%d exact=%d suitable=%d chgronly=%d any=%d\n",
634                rctx.PreferMountedVols, rctx.exact_match, rctx.suitable_device,
635                rctx.autochanger_only, rctx.any_drive);
636             if ((ok = find_suitable_device_for_job(jcr, rctx))) {
637                break;
638             }
639          }
640          /* Look for an exact match all drives */
641          rctx.PreferMountedVols = true;
642          rctx.exact_match = true;
643          rctx.autochanger_only = false;
644          Dmsg5(110, "PrefMnt=%d exact=%d suitable=%d chgronly=%d any=%d\n",
645             rctx.PreferMountedVols, rctx.exact_match, rctx.suitable_device,
646             rctx.autochanger_only, rctx.any_drive);
647          if ((ok = find_suitable_device_for_job(jcr, rctx))) {
648             break;
649          }
650          /* Look for any mounted drive */
651          rctx.exact_match = false;
652          Dmsg5(110, "PrefMnt=%d exact=%d suitable=%d chgronly=%d any=%d\n",
653             rctx.PreferMountedVols, rctx.exact_match, rctx.suitable_device,
654             rctx.autochanger_only, rctx.any_drive);
655          if ((ok = find_suitable_device_for_job(jcr, rctx))) {
656             break;
657          }
658          /* Try any drive */
659          rctx.any_drive = true;
660          Dmsg5(110, "PrefMnt=%d exact=%d suitable=%d chgronly=%d any=%d\n",
661             rctx.PreferMountedVols, rctx.exact_match, rctx.suitable_device,
662             rctx.autochanger_only, rctx.any_drive);
663          if ((ok = find_suitable_device_for_job(jcr, rctx))) {
664             break;
665          }
666          /* Keep reservations locked *except* during wait_for_device() */
667          unlock_reservations();
668          if (!rctx.suitable_device || !wait_for_device(jcr, first)) {
669             Dmsg0(100, "Fail. !suitable_device || !wait_for_device\n");
670             fail = true;
671          }   
672          lock_reservations();
673          first = false;
674          bnet_sig(dir, BNET_HEARTBEAT);  /* Inform Dir that we are alive */
675       }
676       unlock_reservations();
677       if (!ok) {
678          /*
679           * If we get here, there are no suitable devices available, which
680           *  means nothing configured.  If a device is suitable but busy
681           *  with another Volume, we will not come here.
682           */
683          unbash_spaces(dir->msg);
684          pm_strcpy(jcr->errmsg, dir->msg);
685          Jmsg(jcr, M_INFO, 0, _("Failed command: %s\n"), jcr->errmsg);
686          Jmsg(jcr, M_FATAL, 0, _("\n"
687             "     Device \"%s\" with MediaType \"%s\" requested by DIR not found in SD Device resources.\n"),
688               dev_name.c_str(), media_type.c_str());
689          bnet_fsend(dir, NO_device, dev_name.c_str());
690
691          Dmsg1(100, ">dird: %s", dir->msg);
692       }
693    } else {
694       unbash_spaces(dir->msg);
695       pm_strcpy(jcr->errmsg, dir->msg);
696       Jmsg(jcr, M_FATAL, 0, _("Failed command: %s\n"), jcr->errmsg);
697       bnet_fsend(dir, BAD_use, jcr->errmsg);
698       Dmsg1(100, ">dird: %s", dir->msg);
699    }
700
701    release_msgs(jcr);
702    return ok;
703 }
704
705 void release_msgs(JCR *jcr)
706 {
707    alist *msgs = jcr->reserve_msgs;
708    char *msg;
709
710    if (!msgs) {
711       return;
712    }
713    lock_reservations();
714    while ((msg = (char *)msgs->pop())) {
715       free(msg);
716    }
717    delete msgs;
718    jcr->reserve_msgs = NULL;
719    unlock_reservations();
720 }
721
722 /*
723  * Search for a device suitable for this job.
724  */
725 bool find_suitable_device_for_job(JCR *jcr, RCTX &rctx)
726 {
727    bool ok;
728    DIRSTORE *store;
729    char *device_name;
730    alist *dirstore;
731
732    if (rctx.append) {
733       dirstore = jcr->write_store;
734    } else {
735       dirstore = jcr->read_store;
736    }
737    /* 
738     * For each storage device that the user specified, we
739     *  search and see if there is a resource for that device.
740     */
741    Dmsg4(110, "PrefMnt=%d exact=%d suitable=%d chgronly=%d\n",
742       rctx.PreferMountedVols, rctx.exact_match, rctx.suitable_device,
743       rctx.autochanger_only);
744    ok = false;
745    foreach_alist(store, dirstore) {
746       rctx.store = store;
747       foreach_alist(device_name, store->device) {
748          int stat;
749          rctx.device_name = device_name;
750          stat = search_res_for_device(rctx); 
751          if (stat == 1) {             /* found available device */
752             Dmsg1(100, "Suitable device found=%s\n", device_name);
753             ok = true;
754             break;
755          } else if (stat == 0) {      /* device busy */
756             Dmsg1(110, "Suitable device=%s, busy: not use\n", device_name);
757          } else {
758             /* otherwise error */
759             Dmsg0(110, "No suitable device found.\n");
760          }
761       }
762       if (ok) {
763          break;
764       }
765    }
766    return ok;
767 }
768
769 /*
770  * Search for a particular storage device with particular storage
771  *  characteristics (MediaType).
772  */
773 int search_res_for_device(RCTX &rctx) 
774 {
775    AUTOCHANGER *changer;
776    BSOCK *dir = rctx.jcr->dir_bsock;
777    bool ok;
778    int stat;
779
780    Dmsg1(110, "Search res for %s\n", rctx.device_name);
781    /* Look through Autochangers first */
782    foreach_res(changer, R_AUTOCHANGER) {
783       Dmsg1(150, "Try match changer res=%s\n", changer->hdr.name);
784       /* Find resource, and make sure we were able to open it */
785       if (fnmatch(rctx.device_name, changer->hdr.name, 0) == 0) {
786          /* Try each device in this AutoChanger */
787          foreach_alist(rctx.device, changer->device) {
788             Dmsg1(110, "Try changer device %s\n", rctx.device->hdr.name);
789             stat = reserve_device(rctx);
790             if (stat != 1) {             /* try another device */
791                continue;
792             }
793             POOL_MEM dev_name;
794             if (rctx.store->append == SD_APPEND) {
795                Dmsg2(100, "Device %s reserved=%d for append.\n", rctx.device->hdr.name,
796                   rctx.jcr->dcr->dev->reserved_device);
797             } else {
798                Dmsg2(100, "Device %s reserved=%d for read.\n", rctx.device->hdr.name,
799                   rctx.jcr->read_dcr->dev->reserved_device);
800             }
801             if (rctx.notify_dir) {
802                pm_strcpy(dev_name, rctx.device->hdr.name);
803                bash_spaces(dev_name);
804                ok = bnet_fsend(dir, OK_device, dev_name.c_str());  /* Return real device name */
805                Dmsg1(100, ">dird changer: %s", dir->msg);
806             } else {
807                ok = true;
808             }
809             return ok ? 1 : -1;
810          }
811       }
812    }
813
814    /* Now if requested look through regular devices */
815    if (!rctx.autochanger_only) {
816       foreach_res(rctx.device, R_DEVICE) {
817          Dmsg1(150, "Try match res=%s\n", rctx.device->hdr.name);
818          /* Find resource, and make sure we were able to open it */
819          if (fnmatch(rctx.device_name, rctx.device->hdr.name, 0) == 0) {
820             stat = reserve_device(rctx);
821             if (stat != 1) {
822                return stat;
823             }
824             if (rctx.notify_dir) {
825                bash_spaces(rctx.device_name);
826                ok = bnet_fsend(dir, OK_device, rctx.device_name);
827                Dmsg1(100, ">dird dev: %s", dir->msg);
828             } else {
829                ok = true;
830             }
831             return ok ? 1 : -1;
832          }
833       }
834    }
835    return -1;                    /* nothing found */
836 }
837
838 /*
839  *  Try to reserve a specific device.
840  *
841  *  Returns: 1 -- OK, have DCR
842  *           0 -- must wait
843  *          -1 -- fatal error
844  */
845 static int reserve_device(RCTX &rctx)
846 {
847    bool ok;
848    DCR *dcr;
849    const int name_len = MAX_NAME_LENGTH;
850
851    /* Make sure MediaType is OK */
852    Dmsg2(110, "MediaType device=%s request=%s\n",
853          rctx.device->media_type, rctx.store->media_type);
854    if (strcmp(rctx.device->media_type, rctx.store->media_type) != 0) {
855       return -1;
856    }
857
858    /* Make sure device exists -- i.e. we can stat() it */
859    if (!rctx.device->dev) {
860       rctx.device->dev = init_dev(rctx.jcr, rctx.device);
861    }
862    if (!rctx.device->dev) {
863       if (rctx.device->changer_res) {
864         Jmsg(rctx.jcr, M_WARNING, 0, _("\n"
865            "     Device \"%s\" in changer \"%s\" requested by DIR could not be opened or does not exist.\n"),
866              rctx.device->hdr.name, rctx.device_name);
867       } else {
868          Jmsg(rctx.jcr, M_WARNING, 0, _("\n"
869             "     Device \"%s\" requested by DIR could not be opened or does not exist.\n"),
870               rctx.device_name);
871       }
872       return -1;  /* no use waiting */
873    }  
874
875    rctx.suitable_device = true;
876    Dmsg2(110, "Try reserve %s JobId=%u\n", rctx.device->hdr.name,
877          rctx.jcr->JobId);
878    dcr = new_dcr(rctx.jcr, rctx.device->dev);
879    if (!dcr) {
880       BSOCK *dir = rctx.jcr->dir_bsock;
881       bnet_fsend(dir, _("3926 Could not get dcr for device: %s\n"), rctx.device_name);
882       Dmsg1(100, ">dird: %s", dir->msg);
883       return -1;
884    }
885    bstrncpy(dcr->pool_name, rctx.store->pool_name, name_len);
886    bstrncpy(dcr->pool_type, rctx.store->pool_type, name_len);
887    bstrncpy(dcr->media_type, rctx.store->media_type, name_len);
888    bstrncpy(dcr->dev_name, rctx.device_name, name_len);
889    if (rctx.store->append == SD_APPEND) {
890       Dmsg2(100, "have_vol=%d vol=%s\n", rctx.have_volume, rctx.VolumeName);
891       if (!rctx.have_volume) {
892          dcr->any_volume = true;
893          if (dir_find_next_appendable_volume(dcr)) {
894             bstrncpy(rctx.VolumeName, dcr->VolumeName, sizeof(rctx.VolumeName));
895             Dmsg2(100, "JobId=%u looking for Volume=%s\n", (int)rctx.jcr->JobId, rctx.VolumeName);
896             rctx.have_volume = true;
897          } else {
898             Dmsg0(100, "No next volume found\n");
899             rctx.have_volume = false;
900             rctx.VolumeName[0] = 0;
901         }
902       }
903       ok = reserve_device_for_append(dcr, rctx);
904       if (ok) {
905          rctx.jcr->dcr = dcr;
906          Dmsg5(100, "Reserved=%d dev_name=%s mediatype=%s pool=%s ok=%d\n",
907                dcr->dev->reserved_device,
908                dcr->dev_name, dcr->media_type, dcr->pool_name, ok);
909       }
910    } else {
911       ok = reserve_device_for_read(dcr);
912       if (ok) {
913          rctx.jcr->read_dcr = dcr;
914          Dmsg5(100, "Read reserved=%d dev_name=%s mediatype=%s pool=%s ok=%d\n",
915                dcr->dev->reserved_device,
916                dcr->dev_name, dcr->media_type, dcr->pool_name, ok);
917       }
918    }
919    if (!ok) {
920       rctx.have_volume = false;
921       free_dcr(dcr);
922       Dmsg0(110, "Not OK.\n");
923       return 0;
924    }
925    return 1;
926 }
927
928 /*
929  * We "reserve" the drive by setting the ST_READ bit. No one else
930  *  should touch the drive until that is cleared.
931  *  This allows the DIR to "reserve" the device before actually
932  *  starting the job. 
933  */
934 static bool reserve_device_for_read(DCR *dcr)
935 {
936    DEVICE *dev = dcr->dev;
937    JCR *jcr = dcr->jcr;
938    bool ok = false;
939
940    ASSERT(dcr);
941
942    dev->dlock();  
943
944    if (is_device_unmounted(dev)) {             
945       Dmsg1(200, "Device %s is BLOCKED due to user unmount.\n", dev->print_name());
946       Mmsg(jcr->errmsg, _("3601 JobId=%u device %s is BLOCKED due to user unmount.\n"),
947            jcr->JobId, dev->print_name());
948       queue_reserve_message(jcr);
949       goto bail_out;
950    }
951
952    if (dev->is_busy()) {
953       Dmsg4(200, "Device %s is busy ST_READ=%d num_writers=%d reserved=%d.\n", dev->print_name(),
954          dev->state & ST_READ?1:0, dev->num_writers, dev->reserved_device);
955       Mmsg(jcr->errmsg, _("3602 JobId=%u device %s is busy (already reading/writing).\n"),
956             jcr->JobId, dev->print_name());
957       queue_reserve_message(jcr);
958       goto bail_out;
959    }
960
961    dev->clear_append();
962    dev->set_read();
963    ok = true;
964    dev->reserved_device++;
965    Dmsg3(100, "Inc reserve=%d dev=%s %p\n", dev->reserved_device, 
966       dev->print_name(), dev);
967    dcr->reserved_device = true;
968
969 bail_out:
970    dev->dunlock();
971    return ok;
972 }
973
974
975 /*
976  * We reserve the device for appending by incrementing the 
977  *  reserved_device. We do virtually all the same work that
978  *  is done in acquire_device_for_append(), but we do
979  *  not attempt to mount the device. This routine allows
980  *  the DIR to reserve multiple devices before *really* 
981  *  starting the job. It also permits the SD to refuse 
982  *  certain devices (not up, ...).
983  *
984  * Note, in reserving a device, if the device is for the
985  *  same pool and the same pool type, then it is acceptable.
986  *  The Media Type has already been checked. If we are
987  *  the first tor reserve the device, we put the pool
988  *  name and pool type in the device record.
989  */
990 static bool reserve_device_for_append(DCR *dcr, RCTX &rctx)
991 {
992    JCR *jcr = dcr->jcr;
993    DEVICE *dev = dcr->dev;
994    bool ok = false;
995
996    ASSERT(dcr);
997
998    dev->dlock();
999
1000    /* If device is being read, we cannot write it */
1001    if (dev->can_read()) {
1002       Mmsg(jcr->errmsg, _("3603 JobId=%u device %s is busy reading.\n"), 
1003          jcr->JobId, dev->print_name());
1004       Dmsg1(110, "%s", jcr->errmsg);
1005       queue_reserve_message(jcr);
1006       goto bail_out;
1007    }
1008
1009    /* If device is unmounted, we are out of luck */
1010    if (is_device_unmounted(dev)) {
1011       Mmsg(jcr->errmsg, _("3604 JobId=%u device %s is BLOCKED due to user unmount.\n"), 
1012          jcr->JobId, dev->print_name());
1013       Dmsg1(110, "%s", jcr->errmsg);
1014       queue_reserve_message(jcr);
1015       goto bail_out;
1016    }
1017
1018    Dmsg1(110, "reserve_append device is %s\n", dev->is_tape()?"tape":"disk");
1019
1020    /* Now do detailed tests ... */
1021    if (can_reserve_drive(dcr, rctx) != 1) {
1022       Dmsg0(110, "can_reserve_drive!=1\n");
1023       goto bail_out;
1024    }
1025
1026    dev->reserved_device++;
1027    Dmsg3(100, "Inc reserve=%d dev=%s %p\n", dev->reserved_device, 
1028       dev->print_name(), dev);
1029    dcr->reserved_device = true;
1030    ok = true;
1031
1032 bail_out:
1033    dev->dunlock();
1034    return ok;
1035 }
1036
1037 /*
1038  * Returns: 1 if drive can be reserved
1039  *          0 if we should wait
1040  *         -1 on error or impossibility
1041  */
1042 static int can_reserve_drive(DCR *dcr, RCTX &rctx) 
1043 {
1044    DEVICE *dev = dcr->dev;
1045    JCR *jcr = dcr->jcr;
1046
1047    Dmsg5(110, "PrefMnt=%d exact=%d suitable=%d chgronly=%d any=%d\n",
1048          rctx.PreferMountedVols, rctx.exact_match, rctx.suitable_device,
1049          rctx.autochanger_only, rctx.any_drive);
1050
1051    /* setting any_drive overrides PreferMountedVols flag */
1052    if (!rctx.any_drive) {
1053       /*
1054        * When PreferMountedVols is set, we keep track of the 
1055        *  drive in use that has the least number of writers, then if
1056        *  no unmounted drive is found, we try that drive. This   
1057        *  helps spread the load to the least used drives.  
1058        */
1059       if (rctx.try_low_use_drive && dev == rctx.low_use_drive) {
1060          Dmsg3(110, "OK dev=%s == low_drive=%s. JobId=%u\n",
1061             dev->print_name(), rctx.low_use_drive->print_name(), jcr->JobId);
1062          return 1;
1063       }
1064       /* If he wants a free drive, but this one is busy, no go */
1065       if (!rctx.PreferMountedVols && dev->is_busy()) {
1066          /* Save least used drive */
1067          if ((dev->num_writers + dev->reserved_device) < rctx.num_writers) {
1068             rctx.num_writers = dev->num_writers + dev->reserved_device;
1069             rctx.low_use_drive = dev;
1070             Dmsg2(110, "set low use drive=%s num_writers=%d\n", dev->print_name(),
1071                rctx.num_writers);
1072          } else {
1073             Dmsg1(110, "not low use num_writers=%d\n", dev->num_writers+ 
1074                dev->reserved_device);
1075          }
1076          Dmsg1(110, "failed: !prefMnt && busy. JobId=%u\n", jcr->JobId);
1077          Mmsg(jcr->errmsg, _("3605 JobId=%u wants free drive but device %s is busy.\n"), 
1078             jcr->JobId, dev->print_name());
1079          queue_reserve_message(jcr);
1080          return 0;
1081       }
1082
1083       /* Check for prefer mounted volumes */
1084       if (rctx.PreferMountedVols && !dev->VolHdr.VolumeName[0] && dev->is_tape()) {
1085          Mmsg(jcr->errmsg, _("3606 JobId=%u prefers mounted drives, but drive %s has no Volume.\n"), 
1086             jcr->JobId, dev->print_name());
1087          queue_reserve_message(jcr);
1088          Dmsg1(110, "failed: want mounted -- no vol JobId=%u\n", jcr->JobId);
1089          return 0;                 /* No volume mounted */
1090       }
1091
1092       /* Check for exact Volume name match */
1093       if (rctx.exact_match && rctx.have_volume &&
1094           strcmp(dev->VolHdr.VolumeName, rctx.VolumeName) != 0) {
1095          Mmsg(jcr->errmsg, _("3607 JobId=%u wants Vol=\"%s\" drive has Vol=\"%s\" on drive %s.\n"), 
1096             jcr->JobId, rctx.VolumeName, dev->VolHdr.VolumeName, 
1097             dev->print_name());
1098          queue_reserve_message(jcr);
1099          Dmsg2(110, "failed: Not exact match have=%s want=%s\n",
1100                dev->VolHdr.VolumeName, rctx.VolumeName);
1101          return 0;
1102       }
1103    }
1104
1105    /* Check for unused autochanger drive */
1106    if (rctx.autochanger_only && dev->num_writers == 0 &&
1107        dev->VolHdr.VolumeName[0] == 0) {
1108       /* Device is available but not yet reserved, reserve it for us */
1109       Dmsg2(100, "OK Res Unused autochanger %s JobId=%u.\n",
1110          dev->print_name(), jcr->JobId);
1111       bstrncpy(dev->pool_name, dcr->pool_name, sizeof(dev->pool_name));
1112       bstrncpy(dev->pool_type, dcr->pool_type, sizeof(dev->pool_type));
1113       return 1;                       /* reserve drive */
1114    }
1115
1116    /*
1117     * Handle the case that there are no writers
1118     */
1119    if (dev->num_writers == 0) {
1120       /* Now check if there are any reservations on the drive */
1121       if (dev->reserved_device) {           
1122          /* Now check if we want the same Pool and pool type */
1123          if (strcmp(dev->pool_name, dcr->pool_name) == 0 &&
1124              strcmp(dev->pool_type, dcr->pool_type) == 0) {
1125             /* OK, compatible device */
1126             Dmsg2(100, "OK dev: %s num_writers=0, reserved, pool matches JobId=%u\n",
1127                dev->print_name(), jcr->JobId);
1128             return 1;
1129          } else {
1130             /* Drive Pool not suitable for us */
1131             Mmsg(jcr->errmsg, _(
1132 "3608 JobId=%u wants Pool=\"%s\" but have Pool=\"%s\" nreserve=%d on drive %s.\n"), 
1133                   jcr->JobId, dcr->pool_name, dev->pool_name,
1134                   dev->reserved_device, dev->print_name());
1135             queue_reserve_message(jcr);
1136             Dmsg2(110, "failed: busy num_writers=0, reserved, pool=%s wanted=%s\n",
1137                dev->pool_name, dcr->pool_name);
1138             return 0;                 /* wait */
1139          }
1140       } else if (dev->can_append()) {
1141          /* Device in append mode, check if changing pool */
1142          if (strcmp(dev->pool_name, dcr->pool_name) == 0 &&
1143              strcmp(dev->pool_type, dcr->pool_type) == 0) {
1144             Dmsg2(100, "OK dev: %s num_writers=0, can_append, pool matches. JobId=%u\n",
1145                dev->print_name(), jcr->JobId);
1146             /* OK, compatible device */
1147             return 1;
1148          } else {
1149             /* Changing pool, unload old tape if any in drive */
1150             Dmsg0(100, "OK dev: num_writers=0, not reserved, pool change, unload changer\n");
1151             unload_autochanger(dcr, 0);
1152          }
1153       }
1154       /* Device is available but not yet reserved, reserve it for us */
1155       Dmsg2(100, "OK Dev avail reserved %s JobId=%u\n", dev->print_name(),
1156          jcr->JobId);
1157       bstrncpy(dev->pool_name, dcr->pool_name, sizeof(dev->pool_name));
1158       bstrncpy(dev->pool_type, dcr->pool_type, sizeof(dev->pool_type));
1159       return 1;                       /* reserve drive */
1160    }
1161
1162    /*
1163     * Check if the device is in append mode with writers (i.e.
1164     *  available if pool is the same).
1165     */
1166    if (dev->can_append() || dev->num_writers > 0) {
1167       /* Yes, now check if we want the same Pool and pool type */
1168       if (strcmp(dev->pool_name, dcr->pool_name) == 0 &&
1169           strcmp(dev->pool_type, dcr->pool_type) == 0) {
1170          Dmsg2(100, "OK dev: %s num_writers>=0, can_append, pool matches. JobId=%u\n",
1171             dev->print_name(), jcr->JobId);
1172          /* OK, compatible device */
1173          return 1;
1174       } else {
1175          /* Drive Pool not suitable for us */
1176          Mmsg(jcr->errmsg, _("3609 JobId=%u wants Pool=\"%s\" but has Pool=\"%s\" on drive %s.\n"), 
1177                jcr->JobId, dcr->pool_name, dev->pool_name, dev->print_name());
1178          queue_reserve_message(jcr);
1179          Dmsg2(110, "failed: busy num_writers>0, can_append, pool=%s wanted=%s\n",
1180             dev->pool_name, dcr->pool_name);
1181          return 0;                    /* wait */
1182       }
1183    } else {
1184       Pmsg0(000, _("Logic error!!!! Should not get here.\n"));
1185       Mmsg(jcr->errmsg, _("3910 JobId=%u Logic error!!!! drive %s Should not get here.\n"),
1186             jcr->JobId, dev->print_name());
1187       queue_reserve_message(jcr);
1188       Jmsg0(jcr, M_FATAL, 0, _("Logic error!!!! Should not get here.\n"));
1189       return -1;                      /* error, should not get here */
1190    }
1191    Mmsg(jcr->errmsg, _("3911 JobId=%u failed reserve drive %s.\n"), 
1192          jcr->JobId, dev->print_name());
1193    queue_reserve_message(jcr);
1194    Dmsg2(110, "failed: No reserve %s JobId=%u\n", dev->print_name(), jcr->JobId);
1195    return 0;
1196 }
1197
1198 /*
1199  * search_lock is already set on entering this routine 
1200  */
1201 static void queue_reserve_message(JCR *jcr)
1202 {
1203    int i;   
1204    alist *msgs = jcr->reserve_msgs;
1205    char *msg;
1206
1207    if (!msgs) {
1208       return;
1209    }
1210    /*
1211     * Look for duplicate message.  If found, do
1212     * not insert
1213     */
1214    for (i=msgs->size()-1; i >= 0; i--) {
1215       msg = (char *)msgs->get(i);
1216       if (!msg) {
1217          return;
1218       }
1219       /* Comparison based on 4 digit message number */
1220       if (strncmp(msg, jcr->errmsg, 4) == 0) {
1221          return;
1222       }
1223    }      
1224    /* Message unique, so insert it */
1225    jcr->reserve_msgs->push(bstrdup(jcr->errmsg));
1226 }
1227
1228 /*
1229  * Send any reservation messages queued for this jcr
1230  */
1231 void send_drive_reserve_messages(JCR *jcr, void sendit(const char *msg, int len, void *sarg), void *arg)
1232 {
1233    int i;
1234    alist *msgs;
1235    char *msg;
1236
1237    lock_reservations();
1238    msgs = jcr->reserve_msgs;
1239    if (!msgs || msgs->size() == 0) {
1240       unlock_reservations();
1241       return;
1242    }
1243    for (i=msgs->size()-1; i >= 0; i--) {
1244       msg = (char *)msgs->get(i);
1245       if (msg) {
1246          sendit("   ", 3, arg);
1247          sendit(msg, strlen(msg), arg);
1248       } else {
1249          break;
1250       }
1251    }
1252    unlock_reservations();
1253 }