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