1 #include "burp.h"
2 #include "base64.h"
3 #include "cmd.h"
4 #include "conf.h"
5 #include "conffile.h"
6 #include "client/main.h"
7 #include "handy.h"
8 #include "hexmap.h"
9 #include "lock.h"
10 #include "log.h"
11 #include "strlist.h"
12 #include "server/main.h"
13 #include "server/protocol1/bedup.h"
14 #include "server/protocol2/bsigs.h"
15 #include "server/protocol2/bsparse.h"
16 #include "server/protocol2/champ_chooser/champ_server.h"
17
usage_server(void)18 static void usage_server(void)
19 {
20 #ifndef HAVE_WIN32
21 printf("\nThe configuration file specifies whether %s runs in server or client mode.\n", PACKAGE_TARNAME);
22 printf("\nServer usage: %s [options]\n", progname());
23 printf("\n");
24 printf(" Options:\n");
25 printf(" -a c Run as a stand-alone champion chooser.\n");
26 printf(" -c <path> Path to conf file (default: %s).\n", config_default_path());
27 printf(" -d <path> a single client in the status monitor.\n");
28 printf(" -o <option> Override a given configuration option\n");
29 printf(" (you can use this flag several times).\n");
30 printf(" -F Stay in the foreground.\n");
31 printf(" -g Generate initial CA certificates and exit.\n");
32 printf(" -h|-? Print this text and exit.\n");
33 printf(" -i Print index of symbols and exit.\n");
34 printf(" -n Do not fork any children (implies '-F').\n");
35 printf(" -Q Do not log to stdout\n");
36 printf(" -t Dry-run to test config file syntax.\n");
37 printf(" -v Log to stdout.\n");
38 printf(" -V Print version and exit.\n");
39 printf("Options to use with '-a c':\n");
40 printf(" -C <client> Run as if forked via a connection from this client.\n");
41 printf("\n");
42 #endif
43 }
44
usage_client(void)45 static void usage_client(void)
46 {
47 printf("\nClient usage: %s [options]\n", progname());
48 printf("\n");
49 printf(" Options:\n");
50 printf(" -a <action> The action can be one of the following.\n");
51 printf(" b: backup\n");
52 printf(" delete: delete\n");
53 printf(" d: diff\n");
54 printf(" e: estimate\n");
55 printf(" l: list (this is the default when an action is not given)\n");
56 printf(" L: long list\n");
57 printf(" m: monitor interface\n");
58 printf(" p: parseable list\n");
59 printf(" r: restore\n");
60 printf(" R: Restore (matching ordered paths on stdin)\n");
61 #ifndef HAVE_WIN32
62 printf(" s: status monitor (ncurses)\n");
63 printf(" S: status monitor snapshot\n");
64 #endif
65 printf(" t: timed backup\n");
66 printf(" T: check backup timer, but do not actually backup\n");
67 printf(" v: verify\n");
68 printf(" V: Verify (matching ordered paths on stdin)\n");
69 printf(" -b <number> Backup number (default: the most recent backup).\n");
70 printf(" -c <path> Path to conf file (default: %s).\n", config_default_path());
71 printf(" -d <directory> Directory to restore to, or directory to list.\n");
72 printf(" -o <option> Override a given configuration option (you can use this flag several times).\n");
73 printf(" -f Allow overwrite during restore.\n");
74 printf(" -h|-? Print this text and exit.\n");
75 printf(" -i Print index of symbols and exit.\n");
76 printf(" -q <max secs> Randomised delay of starting a timed backup.\n");
77 printf(" -Q Do not log to stdout\n");
78 printf(" -r|-R <regex> Specify a regular expression (case sensitive or insensitive.\n");
79 printf(" -s <number> Number of leading path components to strip during restore.\n");
80 printf(" -t Dry-run to test config file syntax.\n");
81 printf(" -V Print version and exit.\n");
82 printf(" -v Log to stdout.\n");
83 #ifdef HAVE_WIN32
84 printf(" -X Do not use the Windows VSS API when restoring.\n");
85 printf(" -x Do not use the Windows VSS API when restoring,\n");
86 printf(" and strip out VSS data.\n");
87 #else
88 printf(" -x Strip Windows VSS data when restoring.\n");
89 printf("Options to use with '-a S':\n");
90 printf(" -C <client> Show a particular client.\n");
91 printf(" -b <number> Show listable files in a particular backup (requires -C).\n");
92 printf(" -d <path> Show a particular path in a backup (requires -C and -b).\n");
93 printf(" -l <path> Log file for the status monitor.\n");
94 printf(" -z <file> Dump a particular log file in a backup (requires -C and -b).\n");
95 #endif
96 printf("\n");
97 #ifndef HAVE_WIN32
98 printf(" See ");
99 // Older versions of autoconf do not pick up PACKAGE_URL.
100 #ifdef PACKAGE_URL
101 printf("%s or ", PACKAGE_URL);
102 #endif
103 printf( "the man page ('man %s') for usage examples\n",
104 PACKAGE_TARNAME);
105 printf(" and additional configuration options.\n\n");
106 #else
107 printf(" See %s for usage examples and additional configuration\n",
108 PACKAGE_TARNAME);
109 printf(" options.\n\n");
110 #endif
111 }
112
reload(struct conf ** confs,const char * conffile,bool firsttime)113 int reload(struct conf **confs, const char *conffile, bool firsttime)
114 {
115 if(!firsttime) logp("Reloading config\n");
116
117 if(confs_init(confs)) return -1;
118
119 if(conf_load_global_only(conffile, confs)) return -1;
120
121 umask(get_mode_t(confs[OPT_UMASK]));
122
123 // This will turn on syslogging which could not be turned on before
124 // conf_load.
125 log_fzp_set(NULL, confs);
126
127 #ifndef HAVE_WIN32
128 if(get_e_burp_mode(confs[OPT_BURP_MODE])==BURP_MODE_SERVER)
129 setup_signals();
130 #endif
131
132 return 0;
133 }
134
replace_conf_str(struct conf * conf,const char * newval)135 static int replace_conf_str(struct conf *conf, const char *newval)
136 {
137 if(!newval) return 0;
138 return set_string(conf, newval);
139 }
140
usage(void)141 static void usage(void)
142 {
143 usage_server();
144 usage_client();
145 }
146
parse_action(enum action * act,const char * optarg,struct strlist ** cli_overrides)147 static int parse_action(enum action *act, const char *optarg,
148 struct strlist **cli_overrides)
149 {
150 if(!strncmp(optarg, "backup", 1))
151 *act=ACTION_BACKUP;
152 else if(!strncmp(optarg, "timedbackup", 1))
153 *act=ACTION_BACKUP_TIMED;
154 else if(!strncmp(optarg, "Timercheck", 1))
155 *act=ACTION_TIMER_CHECK;
156 else if(!strncmp(optarg, "restore", 1))
157 *act=ACTION_RESTORE;
158 else if(!strncmp(optarg, "Restore", 1))
159 {
160 *act=ACTION_RESTORE;
161 strlist_add(cli_overrides, "restore_list=/dev/stdin", 0);
162 }
163 else if(!strncmp(optarg, "verify", 1))
164 *act=ACTION_VERIFY;
165 else if(!strncmp(optarg, "Verify", 1))
166 {
167 *act=ACTION_VERIFY;
168 strlist_add(cli_overrides, "restore_list=/dev/stdin", 0);
169 }
170 else if(!strncmp(optarg, "list", 1))
171 *act=ACTION_LIST;
172 else if(!strncmp(optarg, "List", 1))
173 *act=ACTION_LIST_LONG;
174 else if(!strncmp(optarg, "parseablelist", 1))
175 *act=ACTION_LIST_PARSEABLE;
176 else if(!strncmp(optarg, "status", 1))
177 *act=ACTION_STATUS;
178 else if(!strncmp(optarg, "Status", 1))
179 *act=ACTION_STATUS_SNAPSHOT;
180 else if(!strncmp(optarg, "estimate", 1))
181 *act=ACTION_ESTIMATE;
182 // Make them spell 'delete' out fully so that it is less likely to be
183 // used accidently.
184 else if(!strncmp_w(optarg, "delete"))
185 *act=ACTION_DELETE;
186 else if(!strncmp(optarg, "champchooser", 1))
187 *act=ACTION_CHAMP_CHOOSER;
188 else if(!strncmp(optarg, "diff", 1))
189 *act=ACTION_DIFF;
190 else if(!strncmp(optarg, "Diff", 1))
191 *act=ACTION_DIFF_LONG;
192 else if(!strncmp(optarg, "monitor", 1))
193 *act=ACTION_MONITOR;
194 else
195 {
196 usage();
197 return -1;
198 }
199 return 0;
200 }
201
202 #ifndef HAVE_WIN32
run_champ_chooser(struct conf ** confs)203 static int run_champ_chooser(struct conf **confs)
204 {
205 const char *orig_client=get_string(confs[OPT_ORIG_CLIENT]);
206 if(orig_client && *orig_client)
207 return champ_chooser_server_standalone(confs);
208 logp("No client name given for standalone champion chooser process.\n");
209 logp("Try using the '-C' option.\n");
210 return 1;
211 }
212
server_modes(enum action act,const char * conffile,struct lock * lock,int generate_ca_only,struct conf ** confs)213 static int server_modes(enum action act,
214 const char *conffile, struct lock *lock, int generate_ca_only,
215 struct conf **confs)
216 {
217 switch(act)
218 {
219 case ACTION_CHAMP_CHOOSER:
220 // We are running on the server machine, wanting to
221 // be a standalone champion chooser process.
222 return run_champ_chooser(confs);
223 default:
224 return server(confs, conffile, lock, generate_ca_only);
225 }
226 }
227 #endif
228
random_delay(struct conf ** confs)229 static void random_delay(struct conf **confs)
230 {
231 int delay;
232 int randomise=get_int(confs[OPT_RANDOMISE]);
233 if(!randomise) return;
234 srand(getpid());
235 delay=rand()%randomise;
236 logp("Sleeping %d seconds\n", delay);
237 sleep(delay);
238 }
239
run_test_confs(struct conf ** confs,const char * client)240 static int run_test_confs(struct conf **confs, const char *client)
241 {
242 int ret=-1;
243 struct conf **cconfs=NULL;
244 if(!client)
245 {
246 confs_dump(confs, 0);
247 ret=0;
248 goto end;
249 }
250 if(!(cconfs=confs_alloc()))
251 goto end;
252 confs_init(cconfs);
253 if(set_string(cconfs[OPT_CNAME], client)
254 || set_string(cconfs[OPT_PEER_VERSION], PACKAGE_VERSION)
255 || conf_load_clientconfdir(confs, cconfs))
256 goto end;
257 confs_dump(cconfs, CONF_FLAG_CC_OVERRIDE|CONF_FLAG_INCEXC);
258
259 end:
260 confs_free(&cconfs);
261 return ret;
262 }
263
get_prog_lock(struct conf ** confs)264 static struct lock *get_prog_lock(struct conf **confs)
265 {
266 struct lock *lock=NULL;
267 const char *lockfile=confs_get_lockfile(confs);
268 if(!(lock=lock_alloc_and_init(lockfile)))
269 goto error;
270 lock_get(lock);
271 switch(lock->status)
272 {
273 case GET_LOCK_GOT:
274 return lock;
275 case GET_LOCK_NOT_GOT:
276 logp("Could not get lockfile.\n");
277 logp("Another process is probably running.\n");
278 goto error;
279 case GET_LOCK_ERROR:
280 default:
281 logp("Could not get lockfile.\n");
282 logp("Maybe you do not have permissions to write to %s.\n", lockfile);
283 goto error;
284 }
285 error:
286 lock_free(&lock);
287 return NULL;
288 }
289
290 #ifdef HAVE_WIN32
291 #define main RealMain
292 #endif
293 #ifndef UTEST
294 static
295 #endif
real_main(int argc,char * argv[])296 int real_main(int argc, char *argv[])
297 {
298 int ret=1;
299 int option=0;
300 int daemon=1;
301 int forking=1;
302 int strip=0;
303 int randomise=0;
304 struct lock *lock=NULL;
305 struct conf **confs=NULL;
306 int forceoverwrite=0;
307 enum action act=ACTION_LIST;
308 const char *backup=NULL;
309 const char *backup2=NULL;
310 char *restoreprefix=NULL;
311 char *stripfrompath=NULL;
312 const char *regex=NULL;
313 const char *browsefile=NULL;
314 char *browsedir=NULL;
315 const char *conffile=config_default_path();
316 const char *orig_client=NULL;
317 const char *logfile=NULL;
318 // The orig_client is the original client that the normal client
319 // would like to restore from.
320 #ifndef HAVE_WIN32
321 int generate_ca_only=0;
322 #endif
323 enum vss_restore vss_restore=VSS_RESTORE_ON;
324 int test_confs=0;
325 enum burp_mode mode;
326 struct strlist *cli_overrides=NULL;
327 int keep_readall_caps=0;
328 int regex_case_insensitive=0;
329
330 log_init(argv[0]);
331 #ifndef HAVE_WIN32
332 if(!strcmp(prog, "bedup"))
333 return run_bedup(argc, argv);
334 if(!strcmp(prog, "bsigs"))
335 return run_bsigs(argc, argv);
336 if(!strcmp(prog, "bsparse"))
337 return run_bsparse(argc, argv);
338 #endif
339
340 while((option=getopt(argc, argv, "a:b:C:c:d:o:Ffghijl:nQq:R:r:s:tVvXxz:?"))!=-1)
341 {
342 switch(option)
343 {
344 case 'a':
345 if(parse_action(&act, optarg,
346 &cli_overrides)) goto end;
347 break;
348 case 'b':
349 // The diff command may have two backups
350 // specified.
351 if(!backup2 && backup) backup2=optarg;
352 if(!backup) backup=optarg;
353 break;
354 case 'C':
355 orig_client=optarg;
356 break;
357 case 'c':
358 conffile=optarg;
359 break;
360 case 'd':
361 restoreprefix=optarg; // for restores
362 browsedir=optarg; // for lists
363 break;
364 case 'F':
365 daemon=0;
366 break;
367 case 'f':
368 forceoverwrite=1;
369 break;
370 case 'g':
371 #ifndef HAVE_WIN32
372 generate_ca_only=1;
373 #endif
374 break;
375 case 'i':
376 cmd_print_all();
377 ret=0;
378 goto end;
379 case 'l':
380 logfile=optarg;
381 break;
382 case 'n':
383 forking=0;
384 break;
385 case 'o':
386 strlist_add(&cli_overrides, optarg, 0);
387 break;
388 case 'Q':
389 strlist_add(&cli_overrides, "progress_counter=0", 0);
390 strlist_add(&cli_overrides, "stdout=0", 0);
391 break;
392 case 'q':
393 randomise=atoi(optarg);
394 break;
395 case 'R':
396 regex_case_insensitive=1;
397 regex=optarg;
398 break;
399 case 'r':
400 regex_case_insensitive=0;
401 regex=optarg;
402 break;
403 case 's':
404 strip=atoi(optarg);
405 break;
406 case 'V':
407 printf("%s-%s\n", progname(), PACKAGE_VERSION);
408 ret=0;
409 goto end;
410 case 'v':
411 strlist_add(&cli_overrides, "stdout=1", 0);
412 break;
413 case 'X':
414 vss_restore=VSS_RESTORE_OFF;
415 break;
416 case 'x':
417 vss_restore=VSS_RESTORE_OFF_STRIP;
418 break;
419 case 't':
420 test_confs=1;
421 break;
422 case 'z':
423 browsefile=optarg;
424 break;
425 case 'h':
426 case '?':
427 default:
428 usage();
429 goto end;
430 }
431 }
432 if(optind<argc)
433 {
434 usage();
435 goto end;
436 }
437
438 if(act==ACTION_MONITOR)
439 {
440 // Try to output everything in JSON.
441 log_set_json(1);
442 // Need to do this so that processes reading stdout get the
443 // result of the printfs of logp straight away.
444 setvbuf(stdout, NULL, _IONBF, 0);
445 }
446
447 if(act==ACTION_LIST_PARSEABLE)
448 strlist_add(&cli_overrides, "stdout=0", 0);
449
450 conf_set_cli_overrides(cli_overrides);
451 if(!(confs=confs_alloc()))
452 goto end;
453
454 if(reload(confs, conffile, 1))
455 goto end;
456
457 // Dry run to test config file syntax.
458 if(test_confs)
459 {
460 ret=run_test_confs(confs, orig_client);
461 goto end;
462 }
463
464 if(!backup) switch(act)
465 {
466 case ACTION_DELETE:
467 logp("No backup specified for deletion.\n");
468 goto end;
469 case ACTION_RESTORE:
470 case ACTION_VERIFY:
471 case ACTION_DIFF:
472 case ACTION_DIFF_LONG:
473 logp("No backup specified. Using the most recent.\n");
474 backup="0";
475 default:
476 break;
477 }
478 if(!backup2) switch(act)
479 {
480 case ACTION_DIFF:
481 case ACTION_DIFF_LONG:
482 logp("No second backup specified. Using file system scan.\n");
483 backup2="n"; // For 'next'.
484 default:
485 break;
486 }
487
488 // The logfile option is only used for the status client stuff.
489 if(logfile
490 && (act!=ACTION_STATUS
491 && act!=ACTION_STATUS_SNAPSHOT))
492 logp("-l <logfile> option obsoleted\n");
493
494 if(orig_client
495 && *orig_client
496 && set_string(confs[OPT_ORIG_CLIENT], orig_client))
497 goto end;
498
499 // The random delay needs to happen before the lock is got, otherwise
500 // you would never be able to use burp by hand.
501 if(randomise) set_int(confs[OPT_RANDOMISE], randomise);
502 mode=get_e_burp_mode(confs[OPT_BURP_MODE]);
503 if(mode==BURP_MODE_CLIENT
504 && (act==ACTION_BACKUP_TIMED || act==ACTION_TIMER_CHECK))
505 random_delay(confs);
506
507 if(mode==BURP_MODE_SERVER)
508 {
509 switch(act)
510 {
511 case ACTION_CHAMP_CHOOSER:
512 // Need to run without getting the lock.
513 break;
514 default:
515 if(!(lock=get_prog_lock(confs)))
516 goto end;
517 break;
518 }
519 }
520 else if(mode==BURP_MODE_CLIENT)
521 {
522 set_int(confs[OPT_VSS_RESTORE], vss_restore);
523 switch(act)
524 {
525 case ACTION_BACKUP:
526 case ACTION_BACKUP_TIMED:
527 case ACTION_TIMER_CHECK:
528 #ifdef ENABLE_KEEP_READALL_CAPS_SUPPORT
529 keep_readall_caps=get_int(confs[OPT_READALL]);
530 // readall=1 cannot work with atime=0 (O_NOATIME)
531 if (keep_readall_caps)
532 set_int(confs[OPT_ATIME], 1);
533 #endif
534 // Need to get the lock.
535 if(!(lock=get_prog_lock(confs)))
536 goto end;
537 break;
538 default:
539 break;
540 }
541 }
542
543 // Change privileges after having got the lock, for convenience.
544 if(chuser_and_or_chgrp(
545 get_string(confs[OPT_USER]), get_string(confs[OPT_GROUP]),
546 keep_readall_caps))
547 return -1;
548
549 set_int(confs[OPT_OVERWRITE], forceoverwrite);
550 set_int(confs[OPT_STRIP], strip);
551 set_int(confs[OPT_FORK], forking);
552 set_int(confs[OPT_DAEMON], daemon);
553 set_int(confs[OPT_REGEX_CASE_INSENSITIVE], regex_case_insensitive);
554
555 strip_trailing_slashes(&restoreprefix);
556 strip_trailing_slashes(&browsedir);
557 if(replace_conf_str(confs[OPT_BACKUP], backup)
558 || replace_conf_str(confs[OPT_BACKUP2], backup2)
559 || replace_conf_str(confs[OPT_RESTOREPREFIX], restoreprefix)
560 || replace_conf_str(confs[OPT_STRIP_FROM_PATH], stripfrompath)
561 || replace_conf_str(confs[OPT_REGEX], regex)
562 || replace_conf_str(confs[OPT_BROWSEFILE], browsefile)
563 || replace_conf_str(confs[OPT_BROWSEDIR], browsedir)
564 || replace_conf_str(confs[OPT_MONITOR_LOGFILE], logfile))
565 goto end;
566
567 base64_init();
568 hexmap_init();
569
570 if(mode==BURP_MODE_SERVER)
571 {
572 #ifdef HAVE_WIN32
573 logp("Sorry, server mode is not implemented for Windows.\n");
574 #else
575 ret=server_modes(act,
576 conffile, lock, generate_ca_only, confs);
577 #endif
578 }
579 else
580 {
581 ret=client(confs, act);
582 }
583
584 end:
585 lock_release(lock);
586 lock_free(&lock);
587 confs_free(&confs);
588 strlists_free(&cli_overrides);
589 return ret;
590 }
591
592 #ifndef UTEST
main(int argc,char * argv[])593 int main(int argc, char *argv[])
594 {
595 return real_main(argc, argv);
596 }
597 #endif
598