]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/stored/job.c
kes Remove fnmatch() in SD that permitted wild card specifications.
[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 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 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    Dsm_check(1);
154    Dmsg1(200, "Run_cmd: %s\n", jcr->dir_bsock->msg);
155    /* The following jobs don't need the FD */
156    switch (jcr->JobType) {
157    case JT_MIGRATE:
158    case JT_COPY:
159    case JT_ARCHIVE:
160       jcr->authenticated = true;
161       do_mac(jcr);
162       return false;
163    }
164
165    set_jcr_job_status(jcr, JS_WaitFD);          /* wait for FD to connect */
166    dir_send_job_status(jcr);
167
168    gettimeofday(&tv, &tz);
169    timeout.tv_nsec = tv.tv_usec * 1000;
170    timeout.tv_sec = tv.tv_sec + me->client_wait;
171
172    Dmsg2(100, "%s waiting %d sec for FD to contact SD\n", 
173         jcr->Job, (int)me->client_wait);
174    /*
175     * Wait for the File daemon to contact us to start the Job,
176     *  when he does, we will be released, unless the 30 minutes
177     *  expires.
178     */
179    P(mutex);
180    for ( ;!job_canceled(jcr); ) {
181       errstat = pthread_cond_timedwait(&jcr->job_start_wait, &mutex, &timeout);
182       if (errstat == 0 || errstat == ETIMEDOUT) {
183          break;
184       }
185    }
186    V(mutex);
187
188    memset(jcr->sd_auth_key, 0, strlen(jcr->sd_auth_key));
189
190    if (jcr->authenticated && !job_canceled(jcr)) {
191       Dmsg1(100, "Running job %s\n", jcr->Job);
192       run_job(jcr);                   /* Run the job */
193    }
194    return false;
195 }
196
197 /*
198  * After receiving a connection (in job.c) if it is
199  *   from the File daemon, this routine is called.
200  */
201 void handle_filed_connection(BSOCK *fd, char *job_name)
202 {
203    JCR *jcr;
204
205    bmicrosleep(0, 50000);             /* wait 50 millisecs */
206    if (!(jcr=get_jcr_by_full_name(job_name))) {
207       Jmsg1(NULL, M_FATAL, 0, _("Job name not found: %s\n"), job_name);
208       Dmsg1(100, "Job name not found: %s\n", job_name);
209       return;
210    }
211
212    jcr->file_bsock = fd;
213    jcr->file_bsock->set_jcr(jcr);
214
215    Dmsg1(110, "Found Job %s\n", job_name);
216
217    if (jcr->authenticated) {
218       Jmsg2(jcr, M_FATAL, 0, _("Hey!!!! JobId %u Job %s already authenticated.\n"),
219          jcr->JobId, jcr->Job);
220       free_jcr(jcr);
221       return;
222    }
223
224    /*
225     * Authenticate the File daemon
226     */
227    if (jcr->authenticated || !authenticate_filed(jcr)) {
228       Dmsg1(100, "Authentication failed Job %s\n", jcr->Job);
229       Jmsg(jcr, M_FATAL, 0, _("Unable to authenticate File daemon\n"));
230    } else {
231       jcr->authenticated = true;
232       Dmsg1(110, "OK Authentication Job %s\n", jcr->Job);
233    }
234
235    if (!jcr->authenticated) {
236       set_jcr_job_status(jcr, JS_ErrorTerminated);
237    }
238    pthread_cond_signal(&jcr->job_start_wait); /* wake waiting job */
239    free_jcr(jcr);
240    return;
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 = bnet_fsend(dir, OK_query);
278             } else {
279                bnet_fsend(dir, 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 = bnet_fsend(dir, OK_query);
293             } else {
294                bnet_fsend(dir, 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       bnet_fsend(dir, 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       bnet_fsend(dir, 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    Dmsg1(900, "stored_free_jcr JobId=%u\n", jcr->JobId);
324    if (jcr->file_bsock) {
325       bnet_close(jcr->file_bsock);
326       jcr->file_bsock = NULL;
327    }
328    if (jcr->job_name) {
329       free_pool_memory(jcr->job_name);
330    }
331    if (jcr->client_name) {
332       free_memory(jcr->client_name);
333       jcr->client_name = NULL;
334    }
335    if (jcr->fileset_name) {
336       free_memory(jcr->fileset_name);
337    }
338    if (jcr->fileset_md5) {
339       free_memory(jcr->fileset_md5);
340    }
341    if (jcr->bsr) {
342       free_bsr(jcr->bsr);
343       jcr->bsr = NULL;
344    }
345    if (jcr->RestoreBootstrap) {
346       unlink(jcr->RestoreBootstrap);
347       free_pool_memory(jcr->RestoreBootstrap);
348       jcr->RestoreBootstrap = NULL;
349    }
350    if (jcr->next_dev || jcr->prev_dev) {
351       Emsg0(M_FATAL, 0, _("In free_jcr(), but still attached to device!!!!\n"));
352    }
353    pthread_cond_destroy(&jcr->job_start_wait);
354    if (jcr->dcrs) {
355       delete jcr->dcrs;
356    }
357    jcr->dcrs = NULL;
358
359    /* Avoid a double free */
360    if (jcr->dcr == jcr->read_dcr) {
361       jcr->read_dcr = NULL;
362    }
363    if (jcr->dcr) {
364       free_dcr(jcr->dcr);
365       jcr->dcr = NULL;
366    }
367    if (jcr->read_dcr) {
368       free_dcr(jcr->read_dcr);
369       jcr->read_dcr = NULL;
370    }
371
372    if (jcr->read_store) {
373       DIRSTORE *store;
374       foreach_alist(store, jcr->read_store) {
375          delete store->device;
376          delete store;
377       }
378       delete jcr->read_store;
379       jcr->read_store = NULL;
380    }
381    if (jcr->write_store) {
382       DIRSTORE *store;
383       foreach_alist(store, jcr->write_store) {
384          delete store->device;
385          delete store;
386       }
387       delete jcr->write_store;
388       jcr->write_store = NULL;
389    }
390    Dsm_check(1);
391    return;
392 }