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