]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/filed/job.c
cfd78f82bdb910c6fc84679f6b6df8cad5507451
[bacula/bacula] / bacula / src / filed / job.c
1 /*
2  *  Bacula File Daemon Job processing
3  *
4  *    Kern Sibbald, October MM
5  *
6  *   Version $Id$
7  *
8  */
9 /*
10    Copyright (C) 2000, 2001, 2002 Kern Sibbald and John Walker
11
12    This program is free software; you can redistribute it and/or
13    modify it under the terms of the GNU General Public License as
14    published by the Free Software Foundation; either version 2 of
15    the License, or (at your option) any later version.
16
17    This program is distributed in the hope that it will be useful,
18    but WITHOUT ANY WARRANTY; without even the implied warranty of
19    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20    General Public License for more details.
21
22    You should have received a copy of the GNU General Public
23    License along with this program; if not, write to the Free
24    Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
25    MA 02111-1307, USA.
26
27  */
28
29 #include "bacula.h"
30 #include "filed.h"
31
32 extern char my_name[];
33 extern CLIENT *me;                    /* our client resource */
34                         
35 /* Imported functions */
36 extern int status_cmd(JCR *jcr);
37                                    
38 /* Forward referenced functions */
39 static int backup_cmd(JCR *jcr);
40 static int bootstrap_cmd(JCR *jcr);
41 static int cancel_cmd(JCR *jcr);
42 static int setdebug_cmd(JCR *jcr);
43 static int estimate_cmd(JCR *jcr);
44 static int exclude_cmd(JCR *jcr);
45 static int hello_cmd(JCR *jcr);
46 static int job_cmd(JCR *jcr);
47 static int include_cmd(JCR *jcr);
48 static int level_cmd(JCR *jcr);
49 static int verify_cmd(JCR *jcr);
50 static int restore_cmd(JCR *jcr);
51 static int storage_cmd(JCR *jcr);
52 static int session_cmd(JCR *jcr);
53 static int response(BSOCK *sd, char *resp, char *cmd);
54 static void filed_free_jcr(JCR *jcr);
55 static int open_sd_read_session(JCR *jcr);
56 static int send_bootstrap_file(JCR *jcr);
57
58
59 /* Exported functions */
60
61 struct s_cmds {
62    char *cmd;
63    int (*func)(JCR *);
64 };
65
66 /*  
67  * The following are the recognized commands from the Director. 
68  */
69 static struct s_cmds cmds[] = {
70    {"backup",   backup_cmd},
71    {"cancel",   cancel_cmd},
72    {"setdebug=", setdebug_cmd},
73    {"estimate", estimate_cmd},
74    {"exclude",  exclude_cmd},
75    {"Hello",    hello_cmd},
76    {"include",  include_cmd},
77    {"JobId=",   job_cmd},
78    {"level = ", level_cmd},
79    {"restore",  restore_cmd},
80    {"session",  session_cmd},
81    {"status",   status_cmd},
82    {"storage ", storage_cmd},
83    {"verify",   verify_cmd},
84    {"bootstrap",bootstrap_cmd},
85    {NULL,       NULL}                  /* list terminator */
86 };
87
88 /* Commands received from director that need scanning */
89 static char jobcmd[]     = "JobId=%d Job=%127s SDid=%d SDtime=%d Authorization=%100s";
90 static char storaddr[]   = "storage address=%s port=%d\n";
91 static char sessioncmd[] = "session %s %ld %ld %ld %ld %ld %ld\n";
92 static char restorecmd[] = "restore where=%s\n";
93 static char verifycmd[]  = "verify level=%20s\n";
94
95 /* Responses sent to Director */
96 static char errmsg[]       = "2999 Invalid command\n";
97 static char no_auth[]      = "2998 No Authorization\n";
98 static char OKinc[]        = "2000 OK include\n";
99 static char OKest[]        = "2000 OK estimate files=%ld bytes=%ld\n";
100 static char OKexc[]        = "2000 OK exclude\n";
101 static char OKlevel[]      = "2000 OK level\n";
102 static char OKbackup[]     = "2000 OK backup\n";
103 static char OKbootstrap[]  = "2000 OK bootstrap\n";
104 static char OKverify[]     = "2000 OK verify\n";
105 static char OKrestore[]    = "2000 OK restore\n";
106 static char OKsession[]    = "2000 OK session\n";
107 static char OKstore[]      = "2000 OK storage\n";
108 static char OKjob[]        = "2000 OK Job\n";
109 static char OKsetdebug[]   = "2000 OK setdebug=%d\n";
110 static char BADjob[]       = "2901 Bad Job\n";
111 static char EndRestore[]   = "2800 End Job TermCode=%d JobFiles=%u JobBytes=%" lld "\n";
112 static char EndBackup[]    = "2801 End Backup Job TermCode=%d JobFiles=%u ReadBytes=%" lld " JobBytes=%" lld "\n";
113
114 /* Responses received from Storage Daemon */
115 static char OK_end[]       = "3000 OK end\n";
116 static char OK_open[]      = "3000 OK open ticket = %d\n";
117 static char OK_data[]      = "3000 OK data\n";
118 static char OK_append[]    = "3000 OK append data\n";
119 static char OKSDbootstrap[] = "3000 OK bootstrap\n";
120
121
122 /* Commands sent to Storage Daemon */
123 static char append_open[]  = "append open session\n";
124 static char append_data[]  = "append data %d\n";
125 static char append_end[]   = "append end session %d\n";
126 static char append_close[] = "append close session %d\n";
127 static char read_open[]    = "read open session = %s %ld %ld %ld %ld %ld %ld\n";
128 static char read_data[]    = "read data %d\n";
129 static char read_close[]   = "read close session %d\n";
130
131 /* 
132  * Accept requests from a Director
133  *
134  * NOTE! We are running as a separate thread
135  *
136  * Send output one line
137  * at a time followed by a zero length transmission.
138  *
139  * Return when the connection is terminated or there
140  * is an error.
141  *
142  * Basic task here is:
143  *   Authenticate Director (during Hello command).
144  *   Accept commands one at a time from the Director
145  *     and execute them.
146  *
147  */
148 void *handle_client_request(void *dirp)
149 {
150    int i, found, quit;
151    JCR *jcr;
152    BSOCK *dir = (BSOCK *)dirp;
153
154    jcr = new_jcr(sizeof(JCR), filed_free_jcr); /* create JCR */
155    jcr->dir_bsock = dir;
156    jcr->ff = init_find_files();
157    jcr->start_time = time(NULL);
158    jcr->last_fname = get_pool_memory(PM_FNAME);
159    jcr->client_name = get_memory(strlen(my_name) + 1);
160    strcpy(jcr->client_name, my_name);
161    dir->jcr = (void *)jcr;
162
163    /**********FIXME******* add command handler error code */
164
165    for (quit=0; !quit;) {
166
167       /* Read command */
168       if (bnet_recv(dir) <= 0) {
169          break;                       /* connection terminated */
170       }
171       dir->msg[dir->msglen] = 0;
172       Dmsg1(100, "<dird: %s", dir->msg);
173       found = FALSE;
174       for (i=0; cmds[i].cmd; i++) {
175          if (strncmp(cmds[i].cmd, dir->msg, strlen(cmds[i].cmd)) == 0) {
176             if (!jcr->authenticated && cmds[i].func != hello_cmd) {
177                bnet_fsend(dir, no_auth);
178                break;
179             }
180             if (!cmds[i].func(jcr)) {    /* do command */
181                quit = TRUE;              /* error, get out */
182                Pmsg0(20, "Command error\n");
183             }
184             found = TRUE;            /* indicate command found */
185             break;
186          }
187       }
188       if (!found) {                   /* command not found */
189          bnet_fsend(dir, errmsg);
190          quit = TRUE;
191          break;
192       }
193    }
194    Dmsg0(100, "Calling term_find_files\n");
195    term_find_files(jcr->ff);
196    Dmsg0(100, "Done with term_find_files\n");
197    free_jcr(jcr);                     /* destroy JCR record */
198    Dmsg0(100, "Done with free_jcr\n");
199    return NULL;
200 }
201
202 /*
203  * Hello from Director he must identify himself and provide his 
204  *  password.
205  */
206 static int hello_cmd(JCR *jcr)
207 {
208    Dmsg0(120, "Calling Authenticate\n");
209    if (!authenticate_director(jcr)) {
210       return 0;
211    }
212    Dmsg0(120, "OK Authenticate\n");
213    jcr->authenticated = TRUE;
214    return 1;
215 }
216
217 /*
218  * Cancel a Job
219  */
220 static int cancel_cmd(JCR *jcr)
221 {
222    BSOCK *dir = jcr->dir_bsock;
223    char Job[MAX_NAME_LENGTH];
224    JCR *cjcr;
225
226    if (sscanf(dir->msg, "cancel Job=%127s", Job) == 1) {
227       if (!(cjcr=get_jcr_by_full_name(Job))) {
228          bnet_fsend(dir, "2901 Job %s not found.\n", Job);
229       } else {
230          cjcr->JobStatus = JS_Cancelled;
231          free_jcr(cjcr);
232          bnet_fsend(dir, "2001 Job %s marked to be cancelled.\n", Job);
233       }
234    } else {
235       bnet_fsend(dir, "2902 Error scanning cancel command.\n");
236    }
237    bnet_sig(dir, BNET_EOD);
238    return 1;
239 }
240
241
242 /*
243  * Set debug level as requested by the Director
244  *
245  */
246 static int setdebug_cmd(JCR *jcr)
247 {
248    BSOCK *dir = jcr->dir_bsock;
249    int level;
250
251    Dmsg1(110, "setdebug_cmd: %s", dir->msg);
252    if (sscanf(dir->msg, "setdebug=%d", &level) != 1 || level < 0) {
253       bnet_fsend(dir, "2991 Bad setdebug command: %s\n", dir->msg);
254       return 0;   
255    }
256    debug_level = level;
257    return bnet_fsend(dir, OKsetdebug, level);
258 }
259
260
261 static int estimate_cmd(JCR *jcr)
262 {
263    BSOCK *dir = jcr->dir_bsock;
264    make_estimate(jcr);
265    return bnet_fsend(dir, OKest, jcr->num_files_examined, jcr->JobBytes);
266 }
267
268 /*
269  * Get JobId and Storage Daemon Authorization key from Director
270  */
271 static int job_cmd(JCR *jcr)
272 {
273    BSOCK *dir = jcr->dir_bsock;
274    POOLMEM *sd_auth_key;
275
276    sd_auth_key = get_memory(dir->msglen);
277    if (sscanf(dir->msg, jobcmd,  &jcr->JobId, jcr->Job,  
278               &jcr->VolSessionId, &jcr->VolSessionTime,
279               sd_auth_key) != 5) {
280       bnet_fsend(dir, BADjob);
281       Jmsg(jcr, M_FATAL, 0, _("Bad Job Command: %s\n"), dir->msg);
282       free_pool_memory(sd_auth_key);
283       return 0;
284    }
285    jcr->sd_auth_key = bstrdup(sd_auth_key);
286    free_pool_memory(sd_auth_key);
287    Dmsg2(120, "JobId=%d Auth=%s\n", jcr->JobId, jcr->sd_auth_key);
288    return bnet_fsend(dir, OKjob);
289 }
290
291 /* 
292  * 
293  * Get list of files/directories to include from Director
294  *
295  */
296 static int include_cmd(JCR *jcr)
297 {
298    BSOCK *dir = jcr->dir_bsock;
299
300    while (bnet_recv(dir) > 0) {
301        dir->msg[dir->msglen] = 0;
302        strip_trailing_junk(dir->msg);
303        Dmsg1(110, "filed<dird: include file %s\n", dir->msg);
304        add_fname_to_include_list(jcr->ff, 1, dir->msg);
305    }
306
307    return bnet_fsend(dir, OKinc);
308 }
309
310 /*
311  * Get list of files to exclude from Director
312  *
313  */
314 static int exclude_cmd(JCR *jcr)
315 {
316    BSOCK *dir = jcr->dir_bsock;
317    char *p;  
318
319    while (bnet_recv(dir) > 0) {
320        dir->msg[dir->msglen] = 0;
321        strip_trailing_junk(dir->msg);
322        /* Skip leading options */
323        for (p=dir->msg; *p && *p != ' '; p++)
324           { }
325        /* Skip spaces */
326        for ( ; *p && *p == ' '; p++)
327           { }
328        add_fname_to_exclude_list(jcr->ff, p);
329        Dmsg1(110, "<dird: exclude file %s\n", dir->msg);
330    }
331
332    return bnet_fsend(dir, OKexc);
333 }
334
335
336 static int bootstrap_cmd(JCR *jcr)
337 {
338    BSOCK *dir = jcr->dir_bsock;
339    POOLMEM *fname = get_pool_memory(PM_FNAME);
340    FILE *bs;
341
342    if (jcr->RestoreBootstrap) {
343       unlink(jcr->RestoreBootstrap);
344       free_pool_memory(jcr->RestoreBootstrap);
345    }
346    Mmsg(&fname, "%s/%s.%s.bootstrap", me->working_directory, me->hdr.name,
347       jcr->Job);
348    Dmsg1(400, "bootstrap=%s\n", fname);
349    jcr->RestoreBootstrap = fname;
350    bs = fopen(fname, "a+");           /* create file */
351    if (!bs) {
352       Jmsg(jcr, M_FATAL, 0, _("Could not create bootstrap file %s: ERR=%s\n"),
353          jcr->RestoreBootstrap, strerror(errno));
354       free_pool_memory(jcr->RestoreBootstrap);
355       jcr->RestoreBootstrap = NULL;
356       return 0;
357    }
358
359    while (bnet_recv(dir) > 0) {
360        Dmsg1(200, "filed<dird: bootstrap file %s\n", dir->msg);
361        fputs(dir->msg, bs);
362    }
363    fclose(bs);
364
365    return bnet_fsend(dir, OKbootstrap);
366 }
367
368
369 /*
370  * Get backup level from Director
371  *
372  */
373 static int level_cmd(JCR *jcr)
374 {
375    BSOCK *dir = jcr->dir_bsock;
376    char *level;
377    struct tm tm;
378    time_t mtime;
379
380    level = (char *) get_memory(dir->msglen);
381    Dmsg1(110, "level_cmd: %s", dir->msg);
382    if (sscanf(dir->msg, "level = %s ", level) != 1) {
383       Jmsg1(jcr, M_FATAL, 0, _("Bad level command: %s\n"), dir->msg);
384       free_memory(level);
385       return 0;
386    }
387    /*
388     * Full backup requested
389     */
390    if (strcmp(level, "full") == 0) {
391       jcr->save_level = L_FULL;
392    /* 
393     * Backup requested since <date> <time>
394     *  This form is also used for incremental and differential
395     */
396    } else if (strcmp(level, "since") == 0) {
397       jcr->save_level = L_SINCE;
398       if (sscanf(dir->msg, "level = since %d-%d-%d %d:%d:%d", 
399                  &tm.tm_year, &tm.tm_mon, &tm.tm_mday,
400                  &tm.tm_hour, &tm.tm_min, &tm.tm_sec) != 6) {
401          Jmsg1(jcr, M_FATAL, 0, "Bad scan of date/time: %s\n", dir->msg);
402          free_memory(level);
403          return 0;
404       }
405       tm.tm_year -= 1900;
406       tm.tm_mon  -= 1;
407       tm.tm_wday = tm.tm_yday = 0;              
408       tm.tm_isdst = -1;
409       mtime = mktime(&tm);
410       Dmsg1(100, "Got since time: %s", ctime(&mtime));
411       jcr->incremental = 1;
412       jcr->mtime = mtime;
413    } else {
414       Jmsg1(jcr, M_FATAL, 0, "Unknown backup level: %s\n", level);
415       free_memory(level);
416       return 0;
417    }
418    free_memory(level);
419    return bnet_fsend(dir, OKlevel);
420 }
421
422 /*
423  * Get session parameters from Director -- this is for a Restore command
424  */
425 static int session_cmd(JCR *jcr)
426 {
427    BSOCK *dir = jcr->dir_bsock;
428
429    Dmsg1(100, "SessionCmd: %s", dir->msg);
430    if (sscanf(dir->msg, sessioncmd, jcr->VolumeName,
431               &jcr->VolSessionId, &jcr->VolSessionTime,
432               &jcr->StartFile, &jcr->EndFile, 
433               &jcr->StartBlock, &jcr->EndBlock) != 7) {
434       Jmsg(jcr, M_FATAL, 0, "Bad session command: %s", dir->msg);
435       return 0;
436    }
437
438    return bnet_fsend(dir, OKsession);
439 }
440
441 /*
442  * Get address of storage daemon from Director
443  *
444  */
445 static int storage_cmd(JCR *jcr)
446 {
447    int stored_port;                /* storage daemon port */
448    BSOCK *dir = jcr->dir_bsock;
449    BSOCK *sd;                         /* storage daemon bsock */
450
451    Dmsg1(100, "StorageCmd: %s", dir->msg);
452    if (sscanf(dir->msg, storaddr, &jcr->stored_addr, &stored_port) != 2) {
453       Jmsg(jcr, M_FATAL, 0, _("Bad storage command: %s"), dir->msg);
454       return 0;
455    }
456    Dmsg2(110, "Open storage: %s:%d\n", jcr->stored_addr, stored_port);
457    /* Open command communications with Storage daemon */
458    /* Try to connect for 1 hour at 10 second intervals */
459    sd = bnet_connect(jcr, 10, 3600, _("Storage daemon"), 
460                      jcr->stored_addr, NULL, stored_port, 1);
461    if (sd == NULL) {
462       Jmsg(jcr, M_FATAL, 0, _("Failed to connect to Storage daemon: %s:%d\n"),
463           jcr->stored_addr, stored_port);
464       return 0;
465    }
466
467    jcr->store_bsock = sd;
468
469    bnet_fsend(sd, "Hello Start Job %s\n", jcr->Job);
470    if (!authenticate_storagedaemon(jcr)) {
471       Jmsg(jcr, M_FATAL, 0, _("Failed to authenticate Storage daemon.\n"));
472       return 0;
473    }
474    Dmsg0(110, "Authenticated with SD.\n");
475
476    /* Send OK to Director */
477    return bnet_fsend(dir, OKstore);
478 }
479
480
481 /*  
482  * Do a backup. For now, we handle only Full and Incremental.
483  */
484 static int backup_cmd(JCR *jcr)
485
486    BSOCK *dir = jcr->dir_bsock;
487    BSOCK *sd = jcr->store_bsock;
488    int len;
489
490    jcr->JobStatus = JS_Blocked;
491    jcr->JobType = JT_BACKUP;
492    Dmsg1(100, "begin backup ff=%p\n", jcr->ff);
493
494    if (sd == NULL) {
495       Jmsg(jcr, M_FATAL, 0, _("Cannot contact Storage daemon\n"));
496       jcr->JobStatus = JS_ErrorTerminated;
497       goto cleanup;
498    }
499
500    bnet_fsend(dir, OKbackup);
501    Dmsg1(110, "bfiled>dird: %s", dir->msg);
502
503    /* 
504     * Send Append Open Session to Storage daemon
505     */
506    bnet_fsend(sd, append_open);
507    Dmsg1(110, ">stored: %s", sd->msg);
508    /* 
509     * Expect to receive back the Ticket number
510     */
511    if (bnet_recv(sd) > 0) {
512       Dmsg1(110, "<stored: %s", sd->msg);
513       if (sscanf(sd->msg, OK_open, &jcr->Ticket) != 1) {
514          Jmsg(jcr, M_FATAL, 0, _("Bad response to append open: %s\n"), sd->msg);
515          jcr->JobStatus = JS_ErrorTerminated;
516          goto cleanup;
517       }
518       Dmsg1(110, "Got Ticket=%d\n", jcr->Ticket);
519    } else {
520       Jmsg(jcr, M_FATAL, 0, _("Bad response from stored to open command\n"));
521       jcr->JobStatus = JS_ErrorTerminated;
522       goto cleanup;
523    }
524
525    /* 
526     * Send Append data command to Storage daemon
527     */
528    bnet_fsend(sd, append_data, jcr->Ticket);
529    Dmsg1(110, ">stored: %s", sd->msg);
530
531    /* 
532     * Expect to get OK data 
533     */
534    Dmsg1(110, "<stored: %s", sd->msg);
535    if (!response(sd, OK_data, "Append Data")) {
536       jcr->JobStatus = JS_ErrorTerminated;
537       goto cleanup;
538    }
539       
540    /*
541     * Send Files to Storage daemon
542     */
543    Dmsg1(110, "begin blast ff=%p\n", jcr->ff);
544    if (!blast_data_to_storage_daemon(jcr, NULL)) {
545       jcr->JobStatus = JS_ErrorTerminated;
546    } else {
547       jcr->JobStatus = JS_Terminated;
548       /* 
549        * Expect to get response to append_data from Storage daemon
550        */
551       if (!response(sd, OK_append, "Append Data")) {
552          jcr->JobStatus = JS_ErrorTerminated;
553          goto cleanup;
554       }
555      
556       /* 
557        * Send Append End Data to Storage daemon
558        */
559       bnet_fsend(sd, append_end, jcr->Ticket);
560       /* Get end OK */
561       if (!response(sd, OK_end, "Append End")) {
562          jcr->JobStatus = JS_ErrorTerminated;
563          goto cleanup;
564       }
565
566       /*
567        * Send Append Close to Storage daemon
568        */
569       bnet_fsend(sd, append_close, jcr->Ticket);
570       while ((len = bnet_recv(sd)) > 0) {
571           /* discard anything else returned from SD */
572       }
573       if (len < 0) {
574          Jmsg(jcr, M_FATAL, 0, _("<stored: net_recv len=%d: ERR=%s\n"), len, bnet_strerror(sd));
575          jcr->JobStatus = JS_ErrorTerminated;
576       }
577    }
578
579 cleanup:
580
581    /* Inform Storage daemon that we are done */
582    if (sd) {
583       bnet_sig(sd, BNET_TERMINATE);
584    }
585
586    bnet_fsend(dir, EndBackup, jcr->JobStatus, jcr->JobFiles, jcr->ReadBytes, jcr->JobBytes);
587
588    /* Inform Director that we are done */
589    bnet_sig(dir, BNET_TERMINATE);
590
591    return jcr->JobStatus == JS_Terminated;
592 }
593
594 /*  
595  * Do a Verify for Director
596  *
597  */
598 static int verify_cmd(JCR *jcr)
599
600    BSOCK *dir = jcr->dir_bsock;
601    BSOCK *sd  = jcr->store_bsock;
602    char level[100];
603
604    jcr->JobType = JT_VERIFY;
605    if (sscanf(dir->msg, verifycmd, level) != 1) {
606       bnet_fsend(dir, "2994 Bad verify command: %s\n", dir->msg);
607       return 0;   
608    }
609    if (strcasecmp(level, "init") == 0) {
610       jcr->JobLevel = L_VERIFY_INIT;
611    } else if (strcasecmp(level, "catalog") == 0){
612       jcr->JobLevel = L_VERIFY_CATALOG;
613    } else if (strcasecmp(level, "volume") == 0){
614       jcr->JobLevel = L_VERIFY_VOLUME_TO_CATALOG;
615    } else if (strcasecmp(level, "data") == 0){
616       jcr->JobLevel = L_VERIFY_DATA;
617    } else {   
618       bnet_fsend(dir, "2994 Bad verify level: %s\n", dir->msg);
619       return 0;   
620    }
621
622    bnet_fsend(dir, OKverify);
623    Dmsg1(110, "bfiled>dird: %s", dir->msg);
624
625    switch (jcr->JobLevel) {
626    case L_VERIFY_INIT:
627    case L_VERIFY_CATALOG:
628       do_verify(jcr);
629       break;
630    case L_VERIFY_VOLUME_TO_CATALOG:
631       if (!open_sd_read_session(jcr)) {
632          return 0;
633       }
634       do_verify_volume(jcr);
635       /* 
636        * Send Close session command to Storage daemon
637        */
638       bnet_fsend(sd, read_close, jcr->Ticket);
639       Dmsg1(130, "bfiled>stored: %s", sd->msg);
640
641       /* ****FIXME**** check response */
642       bnet_recv(sd);                     /* get OK */
643
644       /* Inform Storage daemon that we are done */
645       bnet_sig(sd, BNET_TERMINATE);
646
647       break;
648    default:
649       bnet_fsend(dir, "2994 Bad verify level: %s\n", dir->msg);
650       return 0; 
651    }
652
653    /* Inform Director that we are done */
654    return bnet_sig(dir, BNET_TERMINATE);
655 }
656
657 /*  
658  * Do a Restore for Director
659  *
660  */
661 static int restore_cmd(JCR *jcr)
662
663    BSOCK *dir = jcr->dir_bsock;
664    BSOCK *sd = jcr->store_bsock;
665    POOLMEM *where;
666
667    /*
668     * Scan WHERE (base directory for restore) from command
669     */
670    Dmsg0(150, "restore command\n");
671    /* Pickup where string */
672    where = get_memory(dir->msglen+1);
673    *where = 0;
674    sscanf(dir->msg, restorecmd, where);
675    Dmsg1(150, "Got where=%s\n", where);
676    jcr->where = where;
677
678    bnet_fsend(dir, OKrestore);
679    Dmsg1(110, "bfiled>dird: %s", dir->msg);
680
681    jcr->JobType = JT_RESTORE;
682    jcr->JobStatus = JS_Blocked;
683
684    if (!open_sd_read_session(jcr)) {
685       return 0;
686    }
687
688    /* 
689     * Do restore of files and data
690     */
691    do_restore(jcr);
692
693    /* 
694     * Send Close session command to Storage daemon
695     */
696    bnet_fsend(sd, read_close, jcr->Ticket);
697    Dmsg1(130, "bfiled>stored: %s", sd->msg);
698
699    /* ****FIXME**** check response */
700    bnet_recv(sd);                     /* get OK */
701
702    /* Inform Storage daemon that we are done */
703    bnet_sig(sd, BNET_TERMINATE);
704
705    bnet_fsend(dir, EndRestore, jcr->JobStatus, jcr->num_files_examined, jcr->JobBytes);
706
707    /* Inform Director that we are done */
708    bnet_sig(dir, BNET_TERMINATE);
709
710    Dmsg0(130, "Done in job.c\n");
711    return 1;
712 }
713
714 static int open_sd_read_session(JCR *jcr)
715 {
716    BSOCK *sd = jcr->store_bsock;
717
718    if (!sd) {
719       Jmsg(jcr, M_FATAL, 0, _("Improper calling sequence.\n"));
720       return 0;
721    }
722    Dmsg4(120, "VolSessId=%ld VolsessT=%ld SF=%ld EF=%ld\n",
723       jcr->VolSessionId, jcr->VolSessionTime, jcr->StartFile, jcr->EndFile);
724    Dmsg2(120, "JobId=%d vol=%s\n", jcr->JobId, "DummyVolume");
725    /* 
726     * Open Read Session with Storage daemon
727     */
728    bnet_fsend(sd, read_open, jcr->VolumeName,
729       jcr->VolSessionId, jcr->VolSessionTime, jcr->StartFile, jcr->EndFile, 
730       jcr->StartBlock, jcr->EndBlock);
731    Dmsg1(110, ">stored: %s", sd->msg);
732
733    /* 
734     * Get ticket number
735     */
736    if (bnet_recv(sd) > 0) {
737       Dmsg1(110, "bfiled<stored: %s", sd->msg);
738       if (sscanf(sd->msg, OK_open, &jcr->Ticket) != 1) {
739          Jmsg(jcr, M_FATAL, 0, _("Bad response to SD read open: %s\n"), sd->msg);
740          return 0;
741       }
742       Dmsg1(110, "bfiled: got Ticket=%d\n", jcr->Ticket);
743    } else {
744       Jmsg(jcr, M_FATAL, 0, _("Bad response from stored to read open command\n"));
745       return 0;
746    }
747
748    if (!send_bootstrap_file(jcr)) {
749       return 0;
750    }
751
752    /* 
753     * Start read of data with Storage daemon
754     */
755    bnet_fsend(sd, read_data, jcr->Ticket);
756    Dmsg1(110, ">stored: %s", sd->msg);
757
758    /* 
759     * Get OK data
760     */
761    if (!response(sd, OK_data, "Read Data")) {
762       return 0;
763    }
764    return 1;
765 }
766
767 /* 
768  * Destroy the Job Control Record and associated
769  * resources (sockets).
770  */
771 static void filed_free_jcr(JCR *jcr) 
772 {
773    if (jcr->store_bsock) {
774       bnet_close(jcr->store_bsock);
775    }
776    if (jcr->where) {
777       free_pool_memory(jcr->where);
778    }
779    if (jcr->RestoreBootstrap) {
780       unlink(jcr->RestoreBootstrap);
781       free_pool_memory(jcr->RestoreBootstrap);
782    }
783    if (jcr->last_fname) {
784       free_pool_memory(jcr->last_fname);
785    }
786    return;
787 }
788
789 /*
790  * Get response from Storage daemon to a command we
791  * sent. Check that the response is OK.
792  *
793  *  Returns: 0 on failure
794  *           1 on success
795  */
796 int response(BSOCK *sd, char *resp, char *cmd)
797 {
798    int n;
799
800    if (sd->errors) {
801       return 0;
802    }
803    if ((n = bnet_recv(sd)) > 0) {
804       Dmsg0(110, sd->msg);
805       if (strcmp(sd->msg, resp) == 0) {
806          return 1;
807       }
808    } 
809    /* ********FIXME******** segfault if the following is executed */
810    if (n > 0) {
811       Emsg3(M_FATAL, 0, _("<stored: bad response to %s: wanted: %s, got: %s\n"),
812          cmd, resp, sd->msg);
813    } else {
814       Emsg2(M_FATAL, 0, _("<stored: bad response to %s command: ERR=%s\n"),
815          cmd, bnet_strerror(sd));
816    }
817    return 0;
818 }
819
820 static int send_bootstrap_file(JCR *jcr)
821 {
822    FILE *bs;
823    char buf[2000];
824    BSOCK *sd = jcr->store_bsock;
825    char *bootstrap = "bootstrap\n";
826
827    Dmsg1(400, "send_bootstrap_file: %s\n", jcr->RestoreBootstrap);
828    if (!jcr->RestoreBootstrap) {
829       return 1;
830    }
831    bs = fopen(jcr->RestoreBootstrap, "r");
832    if (!bs) {
833       Jmsg(jcr, M_FATAL, 0, _("Could not open bootstrap file %s: ERR=%s\n"), 
834          jcr->RestoreBootstrap, strerror(errno));
835       jcr->JobStatus = JS_ErrorTerminated;
836       return 0;
837    }
838    strcpy(sd->msg, bootstrap);  
839    sd->msglen = strlen(sd->msg);
840    bnet_send(sd);
841    while (fgets(buf, sizeof(buf), bs)) {
842       sd->msglen = Mmsg(&sd->msg, "%s", buf);
843       bnet_send(sd);       
844    }
845    bnet_sig(sd, BNET_EOD);
846    fclose(bs);
847    if (!response(sd, OKSDbootstrap, "Bootstrap")) {
848       jcr->JobStatus = JS_ErrorTerminated;
849       return 0;
850    }
851    return 1;
852 }