2 * Subroutines to handle waiting for operator intervention
3 * or waiting for a Device to be released
5 * Code for wait_for_sysop() pulled from askdir.c
7 * Kern Sibbald, March 2005
12 Bacula® - The Network Backup Solution
14 Copyright (C) 2000-2006 Free Software Foundation Europe e.V.
16 The main author of Bacula is Kern Sibbald, with contributions from
17 many others, a complete list can be found in the file AUTHORS.
18 This program is Free Software; you can redistribute it and/or
19 modify it under the terms of version two of the GNU General Public
20 License as published by the Free Software Foundation plus additions
21 that are listed in the file LICENSE.
23 This program is distributed in the hope that it will be useful, but
24 WITHOUT ANY WARRANTY; without even the implied warranty of
25 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
26 General Public License for more details.
28 You should have received a copy of the GNU General Public License
29 along with this program; if not, write to the Free Software
30 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
33 Bacula® is a registered trademark of John Walker.
34 The licensor of Bacula is the Free Software Foundation Europe
35 (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich,
36 Switzerland, email:ftf@fsfeurope.org.
40 #include "bacula.h" /* pull in global headers */
41 #include "stored.h" /* pull in Storage Deamon headers */
43 //static bool double_jcr_wait_time(JCR *jcr);
47 * Wait for SysOp to mount a tape on a specific device
49 * Returns: W_ERROR, W_TIMEOUT, W_POLL, W_MOUNT, or W_WAKE
51 int wait_for_sysop(DCR *dcr)
55 struct timespec timeout;
56 time_t last_heartbeat = 0;
57 time_t first_start = time(NULL);
61 DEVICE *dev = dcr->dev;
65 Dmsg1(100, "Enter blocked=%s\n", dev->print_blocked());
66 unmounted = is_device_unmounted(dev);
70 * Wait requested time (dev->rem_wait_sec). However, we also wake up every
71 * HB_TIME seconds and send a heartbeat to the FD and the Director
72 * to keep stateful firewalls from closing them down while waiting
75 add_wait = dev->rem_wait_sec;
76 if (me->heartbeat_interval && add_wait > me->heartbeat_interval) {
77 add_wait = me->heartbeat_interval;
79 /* If the user did not unmount the tape and we are polling, ensure
80 * that we poll at the correct interval.
82 if (!unmounted && dev->vol_poll_interval && add_wait > dev->vol_poll_interval) {
83 add_wait = dev->vol_poll_interval;
87 Dmsg1(400, "blocked=%s\n", dev->print_blocked());
88 dev->dev_prev_blocked = dev->dev_blocked;
89 dev->set_blocked(BST_WAITING_FOR_SYSOP); /* indicate waiting for mount */
92 for ( ; !job_canceled(jcr); ) {
95 gettimeofday(&tv, &tz);
96 timeout.tv_nsec = tv.tv_usec * 1000;
97 timeout.tv_sec = tv.tv_sec + add_wait;
99 Dmsg4(400, "I'm going to sleep on device %s. HB=%d wait=%d add_wait=%d\n",
100 dev->print_name(), (int)me->heartbeat_interval, dev->wait_sec, add_wait);
102 /* Wait required time */
103 stat = pthread_cond_timedwait(&dev->wait_next_vol, &dev->mutex, &timeout);
104 Dmsg2(400, "Wokeup from sleep on device stat=%d blocked=%s\n", stat,
105 dev->print_blocked());
108 dev->rem_wait_sec -= (now - start);
110 /* Note, this always triggers the first time. We want that. */
111 if (me->heartbeat_interval) {
112 if (now - last_heartbeat >= me->heartbeat_interval) {
113 /* send heartbeats */
114 if (jcr->file_bsock) {
115 bnet_sig(jcr->file_bsock, BNET_HEARTBEAT);
116 Dmsg0(400, "Send heartbeat to FD.\n");
118 if (jcr->dir_bsock) {
119 bnet_sig(jcr->dir_bsock, BNET_HEARTBEAT);
121 last_heartbeat = now;
125 if (stat == EINVAL) {
127 Dmsg1(000, "pthread stat=%d\n", stat);
128 Jmsg1(jcr, M_FATAL, 0, _("pthread timedwait error. ERR=%s\n"), be.strerror(stat));
129 stat = W_ERROR; /* error */
134 if (dev->rem_wait_sec <= 0) { /* on exceeding wait time return */
135 Dmsg0(400, "Exceed wait time.\n");
141 * Check if user unmounted the device while we were waiting
143 unmounted = is_device_unmounted(dev);
145 if (!unmounted && dev->vol_poll_interval &&
146 (now - first_start >= dev->vol_poll_interval)) {
147 Dmsg1(400, "In wait blocked=%s\n", dev->print_blocked());
148 dev->poll = true; /* returning a poll event */
153 * Check if user mounted the device while we were waiting
155 if (dev->get_blocked() == BST_MOUNT) { /* mount request ? */
161 * If we did not timeout, then some event happened, so
162 * return to check if state changed.
165 stat = W_WAKE; /* someone woke us */
170 * At this point, we know we woke up because of a timeout,
171 * that was due to a heartbeat, so we just update
172 * the wait counters and continue.
174 add_wait = dev->wait_sec - (now - start);
178 if (me->heartbeat_interval && add_wait > me->heartbeat_interval) {
179 add_wait = me->heartbeat_interval;
184 dev->set_blocked(dev->dev_prev_blocked); /* restore entry state */
185 Dmsg1(400, "set %s\n", dev->print_blocked());
187 Dmsg1(400, "Exit blocked=%s\n", dev->print_blocked());
194 * Wait for any device to be released, then we return, so
195 * higher level code can rescan possible devices.
197 * Returns: true if a device has changed state
198 * false if the total wait time has expired.
200 bool wait_for_device(JCR *jcr, bool first)
204 struct timespec timeout;
207 const int wait_time = 5 * 60; /* wait 5 minutes */
209 Dmsg0(100, "Enter wait_for_device\n");
210 P(device_release_mutex);
213 Jmsg(jcr, M_MOUNT, 0, _("Job %s waiting to reserve a device.\n"), jcr->Job);
216 gettimeofday(&tv, &tz);
217 timeout.tv_nsec = tv.tv_usec * 1000;
218 timeout.tv_sec = tv.tv_sec + wait_time;
220 Dmsg0(100, "I'm going to wait for a device.\n");
222 /* Wait required time */
223 stat = pthread_cond_timedwait(&wait_device_release, &device_release_mutex, &timeout);
224 Dmsg1(100, "Wokeup from sleep on device stat=%d\n", stat);
227 V(device_release_mutex);
228 Dmsg1(100, "Return from wait_device ok=%d\n", ok);
234 * The jcr timers are used for waiting on any device *
235 * Returns: true if time doubled
236 * false if max time expired
238 static bool double_jcr_wait_time(JCR *jcr)
240 jcr->wait_sec *= 2; /* double wait time */
241 if (jcr->wait_sec > jcr->max_wait) { /* but not longer than maxtime */
242 jcr->wait_sec = jcr->max_wait;
245 jcr->rem_wait_sec = jcr->wait_sec;
246 if (jcr->num_wait >= jcr->max_num_wait) {