]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/stored/job.c
Change all sm_checks into Dsm_check for performance reasons
[bacula/bacula] / bacula / src / stored / job.c
1 /*
2    Bacula® - The Network Backup Solution
3
4    Copyright (C) 2000-2011 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 three of the GNU Affero General Public
10    License as published by the Free Software Foundation and included
11    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 Affero 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 Kern Sibbald.
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  */
34
35 #include "bacula.h"
36 #include "stored.h"
37
38 static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
39
40 /* Imported variables */
41 extern uint32_t VolSessionTime;
42
43 /* Imported functions */
44 extern uint32_t newVolSessionId();
45 extern bool do_mac(JCR *jcr);
46
47 /* Requests from the Director daemon */
48 /* Added in 3.1.4 14Sep09 KES */
49 static char jobcmd[] = "JobId=%d job=%127s job_name=%127s client_name=%127s "
50       "type=%d level=%d FileSet=%127s NoAttr=%d SpoolAttr=%d FileSetMD5=%127s "
51       "SpoolData=%d WritePartAfterJob=%d PreferMountedVols=%d SpoolSize=%s "
52       "rerunning=%d VolSessionId=%d VolSessionTime=%d\n";
53
54 /* Responses sent to Director daemon */
55 static char OKjob[]     = "3000 OK Job SDid=%u SDtime=%u Authorization=%s\n";
56 static char BAD_job[]   = "3915 Bad Job command. stat=%d CMD: %s\n";
57
58 /*
59  * Director requests us to start a job
60  * Basic tasks done here:
61  *  - We pickup the JobId to be run from the Director.
62  *  - We pickup the device, media, and pool from the Director
63  *  - Wait for a connection from the File Daemon (FD)
64  *  - Accept commands from the FD (i.e. run the job)
65  *  - Return when the connection is terminated or
66  *    there is an error.
67  */
68 bool job_cmd(JCR *jcr)
69 {
70    int JobId;
71    char auth_key[100];
72    char spool_size[30];
73    char seed[100];
74    BSOCK *dir = jcr->dir_bsock;
75    POOL_MEM job_name, client_name, job, fileset_name, fileset_md5;
76    int JobType, level, spool_attributes, no_attributes, spool_data;
77    int write_part_after_job, PreferMountedVols;
78    int stat;
79    JCR *ojcr;
80
81    /*
82     * Get JobId and permissions from Director
83     */
84    Dmsg1(100, "<dird: %s", dir->msg);
85    bstrncpy(spool_size, "0", sizeof(spool_size));
86    stat = sscanf(dir->msg, jobcmd, &JobId, job.c_str(), job_name.c_str(),
87               client_name.c_str(),
88               &JobType, &level, fileset_name.c_str(), &no_attributes,
89               &spool_attributes, fileset_md5.c_str(), &spool_data,
90               &write_part_after_job, &PreferMountedVols, spool_size,
91               &jcr->rerunning, &jcr->VolSessionId, &jcr->VolSessionTime);
92    if (stat != 17) {
93       pm_strcpy(jcr->errmsg, dir->msg);
94       dir->fsend(BAD_job, stat, jcr->errmsg);
95       Dmsg1(100, ">dird: %s", dir->msg);
96       jcr->setJobStatus(JS_ErrorTerminated);
97       return false;
98    }
99    Dmsg3(100, "==== rerunning=%d VolSesId=%d VolSesTime=%d\n", jcr->rerunning,
100          jcr->VolSessionId, jcr->VolSessionTime);
101    /*
102     * Since this job could be rescheduled, we
103     *  check to see if we have it already. If so
104     *  free the old jcr and use the new one.
105     */
106    ojcr = get_jcr_by_full_name(job.c_str());
107    if (ojcr && !ojcr->authenticated) {
108       Dmsg2(100, "Found ojcr=0x%x Job %s\n", (unsigned)(intptr_t)ojcr, job.c_str());
109       free_jcr(ojcr);
110    }
111    jcr->JobId = JobId;
112    Dmsg2(800, "Start JobId=%d %p\n", JobId, jcr);
113    /*
114     * If job rescheduled because previous was incomplete,
115     * the Resched flag is set and VolSessionId and VolSessionTime
116     * are given to us (same as restarted job).
117     */
118    if (!jcr->rerunning) {
119       jcr->VolSessionId = newVolSessionId();
120       jcr->VolSessionTime = VolSessionTime;
121    }
122    bstrncpy(jcr->Job, job, sizeof(jcr->Job));
123    unbash_spaces(job_name);
124    jcr->job_name = get_pool_memory(PM_NAME);
125    pm_strcpy(jcr->job_name, job_name);
126    unbash_spaces(client_name);
127    jcr->client_name = get_pool_memory(PM_NAME);
128    pm_strcpy(jcr->client_name, client_name);
129    unbash_spaces(fileset_name);
130    jcr->fileset_name = get_pool_memory(PM_NAME);
131    pm_strcpy(jcr->fileset_name, fileset_name);
132    jcr->setJobType(JobType);
133    jcr->setJobLevel(level);
134    jcr->no_attributes = no_attributes;
135    jcr->spool_attributes = spool_attributes;
136    jcr->spool_data = spool_data;
137    jcr->spool_size = str_to_int64(spool_size);
138    jcr->write_part_after_job = write_part_after_job;
139    jcr->fileset_md5 = get_pool_memory(PM_NAME);
140    pm_strcpy(jcr->fileset_md5, fileset_md5);
141    jcr->PreferMountedVols = PreferMountedVols;
142
143
144    jcr->authenticated = false;
145
146    /*
147     * Pass back an authorization key for the File daemon
148     */
149    bsnprintf(seed, sizeof(seed), "%p%d", jcr, JobId);
150    make_session_key(auth_key, seed, 1);
151    dir->fsend(OKjob, jcr->VolSessionId, jcr->VolSessionTime, auth_key);
152    Dmsg2(50, ">dird jid=%u: %s", (uint32_t)jcr->JobId, dir->msg);
153    jcr->sd_auth_key = bstrdup(auth_key);
154    memset(auth_key, 0, sizeof(auth_key));
155    generate_daemon_event(jcr, "JobStart");
156    return true;
157 }
158
159 bool run_cmd(JCR *jcr)
160 {
161    struct timeval tv;
162    struct timezone tz;
163    struct timespec timeout;
164    int errstat = 0;
165
166    Dsm_check(200);
167    Dmsg1(200, "Run_cmd: %s\n", jcr->dir_bsock->msg);
168
169    /* If we do not need the FD, we are doing a migrate, copy, or virtual
170     *   backup.
171     */
172    if (jcr->no_client_used()) {
173       do_mac(jcr);
174       return false;
175    }
176
177    jcr->setJobStatus(JS_WaitFD);          /* wait for FD to connect */
178    dir_send_job_status(jcr);
179
180    gettimeofday(&tv, &tz);
181    timeout.tv_nsec = tv.tv_usec * 1000;
182    timeout.tv_sec = tv.tv_sec + me->client_wait;
183
184    Dmsg3(50, "%s waiting %d sec for FD to contact SD key=%s\n",
185          jcr->Job, (int)(timeout.tv_sec-time(NULL)), jcr->sd_auth_key);
186    Dmsg2(800, "Wait FD for jid=%d %p\n", jcr->JobId, jcr);
187
188    /*
189     * Wait for the File daemon to contact us to start the Job,
190     *  when he does, we will be released, unless the 30 minutes
191     *  expires.
192     */
193    P(mutex);
194    while ( !jcr->authenticated && !job_canceled(jcr) ) {
195       errstat = pthread_cond_timedwait(&jcr->job_start_wait, &mutex, &timeout);
196       if (errstat == ETIMEDOUT || errstat == EINVAL || errstat == EPERM) {
197          break;
198       }
199       Dmsg1(800, "=== Auth cond errstat=%d\n", errstat);
200    }
201    Dmsg3(50, "Auth=%d canceled=%d errstat=%d\n", jcr->authenticated,
202       job_canceled(jcr), errstat);
203    V(mutex);
204    Dmsg2(800, "Auth fail or cancel for jid=%d %p\n", jcr->JobId, jcr);
205
206    memset(jcr->sd_auth_key, 0, strlen(jcr->sd_auth_key));
207
208    if (jcr->authenticated && !job_canceled(jcr)) {
209       Dmsg2(800, "Running jid=%d %p\n", jcr->JobId, jcr);
210       run_job(jcr);                   /* Run the job */
211    }
212    Dmsg2(800, "Done jid=%d %p\n", jcr->JobId, jcr);
213    return false;
214 }
215
216 /*
217  * After receiving a connection (in dircmd.c) if it is
218  *   from the File daemon, this routine is called.
219  */
220 void handle_filed_connection(BSOCK *fd, char *job_name)
221 {
222    JCR *jcr;
223
224 /*
225  * With the following bmicrosleep on, running the 
226  * SD under the debugger fails.   
227  */ 
228 // bmicrosleep(0, 50000);             /* wait 50 millisecs */
229    if (!(jcr=get_jcr_by_full_name(job_name))) {
230       Jmsg1(NULL, M_FATAL, 0, _("FD connect failed: Job name not found: %s\n"), job_name);
231       Dmsg1(3, "**** Job \"%s\" not found.\n", job_name);
232       fd->close();
233       return;
234    }
235
236
237    Dmsg1(50, "Found Job %s\n", job_name);
238
239    if (jcr->authenticated) {
240       Jmsg2(jcr, M_FATAL, 0, _("Hey!!!! JobId %u Job %s already authenticated.\n"),
241          (uint32_t)jcr->JobId, jcr->Job);
242       Dmsg2(50, "Hey!!!! JobId %u Job %s already authenticated.\n",
243          (uint32_t)jcr->JobId, jcr->Job);
244       fd->close();
245       free_jcr(jcr);
246       return;
247    }
248
249    jcr->file_bsock = fd;
250    jcr->file_bsock->set_jcr(jcr);
251
252    /*
253     * Authenticate the File daemon
254     */
255    if (jcr->authenticated || !authenticate_filed(jcr)) {
256       Dmsg1(50, "Authentication failed Job %s\n", jcr->Job);
257       Jmsg(jcr, M_FATAL, 0, _("Unable to authenticate File daemon\n"));
258    } else {
259       jcr->authenticated = true;
260       Dmsg2(50, "OK Authentication jid=%u Job %s\n", (uint32_t)jcr->JobId, jcr->Job);
261    }
262
263    if (!jcr->authenticated) {
264       jcr->setJobStatus(JS_ErrorTerminated);
265    }
266    pthread_cond_signal(&jcr->job_start_wait); /* wake waiting job */
267    free_jcr(jcr);
268    return;
269 }
270
271
272 #ifdef needed
273 /*
274  *   Query Device command from Director
275  *   Sends Storage Daemon's information on the device to the
276  *    caller (presumably the Director).
277  *   This command always returns "true" so that the line is
278  *    not closed on an error.
279  *
280  */
281 bool query_cmd(JCR *jcr)
282 {
283    POOL_MEM dev_name, VolumeName, MediaType, ChangerName;
284    BSOCK *dir = jcr->dir_bsock;
285    DEVRES *device;
286    AUTOCHANGER *changer;
287    bool ok;
288
289    Dmsg1(100, "Query_cmd: %s", dir->msg);
290    ok = sscanf(dir->msg, query_device, dev_name.c_str()) == 1;
291    Dmsg1(100, "<dird: %s\n", dir->msg);
292    if (ok) {
293       unbash_spaces(dev_name);
294       foreach_res(device, R_DEVICE) {
295          /* Find resource, and make sure we were able to open it */
296          if (strcmp(dev_name.c_str(), device->hdr.name) == 0) {
297             if (!device->dev) {
298                device->dev = init_dev(jcr, device);
299             }
300             if (!device->dev) {
301                break;
302             }  
303             ok = dir_update_device(jcr, device->dev);
304             if (ok) {
305                ok = dir->fsend(OK_query);
306             } else {
307                dir->fsend(NO_query);
308             }
309             return ok;
310          }
311       }
312       foreach_res(changer, R_AUTOCHANGER) {
313          /* Find resource, and make sure we were able to open it */
314          if (strcmp(dev_name.c_str(), changer->hdr.name) == 0) {
315             if (!changer->device || changer->device->size() == 0) {
316                continue;              /* no devices */
317             }
318             ok = dir_update_changer(jcr, changer);
319             if (ok) {
320                ok = dir->fsend(OK_query);
321             } else {
322                dir->fsend(NO_query);
323             }
324             return ok;
325          }
326       }
327       /* If we get here, the device/autochanger was not found */
328       unbash_spaces(dir->msg);
329       pm_strcpy(jcr->errmsg, dir->msg);
330       dir->fsend(NO_device, dev_name.c_str());
331       Dmsg1(100, ">dird: %s\n", dir->msg);
332    } else {
333       unbash_spaces(dir->msg);
334       pm_strcpy(jcr->errmsg, dir->msg);
335       dir->fsend(BAD_query, jcr->errmsg);
336       Dmsg1(100, ">dird: %s\n", dir->msg);
337    }
338
339    return true;
340 }
341
342 #endif
343
344
345 /*
346  * Destroy the Job Control Record and associated
347  * resources (sockets).
348  */
349 void stored_free_jcr(JCR *jcr)
350 {
351    Dmsg2(800, "End Job JobId=%u %p\n", jcr->JobId, jcr);
352    if (jcr->dir_bsock) {
353       Dmsg2(800, "Send terminate jid=%d %p\n", jcr->JobId, jcr);
354       jcr->dir_bsock->signal(BNET_EOD);
355       jcr->dir_bsock->signal(BNET_TERMINATE);
356    }
357    if (jcr->file_bsock) {
358       jcr->file_bsock->close();
359       jcr->file_bsock = NULL;
360    }
361    if (jcr->job_name) {
362       free_pool_memory(jcr->job_name);
363    }
364    if (jcr->client_name) {
365       free_memory(jcr->client_name);
366       jcr->client_name = NULL;
367    }
368    if (jcr->fileset_name) {
369       free_memory(jcr->fileset_name);
370    }
371    if (jcr->fileset_md5) {
372       free_memory(jcr->fileset_md5);
373    }
374    if (jcr->bsr) {
375       free_bsr(jcr->bsr);
376       jcr->bsr = NULL;
377    }
378    /* Free any restore volume list created */
379    free_restore_volume_list(jcr);
380    if (jcr->RestoreBootstrap) {
381       unlink(jcr->RestoreBootstrap);
382       free_pool_memory(jcr->RestoreBootstrap);
383       jcr->RestoreBootstrap = NULL;
384    }
385    if (jcr->next_dev || jcr->prev_dev) {
386       Emsg0(M_FATAL, 0, _("In free_jcr(), but still attached to device!!!!\n"));
387    }
388    pthread_cond_destroy(&jcr->job_start_wait);
389    if (jcr->dcrs) {
390       delete jcr->dcrs;
391    }
392    jcr->dcrs = NULL;
393
394    /* Avoid a double free */
395    if (jcr->dcr == jcr->read_dcr) {
396       jcr->read_dcr = NULL;
397    }
398    if (jcr->dcr) {
399       free_dcr(jcr->dcr);
400       jcr->dcr = NULL;
401    }
402    if (jcr->read_dcr) {
403       free_dcr(jcr->read_dcr);
404       jcr->read_dcr = NULL;
405    }
406
407    if (jcr->read_store) {
408       DIRSTORE *store;
409       foreach_alist(store, jcr->read_store) {
410          delete store->device;
411          delete store;
412       }
413       delete jcr->read_store;
414       jcr->read_store = NULL;
415    }
416    if (jcr->write_store) {
417       DIRSTORE *store;
418       foreach_alist(store, jcr->write_store) {
419          delete store->device;
420          delete store;
421       }
422       delete jcr->write_store;
423       jcr->write_store = NULL;
424    }
425    Dsm_check(200);
426
427    if (jcr->JobId != 0)
428       write_state_file(me->working_directory, "bacula-sd", get_first_port_host_order(me->sdaddrs));
429
430    return;
431 }