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