]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/stored/job.c
Fix build without sd lock debug
[bacula/bacula] / bacula / src / stored / job.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  *   Job control and execution for Storage Daemon
30  *
31  *   Kern Sibbald, MM
32  *
33  *   Version $Id$
34  *
35  */
36
37 #include "bacula.h"
38 #include "stored.h"
39
40 static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
41
42 /* Imported variables */
43 extern uint32_t VolSessionTime;
44
45 /* Imported functions */
46 extern uint32_t newVolSessionId();
47 extern bool do_mac(JCR *jcr);
48
49 /* Requests from the Director daemon */
50 static char jobcmd[] = "JobId=%d job=%127s job_name=%127s client_name=%127s "
51       "type=%d level=%d FileSet=%127s NoAttr=%d SpoolAttr=%d FileSetMD5=%127s "
52       "SpoolData=%d WritePartAfterJob=%d PreferMountedVols=%d\n";
53
54
55 /* Responses sent to Director daemon */
56 static char OKjob[]     = "3000 OK Job SDid=%u SDtime=%u Authorization=%s\n";
57 static char BAD_job[]   = "3915 Bad Job command. stat=%d CMD: %s\n";
58 //static char OK_query[]  = "3001 OK query\n";
59 //static char NO_query[]  = "3918 Query failed\n";
60 //static char BAD_query[] = "3917 Bad query command: %s\n";
61
62 /*
63  * Director requests us to start a job
64  * Basic tasks done here:
65  *  - We pickup the JobId to be run from the Director.
66  *  - We pickup the device, media, and pool from the Director
67  *  - Wait for a connection from the File Daemon (FD)
68  *  - Accept commands from the FD (i.e. run the job)
69  *  - Return when the connection is terminated or
70  *    there is an error.
71  */
72 bool job_cmd(JCR *jcr)
73 {
74    int JobId;
75    char auth_key[100];
76    BSOCK *dir = jcr->dir_bsock;
77    POOL_MEM job_name, client_name, job, fileset_name, fileset_md5;
78    int JobType, level, spool_attributes, no_attributes, spool_data;
79    int write_part_after_job, PreferMountedVols;
80    int stat;
81    JCR *ojcr;
82
83    /*
84     * Get JobId and permissions from Director
85     */
86    Dmsg1(100, "<dird: %s", dir->msg);
87    stat = sscanf(dir->msg, jobcmd, &JobId, job.c_str(), job_name.c_str(),
88               client_name.c_str(),
89               &JobType, &level, fileset_name.c_str(), &no_attributes,
90               &spool_attributes, fileset_md5.c_str(), &spool_data, 
91               &write_part_after_job, &PreferMountedVols);
92    if (stat != 13) {
93       pm_strcpy(jcr->errmsg, dir->msg);
94       bnet_fsend(dir, BAD_job, stat, jcr->errmsg);
95       Dmsg1(100, ">dird: %s", dir->msg);
96       set_jcr_job_status(jcr, JS_ErrorTerminated);
97       return false;
98    }
99    /*
100     * Since this job could be rescheduled, we
101     *  check to see if we have it already. If so
102     *  free the old jcr and use the new one.
103     */
104    ojcr = get_jcr_by_full_name(job.c_str());
105    if (ojcr && !ojcr->authenticated) {
106       Dmsg2(100, "Found ojcr=0x%x Job %s\n", (unsigned)(long)ojcr, job.c_str());
107       free_jcr(ojcr);
108    }
109    jcr->JobId = JobId;
110    jcr->VolSessionId = newVolSessionId();
111    jcr->VolSessionTime = VolSessionTime;
112    bstrncpy(jcr->Job, job, sizeof(jcr->Job));
113    unbash_spaces(job_name);
114    jcr->job_name = get_pool_memory(PM_NAME);
115    pm_strcpy(jcr->job_name, job_name);
116    unbash_spaces(client_name);
117    jcr->client_name = get_pool_memory(PM_NAME);
118    pm_strcpy(jcr->client_name, client_name);
119    unbash_spaces(fileset_name);
120    jcr->fileset_name = get_pool_memory(PM_NAME);
121    pm_strcpy(jcr->fileset_name, fileset_name);
122    jcr->JobType = JobType;
123    jcr->JobLevel = level;
124    jcr->no_attributes = no_attributes;
125    jcr->spool_attributes = spool_attributes;
126    jcr->spool_data = spool_data;
127    jcr->write_part_after_job = write_part_after_job;
128    jcr->fileset_md5 = get_pool_memory(PM_NAME);
129    pm_strcpy(jcr->fileset_md5, fileset_md5);
130    jcr->PreferMountedVols = PreferMountedVols;
131
132    jcr->authenticated = false;
133
134    /*
135     * Pass back an authorization key for the File daemon
136     */
137    make_session_key(auth_key, NULL, 1);
138    bnet_fsend(dir, OKjob, jcr->VolSessionId, jcr->VolSessionTime, auth_key);
139    Dmsg1(100, ">dird: %s", dir->msg);
140    jcr->sd_auth_key = bstrdup(auth_key);
141    memset(auth_key, 0, sizeof(auth_key));
142    generate_daemon_event(jcr, "JobStart");
143    return true;
144 }
145
146 bool run_cmd(JCR *jcr)
147 {
148    struct timeval tv;
149    struct timezone tz;
150    struct timespec timeout;
151    int errstat;
152
153    Dmsg1(200, "Run_cmd: %s\n", jcr->dir_bsock->msg);
154    /* The following jobs don't need the FD */
155    switch (jcr->JobType) {
156    case JT_MIGRATE:
157    case JT_COPY:
158    case JT_ARCHIVE:
159       jcr->authenticated = true;
160       do_mac(jcr);
161       return false;
162    }
163
164    set_jcr_job_status(jcr, JS_WaitFD);          /* wait for FD to connect */
165    dir_send_job_status(jcr);
166
167    gettimeofday(&tv, &tz);
168    timeout.tv_nsec = tv.tv_usec * 1000;
169    timeout.tv_sec = tv.tv_sec + me->client_wait;
170
171    Dmsg2(100, "%s waiting %d sec for FD to contact SD\n", 
172         jcr->Job, (int)me->client_wait);
173    /*
174     * Wait for the File daemon to contact us to start the Job,
175     *  when he does, we will be released, unless the 30 minutes
176     *  expires.
177     */
178    P(mutex);
179    for ( ;!job_canceled(jcr); ) {
180       errstat = pthread_cond_timedwait(&jcr->job_start_wait, &mutex, &timeout);
181       if (errstat == 0 || errstat == ETIMEDOUT) {
182          break;
183       }
184    }
185    V(mutex);
186
187    memset(jcr->sd_auth_key, 0, strlen(jcr->sd_auth_key));
188
189    if (jcr->authenticated && !job_canceled(jcr)) {
190       Dmsg1(100, "Running job %s\n", jcr->Job);
191       run_job(jcr);                   /* Run the job */
192    }
193    return false;
194 }
195
196 /*
197  * After receiving a connection (in job.c) if it is
198  *   from the File daemon, this routine is called.
199  */
200 void handle_filed_connection(BSOCK *fd, char *job_name)
201 {
202    JCR *jcr;
203
204    bmicrosleep(0, 50000);             /* wait 50 millisecs */
205    if (!(jcr=get_jcr_by_full_name(job_name))) {
206       Jmsg1(NULL, M_FATAL, 0, _("Job name not found: %s\n"), job_name);
207       Dmsg1(100, "Job name not found: %s\n", job_name);
208       return;
209    }
210
211    jcr->file_bsock = fd;
212    jcr->file_bsock->set_jcr(jcr);
213
214    Dmsg1(110, "Found Job %s\n", job_name);
215
216    if (jcr->authenticated) {
217       Jmsg2(jcr, M_FATAL, 0, _("Hey!!!! JobId %u Job %s already authenticated.\n"),
218          jcr->JobId, jcr->Job);
219       free_jcr(jcr);
220       return;
221    }
222
223    /*
224     * Authenticate the File daemon
225     */
226    if (jcr->authenticated || !authenticate_filed(jcr)) {
227       Dmsg1(100, "Authentication failed Job %s\n", jcr->Job);
228       Jmsg(jcr, M_FATAL, 0, _("Unable to authenticate File daemon\n"));
229    } else {
230       jcr->authenticated = true;
231       Dmsg1(110, "OK Authentication Job %s\n", jcr->Job);
232    }
233
234    if (!jcr->authenticated) {
235       set_jcr_job_status(jcr, JS_ErrorTerminated);
236    }
237    pthread_cond_signal(&jcr->job_start_wait); /* wake waiting job */
238    free_jcr(jcr);
239    return;
240 }
241
242
243 #ifdef needed
244 /*
245  *   Query Device command from Director
246  *   Sends Storage Daemon's information on the device to the
247  *    caller (presumably the Director).
248  *   This command always returns "true" so that the line is
249  *    not closed on an error.
250  *
251  */
252 bool query_cmd(JCR *jcr)
253 {
254    POOL_MEM dev_name, VolumeName, MediaType, ChangerName;
255    BSOCK *dir = jcr->dir_bsock;
256    DEVRES *device;
257    AUTOCHANGER *changer;
258    bool ok;
259
260    Dmsg1(100, "Query_cmd: %s", dir->msg);
261    ok = sscanf(dir->msg, query_device, dev_name.c_str()) == 1;
262    Dmsg1(100, "<dird: %s\n", dir->msg);
263    if (ok) {
264       unbash_spaces(dev_name);
265       foreach_res(device, R_DEVICE) {
266          /* Find resource, and make sure we were able to open it */
267          if (fnmatch(dev_name.c_str(), device->hdr.name, 0) == 0) {
268             if (!device->dev) {
269                device->dev = init_dev(jcr, device);
270             }
271             if (!device->dev) {
272                break;
273             }  
274             ok = dir_update_device(jcr, device->dev);
275             if (ok) {
276                ok = bnet_fsend(dir, OK_query);
277             } else {
278                bnet_fsend(dir, NO_query);
279             }
280             return ok;
281          }
282       }
283       foreach_res(changer, R_AUTOCHANGER) {
284          /* Find resource, and make sure we were able to open it */
285          if (fnmatch(dev_name.c_str(), changer->hdr.name, 0) == 0) {
286             if (!changer->device || changer->device->size() == 0) {
287                continue;              /* no devices */
288             }
289             ok = dir_update_changer(jcr, changer);
290             if (ok) {
291                ok = bnet_fsend(dir, OK_query);
292             } else {
293                bnet_fsend(dir, NO_query);
294             }
295             return ok;
296          }
297       }
298       /* If we get here, the device/autochanger was not found */
299       unbash_spaces(dir->msg);
300       pm_strcpy(jcr->errmsg, dir->msg);
301       bnet_fsend(dir, NO_device, dev_name.c_str());
302       Dmsg1(100, ">dird: %s\n", dir->msg);
303    } else {
304       unbash_spaces(dir->msg);
305       pm_strcpy(jcr->errmsg, dir->msg);
306       bnet_fsend(dir, BAD_query, jcr->errmsg);
307       Dmsg1(100, ">dird: %s\n", dir->msg);
308    }
309
310    return true;
311 }
312
313 #endif
314
315
316 /*
317  * Destroy the Job Control Record and associated
318  * resources (sockets).
319  */
320 void stored_free_jcr(JCR *jcr)
321 {
322    Dmsg1(900, "stored_free_jcr JobId=%u\n", jcr->JobId);
323    if (jcr->file_bsock) {
324       bnet_close(jcr->file_bsock);
325       jcr->file_bsock = NULL;
326    }
327    if (jcr->job_name) {
328       free_pool_memory(jcr->job_name);
329    }
330    if (jcr->client_name) {
331       free_memory(jcr->client_name);
332       jcr->client_name = NULL;
333    }
334    if (jcr->fileset_name) {
335       free_memory(jcr->fileset_name);
336    }
337    if (jcr->fileset_md5) {
338       free_memory(jcr->fileset_md5);
339    }
340    if (jcr->bsr) {
341       free_bsr(jcr->bsr);
342       jcr->bsr = NULL;
343    }
344    if (jcr->RestoreBootstrap) {
345       unlink(jcr->RestoreBootstrap);
346       free_pool_memory(jcr->RestoreBootstrap);
347       jcr->RestoreBootstrap = NULL;
348    }
349    if (jcr->next_dev || jcr->prev_dev) {
350       Emsg0(M_FATAL, 0, _("In free_jcr(), but still attached to device!!!!\n"));
351    }
352    pthread_cond_destroy(&jcr->job_start_wait);
353    if (jcr->dcrs) {
354       delete jcr->dcrs;
355    }
356    jcr->dcrs = NULL;
357
358    if (jcr->dcr) {
359       free_dcr(jcr->dcr);
360       jcr->dcr = NULL;
361    }
362    if (jcr->read_dcr) {
363       free_dcr(jcr->read_dcr);
364       jcr->read_dcr = NULL;
365    }
366
367    if (jcr->read_store) {
368       DIRSTORE *store;
369       foreach_alist(store, jcr->read_store) {
370          delete store->device;
371          delete store;
372       }
373       delete jcr->read_store;
374       jcr->read_store = NULL;
375    }
376    if (jcr->write_store) {
377       DIRSTORE *store;
378       foreach_alist(store, jcr->write_store) {
379          delete store->device;
380          delete store;
381       }
382       delete jcr->write_store;
383       jcr->write_store = NULL;
384    }
385    return;
386 }