1 /*
2    Bacula(R) - The Network Backup Solution
3 
4    Copyright (C) 2000-2020 Kern Sibbald
5 
6    The original author of Bacula is Kern Sibbald, with contributions
7    from many others, a complete list can be found in the file AUTHORS.
8 
9    You may use this file and others of this release according to the
10    license defined in the LICENSE file, which includes the Affero General
11    Public License, v3.0 ("AGPLv3") and some additional permissions and
12    terms pursuant to its AGPLv3 Section 7.
13 
14    This notice must be preserved when any source code is
15    conveyed and/or propagated.
16 
17    Bacula(R) is a registered trademark of Kern Sibbald.
18 */
19 /*
20  *  Bacula File Daemon Job processing
21  *
22  *    Written by Kern Sibbald, October MM
23  */
24 
25 #include "bacula.h"
26 #include "filed.h"
27 #include "ch.h"
28 #ifdef WIN32_VSS
29 #include "vss.h"
30 static pthread_mutex_t vss_mutex = PTHREAD_MUTEX_INITIALIZER;
31 #endif
32 
33 /* Globals */
34 bool win32decomp = false;
35 bool no_win32_write_errors = false;
36 
37 /* Static variables */
38 static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
39 
40 #ifdef HAVE_WIN32
41 const bool have_win32 = true;
42 #else
43 const bool have_win32 = false;
44 #endif
45 
46 #ifdef HAVE_ACL
47 const bool have_acl = true;
48 #else
49 const bool have_acl = false;
50 #endif
51 
52 #if HAVE_XATTR
53 const bool have_xattr = true;
54 #else
55 const bool have_xattr = false;
56 #endif
57 
58 extern CLIENT *me;                    /* our client resource */
59 
60 /* Imported functions */
61 extern int status_cmd(JCR *jcr);
62 extern int qstatus_cmd(JCR *jcr);
63 extern int accurate_cmd(JCR *jcr);
64 extern int collect_cmd(JCR *jcr);
65 
66 /* Forward referenced functions */
67 static int backup_cmd(JCR *jcr);
68 static int component_cmd(JCR *jcr);
69 static int cancel_cmd(JCR *jcr);
70 static int setdebug_cmd(JCR *jcr);
71 static int setbandwidth_cmd(JCR *jcr);
72 static int estimate_cmd(JCR *jcr);
73 static int hello_cmd(JCR *jcr);
74 static int job_cmd(JCR *jcr);
75 static int fileset_cmd(JCR *jcr);
76 static int level_cmd(JCR *jcr);
77 static int verify_cmd(JCR *jcr);
78 static int restore_cmd(JCR *jcr);
79 static int end_restore_cmd(JCR *jcr);
80 static int storage_cmd(JCR *jcr);
81 static int session_cmd(JCR *jcr);
82 static int response(JCR *jcr, BSOCK *sd, char *resp, const char *cmd);
83 static int open_sd_read_session(JCR *jcr);
84 static int runscript_cmd(JCR *jcr);
85 static int runbefore_cmd(JCR *jcr);
86 static int runafter_cmd(JCR *jcr);
87 static int runbeforenow_cmd(JCR *jcr);
88 static int restore_object_cmd(JCR *jcr);
89 static int set_options(findFOPTS *fo, const char *opts);
90 static void set_storage_auth_key(JCR *jcr, char *key);
91 static int sm_dump_cmd(JCR *jcr);
92 static int proxy_cmd(JCR *jcr);
93 static int fd_testnetwork_cmd(JCR *jcr);
94 #ifdef DEVELOPER
95 static int exit_cmd(JCR *jcr);
96 #endif
97 
98 /* Exported functions */
99 
100 #define ACCESS_MONITOR    1
101 #define ACCESS_REMOTE     2
102 
103 /*
104  * The following are the recognized commands from the Director.
105  */
106 struct s_cmds cmds[] = {
107    {"backup",       backup_cmd,    0},
108    {"cancel",       cancel_cmd,    ACCESS_REMOTE},
109    {"setdebug=",    setdebug_cmd,  0},
110    {"setbandwidth=",setbandwidth_cmd, ACCESS_REMOTE},
111    {"snapshot",     snapshot_cmd,  0},
112    {"estimate",     estimate_cmd,  0},
113    {"Hello",        hello_cmd,     1},
114    {"fileset",      fileset_cmd,   0},
115    {"JobId=",       job_cmd,       0},
116    {"level = ",     level_cmd,     0},
117    {"restore ",     restore_cmd,   0},
118    {"endrestore",   end_restore_cmd, 0},
119    {"session",      session_cmd,   0},
120    {"status",       status_cmd,    ACCESS_MONITOR|ACCESS_REMOTE},
121    {".status",      qstatus_cmd,   ACCESS_MONITOR|ACCESS_REMOTE},
122    {"storage ",     storage_cmd,   0},
123    {"verify",       verify_cmd,    0},
124    {"component",    component_cmd, 0},
125    {"RunBeforeNow", runbeforenow_cmd, 0},
126    {"RunBeforeJob", runbefore_cmd, 0},
127    {"RunAfterJob",  runafter_cmd,  0},
128    {"Run",          runscript_cmd, 0},
129    {"accurate",     accurate_cmd,  0},
130    {"restoreobject", restore_object_cmd, 0},
131    {"sm_dump",      sm_dump_cmd, 0},
132    {"stop",         cancel_cmd,  ACCESS_REMOTE},
133    {"proxy",        proxy_cmd,   ACCESS_REMOTE},
134    {"testnetwork",  fd_testnetwork_cmd, 0},
135    {"statistics",   collect_cmd, 0},
136 #ifdef DEVELOPER
137    {"exit",         exit_cmd, 0},
138 #endif
139    {NULL,       NULL}                  /* list terminator */
140 };
141 
142 /* Commands received from director that need scanning */
143 static char jobcmd[]      = "JobId=%d Job=%127s SDid=%d SDtime=%d Authorization=%100s";
144 static char storaddr[]    = "storage address=%s port=%d ssl=%d Authorization=%100s";
145 static char storaddr_v1[] = "storage address=%s port=%d ssl=%d";
146 static char sessioncmd[]  = "session %127s %ld %ld %ld %ld %ld %ld\n";
147 
148 static char restorecmd1[] = "restore replace=%c prelinks=%d where=\n";
149 static char restorefcmd1[] = "restore files=%d replace=%c prelinks=%d where=\n";
150 
151 /* The following restore commands may have a big where=/regexwhere= parameter
152  * the bsscanf is limiting the default %s to 1000c. To allow more than 1000 bytes,
153  * we can specify %xxxxs where xxxx is the size expected in bytes.
154  *
155  * So, the code will add %s\n to the end of the following restore commands
156  */
157 static char restorecmd[]  = "restore replace=%c prelinks=%d where=";
158 static char restorecmdR[] = "restore replace=%c prelinks=%d regexwhere=";
159 static char restorefcmd[]  = "restore files=%d replace=%c prelinks=%d where=";
160 static char restorefcmdR[] = "restore files=%d replace=%c prelinks=%d regexwhere=";
161 
162 static char restoreobjcmd[]  = "restoreobject JobId=%u %d,%d,%d,%d,%d,%d,%s";
163 static char restoreobjcmd1[] = "restoreobject JobId=%u %d,%d,%d,%d,%d,%d\n";
164 static char endrestoreobjectcmd[] = "restoreobject end\n";
165 static char verifycmd[]   = "verify level=%30s";
166 static char estimatecmd[] = "estimate listing=%d";
167 static char runbefore[]   = "RunBeforeJob %s";
168 static char runafter[]    = "RunAfterJob %s";
169 static char runscript[]   = "Run OnSuccess=%d OnFailure=%d AbortOnError=%d When=%d Command=%s";
170 static char setbandwidth[]= "setbandwidth=%lld Job=%127s";
171 
172 /* Responses sent to Director */
173 static char errmsg[]      = "2999 Invalid command\n";
174 static char no_auth[]     = "2998 No Authorization\n";
175 static char invalid_cmd[] = "2997 Invalid command for a Director with Monitor directive enabled.\n";
176 static char OKBandwidth[] = "2000 OK Bandwidth\n";
177 static char OKinc[]       = "2000 OK include\n";
178 static char OKest[]       = "2000 OK estimate files=%s bytes=%s\n";
179 static char OKlevel[]     = "2000 OK level\n";
180 static char OKbackup[]    = "2000 OK backup\n";
181 static char OKverify[]    = "2000 OK verify\n";
182 static char OKrestore[]   = "2000 OK restore\n";
183 static char OKsession[]   = "2000 OK session\n";
184 static char OKstore[]     = "2000 OK storage\n";
185 static char OKstoreend[]  = "2000 OK storage end\n";
186 static char OKjob[]       = "2000 OK Job %s (%s) %s,%s,%s";
187 static char OKsetdebug[]  = "2000 OK setdebug=%ld trace=%ld hangup=%ld"
188                             " blowup=%ld options=%s tags=%s\n";
189 static char BADjob[]      = "2901 Bad Job\n";
190 static char EndJob[]      = "2800 End Job TermCode=%d JobFiles=%d ReadBytes=%lld"
191                             " JobBytes=%lld Errors=%d VSS=%d Encrypt=%d"
192                             " CommBytes=%lld CompressCommBytes=%lld\n";
193 static char OKRunBefore[] = "2000 OK RunBefore\n";
194 static char OKRunBeforeNow[] = "2000 OK RunBeforeNow\n";
195 static char OKRunAfter[]  = "2000 OK RunAfter\n";
196 static char OKRunScript[] = "2000 OK RunScript\n";
197 static char BADcmd[]      = "2902 Bad %s\n";
198 static char OKRestoreObject[] = "2000 OK ObjectRestored\n";
199 static char OKComponentInfo[] = "2000 OK ComponentInfo\n";
200 
201 
202 /* Responses received from Storage Daemon */
203 static char OK_end[]       = "3000 OK end\n";
204 static char OK_close[]     = "3000 OK close Status = %d\n";
205 static char OK_open[]      = "3000 OK open ticket = %d\n";
206 static char OK_data[]      = "3000 OK data\n";
207 static char OK_append[]    = "3000 OK append data\n";
208 
209 
210 /* Commands sent to Storage Daemon */
211 static char append_open[]  = "append open session\n";
212 static char append_data[]  = "append data %d\n";
213 static char append_end[]   = "append end session %d\n";
214 static char append_close[] = "append close session %d\n";
215 static char read_open[]    = "read open session = %s %ld %ld %ld %ld %ld %ld\n";
216 static char read_data[]    = "read data %d\n";
217 static char read_close[]   = "read close session %d\n";
218 static char read_ctrl[]    = "read control %d\n";
219 
220 /* Should tell us if a command is authorized or not */
access_ok(struct s_cmds * cmd,DIRRES * dir)221 static bool access_ok(struct s_cmds *cmd, DIRRES* dir)
222 {
223    if ((cmd->access & ACCESS_MONITOR) && dir->monitor) {
224       return true;
225    }
226    if ((cmd->access & ACCESS_REMOTE) && dir->remote) {
227       return true;
228    }
229    if (!dir->remote && !dir->monitor) {
230       return true;
231    }
232    return false;
233 }
234 
235 /*
236  * Accept requests from a Director
237  *
238  * NOTE! We are running as a separate thread
239  *
240  * Send output one line
241  * at a time followed by a zero length transmission.
242  *
243  * Return when the connection is terminated or there
244  * is an error.
245  *
246  * Basic task here is:
247  *   Authenticate Director (during Hello command).
248  *   Accept commands one at a time from the Director
249  *     and execute them.
250  *
251  * Concerning ClientRunBefore/After, the sequence of events
252  * is rather critical. If they are not done in the right
253  * order one can easily get FD->SD timeouts if the script
254  * runs a long time.
255  *
256  * The current sequence of events is:
257  *  1. Dir starts job with FD
258  *  2. Dir connects to SD
259  *  3. Dir connects to FD
260  *  4. FD connects to SD
261  *  5. FD gets/runs ClientRunBeforeJob and sends ClientRunAfterJob
262  *  6. Dir sends include/exclude
263  *  7. FD sends the file data to SD
264  *  8. SD/FD disconnects while the SD despools data and attributes (optional)
265  *  9. FD runs ClientRunAfterJob
266  */
267 
handle_director_request(BSOCK * dir)268 static void *handle_director_request(BSOCK *dir)
269 {
270    int i;
271    bool found, quit;
272    bool first = true;
273    JCR *jcr;
274    const char jobname[12] = "*Director*";
275    suspendres_t suspend;
276 
277    prevent_os_suspensions(suspend);   /* do not suspend during backup/restore */
278    jcr = new_jcr(sizeof(JCR), filed_free_jcr); /* create JCR */
279    jcr->sd_calls_client_bsock = NULL;
280    jcr->sd_calls_client = false;
281    jcr->dir_bsock = dir;
282    jcr->ff = init_find_files();
283    jcr->start_time = time(NULL);
284    jcr->RunScripts = New(alist(10, not_owned_by_alist));
285    jcr->last_fname = get_pool_memory(PM_FNAME);
286    jcr->last_fname[0] = 0;
287    jcr->client_name = get_memory(strlen(my_name) + 1);
288    pm_strcpy(jcr->client_name, my_name);
289    bstrncpy(jcr->Job, jobname, sizeof(jobname));  /* dummy */
290    jcr->crypto.pki_sign = me->pki_sign;
291    jcr->crypto.pki_encrypt = me->pki_encrypt;
292    jcr->crypto.pki_keypair = me->pki_keypair;
293    jcr->crypto.pki_signers = me->pki_signers;
294    jcr->crypto.pki_recipients = me->pki_recipients;
295 
296    dir->set_jcr(jcr);
297    jcr->set_killable(true);    /* allow dir to kill/cancel job */
298    /* Initialize SD start condition variable */
299    int errstat = pthread_cond_init(&jcr->job_start_wait, NULL);
300    if (errstat != 0) {
301       berrno be;
302       Jmsg1(jcr, M_FATAL, 0, _("Unable to init job cond variable: ERR=%s\n"), be.bstrerror(errstat));
303       goto bail_out;
304    }
305    enable_backup_privileges(NULL, 1 /* ignore_errors */);
306 
307    for (quit=false; !quit;) {
308       jcr->buf_size = DEFAULT_NETWORK_BUFFER_SIZE;  /* overriden by some commands */
309       if (!first) {      /* first call the read is done */
310          /* Read command */
311          if (dir->recv() < 0) {
312             break;               /* connection terminated */
313          }
314       }
315       if (dir->msglen == 0) {    /* Bad connection */
316          break;
317       }
318       first = false;
319       dir->msg[dir->msglen] = 0;
320       Dmsg1(100, "<dird: %s\n", dir->msg);
321       found = false;
322       for (i=0; cmds[i].cmd; i++) {
323          if (strncmp(cmds[i].cmd, dir->msg, strlen(cmds[i].cmd)) == 0) {
324             found = true;         /* indicate command found */
325             if (!jcr->authenticated && cmds[i].func != hello_cmd) {
326                dir->fsend(no_auth);
327                dir->signal(BNET_EOD);
328                break;
329             }
330             if (jcr->authenticated && !access_ok(&cmds[i], jcr->director)) {
331                Dmsg1(100, "Command \"%s\" is invalid.\n", cmds[i].cmd);
332                dir->fsend(invalid_cmd);
333                dir->signal(BNET_EOD);
334                break;
335             }
336             if ((me->disabled_cmds_array && me->disabled_cmds_array[i]) ||
337                 (jcr->director && jcr->director->disabled_cmds_array &&
338                  jcr->director->disabled_cmds_array[i])) {
339                 Jmsg(jcr, M_FATAL, 0, _("Command: \"%s\" is disabled.\n"), cmds[i].cmd);
340                 quit = true;
341                 break;
342             }
343             Dmsg2(100, "Executing %s Dir %s command.\n", cmds[i].cmd, dir->msg);
344             if (!cmds[i].func(jcr)) {         /* do command */
345                quit = true;         /* error or fully terminated, get out */
346                Dmsg1(100, "Quit command loop. Canceled=%d\n", job_canceled(jcr));
347             }
348             break;
349          }
350       }
351       if (!found) {              /* command not found */
352          dir->fsend(errmsg);
353          quit = true;
354          break;
355       }
356    }
357 
358    /* Inform Storage daemon that we are done */
359    if (jcr->store_bsock) {
360       jcr->store_bsock->signal(BNET_TERMINATE);
361    }
362 
363    /* Run the after job */
364    run_scripts(jcr, jcr->RunScripts, "ClientAfterJob");
365 
366    /* send any queued messages before reporting the jobstatus to the director */
367    dequeue_messages(jcr);
368 
369    if (jcr->JobId) {            /* send EndJob if running a job */
370       uint64_t CommBytes, CommCompressedBytes;
371       uint32_t vss, encrypt;
372       /* Send termination status back to Dir */
373       if (jcr->store_bsock) {
374          CommBytes = jcr->store_bsock->CommBytes();
375          CommCompressedBytes = jcr->store_bsock->CommCompressedBytes();
376       } else {
377          CommBytes = CommCompressedBytes = 0;
378       }
379       encrypt = jcr->crypto.pki_encrypt;
380       vss = jcr->Snapshot;
381       dir->fsend(EndJob, jcr->JobStatus, jcr->JobFiles,
382               jcr->ReadBytes, jcr->JobBytes, jcr->JobErrors, vss,
383               encrypt, CommBytes, CommCompressedBytes);
384       //Dmsg0(0, dir->msg);
385    }
386 
387    generate_daemon_event(jcr, "JobEnd");
388    generate_plugin_event(jcr, bEventJobEnd);
389 
390 bail_out:
391    dequeue_messages(jcr);  /* send any queued messages, will no longer impact
392                             * the job status... */
393    dequeue_daemon_messages(jcr);
394 
395    /* Inform Director that we are done */
396    dir->signal(BNET_TERMINATE);
397 
398    free_and_null_pool_memory(jcr->job_metadata);
399 
400    /* Clean up fileset */
401    FF_PKT *ff = jcr->ff;
402    findFILESET *fileset = ff->fileset;
403    if (fileset) {
404       int i, j, k;
405       /* Delete FileSet Include lists */
406       for (i=0; i<fileset->include_list.size(); i++) {
407          findINCEXE *incexe = (findINCEXE *)fileset->include_list.get(i);
408          for (j=0; j<incexe->opts_list.size(); j++) {
409             findFOPTS *fo = (findFOPTS *)incexe->opts_list.get(j);
410             if (fo->plugin) {
411                free(fo->plugin);
412             }
413             for (k=0; k<fo->regex.size(); k++) {
414                regfree((regex_t *)fo->regex.get(k));
415             }
416             for (k=0; k<fo->regexdir.size(); k++) {
417                regfree((regex_t *)fo->regexdir.get(k));
418             }
419             for (k=0; k<fo->regexfile.size(); k++) {
420                regfree((regex_t *)fo->regexfile.get(k));
421             }
422             fo->regex.destroy();
423             fo->regexdir.destroy();
424             fo->regexfile.destroy();
425             fo->wild.destroy();
426             fo->wilddir.destroy();
427             fo->wildfile.destroy();
428             fo->wildbase.destroy();
429             fo->base.destroy();
430             fo->fstype.destroy();
431             fo->drivetype.destroy();
432          }
433          incexe->opts_list.destroy();
434          incexe->name_list.destroy();
435          incexe->plugin_list.destroy();
436          if (incexe->ignoredir) {
437             free(incexe->ignoredir);
438          }
439       }
440       fileset->include_list.destroy();
441 
442       /* Delete FileSet Exclude lists */
443       for (i=0; i<fileset->exclude_list.size(); i++) {
444          findINCEXE *incexe = (findINCEXE *)fileset->exclude_list.get(i);
445          for (j=0; j<incexe->opts_list.size(); j++) {
446             findFOPTS *fo = (findFOPTS *)incexe->opts_list.get(j);
447             fo->regex.destroy();
448             fo->regexdir.destroy();
449             fo->regexfile.destroy();
450             fo->wild.destroy();
451             fo->wilddir.destroy();
452             fo->wildfile.destroy();
453             fo->wildbase.destroy();
454             fo->base.destroy();
455             fo->fstype.destroy();
456             fo->drivetype.destroy();
457          }
458          incexe->opts_list.destroy();
459          incexe->name_list.destroy();
460          incexe->plugin_list.destroy();
461          if (incexe->ignoredir) {
462             free(incexe->ignoredir);
463          }
464       }
465       fileset->exclude_list.destroy();
466       free(fileset);
467    }
468    ff->fileset = NULL;
469    ff->mount_points.destroy();
470    Dmsg0(100, "Calling term_find_files\n");
471    term_find_files(jcr->ff);
472    jcr->ff = NULL;
473    Dmsg0(100, "Done with term_find_files\n");
474    pthread_cond_destroy(&jcr->job_start_wait);
475    free_jcr(jcr);                     /* destroy JCR record */
476    Dmsg0(100, "Done with free_jcr\n");
477    allow_os_suspensions(suspend);            /* FD can now be suspended */
478    Dsm_check(100);
479    garbage_collect_memory_pool();
480    return NULL;
481 }
482 
483 
484 /*
485  * Accept requests from a Director or a Storage daemon
486  */
handle_connection_request(void * caller)487 void *handle_connection_request(void *caller)
488 {
489    BSOCK *bs = (BSOCK *)caller;
490 
491    if (bs->recv() > 0) {
492       if (strncmp(bs->msg, "Ping", 4) == 0) {
493          bs->fsend("2000 Ping OK\n");
494          bs->destroy();
495          return NULL;
496       }
497       if (bs->msglen < 25 || bs->msglen > 500) {
498          goto bail_out;
499       }
500       if (strncmp(bs->msg, "Hello FD: Bacula Storage", 20) ==0) {
501          return handle_storage_connection(bs);
502       }
503       if (strncmp(bs->msg, "Hello ", 5) == 0) {
504          return handle_director_request(bs);
505       }
506    }
507 bail_out:
508    Dmsg2(100, "Bad command from %s. Len=%d.\n", bs->who(), bs->msglen);
509    char addr[64];
510    char *who = bs->get_peer(addr, sizeof(addr)) ? bs->who() : addr;
511    Qmsg2(NULL, M_SECURITY, 0, _("FD expecting Hello got bad command from %s. Len=%d.\n"), who, bs->msglen);
512    sleep(5);
513    bs->destroy();
514    return NULL;
515 }
516 
517 
518 /*
519  * Test the Network between FD/SD
520  */
fd_testnetwork_cmd(JCR * jcr)521 static int fd_testnetwork_cmd(JCR *jcr)
522 {
523    bool can_compress, ok=true;
524    BSOCK *sd = jcr->store_bsock;
525    int64_t nb=0, nb2=0;
526    char ed1[50];
527    btime_t start, end;
528 
529    if (!sd || !jcr->dir_bsock) {
530       return 1;
531    }
532    if (sscanf(jcr->dir_bsock->msg, "testnetwork bytes=%lld", &nb) != 1 || nb <= 0) {
533       sd->fsend("2999 testnetwork command error\n");
534       return 1;
535    }
536 
537    /* We disable the comline compression, else all numbers will be wrong */
538    can_compress = sd->can_compress();
539 
540    sd->fsend("testnetwork bytes=%lld\n", nb);
541    sd->clear_compress();
542 
543    /* In the first step, we send X bytes to the SD */
544    memset(sd->msg, 0xAA, sizeof_pool_memory(sd->msg));
545    sd->msglen = sizeof_pool_memory(sd->msg);
546 
547    start = get_current_btime();
548    for (nb2 = nb ; nb2 > 0 && ok ; nb2 -= sd->msglen) {
549       if (nb2 < sd->msglen) {
550          sd->msglen = nb2;
551       }
552       ok = sd->send();
553    }
554    sd->signal(BNET_EOD);
555    end = get_current_btime() + 1;
556 
557    if (!ok) {
558       goto bail_out;
559    }
560 
561    jcr->dir_bsock->fsend("2000 OK bytes=%lld duration=%lldms write_speed=%sB/s\n",
562                          nb, end/1000 - start/1000,
563                          edit_uint64_with_suffix(nb * 1000000 / (end - start), ed1));
564 
565    /* Now we receive X bytes from the SD */
566    start = get_current_btime();
567    for (nb2 = 0; sd->recv() > 0; nb2 += sd->msglen) { }
568    end = get_current_btime() + 1;
569 
570    jcr->dir_bsock->fsend("2000 OK bytes=%lld duration=%lldms read_speed=%sB/s\n",
571                          nb2, end/1000 - start/1000,
572                          edit_uint64_with_suffix(nb2 * 1000000 / (end - start), ed1));
573 
574    jcr->dir_bsock->signal(BNET_CMD_OK);
575 
576 bail_out:
577    if (can_compress) {
578       sd->set_compress();
579    }
580    if (!ok) {
581       jcr->dir_bsock->fsend("2999 network test failed ERR=%s\n", sd->errmsg);
582       jcr->dir_bsock->signal(BNET_CMD_FAILED);
583    }
584 
585    return 1;
586 }
587 
proxy_cmd(JCR * jcr)588 static int proxy_cmd(JCR *jcr)
589 {
590    bool OK=true, fdcalled = false;
591    BSOCK *cons_bsock;
592    CONSRES *cons = jcr->director->console;
593    int v, maxfd;
594    fd_set fdset;
595    struct timeval tv;
596 
597    if (!cons) {
598       cons = (CONSRES *)GetNextRes(R_CONSOLE, NULL);
599    }
600    /* Here, dir_bsock is not really the director, this is a console */
601    cons_bsock = connect_director(jcr, cons);
602    if (!cons_bsock) {
603       jcr->dir_bsock->signal(BNET_ERROR_MSG);
604       jcr->dir_bsock->fsend("2999 proxy error. ERR=%s\n", jcr->errmsg);
605       jcr->dir_bsock->signal(BNET_MAIN_PROMPT);
606       /* Error during the connect */
607       return 1;
608    }
609 
610    /* Inform the console that the command is OK */
611    jcr->dir_bsock->fsend("2000 proxy OK.\n");
612    jcr->dir_bsock->signal(BNET_MAIN_PROMPT);
613 
614    maxfd = MAX(cons_bsock->m_fd, jcr->dir_bsock->m_fd) + 1;
615 
616    /* Start to forward events from one to the other
617     * It can be done with 2 threads, or with a select
618     */
619    do {
620       FD_ZERO(&fdset);
621       FD_SET((unsigned)cons_bsock->m_fd, &fdset);
622       FD_SET((unsigned)jcr->dir_bsock->m_fd, &fdset);
623 
624       tv.tv_sec = 5;
625       tv.tv_usec = 0;
626       switch ((v = select(maxfd, &fdset, NULL, NULL, &tv))) {
627       case 0:                      /* timeout */
628          OK = !jcr->is_canceled();
629          break;
630       case -1:
631          Dmsg1(0, "Bad call to select ERR=%d\n", errno);
632          OK = false;
633       default:
634 #ifdef HAVE_TLS
635          if (cons_bsock->tls && !tls_bsock_probe(cons_bsock)) {
636             /* maybe a session key negotiation waked up the socket */
637             FD_CLR(cons_bsock->m_fd, &fdset);
638          }
639          if (jcr->dir_bsock->tls && !tls_bsock_probe(jcr->dir_bsock)) {
640             /* maybe a session key negotiation waked up the socket */
641             FD_CLR(jcr->dir_bsock->m_fd, &fdset);
642          }
643 #endif
644          break;
645       }
646       Dmsg1(DT_NETWORK, "select = %d\n", v);
647       if (OK) {
648          if (FD_ISSET(cons_bsock->m_fd, &fdset)) {
649             v = cons_bsock->recv();
650             if (v == BNET_SIGNAL) {
651                if (cons_bsock->msglen == BNET_FDCALLED) {
652                   OK = false;
653                   fdcalled = true;
654                } else {
655                   jcr->dir_bsock->signal(cons_bsock->msglen);
656                }
657 
658             } else if (v >= 0) {
659                jcr->dir_bsock->fsend("%s", cons_bsock->msg);
660 
661             } else {
662                /* We should not have such kind of message */
663                OK = false;
664             }
665          }
666          if (FD_ISSET(jcr->dir_bsock->m_fd, &fdset)) {
667             v = jcr->dir_bsock->recv();
668             if (v == BNET_SIGNAL) {
669                cons_bsock->signal(jcr->dir_bsock->msglen);
670             } else if (v >= 0) {
671                cons_bsock->fsend("%s", jcr->dir_bsock->msg);
672             } else {
673                /* We should not have such kind of message */
674                OK = false;
675             }
676          }
677       }
678       if (cons_bsock->is_error() || jcr->dir_bsock->is_error()) {
679          OK = false;
680       }
681    } while (OK && !jcr->is_canceled());
682 
683    /* Close the socket, nothing more will come */
684    jcr->dir_bsock->signal(BNET_TERMINATE);
685    jcr->dir_bsock->close();
686    if (fdcalled) {
687       handle_connection_request(cons_bsock); /* will release the socket */
688    } else {
689       free_bsock(cons_bsock);
690    }
691    return 1;
692 }
693 
sm_dump_cmd(JCR * jcr)694 static int sm_dump_cmd(JCR *jcr)
695 {
696    close_memory_pool();
697    sm_dump(false, true);
698    jcr->dir_bsock->fsend("2000 sm_dump OK\n");
699    return 1;
700 }
701 
702 #ifdef DEVELOPER
exit_cmd(JCR * jcr)703 static int exit_cmd(JCR *jcr)
704 {
705    jcr->dir_bsock->fsend("2000 exit OK\n");
706    terminate_filed(0);
707    return 0;
708 }
709 #endif
710 
711 /*
712  * Hello from Director he must identify himself and provide his
713  *  password.
714  */
hello_cmd(JCR * jcr)715 static int hello_cmd(JCR *jcr)
716 {
717    Dmsg0(120, "Calling Authenticate\n");
718    if (!validate_dir_hello(jcr)) {
719       return 0;
720    }
721    if (!authenticate_director(jcr)) {
722       return 0;
723    }
724    Dmsg0(120, "OK Authenticate\n");
725    jcr->authenticated = true;
726 
727    dequeue_messages(jcr);     /* dequeue any daemon messages */
728    return 1;
729 }
730 
731 /*
732  * Cancel a Job
733  */
cancel_cmd(JCR * jcr)734 static int cancel_cmd(JCR *jcr)
735 {
736    BSOCK *dir = jcr->dir_bsock;
737    char Job[MAX_NAME_LENGTH];
738    JCR *cjcr;
739    int status;
740    const char *reason;
741 
742    if (sscanf(dir->msg, "cancel Job=%127s", Job) == 1) {
743       status = JS_Canceled;
744       reason = "canceled";
745    } else if (sscanf(dir->msg, "stop Job=%127s", Job) == 1) {
746       status = JS_Incomplete;
747       reason = "stopped";
748    } else {
749       dir->fsend(_("2902 Error scanning cancel command.\n"));
750       goto bail_out;
751    }
752    if (!(cjcr=get_jcr_by_full_name(Job))) {
753       dir->fsend(_("2901 Job %s not found.\n"), Job);
754    } else {
755       generate_plugin_event(cjcr, bEventCancelCommand, NULL);
756       cjcr->setJobStatus(status);
757       if (cjcr->store_bsock) {
758          cjcr->store_bsock->cancel();
759       }
760       cjcr->my_thread_send_signal(TIMEOUT_SIGNAL);
761       free_jcr(cjcr);
762       dir->fsend(_("2001 Job \"%s\" marked to be %s.\n"),
763          Job, reason);
764    }
765 
766 bail_out:
767    dir->signal(BNET_EOD);
768    return 1;
769 }
770 
771 /**
772  * Set bandwidth limit as requested by the Director
773  *
774  */
setbandwidth_cmd(JCR * jcr)775 static int setbandwidth_cmd(JCR *jcr)
776 {
777    BSOCK *dir = jcr->dir_bsock;
778    int64_t bw=0;
779    JCR *cjcr;
780    char Job[MAX_NAME_LENGTH];
781    *Job=0;
782 
783    if (sscanf(dir->msg, setbandwidth, &bw, Job) != 2 || bw < 0) {
784       pm_strcpy(jcr->errmsg, dir->msg);
785       dir->fsend(_("2991 Bad setbandwidth command: %s\n"), jcr->errmsg);
786       return 0;
787    }
788 
789    if (*Job) {
790       if(!(cjcr=get_jcr_by_full_name(Job))) {
791          dir->fsend(_("2901 Job %s not found.\n"), Job);
792       } else {
793          cjcr->max_bandwidth = bw;
794          if (cjcr->store_bsock) {
795             cjcr->store_bsock->set_bwlimit(bw);
796          }
797          free_jcr(cjcr);
798       }
799 
800    } else {                           /* No job requested, apply globally */
801       me->max_bandwidth_per_job = bw; /* Overwrite directive */
802       foreach_jcr(cjcr) {
803          cjcr->max_bandwidth = bw;
804          if (cjcr->store_bsock) {
805             cjcr->store_bsock->set_bwlimit(bw);
806          }
807       }
808       endeach_jcr(cjcr);
809    }
810 
811    return dir->fsend(OKBandwidth);
812 }
813 
814 /**
815  * Set debug level as requested by the Director
816  *
817  */
setdebug_cmd(JCR * jcr)818 static int setdebug_cmd(JCR *jcr)
819 {
820    BSOCK *dir = jcr->dir_bsock;
821    int32_t trace, lvl;
822    int32_t hangup = -1;
823    int32_t blowup = -1;
824    int64_t level, level_tags = 0;
825    int scan;
826    char options[60];
827    char tags[512];
828 
829    Dmsg1(50, "setdebug_cmd: %s", dir->msg);
830    tags[0] = options[0] = 0;
831    scan = sscanf(dir->msg, "setdebug=%ld trace=%ld hangup=%ld blowup=%ld"
832              " options=%55s tags=%511s",
833                  &lvl, &trace, &hangup, &blowup, options, tags);
834    if (scan != 6) {
835       scan = sscanf(dir->msg, "setdebug=%ld trace=%ld hangup=%ld",
836                     &lvl, &trace, &hangup);
837       if (scan != 3) {
838          Dmsg2(20, "sscanf failed: msg=%s scan=%d\n", dir->msg, scan);
839          if (sscanf(dir->msg, "setdebug=%ld trace=%ld", &lvl, &trace) != 2) {
840             pm_strcpy(jcr->errmsg, dir->msg);
841             dir->fsend(_("2991 Bad setdebug command: %s\n"), jcr->errmsg);
842             return 0;
843          } else {
844             hangup = -1;
845          }
846       }
847    }
848    level = lvl;
849    set_trace(trace);
850    set_hangup(hangup);
851    set_blowup(blowup);
852    if (!debug_parse_tags(tags, &level_tags)) {
853       *tags = 0;
854    }
855    if (level >= 0) {
856       debug_level = level;
857    }
858    debug_level_tags = level_tags;
859 
860    /* Parse specific FD options */
861    for (char *p = options; *p ; p++) {
862       switch(*p) {
863       case 'i':
864          /* Turn on/off ignore bwrite() errors on restore */
865          no_win32_write_errors = true;
866          break;
867       case 'd':
868          /* Turn on/off decomp of BackupRead() streams */
869          win32decomp = true;
870          break;
871       }
872    }
873 
874    /* handle other options */
875    set_debug_flags(options);
876 
877    Dmsg6(150, "level=%ld trace=%ld hangup=%ld blowup=%d options=%s tags=%s\n",
878          lvl, get_trace(), get_hangup(), get_blowup(), options, tags);
879    return dir->fsend(OKsetdebug, lvl, get_trace(), get_hangup(),
880              get_blowup(), options, tags);
881 }
882 
883 
estimate_cmd(JCR * jcr)884 static int estimate_cmd(JCR *jcr)
885 {
886    BSOCK *dir = jcr->dir_bsock;
887    char ed1[50], ed2[50];
888 
889    if (sscanf(dir->msg, estimatecmd, &jcr->listing) != 1) {
890       pm_strcpy(jcr->errmsg, dir->msg);
891       Jmsg(jcr, M_FATAL, 0, _("Bad estimate command: %s"), jcr->errmsg);
892       dir->fsend(_("2992 Bad estimate command.\n"));
893       return 0;
894    }
895    make_estimate(jcr);
896    dir->fsend(OKest, edit_uint64_with_commas(jcr->num_files_examined, ed1),
897       edit_uint64_with_commas(jcr->JobBytes, ed2));
898    dir->signal(BNET_EOD);
899    return 1;
900 }
901 
902 /**
903  * Get JobId and Storage Daemon Authorization key from Director
904  */
job_cmd(JCR * jcr)905 static int job_cmd(JCR *jcr)
906 {
907    BSOCK *dir = jcr->dir_bsock;
908    POOL_MEM sd_auth_key(PM_MESSAGE);
909    sd_auth_key.check_size(dir->msglen);
910 
911    if (sscanf(dir->msg, jobcmd,  &jcr->JobId, jcr->Job,
912               &jcr->VolSessionId, &jcr->VolSessionTime,
913               sd_auth_key.c_str()) != 5) {
914       pm_strcpy(jcr->errmsg, dir->msg);
915       Jmsg(jcr, M_FATAL, 0, _("Bad Job Command: %s"), jcr->errmsg);
916       dir->fsend(BADjob);
917       return 0;
918    }
919    set_jcr_in_tsd(jcr);
920    set_storage_auth_key(jcr, sd_auth_key.c_str());
921    Dmsg2(120, "JobId=%d Auth=%s\n", jcr->JobId, jcr->sd_auth_key);
922    Mmsg(jcr->errmsg, "JobId=%d Job=%s", jcr->JobId, jcr->Job);
923    new_plugins(jcr);                  /* instantiate plugins for this jcr */
924    generate_plugin_event(jcr, bEventJobStart, (void *)jcr->errmsg);
925 #ifdef HAVE_WIN32
926    return dir->fsend(OKjob, VERSION, LSMDATE, win_os, DISTNAME, DISTVER);
927 #else
928     return dir->fsend(OKjob, VERSION, LSMDATE, HOST_OS, DISTNAME, DISTVER);
929 #endif
930 }
931 
job_code_callback_filed(JCR * jcr,const char * param,char * buf,int buflen)932 extern "C" char *job_code_callback_filed(JCR *jcr, const char* param, char *buf, int buflen)
933 {
934    switch (param[0]) {
935    case 'D':
936       if (jcr->director) {
937          return jcr->director->hdr.name;
938       }
939       break;
940    case 'S':
941       return jcr->PrevJob;
942    }
943    return NULL;
944 
945 }
946 
runbefore_cmd(JCR * jcr)947 static int runbefore_cmd(JCR *jcr)
948 {
949    bool ok;
950    BSOCK *dir = jcr->dir_bsock;
951    POOLMEM *cmd = get_memory(dir->msglen+1);
952    RUNSCRIPT *script;
953 
954    Dmsg1(100, "runbefore_cmd: %s", dir->msg);
955    if (sscanf(dir->msg, runbefore, cmd) != 1) {
956       pm_strcpy(jcr->errmsg, dir->msg);
957       Jmsg1(jcr, M_FATAL, 0, _("Bad RunBeforeJob command: %s\n"), jcr->errmsg);
958       dir->fsend(_("2905 Bad RunBeforeJob command.\n"));
959       free_memory(cmd);
960       return 0;
961    }
962    unbash_spaces(cmd);
963 
964    /* Run the command now */
965    script = new_runscript();
966    script->set_job_code_callback(job_code_callback_filed);
967    script->set_command(cmd);
968    script->when = SCRIPT_Before;
969    ok = script->run(jcr, "ClientRunBeforeJob");
970    free_runscript(script);
971 
972    free_memory(cmd);
973    if (ok) {
974       dir->fsend(OKRunBefore);
975       return 1;
976    } else {
977       dir->fsend(_("2905 Bad RunBeforeJob command.\n"));
978       return 0;
979    }
980 }
981 
runbeforenow_cmd(JCR * jcr)982 static int runbeforenow_cmd(JCR *jcr)
983 {
984    BSOCK *dir = jcr->dir_bsock;
985 
986    run_scripts(jcr, jcr->RunScripts, "ClientBeforeJob");
987    if (job_canceled(jcr)) {
988       dir->fsend(_("2905 Bad RunBeforeNow command.\n"));
989       Dmsg0(100, "Back from run_scripts ClientBeforeJob now: FAILED\n");
990       return 0;
991    } else {
992       dir->fsend(OKRunBeforeNow);
993       Dmsg0(100, "Back from run_scripts ClientBeforeJob now: OK\n");
994       return 1;
995    }
996 }
997 
runafter_cmd(JCR * jcr)998 static int runafter_cmd(JCR *jcr)
999 {
1000    BSOCK *dir = jcr->dir_bsock;
1001    POOLMEM *msg = get_memory(dir->msglen+1);
1002    RUNSCRIPT *cmd;
1003 
1004    Dmsg1(100, "runafter_cmd: %s", dir->msg);
1005    if (sscanf(dir->msg, runafter, msg) != 1) {
1006       pm_strcpy(jcr->errmsg, dir->msg);
1007       Jmsg1(jcr, M_FATAL, 0, _("Bad RunAfter command: %s\n"), jcr->errmsg);
1008       dir->fsend(_("2905 Bad RunAfterJob command.\n"));
1009       free_memory(msg);
1010       return 0;
1011    }
1012    unbash_spaces(msg);
1013 
1014    cmd = new_runscript();
1015    cmd->set_job_code_callback(job_code_callback_filed);
1016    cmd->set_command(msg);
1017    cmd->on_success = true;
1018    cmd->on_failure = false;
1019    cmd->when = SCRIPT_After;
1020 
1021    jcr->RunScripts->append(cmd);
1022 
1023    free_pool_memory(msg);
1024    return dir->fsend(OKRunAfter);
1025 }
1026 
runscript_cmd(JCR * jcr)1027 static int runscript_cmd(JCR *jcr)
1028 {
1029    BSOCK *dir = jcr->dir_bsock;
1030    POOLMEM *msg = get_memory(dir->msglen+1);
1031    int on_success, on_failure, fail_on_error;
1032 
1033    RUNSCRIPT *cmd = new_runscript() ;
1034    cmd->set_job_code_callback(job_code_callback_filed);
1035 
1036    Dmsg1(100, "runscript_cmd: '%s'\n", dir->msg);
1037    /* Note, we cannot sscanf into bools */
1038    if (sscanf(dir->msg, runscript, &on_success,
1039                                   &on_failure,
1040                                   &fail_on_error,
1041                                   &cmd->when,
1042                                   msg) != 5) {
1043       pm_strcpy(jcr->errmsg, dir->msg);
1044       Jmsg1(jcr, M_FATAL, 0, _("Bad RunScript command: %s\n"), jcr->errmsg);
1045       dir->fsend(_("2905 Bad RunScript command.\n"));
1046       free_runscript(cmd);
1047       free_memory(msg);
1048       return 0;
1049    }
1050    cmd->on_success = on_success;
1051    cmd->on_failure = on_failure;
1052    cmd->fail_on_error = fail_on_error;
1053    unbash_spaces(msg);
1054 
1055    cmd->set_command(msg);
1056    cmd->debug();
1057    jcr->RunScripts->append(cmd);
1058 
1059    free_pool_memory(msg);
1060    return dir->fsend(OKRunScript);
1061 }
1062 
1063 /*
1064  * This reads data sent from the Director from the
1065  *   RestoreObject table that allows us to get objects
1066  *   that were backed up (VSS .xml data) and are needed
1067  *   before starting the restore.
1068  */
restore_object_cmd(JCR * jcr)1069 static int restore_object_cmd(JCR *jcr)
1070 {
1071    BSOCK *dir = jcr->dir_bsock;
1072    int32_t FileIndex;
1073    restore_object_pkt rop;
1074 
1075    memset(&rop, 0, sizeof(rop));
1076    rop.pkt_size = sizeof(rop);
1077    rop.pkt_end = sizeof(rop);
1078 
1079    Dmsg1(100, "Enter restoreobject_cmd: %s", dir->msg);
1080    if (strcmp(dir->msg, endrestoreobjectcmd) == 0) {
1081       Dmsg0(20, "Got endrestoreobject\n");
1082       generate_plugin_event(jcr, bEventRestoreObject, NULL);
1083       return dir->fsend(OKRestoreObject);
1084    }
1085 
1086    rop.plugin_name = (char *)malloc(dir->msglen);
1087    *rop.plugin_name = 0;
1088 
1089    if (sscanf(dir->msg, restoreobjcmd, &rop.JobId, &rop.object_len,
1090               &rop.object_full_len, &rop.object_index,
1091               &rop.object_type, &rop.object_compression, &FileIndex,
1092               rop.plugin_name) != 8) {
1093 
1094       /* Old version, no plugin_name */
1095       if (sscanf(dir->msg, restoreobjcmd1, &rop.JobId, &rop.object_len,
1096                  &rop.object_full_len, &rop.object_index,
1097                  &rop.object_type, &rop.object_compression, &FileIndex) != 7) {
1098          Dmsg0(5, "Bad restore object command\n");
1099          pm_strcpy(jcr->errmsg, dir->msg);
1100          Jmsg1(jcr, M_FATAL, 0, _("Bad RestoreObject command: %s\n"), jcr->errmsg);
1101          goto bail_out;
1102       }
1103    }
1104 
1105    unbash_spaces(rop.plugin_name);
1106 
1107    Dmsg7(100, "Recv object: JobId=%u objlen=%d full_len=%d objinx=%d objtype=%d "
1108          "FI=%d plugin_name=%s\n",
1109          rop.JobId, rop.object_len, rop.object_full_len,
1110          rop.object_index, rop.object_type, FileIndex, rop.plugin_name);
1111    /* Read Object name */
1112    if (dir->recv() < 0) {
1113       goto bail_out;
1114    }
1115    Dmsg2(100, "Recv Oname object: len=%d Oname=%s\n", dir->msglen, dir->msg);
1116    rop.object_name = bstrdup(dir->msg);
1117 
1118    /* Read Object */
1119    if (dir->recv() < 0) {
1120       goto bail_out;
1121    }
1122    /* Transfer object from message buffer, and get new message buffer */
1123    rop.object = dir->msg;
1124    dir->msg = get_pool_memory(PM_MESSAGE);
1125 
1126    /* If object is compressed, uncompress it */
1127    if (rop.object_compression == 1) {   /* zlib level 9 */
1128       int stat;
1129       int out_len = rop.object_full_len + 100;
1130       POOLMEM *obj = get_memory(out_len);
1131       Dmsg2(100, "Inflating from %d to %d\n", rop.object_len, rop.object_full_len);
1132       stat = Zinflate(rop.object, rop.object_len, obj, out_len);
1133       Dmsg1(100, "Zinflate stat=%d\n", stat);
1134       if (out_len != rop.object_full_len) {
1135          Jmsg3(jcr, M_ERROR, 0, ("Decompression failed. Len wanted=%d got=%d. Object=%s\n"),
1136             rop.object_full_len, out_len, rop.object_name);
1137       }
1138       free_pool_memory(rop.object);   /* release compressed object */
1139       rop.object = obj;               /* new uncompressed object */
1140       rop.object_len = out_len;
1141    }
1142    Dmsg2(100, "Recv Object: len=%d Object=%s\n", rop.object_len, rop.object);
1143    /* we still need to do this to detect a vss restore */
1144    if (strcmp(rop.object_name, "job_metadata.xml") == 0) {
1145       Dmsg0(100, "got job metadata\n");
1146       jcr->got_metadata = true;
1147    }
1148 
1149    generate_plugin_event(jcr, bEventRestoreObject, (void *)&rop);
1150 
1151    if (rop.object_name) {
1152       free(rop.object_name);
1153    }
1154    if (rop.object) {
1155       free_pool_memory(rop.object);
1156    }
1157    if (rop.plugin_name) {
1158       free(rop.plugin_name);
1159    }
1160 
1161    Dmsg1(100, "Send: %s", OKRestoreObject);
1162    return 1;
1163 
1164 bail_out:
1165    dir->fsend(_("2909 Bad RestoreObject command.\n"));
1166    return 0;
1167 
1168 }
1169 
1170 
init_fileset(JCR * jcr)1171 static bool init_fileset(JCR *jcr)
1172 {
1173    FF_PKT *ff;
1174    findFILESET *fileset;
1175 
1176    if (!jcr->ff) {
1177       return false;
1178    }
1179    ff = jcr->ff;
1180    if (ff->fileset) {
1181       return false;
1182    }
1183    fileset = (findFILESET *)bmalloc(sizeof(findFILESET));
1184    ff->fileset = fileset;
1185    fileset->state = state_none;
1186    fileset->include_list.init(1, true);
1187    fileset->exclude_list.init(1, true);
1188    return true;
1189 }
1190 
append_file(JCR * jcr,findINCEXE * incexe,const char * buf,bool is_file)1191 static void append_file(JCR *jcr, findINCEXE *incexe,
1192                         const char *buf, bool is_file)
1193 {
1194    if (is_file) {
1195 #ifdef HAVE_WIN32
1196       /* Special case for / under Win32,
1197        * user is requesting to include all local drives
1198        */
1199       if (strcmp(buf, "/") == 0) {
1200          //list_drives(&incexe->name_list);
1201 
1202       } else {
1203          incexe->name_list.append(new_dlistString(buf));
1204       }
1205 #else
1206       incexe->name_list.append(new_dlistString(buf));
1207 #endif  /* HAVE_WIN32 */
1208 
1209    } else if (me->plugin_directory) {
1210       generate_plugin_event(jcr, bEventPluginCommand, (void *)buf);
1211       incexe->plugin_list.append(new_dlistString(buf));
1212    } else {
1213       Jmsg(jcr, M_FATAL, 0,
1214            _("Plugin Directory not defined. Cannot use plugin: \"%s\"\n"),
1215            buf);
1216    }
1217 }
1218 
1219 /**
1220  * Add fname to include/exclude fileset list. First check for
1221  * | and < and if necessary perform command.
1222  */
add_file_to_fileset(JCR * jcr,const char * fname,bool is_file)1223 void add_file_to_fileset(JCR *jcr, const char *fname, bool is_file)
1224 {
1225    findFILESET *fileset = jcr->ff->fileset;
1226    char *p;
1227    BPIPE *bpipe;
1228    POOLMEM *fn;
1229    FILE *ffd;
1230    char buf[1000];
1231    int ch;
1232    int stat;
1233 
1234    p = (char *)fname;
1235    ch = (uint8_t)*p;
1236    switch (ch) {
1237    case '|':
1238       Dmsg1(100, "Doing | of '%s' include on client.\n", p + 1);
1239       p++;                            /* skip over | */
1240       fn = get_pool_memory(PM_FNAME);
1241       fn = edit_job_codes(jcr, fn, p, "", job_code_callback_filed);
1242       bpipe = open_bpipe(fn, 0, "r");
1243       if (!bpipe) {
1244          berrno be;
1245          Jmsg(jcr, M_FATAL, 0, _("Cannot run program: %s. ERR=%s\n"),
1246             p, be.bstrerror());
1247          free_pool_memory(fn);
1248          return;
1249       }
1250       free_pool_memory(fn);
1251       while (fgets(buf, sizeof(buf), bpipe->rfd)) {
1252          strip_trailing_junk(buf);
1253          if (*buf) {            /* Avoid empty lines */
1254             append_file(jcr, fileset->incexe, buf, is_file);
1255          }
1256       }
1257       if ((stat=close_bpipe(bpipe)) != 0) {
1258          berrno be;
1259          Jmsg(jcr, M_FATAL, 0, _("Error running program: %s. stat=%d: ERR=%s\n"),
1260             p, be.code(stat), be.bstrerror(stat));
1261          return;
1262       }
1263       break;
1264    case '<':
1265       Dmsg1(100, "Doing < of '%s' include on client.\n", p + 1);
1266       p++;                      /* skip over < */
1267       if ((ffd = fopen(p, "rb")) == NULL) {
1268          berrno be;
1269          Jmsg(jcr, M_FATAL, 0,
1270               _("Cannot open FileSet input file: %s. ERR=%s\n"),
1271             p, be.bstrerror());
1272          return;
1273       }
1274       while (fgets(buf, sizeof(buf), ffd)) {
1275          strip_trailing_junk(buf);
1276          append_file(jcr, fileset->incexe, buf, is_file);
1277       }
1278       fclose(ffd);
1279       break;
1280    default:
1281       append_file(jcr, fileset->incexe, fname, is_file);
1282       break;
1283    }
1284 }
1285 
get_incexe(JCR * jcr)1286 findINCEXE *get_incexe(JCR *jcr)
1287 {
1288    if (jcr->ff && jcr->ff->fileset) {
1289       return jcr->ff->fileset->incexe;
1290    }
1291    return NULL;
1292 }
1293 
set_incexe(JCR * jcr,findINCEXE * incexe)1294 void set_incexe(JCR *jcr, findINCEXE *incexe)
1295 {
1296    findFILESET *fileset = jcr->ff->fileset;
1297    fileset->incexe = incexe;
1298 }
1299 
1300 
1301 /**
1302  * Define a new Exclude block in the FileSet
1303  */
new_exclude(JCR * jcr)1304 findINCEXE *new_exclude(JCR *jcr)
1305 {
1306    findFILESET *fileset = jcr->ff->fileset;
1307 
1308    /* New exclude */
1309    fileset->incexe = (findINCEXE *)bmalloc(sizeof(findINCEXE));
1310    fileset->incexe->opts_list.init(1, true);
1311    fileset->incexe->name_list.init();
1312    fileset->incexe->plugin_list.init();
1313    fileset->exclude_list.append(fileset->incexe);
1314    return fileset->incexe;
1315 }
1316 
1317 /**
1318  * Define a new Include block in the FileSet
1319  */
new_include(JCR * jcr)1320 findINCEXE *new_include(JCR *jcr)
1321 {
1322    findFILESET *fileset = jcr->ff->fileset;
1323 
1324    /* New include */
1325    fileset->incexe = (findINCEXE *)bmalloc(sizeof(findINCEXE));
1326    fileset->incexe->opts_list.init(1, true);
1327    fileset->incexe->name_list.init(); /* for dlist;  was 1,true for alist */
1328    fileset->incexe->plugin_list.init();
1329    fileset->include_list.append(fileset->incexe);
1330    return fileset->incexe;
1331 }
1332 
1333 /**
1334  * Define a new preInclude block in the FileSet
1335  *   That is the include is prepended to the other
1336  *   Includes.  This is used for plugin exclusions.
1337  */
new_preinclude(JCR * jcr)1338 findINCEXE *new_preinclude(JCR *jcr)
1339 {
1340    findFILESET *fileset = jcr->ff->fileset;
1341 
1342    /* New pre-include */
1343    fileset->incexe = (findINCEXE *)bmalloc(sizeof(findINCEXE));
1344    fileset->incexe->opts_list.init(1, true);
1345    fileset->incexe->name_list.init(); /* for dlist;  was 1,true for alist */
1346    fileset->incexe->plugin_list.init();
1347    fileset->include_list.prepend(fileset->incexe);
1348    return fileset->incexe;
1349 }
1350 
start_options(FF_PKT * ff)1351 static findFOPTS *start_options(FF_PKT *ff)
1352 {
1353    int state = ff->fileset->state;
1354    findINCEXE *incexe = ff->fileset->incexe;
1355 
1356    if (state != state_options) {
1357       ff->fileset->state = state_options;
1358       findFOPTS *fo = (findFOPTS *)bmalloc(sizeof(findFOPTS));
1359       fo->regex.init(1, true);
1360       fo->regexdir.init(1, true);
1361       fo->regexfile.init(1, true);
1362       fo->wild.init(1, true);
1363       fo->wilddir.init(1, true);
1364       fo->wildfile.init(1, true);
1365       fo->wildbase.init(1, true);
1366       fo->base.init(1, true);
1367       fo->fstype.init(1, true);
1368       fo->drivetype.init(1, true);
1369       incexe->current_opts = fo;
1370       incexe->opts_list.append(fo);
1371    }
1372    return incexe->current_opts;
1373 }
1374 
1375 /*
1376  * Used by plugins to define a new options block
1377  */
new_options(JCR * jcr,findINCEXE * incexe)1378 void new_options(JCR *jcr, findINCEXE *incexe)
1379 {
1380    if (!incexe) {
1381       incexe = jcr->ff->fileset->incexe;
1382    }
1383    findFOPTS *fo = (findFOPTS *)bmalloc(sizeof(findFOPTS));
1384    fo->regex.init(1, true);
1385    fo->regexdir.init(1, true);
1386    fo->regexfile.init(1, true);
1387    fo->wild.init(1, true);
1388    fo->wilddir.init(1, true);
1389    fo->wildfile.init(1, true);
1390    fo->wildbase.init(1, true);
1391    fo->base.init(1, true);
1392    fo->fstype.init(1, true);
1393    fo->drivetype.init(1, true);
1394    incexe->current_opts = fo;
1395    incexe->opts_list.prepend(fo);
1396    jcr->ff->fileset->state = state_options;
1397 }
1398 
1399 /**
1400  * Add a regex to the current fileset
1401  */
add_regex_to_fileset(JCR * jcr,const char * item,int type)1402 int add_regex_to_fileset(JCR *jcr, const char *item, int type)
1403 {
1404    findFOPTS *current_opts = start_options(jcr->ff);
1405    regex_t *preg;
1406    int rc;
1407    char prbuf[500];
1408 
1409    preg = (regex_t *)malloc(sizeof(regex_t));
1410    if (current_opts->flags & FO_IGNORECASE) {
1411       rc = regcomp(preg, item, REG_EXTENDED|REG_ICASE);
1412    } else {
1413       rc = regcomp(preg, item, REG_EXTENDED);
1414    }
1415    if (rc != 0) {
1416       regerror(rc, preg, prbuf, sizeof(prbuf));
1417       regfree(preg);
1418       free(preg);
1419       Jmsg(jcr, M_FATAL, 0, _("REGEX %s compile error. ERR=%s\n"), item, prbuf);
1420       return state_error;
1421    }
1422    if (type == ' ') {
1423       current_opts->regex.append(preg);
1424    } else if (type == 'D') {
1425       current_opts->regexdir.append(preg);
1426    } else if (type == 'F') {
1427       current_opts->regexfile.append(preg);
1428    } else {
1429       return state_error;
1430    }
1431    return state_options;
1432 }
1433 
1434 /**
1435  * Add a wild card to the current fileset
1436  */
add_wild_to_fileset(JCR * jcr,const char * item,int type)1437 int add_wild_to_fileset(JCR *jcr, const char *item, int type)
1438 {
1439    findFOPTS *current_opts = start_options(jcr->ff);
1440 
1441    if (type == ' ') {
1442       current_opts->wild.append(bstrdup(item));
1443    } else if (type == 'D') {
1444       current_opts->wilddir.append(bstrdup(item));
1445    } else if (type == 'F') {
1446       current_opts->wildfile.append(bstrdup(item));
1447    } else if (type == 'B') {
1448       current_opts->wildbase.append(bstrdup(item));
1449    } else {
1450       return state_error;
1451    }
1452    return state_options;
1453 }
1454 
1455 
1456 /**
1457  * Add options to the current fileset
1458  */
add_options_to_fileset(JCR * jcr,const char * item)1459 int add_options_to_fileset(JCR *jcr, const char *item)
1460 {
1461    findFOPTS *current_opts = start_options(jcr->ff);
1462 
1463    set_options(current_opts, item);
1464    return state_options;
1465 }
1466 
add_fileset(JCR * jcr,const char * item)1467 static void add_fileset(JCR *jcr, const char *item)
1468 {
1469    FF_PKT *ff = jcr->ff;
1470    findFILESET *fileset = ff->fileset;
1471    int state = fileset->state;
1472    findFOPTS *current_opts;
1473 
1474    /* Get code, optional subcode, and position item past the dividing space */
1475    Dmsg1(100, "%s\n", item);
1476    int code = item[0];
1477    if (code != '\0') {
1478       ++item;
1479    }
1480    int subcode = ' ';               /* A space is always a valid subcode */
1481    if (item[0] != '\0' && item[0] != ' ') {
1482       subcode = item[0];
1483       ++item;
1484    }
1485    if (*item == ' ') {
1486       ++item;
1487    }
1488 
1489    /* Skip all lines we receive after an error */
1490    if (state == state_error) {
1491       Dmsg0(100, "State=error return\n");
1492       return;
1493    }
1494 
1495    /**
1496     * The switch tests the code for validity.
1497     * The subcode is always good if it is a space, otherwise we must confirm.
1498     * We set state to state_error first assuming the subcode is invalid,
1499     * requiring state to be set in cases below that handle subcodes.
1500     */
1501    if (subcode != ' ') {
1502       state = state_error;
1503       Dmsg0(100, "Set state=error or double code.\n");
1504    }
1505    switch (code) {
1506    case 'I':
1507       (void)new_include(jcr);
1508       break;
1509    case 'E':
1510       (void)new_exclude(jcr);
1511       break;
1512    case 'N':                             /* null */
1513       state = state_none;
1514       break;
1515    case 'F':                             /* file = */
1516       /* File item to include or exclude list */
1517       state = state_include;
1518       add_file_to_fileset(jcr, item, true);
1519       break;
1520    case 'P':                              /* plugin */
1521       /* Plugin item to include list */
1522       state = state_include;
1523       add_file_to_fileset(jcr, item, false);
1524       break;
1525    case 'R':                              /* regex */
1526       state = add_regex_to_fileset(jcr, item, subcode);
1527       break;
1528    case 'B':
1529       current_opts = start_options(ff);
1530       current_opts->base.append(bstrdup(item));
1531       state = state_options;
1532       break;
1533    case 'X':                             /* Filetype or Drive type */
1534       current_opts = start_options(ff);
1535       state = state_options;
1536       if (subcode == ' ') {
1537          current_opts->fstype.append(bstrdup(item));
1538       } else if (subcode == 'D') {
1539          current_opts->drivetype.append(bstrdup(item));
1540       } else {
1541          state = state_error;
1542       }
1543       break;
1544    case 'W':                               /* wild cards */
1545       state = add_wild_to_fileset(jcr, item, subcode);
1546       break;
1547    case 'O':                                /* Options */
1548       state = add_options_to_fileset(jcr, item);
1549       break;
1550    case 'Z':                                /* ignore dir */
1551       state = state_include;
1552       fileset->incexe->ignoredir = bstrdup(item);
1553       break;
1554    case 'D':
1555       current_opts = start_options(ff);
1556 //    current_opts->reader = bstrdup(item); /* deprecated */
1557       state = state_options;
1558       break;
1559    case 'T':
1560       current_opts = start_options(ff);
1561 //    current_opts->writer = bstrdup(item); /* deprecated */
1562       state = state_options;
1563       break;
1564    case 'G':                    /* Plugin command for this Option block */
1565       current_opts = start_options(ff);
1566       current_opts->plugin = bstrdup(item);
1567       state = state_options;
1568       break;
1569    default:
1570       Jmsg(jcr, M_FATAL, 0, _("Invalid FileSet command: %s\n"), item);
1571       state = state_error;
1572       break;
1573    }
1574    ff->fileset->state = state;
1575 }
1576 
term_fileset(JCR * jcr)1577 static bool term_fileset(JCR *jcr)
1578 {
1579    FF_PKT *ff = jcr->ff;
1580 
1581 #ifdef xxx_DEBUG_CODE
1582    findFILESET *fileset = ff->fileset;
1583    int i, j, k;
1584 
1585    for (i=0; i<fileset->include_list.size(); i++) {
1586       findINCEXE *incexe = (findINCEXE *)fileset->include_list.get(i);
1587       Dmsg0(400, "I\n");
1588       for (j=0; j<incexe->opts_list.size(); j++) {
1589          findFOPTS *fo = (findFOPTS *)incexe->opts_list.get(j);
1590          for (k=0; k<fo->regex.size(); k++) {
1591             Dmsg1(400, "R %s\n", (char *)fo->regex.get(k));
1592          }
1593          for (k=0; k<fo->regexdir.size(); k++) {
1594             Dmsg1(400, "RD %s\n", (char *)fo->regexdir.get(k));
1595          }
1596          for (k=0; k<fo->regexfile.size(); k++) {
1597             Dmsg1(400, "RF %s\n", (char *)fo->regexfile.get(k));
1598          }
1599          for (k=0; k<fo->wild.size(); k++) {
1600             Dmsg1(400, "W %s\n", (char *)fo->wild.get(k));
1601          }
1602          for (k=0; k<fo->wilddir.size(); k++) {
1603             Dmsg1(400, "WD %s\n", (char *)fo->wilddir.get(k));
1604          }
1605          for (k=0; k<fo->wildfile.size(); k++) {
1606             Dmsg1(400, "WF %s\n", (char *)fo->wildfile.get(k));
1607          }
1608          for (k=0; k<fo->wildbase.size(); k++) {
1609             Dmsg1(400, "WB %s\n", (char *)fo->wildbase.get(k));
1610          }
1611          for (k=0; k<fo->base.size(); k++) {
1612             Dmsg1(400, "B %s\n", (char *)fo->base.get(k));
1613          }
1614          for (k=0; k<fo->fstype.size(); k++) {
1615             Dmsg1(400, "X %s\n", (char *)fo->fstype.get(k));
1616          }
1617          for (k=0; k<fo->drivetype.size(); k++) {
1618             Dmsg1(400, "XD %s\n", (char *)fo->drivetype.get(k));
1619          }
1620       }
1621       if (incexe->ignoredir) {
1622          Dmsg1(400, "Z %s\n", incexe->ignoredir);
1623       }
1624       dlistString *node;
1625       foreach_dlist(node, &incexe->name_list) {
1626          Dmsg1(400, "F %s\n", node->c_str());
1627       }
1628       foreach_dlist(node, &incexe->plugin_list) {
1629          Dmsg1(400, "P %s\n", node->c_str());
1630       }
1631    }
1632    for (i=0; i<fileset->exclude_list.size(); i++) {
1633       findINCEXE *incexe = (findINCEXE *)fileset->exclude_list.get(i);
1634       Dmsg0(400, "E\n");
1635       for (j=0; j<incexe->opts_list.size(); j++) {
1636          findFOPTS *fo = (findFOPTS *)incexe->opts_list.get(j);
1637          for (k=0; k<fo->regex.size(); k++) {
1638             Dmsg1(400, "R %s\n", (char *)fo->regex.get(k));
1639          }
1640          for (k=0; k<fo->regexdir.size(); k++) {
1641             Dmsg1(400, "RD %s\n", (char *)fo->regexdir.get(k));
1642          }
1643          for (k=0; k<fo->regexfile.size(); k++) {
1644             Dmsg1(400, "RF %s\n", (char *)fo->regexfile.get(k));
1645          }
1646          for (k=0; k<fo->wild.size(); k++) {
1647             Dmsg1(400, "W %s\n", (char *)fo->wild.get(k));
1648          }
1649          for (k=0; k<fo->wilddir.size(); k++) {
1650             Dmsg1(400, "WD %s\n", (char *)fo->wilddir.get(k));
1651          }
1652          for (k=0; k<fo->wildfile.size(); k++) {
1653             Dmsg1(400, "WF %s\n", (char *)fo->wildfile.get(k));
1654          }
1655          for (k=0; k<fo->wildbase.size(); k++) {
1656             Dmsg1(400, "WB %s\n", (char *)fo->wildbase.get(k));
1657          }
1658          for (k=0; k<fo->base.size(); k++) {
1659             Dmsg1(400, "B %s\n", (char *)fo->base.get(k));
1660          }
1661          for (k=0; k<fo->fstype.size(); k++) {
1662             Dmsg1(400, "X %s\n", (char *)fo->fstype.get(k));
1663          }
1664          for (k=0; k<fo->drivetype.size(); k++) {
1665             Dmsg1(400, "XD %s\n", (char *)fo->drivetype.get(k));
1666          }
1667       }
1668       dlistString *node;
1669       foreach_dlist(node, &incexe->name_list) {
1670          Dmsg1(400, "F %s\n", node->c_str());
1671       }
1672       foreach_dlist(node, &incexe->plugin_list) {
1673          Dmsg1(400, "P %s\n", node->c_str());
1674       }
1675    }
1676 #endif
1677    return ff->fileset->state != state_error;
1678 }
1679 
1680 
1681 /**
1682  * As an optimization, we should do this during
1683  *  "compile" time in filed/job.c, and keep only a bit mask
1684  *  and the Verify options.
1685  */
set_options(findFOPTS * fo,const char * opts)1686 static int set_options(findFOPTS *fo, const char *opts)
1687 {
1688    int j;
1689    const char *p;
1690    char strip[100];
1691 
1692 // Commented out as it is not backward compatible - KES
1693 
1694    for (p=opts; *p; p++) {
1695       switch (*p) {
1696       case 'a':                 /* alway replace */
1697       case '0':                 /* no option */
1698          break;
1699       case 'e':
1700          fo->flags |= FO_EXCLUDE;
1701          break;
1702       case 'f':
1703          fo->flags |= FO_MULTIFS;
1704          break;
1705       case 'h':                 /* no recursion */
1706          fo->flags |= FO_NO_RECURSION;
1707          break;
1708       case 'H':                 /* no hard link handling */
1709          fo->flags |= FO_NO_HARDLINK;
1710          break;
1711       case 'i':
1712          fo->flags |= FO_IGNORECASE;
1713          break;
1714       case 'M':                 /* MD5 */
1715          fo->flags |= FO_MD5;
1716          break;
1717       case 'n':
1718          fo->flags |= FO_NOREPLACE;
1719          break;
1720       case 'p':                 /* use portable data format */
1721          fo->flags |= FO_PORTABLE;
1722          break;
1723       case 'R':                 /* Resource forks and Finder Info */
1724          fo->flags |= FO_HFSPLUS;
1725          break;
1726       case 'r':                 /* read fifo */
1727          fo->flags |= FO_READFIFO;
1728          break;
1729       case 'S':
1730          switch(*(p + 1)) {
1731          case '1':
1732             fo->flags |= FO_SHA1;
1733             p++;
1734             break;
1735 #ifdef HAVE_SHA2
1736          case '2':
1737             fo->flags |= FO_SHA256;
1738             p++;
1739             break;
1740          case '3':
1741             fo->flags |= FO_SHA512;
1742             p++;
1743             break;
1744 #endif
1745          default:
1746             /*
1747              * If 2 or 3 is seen here, SHA2 is not configured, so
1748              *  eat the option, and drop back to SHA-1.
1749              */
1750             if (p[1] == '2' || p[1] == '3') {
1751                p++;
1752             }
1753             fo->flags |= FO_SHA1;
1754             break;
1755          }
1756          break;
1757       case 's':
1758          fo->flags |= FO_SPARSE;
1759          break;
1760       case 'm':
1761          fo->flags |= FO_MTIMEONLY;
1762          break;
1763       case 'k':
1764          fo->flags |= FO_KEEPATIME;
1765          break;
1766       case 'A':
1767          fo->flags |= FO_ACL;
1768          break;
1769       case 'V':                  /* verify options */
1770          /* Copy Verify Options */
1771          for (j=0; *p && *p != ':'; p++) {
1772             fo->VerifyOpts[j] = *p;
1773             if (j < (int)sizeof(fo->VerifyOpts) - 1) {
1774                j++;
1775             }
1776          }
1777          fo->VerifyOpts[j] = 0;
1778          break;
1779       case 'C':                  /* accurate options */
1780          /* Copy Accurate Options */
1781          for (j=0; *p && *p != ':'; p++) {
1782             fo->AccurateOpts[j] = *p;
1783             if (j < (int)sizeof(fo->AccurateOpts) - 1) {
1784                j++;
1785             }
1786          }
1787          fo->AccurateOpts[j] = 0;
1788          break;
1789       case 'J':                  /* Basejob options */
1790          /* Copy BaseJob Options */
1791          for (j=0; *p && *p != ':'; p++) {
1792             fo->BaseJobOpts[j] = *p;
1793             if (j < (int)sizeof(fo->BaseJobOpts) - 1) {
1794                j++;
1795             }
1796          }
1797          fo->BaseJobOpts[j] = 0;
1798          break;
1799       case 'P':                  /* strip path */
1800          /* Get integer */
1801          p++;                    /* skip P */
1802          for (j=0; *p && *p != ':'; p++) {
1803             strip[j] = *p;
1804             if (j < (int)sizeof(strip) - 1) {
1805                j++;
1806             }
1807          }
1808          strip[j] = 0;
1809          fo->strip_path = atoi(strip);
1810          fo->flags |= FO_STRIPPATH;
1811          Dmsg2(100, "strip=%s strip_path=%d\n", strip, fo->strip_path);
1812          break;
1813       case 'w':
1814          fo->flags |= FO_IF_NEWER;
1815          break;
1816       case 'W':
1817          fo->flags |= FO_ENHANCEDWILD;
1818          break;
1819       case 'Z':                 /* compression */
1820          p++;                   /* skip Z */
1821          if (*p >= '0' && *p <= '9') {
1822             fo->flags |= FO_COMPRESS;
1823             fo->Compress_algo = COMPRESS_GZIP;
1824             fo->Compress_level = *p - '0';
1825          }
1826          else if (*p == 'o') {
1827             fo->flags |= FO_COMPRESS;
1828             fo->Compress_algo = COMPRESS_LZO1X;
1829             fo->Compress_level = 1; /* not used with LZO */
1830          }
1831          break;
1832       case 'K':
1833          fo->flags |= FO_NOATIME;
1834          break;
1835       case 'c':
1836          fo->flags |= FO_CHKCHANGES;
1837          break;
1838       case 'N':
1839          fo->flags |= FO_HONOR_NODUMP;
1840          break;
1841       case 'X':
1842          fo->flags |= FO_XATTR;
1843          break;
1844       default:
1845          Jmsg1(NULL, M_ERROR, 0, _("Unknown include/exclude option: %c\n"), *p);
1846          break;
1847       }
1848    }
1849    return state_options;
1850 }
1851 
1852 
1853 /**
1854  * Director is passing his Fileset
1855  */
fileset_cmd(JCR * jcr)1856 static int fileset_cmd(JCR *jcr)
1857 {
1858    POOL_MEM buf(PM_MESSAGE);
1859    BSOCK *dir = jcr->dir_bsock;
1860    int rtnstat;
1861 
1862 #if HAVE_WIN32
1863    jcr->Snapshot = (strstr(dir->msg, "vss=1") != NULL);
1864 #else
1865    jcr->Snapshot = (strstr(dir->msg, "snap=1") != NULL);
1866 #endif
1867    if (!init_fileset(jcr)) {
1868       return 0;
1869    }
1870    while (dir->recv() >= 0) {
1871       strip_trailing_junk(dir->msg);
1872       Dmsg1(500, "Fileset: %s\n", dir->msg);
1873       pm_strcpy(buf, dir->msg);
1874       add_fileset(jcr, buf.c_str());
1875    }
1876    if (!term_fileset(jcr)) {
1877       return 0;
1878    }
1879    rtnstat = dir->fsend(OKinc);
1880    generate_plugin_event(jcr, bEventEndFileSet);
1881    return rtnstat;
1882 }
1883 
1884 
1885 /*
1886  * The Director sends us the component info file, which
1887  *   we will in turn pass to the VSS plugin.
1888  */
component_cmd(JCR * jcr)1889 static int component_cmd(JCR *jcr)
1890 {
1891    BSOCK *dir = jcr->dir_bsock;
1892 
1893    while (dir->recv() >= 0) {
1894        Dmsg1(200, "filed<dird: component: %s", dir->msg);
1895        generate_plugin_event(jcr, bEventComponentInfo, (void *)dir->msg);
1896    }
1897    return dir->fsend(OKComponentInfo);
1898 }
1899 
1900 
1901 /**
1902  * Get backup level from Director
1903  *
1904  * Note: there are odd things such as accurate_differential,
1905  *  and accurate_incremental that are passed in level, thus
1906  *  the calls to strstr() below.
1907  *
1908  */
level_cmd(JCR * jcr)1909 static int level_cmd(JCR *jcr)
1910 {
1911    BSOCK *dir = jcr->dir_bsock;
1912    POOLMEM *level, *buf = NULL;
1913    int mtime_only;
1914 
1915    level = get_memory(dir->msglen+1);
1916    Dmsg1(10, "level_cmd: %s", dir->msg);
1917 
1918    /* keep compatibility with older directors */
1919    if (strstr(dir->msg, "accurate")) {
1920       jcr->accurate = true;
1921    }
1922    if (strstr(dir->msg, "rerunning")) {
1923       jcr->rerunning = true;
1924    }
1925    if (sscanf(dir->msg, "level = %s ", level) != 1) {
1926       goto bail_out;
1927    }
1928    /* Base backup requested? */
1929    if (strcasecmp(level, "base") == 0) {
1930       jcr->setJobLevel(L_BASE);
1931    /* Full backup requested? */
1932    } else if (strcasecmp(level, "full") == 0) {
1933       jcr->setJobLevel(L_FULL);
1934    } else if (strstr(level, "differential")) {
1935       jcr->setJobLevel(L_DIFFERENTIAL);
1936       free_memory(level);
1937       return 1;
1938    } else if (strstr(level, "incremental")) {
1939       jcr->setJobLevel(L_INCREMENTAL);
1940       free_memory(level);
1941       return 1;
1942    /*
1943     * We get his UTC since time, then sync the clocks and correct it
1944     *   to agree with our clock.
1945     */
1946    } else if (strcasecmp(level, "since_utime") == 0) {
1947       buf = get_memory(dir->msglen+1);
1948       utime_t since_time, adj;
1949       btime_t his_time, bt_start, rt=0, bt_adj=0, his_time_prev=0, n=0;
1950       if (jcr->getJobLevel() == L_NONE) {
1951          jcr->setJobLevel(L_SINCE);     /* if no other job level set, do it now */
1952       }
1953       if (sscanf(dir->msg, "level = since_utime %s mtime_only=%d prev_job=%127s",
1954                  buf, &mtime_only, jcr->PrevJob) != 3) {
1955          if (sscanf(dir->msg, "level = since_utime %s mtime_only=%d",
1956                     buf, &mtime_only) != 2) {
1957             goto bail_out;
1958          }
1959       }
1960       since_time = str_to_uint64(buf);  /* this is the since time */
1961       Dmsg2(100, "since_time=%lld prev_job=%s\n", since_time, jcr->PrevJob);
1962       char ed1[50], ed2[50];
1963       /*
1964        * Sync clocks by polling him for the time. We take
1965        *   10 samples of his time throwing out the first two.
1966        */
1967       for (int i=0; i<10; i++) {
1968          bt_start = get_current_btime();
1969          dir->signal(BNET_BTIME);     /* poll for time */
1970          if (dir->recv() <= 0) {      /* get response */
1971             goto bail_out;
1972          }
1973          if (sscanf(dir->msg, "btime %50s", buf) != 1) {
1974             goto bail_out;
1975          }
1976          his_time = str_to_uint64(buf);
1977          rt = get_current_btime() - bt_start; /* compute round trip time */
1978          /* skip first two results and check for leap second */
1979          /* if any of the FD or DIR went back in time, skip this iteration */
1980          if (i < 2 || (his_time_prev > 0 && his_time < his_time_prev) || rt<0) {
1981             his_time_prev = his_time;
1982             continue;
1983          }
1984          his_time_prev = his_time;
1985          n++;
1986          Dmsg2(100, "Dirtime=%s FDtime=%s\n", edit_uint64(his_time, ed1),
1987                edit_uint64(bt_start, ed2));
1988          bt_adj +=  bt_start - his_time - rt/2;
1989          Dmsg2(100, "rt=%s adj=%s\n", edit_uint64(rt, ed1), edit_uint64(bt_adj, ed2));
1990       }
1991       adj = 0;
1992       if (n > 0) { /* Should be 1 in the worst case */
1993          bt_adj = bt_adj / n;            /* compute average time */
1994          Dmsg2(100, "rt=%s adj=%s\n", edit_uint64(rt, ed1), edit_uint64(bt_adj, ed2));
1995          adj = btime_to_utime(bt_adj);
1996          since_time += adj;              /* adjust for clock difference */
1997       }
1998       /* Don't notify if time within 3 seconds */
1999       if (adj > 3 || adj < -3) {
2000          int type;
2001          if (adj > 600 || adj < -600) {
2002             type = M_WARNING;
2003          } else {
2004             type = M_INFO;
2005          }
2006          Jmsg(jcr, type, 0, _("DIR and FD clocks differ by %lld seconds, FD automatically compensating.\n"), adj);
2007       }
2008       dir->signal(BNET_EOD);
2009 
2010       Dmsg2(100, "adj=%lld since_time=%lld\n", adj, since_time);
2011       jcr->incremental = 1;           /* set incremental or decremental backup */
2012       jcr->mtime = since_time;        /* set since time */
2013       generate_plugin_event(jcr, bEventSince, (void *)(time_t)jcr->mtime);
2014    } else {
2015       Jmsg1(jcr, M_FATAL, 0, _("Unknown backup level: %s\n"), level);
2016       free_memory(level);
2017       return 0;
2018    }
2019    free_memory(level);
2020    if (buf) {
2021       free_memory(buf);
2022    }
2023    generate_plugin_event(jcr, bEventLevel, (void*)(intptr_t)jcr->getJobLevel());
2024    return dir->fsend(OKlevel);
2025 
2026 bail_out:
2027    pm_strcpy(jcr->errmsg, dir->msg);
2028    Jmsg1(jcr, M_FATAL, 0, _("Bad level command: %s\n"), jcr->errmsg);
2029    free_memory(level);
2030    if (buf) {
2031       free_memory(buf);
2032    }
2033    return 0;
2034 }
2035 
2036 /**
2037  * Get session parameters from Director -- this is for a Restore command
2038  *   This is deprecated. It is now passed via the bsr.
2039  */
session_cmd(JCR * jcr)2040 static int session_cmd(JCR *jcr)
2041 {
2042    BSOCK *dir = jcr->dir_bsock;
2043 
2044    Dmsg1(100, "SessionCmd: %s", dir->msg);
2045    if (sscanf(dir->msg, sessioncmd, jcr->VolumeName,
2046               &jcr->VolSessionId, &jcr->VolSessionTime,
2047               &jcr->StartFile, &jcr->EndFile,
2048               &jcr->StartBlock, &jcr->EndBlock) != 7) {
2049       pm_strcpy(jcr->errmsg, dir->msg);
2050       Jmsg(jcr, M_FATAL, 0, _("Bad session command: %s"), jcr->errmsg);
2051       return 0;
2052    }
2053 
2054    return dir->fsend(OKsession);
2055 }
2056 
set_storage_auth_key(JCR * jcr,char * key)2057 static void set_storage_auth_key(JCR *jcr, char *key)
2058 {
2059    /* if no key don't update anything */
2060    if (!*key) {
2061       return;
2062    }
2063 
2064    /**
2065     * We can be contacting multiple storage daemons.
2066     * So, make sure that any old jcr->store_bsock is cleaned up.
2067     */
2068    free_bsock(jcr->store_bsock);
2069 
2070    /**
2071     * We can be contacting multiple storage daemons.
2072     *   So, make sure that any old jcr->sd_auth_key is cleaned up.
2073     */
2074    if (jcr->sd_auth_key) {
2075       /*
2076        * If we already have a Authorization key, director can do multi
2077        * storage restore
2078        */
2079       Dmsg0(5, "set multi_restore=true\n");
2080       jcr->multi_restore = true;
2081       bfree(jcr->sd_auth_key);
2082    }
2083 
2084    jcr->sd_auth_key = bstrdup(key);
2085    Dmsg1(200, "set sd auth key %s\n", jcr->sd_auth_key);
2086 }
2087 
2088 /**
2089  * Get address of storage daemon from Director
2090  *
2091  */
storage_cmd(JCR * jcr)2092 static int storage_cmd(JCR *jcr)
2093 {
2094    int stored_port = 0;            /* storage daemon port */
2095    int enable_ssl;                 /* enable ssl to sd */
2096    POOL_MEM sd_auth_key(PM_MESSAGE);
2097    BSOCK *dir = jcr->dir_bsock;
2098    BSOCK *sd;
2099 
2100    Dmsg1(100, "StorageCmd: %s", dir->msg);
2101    sd_auth_key.check_size(dir->msglen);
2102    if (sscanf(dir->msg, storaddr, &jcr->stored_addr, &stored_port,
2103               &enable_ssl, sd_auth_key.c_str()) == 4) {
2104       Dmsg1(100, "Set auth key %s\n", sd_auth_key.c_str());
2105       set_storage_auth_key(jcr, sd_auth_key.c_str());
2106   } else if (sscanf(dir->msg, storaddr_v1, &jcr->stored_addr,
2107                  &stored_port, &enable_ssl) != 3) {
2108       pm_strcpy(jcr->errmsg, dir->msg);
2109       Jmsg(jcr, M_FATAL, 0, _("Bad storage command: %s"), jcr->errmsg);
2110       Pmsg1(010, "Bad storage command: %s", jcr->errmsg);
2111       goto bail_out;
2112    }
2113 
2114 
2115    /* TODO: see if we put limit on restore and backup... */
2116    if (!jcr->max_bandwidth) {
2117       if (jcr->director->max_bandwidth_per_job) {
2118          jcr->max_bandwidth = jcr->director->max_bandwidth_per_job;
2119 
2120       } else if (me->max_bandwidth_per_job) {
2121          jcr->max_bandwidth = me->max_bandwidth_per_job;
2122       }
2123    }
2124 
2125    if (stored_port != 0) { /* We are doing the connecting */
2126       Dmsg3(110, "Connect to storage: %s:%d ssl=%d\n", jcr->stored_addr, stored_port,
2127             enable_ssl);
2128       jcr->sd_calls_client = false;
2129       sd = new_bsock();
2130       /* Open command communications with Storage daemon */
2131       /* Try to connect for 1 hour at 10 second intervals */
2132       sd->set_source_address(me->FDsrc_addr);
2133       if (!sd->connect(jcr, 10, (int)me->SDConnectTimeout, me->heartbeat_interval,
2134                 _("Storage daemon"), jcr->stored_addr, NULL, stored_port, 1)) {
2135          /* destroy() OK because sd is local */
2136          sd->destroy();
2137          Jmsg2(jcr, M_FATAL, 0, _("Failed to connect to Storage daemon: %s:%d\n"),
2138              jcr->stored_addr, stored_port);
2139          Dmsg2(100, "Failed to connect to Storage daemon: %s:%d\n",
2140              jcr->stored_addr, stored_port);
2141          goto bail_out;
2142       }
2143 
2144       Dmsg0(110, "Connection OK to SD.\n");
2145       jcr->store_bsock = sd;
2146    } else {                      /* The storage daemon called us */
2147       struct timeval tv;
2148       struct timezone tz;
2149       struct timespec timeout;
2150       int errstat;
2151 
2152       free_bsock(jcr->store_bsock);
2153       jcr->sd_calls_client = true;
2154 
2155       /*
2156        * Wait for the Storage daemon to contact us to start the Job,
2157        *  when he does, we will be released, unless the 30 minutes
2158        *  expires.
2159        */
2160       gettimeofday(&tv, &tz);
2161       timeout.tv_nsec = tv.tv_usec * 1000;
2162       timeout.tv_sec = tv.tv_sec + 30 * 60;  /* wait 30 minutes */
2163       P(mutex);
2164       while (jcr->sd_calls_client_bsock == NULL && !jcr->is_job_canceled()) {
2165          errstat = pthread_cond_timedwait(&jcr->job_start_wait, &mutex, &timeout);
2166          if (errstat == ETIMEDOUT || errstat == EINVAL || errstat == EPERM) {
2167             break;
2168          }
2169          Dmsg1(800, "=== Auth cond errstat=%d\n", errstat);
2170       }
2171       V(mutex);
2172       Dmsg2(800, "Auth fail or cancel for jid=%d %p\n", jcr->JobId, jcr);
2173 
2174       /* We should already have a storage connection! */
2175       if (jcr->sd_calls_client_bsock == NULL) {
2176          Pmsg0(000, "Failed connect from Storage daemon. SD bsock=NULL.\n");
2177          Pmsg1(000, "Storagecmd: %s", dir->msg);
2178          Jmsg0(jcr, M_FATAL, 0, _("Failed connect from Storage daemon. SD bsock=NULL.\n"));
2179          goto bail_out;
2180       }
2181       if (jcr->is_job_canceled()) {
2182          goto bail_out;
2183       }
2184       /* Assign the new socket to the main one */
2185       jcr->lock_auth();
2186       jcr->store_bsock = jcr->sd_calls_client_bsock;
2187       jcr->sd_calls_client_bsock = NULL;
2188       jcr->unlock_auth();
2189    }
2190    jcr->store_bsock->set_bwlimit(jcr->max_bandwidth);
2191 
2192    if (!send_hello_sd(jcr, jcr->Job)) {
2193       goto bail_out;
2194    }
2195 
2196    if (!authenticate_storagedaemon(jcr)) {
2197       goto bail_out;
2198    }
2199    memset(jcr->sd_auth_key, 0, strlen(jcr->sd_auth_key));
2200    Dmsg0(110, "Authenticated with SD.\n");
2201 
2202    /* Send OK to Director */
2203    return dir->fsend(OKstore);
2204 
2205 bail_out:
2206    dir->fsend(BADcmd, "storage");
2207    return 0;
2208 }
2209 
2210 #ifdef HAVE_WIN32
2211 /* TODO: merge find.c ? */
is_excluded(findFILESET * fileset,char * path)2212 static bool is_excluded(findFILESET *fileset, char *path)
2213 {
2214    int fnm_flags=FNM_CASEFOLD;
2215    int fnmode=0;
2216 
2217    /* Now apply the Exclude { } directive */
2218    for (int i=0; i<fileset->exclude_list.size(); i++) {
2219       findINCEXE *incexe = (findINCEXE *)fileset->exclude_list.get(i);
2220       dlistString *node;
2221 
2222       foreach_dlist(node, &incexe->name_list) {
2223          char *fname = node->c_str();
2224          Dmsg2(DT_VOLUME|50, "Testing %s against %s\n", path, fname);
2225          if (fnmatch(fname, path, fnmode|fnm_flags) == 0) {
2226             Dmsg1(050, "Reject wild2: %s\n", path);
2227             return true;
2228          }
2229          /* On windows, the path separator is a bit complex to handle. For
2230           * example, in fnmatch(), \ is written as \\\\ in the config file / is
2231           * different from \ So we have our own little strcmp for filenames
2232           */
2233          char *p;
2234          bool same=true;
2235          for (p = path; *p && *fname && same ; p++, fname++) {
2236             if (!((IsPathSeparator(*p) && IsPathSeparator(*fname)) ||
2237                   (tolower(*p) == tolower(*fname)))) {
2238                same = false;           /* Stop after the first one */
2239             }
2240          }
2241 
2242          if (same) {
2243             /* End of the for loop, strings looks to be identical */
2244             Dmsg1(DT_VOLUME|50, "Reject: %s\n", path);
2245             return true;
2246          }
2247 
2248          /* Looks to be the same string, but with a trailing slash */
2249          if (fname[0] && IsPathSeparator(fname[0]) && fname[1] == '\0'
2250              && p[0] == '\0')
2251          {
2252             Dmsg1(DT_VOLUME|50, "Reject: %s\n", path);
2253             return true;
2254          }
2255       }
2256    }
2257    return false;
2258 }
2259 
2260 /*
2261  * For VSS we need to know which windows drives
2262  * are used, because we create a snapshot of all used
2263  * drives before operation
2264  *
2265  */
2266 static int
get_win32_driveletters(JCR * jcr,FF_PKT * ff,char * szDrives)2267 get_win32_driveletters(JCR *jcr, FF_PKT *ff, char* szDrives)
2268 {
2269    int nCount = 0;
2270 
2271    findFILESET *fileset = ff->fileset;
2272    int  flags = 0;
2273    char drive[4];
2274 
2275    MTab mtab;
2276    mtab.get();                  /* read the disk structure */
2277 
2278    /* Keep this part for compatibility reasons */
2279    strcpy(drive, "c:\\");
2280    for (int i=0; szDrives[i] ; i++) {
2281       drive[0] = szDrives[i];
2282       if (mtab.addInSnapshotSet(drive)) { /* When all volumes are selected, we can stop */
2283          Dmsg0(DT_VOLUME|50, "All Volumes are marked, stopping the loop here\n");
2284          goto all_included;
2285       }
2286    }
2287 
2288    if (fileset) {
2289       dlistString *node;
2290 
2291       for (int i=0; i<fileset->include_list.size(); i++) {
2292 
2293          findFOPTS  *fo;
2294          findINCEXE *incexe = (findINCEXE *)fileset->include_list.get(i);
2295 
2296          /* look through all files */
2297          foreach_dlist(node, &incexe->name_list) {
2298             char *fname = node->c_str();
2299             if (mtab.addInSnapshotSet(fname)) {
2300                /* When all volumes are selected, we can stop */
2301                Dmsg0(DT_VOLUME|50, "All Volumes are marked, stopping the loop here\n");
2302                goto all_included;
2303             }
2304          }
2305 
2306          foreach_alist(fo, &incexe->opts_list) {
2307             flags |= fo->flags; /* We are looking for FO_MULTIFS and recurse */
2308          }
2309       }
2310 
2311       /* TODO: it needs to be done Include by Include, but in the worst case,
2312        * we take too much snapshots...
2313        */
2314       if (flags & FO_MULTIFS) {
2315          /* Need to add subdirectories */
2316          POOLMEM   *fn = get_pool_memory(PM_FNAME);
2317          MTabEntry *elt, *elt2;
2318          int len;
2319 
2320          Dmsg0(DT_VOLUME|50, "OneFS is set, looking for remaining volumes\n");
2321 
2322          foreach_rblist(elt, mtab.entries) {
2323             if (elt->in_SnapshotSet) {
2324                continue;         /* Already in */
2325             }
2326             /* A volume can have multiple mount points */
2327             for (wchar_t *p = elt->first() ; p && *p ; p = elt->next(p)) {
2328                wchar_2_UTF8(&fn, p);
2329 
2330                Dmsg1(DT_VOLUME|50, "Looking for path %s\n", fn);
2331 
2332                /* First case, root drive (c:/, e:/, d:/), not a submount point */
2333                len = strlen(fn);
2334                if (len <= 3) {
2335                   Dmsg1(DT_VOLUME|50, "Skiping %s\n", fn);
2336                   continue;
2337                }
2338 
2339                /* First thing is to look in the exclude list to see if this directory
2340                 * is explicitely excluded
2341                 */
2342                if (is_excluded(fileset, fn)) {
2343                   Dmsg1(DT_VOLUME|50, "Looks to be excluded %s\n", fn);
2344                   continue;
2345                }
2346 
2347                /* c:/vol/vol2/vol3
2348                 * will look c:/, then c:/vol/, then c:/vol2/ and if one of them
2349                 * is selected, the sub volume will be directly marked.
2350                 */
2351                for (char *p1 = fn ; *p1 && !elt->in_SnapshotSet ; p1++) {
2352                   if (IsPathSeparator(*p1)) {
2353 
2354                      char c = *(p1 + 1);
2355                      *(p1 + 1) = 0;
2356 
2357                      /* We look for the previous directory, and if marked, we mark
2358                       * the current one as well
2359                       */
2360                      Dmsg1(DT_VOLUME|50, "Looking for %s\n", fn);
2361                      elt2 = mtab.search(fn);
2362                      if (elt2 && elt2->in_SnapshotSet) {
2363                         Dmsg0(DT_VOLUME|50, "Put volume in SnapshotSet\n");
2364                         elt->setInSnapshotSet();
2365                      }
2366 
2367                      *(p1 + 1) = c; /* restore path separator */
2368                   }
2369                }
2370             }
2371          }
2372          free_pool_memory(fn);
2373       }
2374    all_included:
2375       /* Now, we look the volume list to know which one to include */
2376       MTabEntry *elt;
2377       foreach_rblist(elt, mtab.entries) {
2378          if (elt->in_SnapshotSet) {
2379             Dmsg1(DT_VOLUME|50,"Adding volume in mount_points list %ls\n",elt->volumeName);
2380             nCount++;
2381             ff->mount_points.append(bwcsdup(elt->volumeName));
2382          }
2383       }
2384    }
2385 
2386    return nCount;
2387 }
2388 #endif  /* HAVE_WIN32 */
2389 
2390 /*
2391  * Do a backup.
2392  */
backup_cmd(JCR * jcr)2393 static int backup_cmd(JCR *jcr)
2394 {
2395    BSOCK *dir = jcr->dir_bsock;
2396    BSOCK *sd = jcr->store_bsock;
2397    int ok = 0;
2398    int SDJobStatus;
2399    int32_t FileIndex;
2400 
2401    if (sscanf(dir->msg, "backup FileIndex=%ld\n", &FileIndex) == 1) {
2402       jcr->JobFiles = FileIndex;
2403       Dmsg1(100, "JobFiles=%ld\n", jcr->JobFiles);
2404    }
2405 
2406    /*
2407     * If explicitly requesting FO_ACL or FO_XATTR, fail job if it
2408     *  is not available on Client machine
2409     */
2410    if (jcr->ff->flags & FO_ACL && !(have_acl||have_win32)) {
2411       Jmsg(jcr, M_FATAL, 0, _("ACL support not configured for Client.\n"));
2412       goto cleanup;
2413    }
2414    if (jcr->ff->flags & FO_XATTR && !have_xattr) {
2415       Jmsg(jcr, M_FATAL, 0, _("XATTR support not configured for Client.\n"));
2416       goto cleanup;
2417    }
2418    jcr->setJobStatus(JS_Blocked);
2419    jcr->setJobType(JT_BACKUP);
2420    Dmsg1(100, "begin backup ff=%p\n", jcr->ff);
2421    if (sd == NULL) {
2422       Jmsg(jcr, M_FATAL, 0, _("Cannot contact Storage daemon\n"));
2423       dir->fsend(BADcmd, "backup");
2424       goto cleanup;
2425    }
2426 
2427    dir->fsend(OKbackup);
2428    Dmsg1(110, "filed>dird: %s", dir->msg);
2429 
2430    /*
2431     * Send Append Open Session to Storage daemon
2432     */
2433    sd->fsend(append_open);
2434    Dmsg1(110, ">stored: %s", sd->msg);
2435    /**
2436     * Expect to receive back the Ticket number
2437     */
2438    if (bget_msg(sd) >= 0) {
2439       Dmsg1(110, "<stored: %s", sd->msg);
2440       if (sscanf(sd->msg, OK_open, &jcr->Ticket) != 1) {
2441          Jmsg(jcr, M_FATAL, 0, _("Bad response to append open: %s\n"), sd->msg);
2442          goto cleanup;
2443       }
2444       Dmsg1(110, "Got Ticket=%d\n", jcr->Ticket);
2445    } else {
2446       Jmsg(jcr, M_FATAL, 0, _("Bad response from stored to open command\n"));
2447       goto cleanup;
2448    }
2449 
2450    /**
2451     * Send Append data command to Storage daemon
2452     */
2453    sd->fsend(append_data, jcr->Ticket);
2454    Dmsg1(110, ">stored: %s", sd->msg);
2455 
2456    /**
2457     * Expect to get OK data
2458     */
2459    Dmsg1(110, "<stored: %s", sd->msg);
2460    if (!response(jcr, sd, OK_data, "Append Data")) {
2461       goto cleanup;
2462    }
2463 
2464    generate_daemon_event(jcr, "JobStart");
2465    generate_plugin_event(jcr, bEventStartBackupJob);
2466 
2467    if (jcr->Snapshot) {
2468 #if defined(WIN32_VSS)
2469       P(vss_mutex);
2470    /* START VSS ON WIN32 */
2471       jcr->pVSSClient = VSSInit();
2472       if (jcr->pVSSClient->InitializeForBackup(jcr)) {
2473          generate_plugin_event(jcr, bEventVssBackupAddComponents);
2474          /* tell vss which drives to snapshot */
2475          char szWinDriveLetters[27];
2476          *szWinDriveLetters=0;
2477          generate_plugin_event(jcr, bEventVssPrepareSnapshot, szWinDriveLetters);
2478          if (get_win32_driveletters(jcr, jcr->ff, szWinDriveLetters)) {
2479             Jmsg(jcr, M_INFO, 0, _("Generate VSS snapshots. Driver=\"%s\"\n"),
2480                  jcr->pVSSClient->GetDriverName());
2481 
2482             if (!jcr->pVSSClient->CreateSnapshots(&jcr->ff->mount_points)) {
2483                berrno be;
2484                Jmsg(jcr, M_FATAL, 0, _("VSS CreateSnapshots failed. ERR=%s\n"),
2485                     be.bstrerror());
2486             } else {
2487                /* inform user about writer states */
2488                for (int i=0; i < (int)jcr->pVSSClient->GetWriterCount(); i++) {
2489                   if (jcr->pVSSClient->GetWriterState(i) < 1) {
2490                      Jmsg(jcr, M_INFO, 0, _("VSS Writer (PrepareForBackup): %s\n"),
2491                           jcr->pVSSClient->GetWriterInfo(i));
2492                   }
2493                }
2494             }
2495          } else {
2496             Jmsg(jcr, M_WARNING, 0, _("No drive letters found for generating VSS snapshots.\n"));
2497          }
2498       } else {
2499          berrno be;
2500          Jmsg(jcr, M_FATAL, 0, _("VSS was not initialized properly. ERR=%s\n"),
2501             be.bstrerror());
2502       }
2503       V(vss_mutex);
2504 #else
2505       Dmsg0(10, "Open a snapshot session\n");
2506       /* TODO: See if we abort the job */
2507       jcr->Snapshot = open_snapshot_backup_session(jcr);
2508 #endif
2509    }
2510    /* Call RunScript just after the Snapshot creation, usually, we restart services */
2511    run_scripts(jcr, jcr->RunScripts, "ClientAfterVSS");
2512 
2513    /*
2514     * Send Files to Storage daemon
2515     */
2516    Dmsg1(110, "begin blast ff=%p\n", (FF_PKT *)jcr->ff);
2517    if (!blast_data_to_storage_daemon(jcr, NULL)) {
2518       jcr->setJobStatus(JS_ErrorTerminated);
2519       sd->suppress_error_messages(true);
2520       Dmsg0(110, "Error in blast_data.\n");
2521    } else {
2522       jcr->setJobStatus(JS_Terminated);
2523       /* Note, the above set status will not override an error */
2524       if (!(jcr->JobStatus == JS_Terminated || jcr->JobStatus == JS_Warnings)) {
2525          sd->suppress_error_messages(true);
2526          goto cleanup;                /* bail out now */
2527       }
2528       /**
2529        * Expect to get response to append_data from Storage daemon
2530        */
2531       if (!response(jcr, sd, OK_append, "Append Data")) {
2532          jcr->setJobStatus(JS_ErrorTerminated);
2533          goto cleanup;
2534       }
2535 
2536       /**
2537        * Send Append End Data to Storage daemon
2538        */
2539       sd->fsend(append_end, jcr->Ticket);
2540       /* Get end OK */
2541       if (!response(jcr, sd, OK_end, "Append End")) {
2542          jcr->setJobStatus(JS_ErrorTerminated);
2543          goto cleanup;
2544       }
2545 
2546       /**
2547        * Send Append Close to Storage daemon
2548        */
2549       sd->fsend(append_close, jcr->Ticket);
2550       while (bget_msg(sd) >= 0) {    /* stop on signal or error */
2551          if (sscanf(sd->msg, OK_close, &SDJobStatus) == 1) {
2552             ok = 1;
2553             Dmsg2(200, "SDJobStatus = %d %c\n", SDJobStatus, (char)SDJobStatus);
2554          }
2555       }
2556       if (!ok) {
2557          Jmsg(jcr, M_FATAL, 0, _("Append Close with SD failed.\n"));
2558          goto cleanup;
2559       }
2560       if (!(SDJobStatus == JS_Terminated || SDJobStatus == JS_Warnings ||
2561             SDJobStatus == JS_Incomplete)) {
2562          Jmsg(jcr, M_FATAL, 0, _("Bad status %d %c returned from Storage Daemon.\n"),
2563             SDJobStatus, (char)SDJobStatus);
2564       }
2565    }
2566 
2567 cleanup:
2568 #if defined(WIN32_VSS)
2569    if (jcr->Snapshot) {
2570       Win32ConvCleanupCache();
2571       if (jcr->pVSSClient) {
2572          jcr->pVSSClient->DestroyWriterInfo();
2573       }
2574    }
2575 #endif
2576    generate_plugin_event(jcr, bEventEndBackupJob);
2577    return 0;                          /* return and stop command loop */
2578 }
2579 
2580 /**
2581  * Do a Verify for Director
2582  *
2583  */
verify_cmd(JCR * jcr)2584 static int verify_cmd(JCR *jcr)
2585 {
2586    BSOCK *dir = jcr->dir_bsock;
2587    BSOCK *sd  = jcr->store_bsock;
2588    char level[100];
2589 
2590    jcr->setJobType(JT_VERIFY);
2591    if (sscanf(dir->msg, verifycmd, level) != 1) {
2592       dir->fsend(_("2994 Bad verify command: %s\n"), dir->msg);
2593       return 0;
2594    }
2595 
2596    if (strcasecmp(level, "init") == 0) {
2597       jcr->setJobLevel(L_VERIFY_INIT);
2598    } else if (strcasecmp(level, "catalog") == 0){
2599       jcr->setJobLevel(L_VERIFY_CATALOG);
2600    } else if (strcasecmp(level, "volume") == 0){
2601       jcr->setJobLevel(L_VERIFY_VOLUME_TO_CATALOG);
2602    } else if (strcasecmp(level, "data") == 0){
2603       jcr->setJobLevel(L_VERIFY_DATA);
2604    } else if (strcasecmp(level, "disk_to_catalog") == 0) {
2605       jcr->setJobLevel(L_VERIFY_DISK_TO_CATALOG);
2606    } else {
2607       dir->fsend(_("2994 Bad verify level: %s\n"), dir->msg);
2608       return 0;
2609    }
2610 
2611    dir->fsend(OKverify);
2612 
2613    generate_daemon_event(jcr, "JobStart");
2614    generate_plugin_event(jcr, bEventLevel,(void *)(intptr_t)jcr->getJobLevel());
2615    generate_plugin_event(jcr, bEventStartVerifyJob);
2616 
2617    Dmsg1(110, "filed>dird: %s", dir->msg);
2618 
2619    switch (jcr->getJobLevel()) {
2620    case L_VERIFY_INIT:
2621    case L_VERIFY_CATALOG:
2622       do_verify(jcr);
2623       break;
2624    case L_VERIFY_DATA:
2625    case L_VERIFY_VOLUME_TO_CATALOG:
2626       if (!open_sd_read_session(jcr)) {
2627          return 0;
2628       }
2629       start_dir_heartbeat(jcr);
2630       do_verify_volume(jcr);
2631       stop_dir_heartbeat(jcr);
2632       /*
2633        * Send Close session command to Storage daemon
2634        */
2635       sd->fsend(read_close, jcr->Ticket);
2636       Dmsg1(130, "filed>stored: %s", sd->msg);
2637 
2638       /* ****FIXME**** check response */
2639       bget_msg(sd);                      /* get OK */
2640 
2641       /* Inform Storage daemon that we are done */
2642       sd->signal(BNET_TERMINATE);
2643 
2644       break;
2645    case L_VERIFY_DISK_TO_CATALOG:
2646       do_verify(jcr);
2647       break;
2648    default:
2649       dir->fsend(_("2994 Bad verify level: %s\n"), dir->msg);
2650       return 0;
2651    }
2652 
2653    dir->signal(BNET_EOD);
2654    generate_plugin_event(jcr, bEventEndVerifyJob);
2655    return 0;                          /* return and terminate command loop */
2656 }
2657 
2658 /*
2659  * Do a Restore for Director
2660  *
2661  */
restore_cmd(JCR * jcr)2662 static int restore_cmd(JCR *jcr)
2663 {
2664    BSOCK *dir = jcr->dir_bsock;
2665    BSOCK *sd = jcr->store_bsock;
2666    POOLMEM *args=NULL, *restore_where=NULL, *restore_rwhere=NULL;
2667    bool use_regexwhere=false;
2668    int prefix_links;
2669    char replace;
2670    bool scan_ok = true;
2671    int files;
2672    int ret = 0;
2673 
2674    /**
2675     * Scan WHERE (base directory for restore) from command
2676     */
2677    Dmsg0(100, "restore command\n");
2678 #if defined(WIN32_VSS)
2679 
2680    /**
2681     * No need to enable VSS for restore if we do not have plugin
2682     *  data to restore
2683     */
2684    jcr->Snapshot = jcr->got_metadata;
2685 #endif
2686 
2687    /* Pickup where string */
2688    args = get_memory(dir->msglen+1);
2689    *args = 0;
2690 
2691    restore_where = get_pool_memory(PM_FNAME);
2692    restore_rwhere = get_pool_memory(PM_FNAME);
2693 
2694    /* We don't know the size of where/rwhere in advance,
2695     * where= -> where=%202s\n
2696     */
2697    Mmsg(restore_where, "%s%%%ds\n", restorefcmd, dir->msglen);
2698    Mmsg(restore_rwhere, "%s%%%ds\n", restorefcmdR, dir->msglen);
2699 
2700    Dmsg2(200, "where=%srwhere=%s", restore_where, restore_rwhere);
2701 
2702    /* Scan for new form with number of files to restore */
2703    if (sscanf(dir->msg, restore_where, &files, &replace, &prefix_links, args) != 4) {
2704       if (sscanf(dir->msg, restore_rwhere, &files, &replace, &prefix_links, args) != 4) {
2705          if (sscanf(dir->msg, restorefcmd1, &files, &replace, &prefix_links) != 3) {
2706             scan_ok = false;
2707          }
2708          *args = 0;             /* No where argument */
2709       } else {
2710          use_regexwhere = true;
2711       }
2712    }
2713 
2714    if (scan_ok) {
2715       jcr->ExpectedFiles = files;
2716    } else {
2717       /* Scan for old form without number of files */
2718       jcr->ExpectedFiles = 0;
2719 
2720       /* where= -> where=%202s\n */
2721       Mmsg(restore_where, "%s%%%ds\n", restorecmd, dir->msglen);
2722       Mmsg(restore_rwhere, "%s%%%ds\n", restorecmdR, dir->msglen);
2723 
2724       if (sscanf(dir->msg, restore_where, &replace, &prefix_links, args) != 3) {
2725          if (sscanf(dir->msg, restore_rwhere, &replace, &prefix_links, args) != 3){
2726             if (sscanf(dir->msg, restorecmd1, &replace, &prefix_links) != 2) {
2727                pm_strcpy(jcr->errmsg, dir->msg);
2728                Jmsg(jcr, M_FATAL, 0, _("Bad replace command. CMD=%s\n"), jcr->errmsg);
2729                goto free_mempool;
2730             }
2731             *args = 0;          /* No where argument */
2732          } else {
2733             use_regexwhere = true;
2734          }
2735       }
2736    }
2737 
2738    /* Turn / into nothing */
2739    if (IsPathSeparator(args[0]) && args[1] == '\0') {
2740       args[0] = '\0';
2741    }
2742 
2743    Dmsg2(150, "Got replace %c, where=%s\n", replace, args);
2744    unbash_spaces(args);
2745 
2746    /* Keep track of newly created directories to apply them correct attributes */
2747    if (replace == REPLACE_NEVER || replace == REPLACE_IFNEWER) {
2748       jcr->keep_path_list = true;
2749    }
2750 
2751    if (use_regexwhere) {
2752       jcr->where_bregexp = get_bregexps(args);
2753       if (!jcr->where_bregexp) {
2754          Jmsg(jcr, M_FATAL, 0, _("Bad where regexp. where=%s\n"), args);
2755          goto free_mempool;
2756       }
2757       jcr->RegexWhere = bstrdup(args);
2758    } else {
2759       jcr->where = bstrdup(args);
2760    }
2761 
2762    jcr->replace = replace;
2763    jcr->prefix_links = prefix_links;
2764 
2765    dir->fsend(OKrestore);
2766    Dmsg1(110, "filed>dird: %s", dir->msg);
2767 
2768    jcr->setJobType(JT_RESTORE);
2769 
2770    jcr->setJobStatus(JS_Blocked);
2771 
2772    if (!open_sd_read_session(jcr)) {
2773       jcr->setJobStatus(JS_ErrorTerminated);
2774       goto bail_out;
2775    }
2776 
2777    jcr->setJobStatus(JS_Running);
2778 
2779    /**
2780     * Do restore of files and data
2781     */
2782    start_dir_heartbeat(jcr);
2783    generate_daemon_event(jcr, "JobStart");
2784    generate_plugin_event(jcr, bEventStartRestoreJob);
2785 
2786 #if defined(WIN32_VSS)
2787    /* START VSS ON WIN32 */
2788    if (jcr->Snapshot) {
2789       jcr->pVSSClient = VSSInit();
2790       if (!jcr->pVSSClient->InitializeForRestore(jcr)) {
2791          berrno be;
2792          Jmsg(jcr, M_WARNING, 0, _("VSS was not initialized properly. VSS support is disabled. ERR=%s\n"), be.bstrerror());
2793       }
2794       //free_and_null_pool_memory(jcr->job_metadata);
2795       run_scripts(jcr, jcr->RunScripts, "ClientAfterVSS");
2796    }
2797 #endif
2798 
2799    if (!jcr->is_canceled()) {
2800       do_restore(jcr);
2801    }
2802 
2803    stop_dir_heartbeat(jcr);
2804 
2805    jcr->setJobStatus(JS_Terminated);
2806    if (jcr->JobStatus != JS_Terminated) {
2807       sd->suppress_error_messages(true);
2808    }
2809 
2810    /**
2811     * Send Close session command to Storage daemon
2812     */
2813    sd->fsend(read_close, jcr->Ticket);
2814    Dmsg1(100, "filed>stored: %s", sd->msg);
2815 
2816    bget_msg(sd);                      /* get OK */
2817 
2818    /* Inform Storage daemon that we are done */
2819    sd->signal(BNET_TERMINATE);
2820 
2821 #if defined(WIN32_VSS)
2822    /* STOP VSS ON WIN32 */
2823    /* tell vss to close the restore session */
2824    Dmsg0(100, "About to call CloseRestore\n");
2825    if (jcr->Snapshot) {
2826 #if 0
2827       generate_plugin_event(jcr, bEventVssBeforeCloseRestore);
2828 #endif
2829       Dmsg0(100, "Really about to call CloseRestore\n");
2830       if (jcr->pVSSClient->CloseRestore()) {
2831          Dmsg0(100, "CloseRestore success\n");
2832 #if 0
2833          /* inform user about writer states */
2834          for (int i=0; i<(int)jcr->pVSSClient->GetWriterCount(); i++) {
2835             int msg_type = M_INFO;
2836             if (jcr->pVSSClient->GetWriterState(i) < 1) {
2837                //msg_type = M_WARNING;
2838                //jcr->JobErrors++;
2839             }
2840             Jmsg(jcr, msg_type, 0, _("VSS Writer (RestoreComplete): %s\n"),
2841                  jcr->pVSSClient->GetWriterInfo(i));
2842          }
2843 #endif
2844       }
2845       else {
2846          Dmsg1(100, "CloseRestore fail - %08x\n", errno);
2847       }
2848    }
2849 #endif
2850 
2851 bail_out:
2852    bfree_and_null(jcr->where);
2853    bfree_and_null(jcr->RegexWhere);
2854 
2855    Dmsg0(100, "Done in job.c\n");
2856 
2857    if (jcr->multi_restore) {
2858       Dmsg0(100, OKstoreend);
2859       dir->fsend(OKstoreend);
2860       ret = 1;     /* we continue the loop, waiting for next part */
2861    } else {
2862       ret = 0;     /* we stop here */
2863    }
2864 
2865    if (job_canceled(jcr)) {
2866       ret = 0;     /* we stop here */
2867    }
2868 
2869    if (ret == 0) {
2870       end_restore_cmd(jcr);  /* stopping so send bEventEndRestoreJob */
2871    }
2872 
2873 free_mempool:
2874    free_and_null_pool_memory(args);
2875    free_and_null_pool_memory(restore_where);
2876    free_and_null_pool_memory(restore_rwhere);
2877 
2878    return ret;
2879 }
2880 
end_restore_cmd(JCR * jcr)2881 static int end_restore_cmd(JCR *jcr)
2882 {
2883    Dmsg0(5, "end_restore_cmd\n");
2884    if (jcr->JobErrors) {
2885       jcr->setJobStatus(JS_ErrorTerminated);
2886    }
2887    generate_plugin_event(jcr, bEventEndRestoreJob);
2888    return 0;                          /* return and terminate command loop */
2889 }
2890 
open_sd_read_session(JCR * jcr)2891 static int open_sd_read_session(JCR *jcr)
2892 {
2893    BSOCK *sd = jcr->store_bsock;
2894 
2895    if (!sd) {
2896       Jmsg(jcr, M_FATAL, 0, _("Improper calling sequence.\n"));
2897       return 0;
2898    }
2899    Dmsg4(120, "VolSessId=%ld VolsessT=%ld SF=%ld EF=%ld\n",
2900       jcr->VolSessionId, jcr->VolSessionTime, jcr->StartFile, jcr->EndFile);
2901    Dmsg2(120, "JobId=%d vol=%s\n", jcr->JobId, "DummyVolume");
2902    /*
2903     * Open Read Session with Storage daemon
2904     */
2905    sd->fsend(read_open, "DummyVolume",
2906       jcr->VolSessionId, jcr->VolSessionTime, jcr->StartFile, jcr->EndFile,
2907       jcr->StartBlock, jcr->EndBlock);
2908    Dmsg1(110, ">stored: %s", sd->msg);
2909 
2910    /*
2911     * Get ticket number
2912     */
2913    if (bget_msg(sd) >= 0) {
2914       Dmsg1(110, "filed<stored: %s", sd->msg);
2915       if (sscanf(sd->msg, OK_open, &jcr->Ticket) != 1) {
2916          Jmsg(jcr, M_FATAL, 0, _("Bad response to SD read open: %s\n"), sd->msg);
2917          return 0;
2918       }
2919       Dmsg1(110, "filed: got Ticket=%d\n", jcr->Ticket);
2920    } else {
2921       Jmsg(jcr, M_FATAL, 0, _("Bad response from stored to read open command\n"));
2922       return 0;
2923    }
2924 
2925    /*
2926     * Use interactive session for the current restore
2927     */
2928    if (jcr->interactive_session) {
2929       sd->fsend(read_ctrl, jcr->Ticket);
2930       Dmsg1(110, ">stored: %s", sd->msg);
2931    }
2932 
2933    /*
2934     * Start read of data with Storage daemon
2935     */
2936    sd->fsend(read_data, jcr->Ticket);
2937    Dmsg1(110, ">stored: %s", sd->msg);
2938 
2939    /*
2940     * Get OK data
2941     */
2942    if (!response(jcr, sd, OK_data, "Read Data")) {
2943       return 0;
2944    }
2945    return 1;
2946 }
2947 
2948 /**
2949  * Destroy the Job Control Record and associated
2950  * resources (sockets).
2951  */
filed_free_jcr(JCR * jcr)2952 void filed_free_jcr(JCR *jcr)
2953 {
2954    if (jcr->dir_bsock) {
2955       free_bsock(jcr->dir_bsock);
2956       jcr->dir_bsock = NULL;
2957    }
2958    if (jcr->sd_calls_client_bsock) {
2959       free_bsock(jcr->sd_calls_client_bsock);
2960       jcr->sd_calls_client_bsock = NULL;
2961    }
2962    if (jcr->store_bsock) {
2963       free_bsock(jcr->store_bsock);
2964       jcr->store_bsock = NULL;
2965    }
2966    if (jcr->last_fname) {
2967       free_pool_memory(jcr->last_fname);
2968    }
2969 #ifdef WIN32_VSS
2970    VSSCleanup(jcr->pVSSClient);
2971 #endif
2972    free_plugins(jcr);                 /* release instantiated plugins */
2973    free_runscripts(jcr->RunScripts);
2974    delete jcr->RunScripts;
2975    free_path_list(jcr);
2976 
2977    if (jcr->JobId != 0) {
2978       write_state_file(me->working_directory, "bacula-fd", get_first_port_host_order(me->FDaddrs));
2979    }
2980    return;
2981 }
2982 
2983 /**
2984  * Get response from Storage daemon to a command we
2985  * sent. Check that the response is OK.
2986  *
2987  *  Returns: 0 on failure
2988  *           1 on success
2989  */
response(JCR * jcr,BSOCK * sd,char * resp,const char * cmd)2990 int response(JCR *jcr, BSOCK *sd, char *resp, const char *cmd)
2991 {
2992    int ret;
2993 
2994    if (sd->errors) {
2995       return 0;
2996    }
2997    if ((ret = bget_msg(sd)) > 0) {
2998       Dmsg0(110, sd->msg);
2999       if (strcmp(sd->msg, resp) == 0) {
3000          return 1;
3001       }
3002    }
3003    if (job_canceled(jcr)) {
3004       return 0;                       /* if canceled avoid useless error messages */
3005    }
3006    if (sd->is_error()) {
3007       Jmsg2(jcr, M_FATAL, 0, _("Comm error with SD. bad response to %s. ERR=%s\n"),
3008          cmd, sd->bstrerror());
3009    } else {
3010       char buf[256];
3011       if (ret > 0) {
3012          Jmsg4(jcr, M_FATAL, 0, _("Bad response from SD to %s command. Wanted %s, got len=%ld msg=\"%s\"\n"),
3013             cmd, resp, sd->msglen, smartdump(sd->msg, sd->msglen, buf, sizeof(buf)));
3014       } else {
3015          Jmsg3(jcr, M_FATAL, 0, _("Bad response from SD to %s command. Wanted %s, got SIGNAL %s\n"),
3016             cmd, resp, bnet_sig_to_ascii(ret));
3017       }
3018    }
3019    return 0;
3020 }
3021