]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/stored/job.c
721768544ca14b0f7a95385b2857c0256dbf7728
[bacula/bacula] / bacula / src / stored / job.c
1 /*
2    Bacula(R) - The Network Backup Solution
3
4    Copyright (C) 2000-2016 Kern Sibbald
5
6    The original author of Bacula is Kern Sibbald, with contributions
7    from many others, a complete list can be found in the file AUTHORS.
8
9    You may use this file and others of this release according to the
10    license defined in the LICENSE file, which includes the Affero General
11    Public License, v3.0 ("AGPLv3") and some additional permissions and
12    terms pursuant to its AGPLv3 Section 7.
13
14    This notice must be preserved when any source code is 
15    conveyed and/or propagated.
16
17    Bacula(R) is a registered trademark of Kern Sibbald.
18 */
19 /*
20  *   Job control and execution for Storage Daemon
21  *
22  *   Written by Kern Sibbald, MM
23  *
24  */
25
26 #include "bacula.h"
27 #include "stored.h"
28
29 static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
30
31 /* Imported variables */
32 extern STORES *me;                    /* our Global resource */
33 extern uint32_t VolSessionTime;
34
35 /* Imported functions */
36 extern uint32_t newVolSessionId();
37 extern bool do_vbackup(JCR *jcr);
38
39 /* Requests from the Director daemon */
40 static char jobcmd[] = "JobId=%d job=%127s job_name=%127s client_name=%127s "
41       "type=%d level=%d FileSet=%127s NoAttr=%d SpoolAttr=%d FileSetMD5=%127s "
42       "SpoolData=%d WritePartAfterJob=%d PreferMountedVols=%d SpoolSize=%s "
43       "rerunning=%d VolSessionId=%d VolSessionTime=%d sd_client=%d "
44       "Authorization=%s\n";
45
46 /* Responses sent to Director daemon */
47 static char OKjob[]     = "3000 OK Job SDid=%u SDtime=%u Authorization=%s\n";
48 static char BAD_job[]   = "3915 Bad Job command. stat=%d CMD: %s\n";
49
50 /*
51  * Director requests us to start a job
52  * Basic tasks done here:
53  *  - We pickup the JobId to be run from the Director.
54  *  - We pickup the device, media, and pool from the Director
55  *  - Wait for a connection from the File Daemon (FD)
56  *  - Accept commands from the FD (i.e. run the job)
57  *  - Return when the connection is terminated or
58  *    there is an error.
59  */
60 bool job_cmd(JCR *jcr)
61 {
62    int32_t JobId;
63    char sd_auth_key[200];
64    char spool_size[30];
65    char seed[100];
66    BSOCK *dir = jcr->dir_bsock;
67    POOL_MEM job_name, client_name, job, fileset_name, fileset_md5;
68    int32_t JobType, level, spool_attributes, no_attributes, spool_data;
69    int32_t write_part_after_job, PreferMountedVols;
70    int32_t rerunning;
71    int32_t is_client;
72    int stat;
73    JCR *ojcr;
74
75    /*
76     * Get JobId and permissions from Director
77     */
78    Dmsg1(100, "<dird: %s", dir->msg);
79    bstrncpy(spool_size, "0", sizeof(spool_size));
80    stat = sscanf(dir->msg, jobcmd, &JobId, job.c_str(), job_name.c_str(),
81               client_name.c_str(),
82               &JobType, &level, fileset_name.c_str(), &no_attributes,
83               &spool_attributes, fileset_md5.c_str(), &spool_data,
84               &write_part_after_job, &PreferMountedVols, spool_size,
85               &rerunning, &jcr->VolSessionId, &jcr->VolSessionTime,
86               &is_client, &sd_auth_key);
87    if (stat != 19) {
88       pm_strcpy(jcr->errmsg, dir->msg);
89       dir->fsend(BAD_job, stat, jcr->errmsg);
90       Dmsg1(100, ">dird: %s", dir->msg);
91       jcr->setJobStatus(JS_ErrorTerminated);
92       return false;
93    }
94    jcr->rerunning = rerunning;
95    jcr->sd_client = is_client;
96    if (is_client) {
97       jcr->sd_auth_key = bstrdup(sd_auth_key);
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    set_jcr_in_tsd(jcr);
114
115    /*
116     * If job rescheduled because previous was incomplete,
117     * the Resched flag is set and VolSessionId and VolSessionTime
118     * are given to us (same as restarted job).
119     */
120    if (!jcr->rerunning) {
121       jcr->VolSessionId = newVolSessionId();
122       jcr->VolSessionTime = VolSessionTime;
123    }
124    bstrncpy(jcr->Job, job, sizeof(jcr->Job));
125    unbash_spaces(job_name);
126    jcr->job_name = get_pool_memory(PM_NAME);
127    pm_strcpy(jcr->job_name, job_name);
128    unbash_spaces(client_name);
129    jcr->client_name = get_pool_memory(PM_NAME);
130    pm_strcpy(jcr->client_name, client_name);
131    unbash_spaces(fileset_name);
132    jcr->fileset_name = get_pool_memory(PM_NAME);
133    pm_strcpy(jcr->fileset_name, fileset_name);
134    jcr->setJobType(JobType);
135    jcr->setJobLevel(level);
136    jcr->no_attributes = no_attributes;
137    jcr->spool_attributes = spool_attributes;
138    jcr->spool_data = spool_data;
139    jcr->spool_size = str_to_int64(spool_size);
140    jcr->write_part_after_job = write_part_after_job;
141    jcr->fileset_md5 = get_pool_memory(PM_NAME);
142    pm_strcpy(jcr->fileset_md5, fileset_md5);
143    jcr->PreferMountedVols = PreferMountedVols;
144
145
146    jcr->authenticated = false;
147
148    /*
149     * Pass back an authorization key for the File daemon
150     */
151    if (jcr->sd_client) {
152       bstrncpy(sd_auth_key, "xxx", 3);
153    } else {
154       bsnprintf(seed, sizeof(seed), "%p%d", jcr, JobId);
155       make_session_key(sd_auth_key, seed, 1);
156    }
157    dir->fsend(OKjob, jcr->VolSessionId, jcr->VolSessionTime, sd_auth_key);
158    Dmsg2(150, ">dird jid=%u: %s", (uint32_t)jcr->JobId, dir->msg);
159    /* If not client, set key, otherwise it is already set */
160    if (!jcr->sd_client) {
161       jcr->sd_auth_key = bstrdup(sd_auth_key);
162       memset(sd_auth_key, 0, sizeof(sd_auth_key));
163    }
164    new_plugins(jcr);            /* instantiate the plugins */
165    generate_daemon_event(jcr, "JobStart");
166    generate_plugin_event(jcr, bsdEventJobStart, (void *)"JobStart");
167    return true;
168 }
169
170 bool run_cmd(JCR *jcr)
171 {
172    struct timeval tv;
173    struct timezone tz;
174    struct timespec timeout;
175    int errstat = 0;
176
177    Dsm_check(200);
178    Dmsg1(200, "Run_cmd: %s\n", jcr->dir_bsock->msg);
179
180    /* If we do not need the FD, we are doing a virtual backup. */
181    if (jcr->no_client_used()) {
182       do_vbackup(jcr);
183       return false;
184    }
185
186    jcr->sendJobStatus(JS_WaitFD);          /* wait for FD to connect */
187
188    Dmsg2(050, "sd_calls_client=%d sd_client=%d\n", jcr->sd_calls_client, jcr->sd_client);
189    if (jcr->sd_calls_client) {
190       if (!read_client_hello(jcr)) {
191          return false;
192       }
193       /*
194        * Authenticate the File daemon
195        */
196       Dmsg0(050, "=== Authenticate FD\n");
197       if (jcr->authenticated || !authenticate_filed(jcr, jcr->file_bsock, jcr->FDVersion)) {
198          Dmsg1(050, "Authentication failed Job %s\n", jcr->Job);
199          Jmsg(jcr, M_FATAL, 0, _("Unable to authenticate File daemon\n"));
200       } else {
201          jcr->authenticated = true;
202       }
203    } else if (!jcr->sd_client) {
204       /* We wait to receive connection from Client */
205       gettimeofday(&tv, &tz);
206       timeout.tv_nsec = tv.tv_usec * 1000;
207       timeout.tv_sec = tv.tv_sec + me->client_wait;
208
209       Dmsg3(050, "%s waiting %d sec for FD to contact SD key=%s\n",
210             jcr->Job, (int)(timeout.tv_sec-time(NULL)), jcr->sd_auth_key);
211
212       Dmsg3(800, "=== Block Job=%s jid=%d %p\n", jcr->Job, jcr->JobId, jcr);
213
214       /*
215        * Wait for the File daemon to contact us to start the Job,
216        *  when he does, we will be released, unless the 30 minutes
217        *  expires.
218        */
219       P(mutex);
220       while ( !jcr->authenticated && !job_canceled(jcr) ) {
221          errstat = pthread_cond_timedwait(&jcr->job_start_wait, &mutex, &timeout);
222          if (errstat == ETIMEDOUT || errstat == EINVAL || errstat == EPERM) {
223             break;
224          }
225          Dmsg1(800, "=== Auth cond errstat=%d\n", errstat);
226       }
227       Dmsg4(050, "=== Auth=%d jid=%d canceled=%d errstat=%d\n",
228          jcr->JobId, jcr->authenticated, job_canceled(jcr), errstat);
229       V(mutex);
230       Dmsg2(800, "Auth fail or cancel for jid=%d %p\n", jcr->JobId, jcr);
231    }
232
233    memset(jcr->sd_auth_key, 0, strlen(jcr->sd_auth_key));
234
235    if (jcr->authenticated && !job_canceled(jcr)) {
236       Dmsg2(800, "Running jid=%d %p\n", jcr->JobId, jcr);
237       run_job(jcr);                   /* Run the job */
238    }
239    Dmsg2(800, "Done jid=%d %p\n", jcr->JobId, jcr);
240    return false;
241 }
242
243
244 #ifdef needed
245 /*
246  *   Query Device command from Director
247  *   Sends Storage Daemon's information on the device to the
248  *    caller (presumably the Director).
249  *   This command always returns "true" so that the line is
250  *    not closed on an error.
251  *
252  */
253 bool query_cmd(JCR *jcr)
254 {
255    POOL_MEM dev_name, VolumeName, MediaType, ChangerName;
256    BSOCK *dir = jcr->dir_bsock;
257    DEVRES *device;
258    AUTOCHANGER *changer;
259    bool ok;
260
261    Dmsg1(100, "Query_cmd: %s", dir->msg);
262    ok = sscanf(dir->msg, query_device, dev_name.c_str()) == 1;
263    Dmsg1(100, "<dird: %s\n", dir->msg);
264    if (ok) {
265       unbash_spaces(dev_name);
266       foreach_res(device, R_DEVICE) {
267          /* Find resource, and make sure we were able to open it */
268          if (strcmp(dev_name.c_str(), device->hdr.name) == 0) {
269             if (!device->dev) {
270                device->dev = init_dev(jcr, device);
271             }
272             if (!device->dev) {
273                break;
274             }
275             ok = dir_update_device(jcr, device->dev);
276             if (ok) {
277                ok = dir->fsend(OK_query);
278             } else {
279                dir->fsend(NO_query);
280             }
281             return ok;
282          }
283       }
284       foreach_res(changer, R_AUTOCHANGER) {
285          /* Find resource, and make sure we were able to open it */
286          if (strcmp(dev_name.c_str(), changer->hdr.name) == 0) {
287             if (!changer->device || changer->device->size() == 0) {
288                continue;              /* no devices */
289             }
290             ok = dir_update_changer(jcr, changer);
291             if (ok) {
292                ok = dir->fsend(OK_query);
293             } else {
294                dir->fsend(NO_query);
295             }
296             return ok;
297          }
298       }
299       /* If we get here, the device/autochanger was not found */
300       unbash_spaces(dir->msg);
301       pm_strcpy(jcr->errmsg, dir->msg);
302       dir->fsend(NO_device, dev_name.c_str());
303       Dmsg1(100, ">dird: %s\n", dir->msg);
304    } else {
305       unbash_spaces(dir->msg);
306       pm_strcpy(jcr->errmsg, dir->msg);
307       dir->fsend(BAD_query, jcr->errmsg);
308       Dmsg1(100, ">dird: %s\n", dir->msg);
309    }
310
311    return true;
312 }
313
314 #endif
315
316
317 /*
318  * Destroy the Job Control Record and associated
319  * resources (sockets).
320  */
321 void stored_free_jcr(JCR *jcr)
322 {
323    Dmsg2(800, "End Job JobId=%u %p\n", jcr->JobId, jcr);
324    if (jcr->jobmedia_queue) {
325       flush_jobmedia_queue(jcr);
326       delete jcr->jobmedia_queue;
327       jcr->jobmedia_queue = NULL;
328    }
329    if (jcr->dir_bsock) {
330       Dmsg2(800, "Send terminate jid=%d %p\n", jcr->JobId, jcr);
331       jcr->dir_bsock->signal(BNET_EOD);
332       jcr->dir_bsock->signal(BNET_TERMINATE);
333    }
334    free_bsock(jcr->file_bsock);
335    if (jcr->job_name) {
336       free_pool_memory(jcr->job_name);
337    }
338    if (jcr->client_name) {
339       free_memory(jcr->client_name);
340       jcr->client_name = NULL;
341    }
342    if (jcr->fileset_name) {
343       free_memory(jcr->fileset_name);
344    }
345    if (jcr->fileset_md5) {
346       free_memory(jcr->fileset_md5);
347    }
348    if (jcr->bsr) {
349       free_bsr(jcr->bsr);
350       jcr->bsr = NULL;
351    }
352    /* Free any restore volume list created */
353    free_restore_volume_list(jcr);
354    if (jcr->RestoreBootstrap) {
355       unlink(jcr->RestoreBootstrap);
356       free_pool_memory(jcr->RestoreBootstrap);
357       jcr->RestoreBootstrap = NULL;
358    }
359    if (jcr->next_dev || jcr->prev_dev) {
360       Emsg0(M_FATAL, 0, _("In free_jcr(), but still attached to device!!!!\n"));
361    }
362    pthread_cond_destroy(&jcr->job_start_wait);
363    if (jcr->dcrs) {
364       delete jcr->dcrs;
365    }
366    jcr->dcrs = NULL;
367
368    /* Avoid a double free */
369    if (jcr->dcr == jcr->read_dcr) {
370       jcr->read_dcr = NULL;
371    }
372    if (jcr->dcr) {
373       free_dcr(jcr->dcr);
374       jcr->dcr = NULL;
375    }
376    if (jcr->read_dcr) {
377       free_dcr(jcr->read_dcr);
378       jcr->read_dcr = NULL;
379    }
380
381    if (jcr->read_store) {
382       DIRSTORE *store;
383       foreach_alist(store, jcr->read_store) {
384          delete store->device;
385          delete store;
386       }
387       delete jcr->read_store;
388       jcr->read_store = NULL;
389    }
390    if (jcr->write_store) {
391       DIRSTORE *store;
392       foreach_alist(store, jcr->write_store) {
393          delete store->device;
394          delete store;
395       }
396       delete jcr->write_store;
397       jcr->write_store = NULL;
398    }
399    Dsm_check(200);
400
401    if (jcr->JobId != 0)
402       write_state_file(me->working_directory, "bacula-sd", get_first_port_host_order(me->sdaddrs));
403
404    return;
405 }