1 /*
2 BAREOS® - Backup Archiving REcovery Open Sourced
3
4 Copyright (C) 2000-2012 Free Software Foundation Europe e.V.
5 Copyright (C) 2011-2016 Planets Communications B.V.
6 Copyright (C) 2013-2020 Bareos GmbH & Co. KG
7
8 This program is Free Software; you can redistribute it and/or
9 modify it under the terms of version three of the GNU Affero General Public
10 License as published by the Free Software Foundation and included
11 in the file LICENSE.
12
13 This program is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Affero General Public License for more details.
17
18 You should have received a copy of the GNU Affero General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
21 02110-1301, USA.
22 */
23 /*
24 * Kern Sibbald, March MM
25 */
26 /**
27 * @file
28 * the main program
29 */
30
31 #include "include/bareos.h"
32 #include "cats/cats_backends.h"
33 #include "cats/sql.h"
34 #include "cats/sql_pooling.h"
35 #include "dird.h"
36 #include "dird_globals.h"
37 #include "dird/check_catalog.h"
38 #include "dird/job.h"
39 #include "dird/scheduler.h"
40 #include "dird/socket_server.h"
41 #include "dird/stats.h"
42 #include "lib/daemon.h"
43 #include "lib/berrno.h"
44 #include "lib/edit.h"
45 #include "lib/tls_openssl.h"
46 #include "lib/bsignal.h"
47 #include "lib/daemon.h"
48 #include "lib/parse_conf.h"
49 #include "lib/thread_specific_data.h"
50 #include "lib/util.h"
51 #include "lib/watchdog.h"
52
53 #ifndef HAVE_REGEX_H
54 # include "lib/bregex.h"
55 #else
56 # include <regex.h>
57 #endif
58 #include <dirent.h>
59 #define NAMELEN(dirent) (strlen((dirent)->d_name))
60 #ifndef HAVE_READDIR_R
61 int Readdir_r(DIR* dirp, struct dirent* entry, struct dirent** result);
62 #endif
63
64 using namespace directordaemon;
65
66 /* Forward referenced subroutines */
67 namespace directordaemon {
68
69 #if !defined(HAVE_WIN32)
70 static
71 #endif
72 void
73 TerminateDird(int sig);
74 } // namespace directordaemon
75
76 static bool CheckResources();
77 static bool InitializeSqlPooling(void);
78 static void CleanUpOldFiles();
79 static bool InitSighandlerSighup();
80 static JobControlRecord* PrepareJobToRun(const char* job_name);
81
82 /* Exported subroutines */
83 extern bool ParseDirConfig(const char* configfile, int exit_code);
84 extern bool PrintMessage(void* sock, const char* fmt, ...);
85
86 /* Imported subroutines */
87 void StoreJobtype(LEX* lc, ResourceItem* item, int index, int pass);
88 void StoreProtocoltype(LEX* lc, ResourceItem* item, int index, int pass);
89 void StoreLevel(LEX* lc, ResourceItem* item, int index, int pass);
90 void StoreReplace(LEX* lc, ResourceItem* item, int index, int pass);
91 void StoreMigtype(LEX* lc, ResourceItem* item, int index, int pass);
92 void InitDeviceResources();
93
94 static char* runjob = NULL;
95 static bool background = true;
96 static bool test_config = false;
97 static alist* reload_table = NULL;
98
99 /* Globals Imported */
100 extern ResourceItem job_items[];
101
102 struct resource_table_reference {
103 int JobCount;
104 BareosResource** res_table;
105 };
106
FreeSavedResources(resource_table_reference * table)107 static void FreeSavedResources(resource_table_reference* table)
108 {
109 int num = my_config->r_last_ - my_config->r_first_ + 1;
110
111 if (!table->res_table) { return; }
112
113 for (int j = 0; j < num; j++) {
114 my_config->FreeResourceCb_(table->res_table[j], my_config->r_first_ + j);
115 }
116 free(table->res_table);
117 }
118
119 /**
120 * Called here at the end of every job that was hooked decrementing the active
121 * JobCount. When it goes to zero, no one is using the associated resource
122 * table, so free it.
123 */
ReloadJobEndCb(JobControlRecord * jcr,void * ctx)124 static void ReloadJobEndCb(JobControlRecord* jcr, void* ctx)
125 {
126 int i;
127 resource_table_reference* table;
128
129 LockJobs();
130 LockRes(my_config);
131
132 foreach_alist_index (i, table, reload_table) {
133 if (table == (resource_table_reference*)ctx) {
134 if (table->JobCount) {
135 table->JobCount--;
136 if (table->JobCount == 0) {
137 Dmsg1(100, "Last reference to old configuration table: %#010x\n",
138 table);
139 FreeSavedResources(table);
140 reload_table->remove(i);
141 free(table);
142 break;
143 }
144 }
145 }
146 }
147
148 UnlockRes(my_config);
149 UnlockJobs();
150 }
151
152 /**
153 * This allows the message handler to operate on the database by using a pointer
154 * to this function. The pointer is needed because the other daemons do not have
155 * access to the database. If the pointer is not defined (other daemons), then
156 * writing the database is disabled.
157 */
DirDbLogInsert(JobControlRecord * jcr,utime_t mtime,const char * msg)158 static bool DirDbLogInsert(JobControlRecord* jcr,
159 utime_t mtime,
160 const char* msg)
161 {
162 int length;
163 char ed1[50];
164 char dt[MAX_TIME_LENGTH];
165 PoolMem query(PM_MESSAGE), esc_msg(PM_MESSAGE);
166
167 if (!jcr || !jcr->db || !jcr->db->IsConnected()) { return false; }
168 length = strlen(msg);
169 esc_msg.check_size(length * 2 + 1);
170 jcr->db->EscapeString(jcr, esc_msg.c_str(), msg, length);
171
172 bstrutime(dt, sizeof(dt), mtime);
173 Mmsg(query, "INSERT INTO Log (JobId, Time, LogText) VALUES (%s,'%s','%s')",
174 edit_int64(jcr->JobId, ed1), dt, esc_msg.c_str());
175
176 return jcr->db->SqlQuery(query.c_str());
177 }
178
usage()179 static void usage()
180 {
181 kBareosVersionStrings.PrintCopyrightWithFsfAndPlanets(stderr, 2000);
182 fprintf(
183 stderr,
184 _("Usage: bareos-dir [options]\n"
185 " -c <path> use <path> as configuration file or directory\n"
186 " -d <nn> set debug level to <nn>\n"
187 " -dt print timestamp in debug output\n"
188 " -f run in foreground (for debugging)\n"
189 " -g <group> run as group <group>\n"
190 " -m print kaboom output (for debugging)\n"
191 " -r <job> run <job> now\n"
192 " -s no signals (for debugging)\n"
193 " -t test - read configuration and exit\n"
194 " -u <user> run as user <user>\n"
195 " -v verbose user messages\n"
196 " -xc print configuration and exit\n"
197 " -xs print configuration file schema in JSON format "
198 "and exit\n"
199 " -? print this message.\n"
200 "\n"));
201
202 exit(1);
203 }
204
205
206 /*********************************************************************
207 *
208 * Main BAREOS Director Server program
209 *
210 */
211 #if defined(HAVE_WIN32)
212 # define main BareosMain
213 #endif
214
main(int argc,char * argv[])215 int main(int argc, char* argv[])
216 {
217 int ch;
218 cat_op mode;
219 bool no_signals = false;
220 bool export_config = false;
221 bool export_config_schema = false;
222 char* uid = NULL;
223 char* gid = NULL;
224
225 setlocale(LC_ALL, "");
226 tzset();
227 bindtextdomain("bareos", LOCALEDIR);
228 textdomain("bareos");
229
230 InitStackDump();
231 MyNameIs(argc, argv, "bareos-dir");
232 InitMsg(NULL, NULL); /* initialize message handler */
233 daemon_start_time = time(NULL);
234
235 console_command = RunConsoleCommand;
236
237 while ((ch = getopt(argc, argv, "c:d:fg:mr:stu:vx:z:?")) != -1) {
238 switch (ch) {
239 case 'c': /* specify config file */
240 if (configfile != NULL) { free(configfile); }
241 configfile = strdup(optarg);
242 break;
243
244 case 'd': /* set debug level */
245 if (*optarg == 't') {
246 dbg_timestamp = true;
247 } else {
248 debug_level = atoi(optarg);
249 if (debug_level <= 0) { debug_level = 1; }
250 }
251 Dmsg1(10, "Debug level = %d\n", debug_level);
252 break;
253
254 case 'f': /* run in foreground */
255 background = false;
256 break;
257
258 case 'g': /* set group id */
259 gid = optarg;
260 break;
261
262 case 'm': /* print kaboom output */
263 prt_kaboom = true;
264 break;
265
266 case 'r': /* run job */
267 if (runjob != NULL) { free(runjob); }
268 if (optarg) { runjob = strdup(optarg); }
269 break;
270
271 case 's': /* turn off signals */
272 no_signals = true;
273 break;
274
275 case 't': /* test config */
276 test_config = true;
277 break;
278
279 case 'u': /* set uid */
280 uid = optarg;
281 break;
282
283 case 'v': /* verbose */
284 verbose++;
285 break;
286
287 case 'x': /* export configuration/schema and exit */
288 if (*optarg == 's') {
289 export_config_schema = true;
290 } else if (*optarg == 'c') {
291 export_config = true;
292 } else {
293 usage();
294 }
295 break;
296
297 case 'z': /* switch network debugging on */
298 if (!BnetDump::EvaluateCommandLineArgs(optarg)) { exit(1); }
299 break;
300
301 case '?':
302 default:
303 usage();
304 break;
305 }
306 }
307 argc -= optind;
308 argv += optind;
309
310 if (!no_signals) { InitSignals(TerminateDird); }
311
312 if (argc) {
313 if (configfile != NULL) { free(configfile); }
314 configfile = strdup(*argv);
315 argc--;
316 argv++;
317 }
318 if (argc) { usage(); }
319
320 /*
321 * See if we want to drop privs.
322 */
323 if (geteuid() == 0) {
324 drop(uid, gid, false); /* reduce privileges if requested */
325 }
326
327 if (export_config_schema) {
328 PoolMem buffer;
329
330 my_config = InitDirConfig(configfile, M_ERROR_TERM);
331 PrintConfigSchemaJson(buffer);
332 printf("%s\n", buffer.c_str());
333 goto bail_out;
334 }
335
336 my_config = InitDirConfig(configfile, M_ERROR_TERM);
337 my_config->ParseConfig();
338
339 if (export_config) {
340 my_config->DumpResources(PrintMessage, NULL);
341 goto bail_out;
342 }
343
344 if (!test_config) { /* we don't need to do this block in test mode */
345 if (background) {
346 daemon_start();
347 InitStackDump(); /* grab new pid */
348 }
349 }
350 if (InitCrypto() != 0) {
351 Jmsg((JobControlRecord*)NULL, M_ERROR_TERM, 0,
352 _("Cryptography library initialization failed.\n"));
353 goto bail_out;
354 }
355
356 if (!CheckResources()) {
357 Jmsg((JobControlRecord*)NULL, M_ERROR_TERM, 0,
358 _("Please correct the configuration in %s\n"),
359 my_config->get_base_config_path().c_str());
360 goto bail_out;
361 }
362
363 if (!test_config) { /* we don't need to do this block in test mode */
364 /* Create pid must come after we are a daemon -- so we have our final pid */
365 CreatePidFile(me->pid_directory, "bareos-dir",
366 GetFirstPortHostOrder(me->DIRaddrs));
367 ReadStateFile(me->working_directory, "bareos-dir",
368 GetFirstPortHostOrder(me->DIRaddrs));
369 }
370
371 SetJcrInThreadSpecificData(nullptr);
372
373 #if defined(HAVE_DYNAMIC_CATS_BACKENDS)
374 for (const auto& backend_dir : me->backend_directories) {
375 Dmsg1(100, "backend path: %s\n", backend_dir.c_str());
376 }
377
378 DbSetBackendDirs(me->backend_directories);
379 #endif
380 LoadDirPlugins(me->plugin_directory, me->plugin_names);
381
382 /*
383 * If we are in testing mode, we don't try to fix the catalog
384 */
385 mode = (test_config) ? CHECK_CONNECTION : UPDATE_AND_FIX;
386
387 if (!CheckCatalog(mode)) {
388 Jmsg((JobControlRecord*)NULL, M_ERROR_TERM, 0,
389 _("Please correct the configuration in %s\n"),
390 my_config->get_base_config_path().c_str());
391 goto bail_out;
392 }
393
394 if (test_config) {
395 if (my_config->HasWarnings()) {
396 /* messaging not initialized, so Jmsg with M_WARNING doesn't work */
397 fprintf(stderr, _("There are configuration warnings:\n"));
398 for (auto& warning : my_config->GetWarnings()) {
399 fprintf(stderr, " * %s\n", warning.c_str());
400 }
401 }
402 TerminateDird(0);
403 }
404
405 if (!InitializeSqlPooling()) {
406 Jmsg((JobControlRecord*)NULL, M_ERROR_TERM, 0,
407 _("Please correct the configuration in %s\n"),
408 my_config->get_base_config_path().c_str());
409 goto bail_out;
410 }
411
412 MyNameIs(0, NULL, me->resource_name_); /* set user defined name */
413
414 CleanUpOldFiles();
415
416 SetDbLogInsertCallback(DirDbLogInsert);
417
418 InitSighandlerSighup();
419
420 InitConsoleMsg(working_directory);
421
422 StartWatchdog(); /* start network watchdog thread */
423
424 InitJcrChain();
425 if (me->jcr_watchdog_time) {
426 InitJcrSubsystem(
427 me->jcr_watchdog_time); /* start JobControlRecord watchdogs etc. */
428 }
429
430 InitJobServer(me->MaxConcurrentJobs);
431
432 DbgJcrAddHook(
433 DbDebugPrint); /* used to debug BareosDb connexion after fatal signal */
434
435 // InitDeviceResources();
436
437 StartStatisticsThread();
438
439 Dmsg0(200, "Start UA server\n");
440 if (!StartSocketServer(me->DIRaddrs)) { TerminateDird(0); }
441
442 Dmsg0(200, "wait for next job\n");
443
444 if (runjob) {
445 JobControlRecord* jcr = PrepareJobToRun(runjob);
446 if (jcr) { ExecuteJob(jcr); }
447 } else {
448 Scheduler::GetMainScheduler().Run();
449 }
450
451 bail_out:
452 TerminateDird(0);
453 return 0;
454 }
455
456 /**
457 * Cleanup and then exit
458 *
459 */
460 namespace directordaemon {
461 #if !defined(HAVE_WIN32)
462 static
463 #endif
464 void
TerminateDird(int sig)465 TerminateDird(int sig)
466 {
467 static bool is_reloading = false;
468
469 if (is_reloading) { /* avoid recursive termination problems */
470 Bmicrosleep(2, 0); /* yield */
471 exit(1);
472 }
473
474 is_reloading = true;
475 debug_level = 0; /* turn off debug */
476
477 DestroyConfigureUsageString();
478 StopSocketServer();
479 StopStatisticsThread();
480 StopWatchdog();
481 DbSqlPoolDestroy();
482 DbFlushBackends();
483 UnloadDirPlugins();
484 if (!test_config && me) { /* we don't need to do this block in test mode */
485 WriteStateFile(me->working_directory, "bareos-dir",
486 GetFirstPortHostOrder(me->DIRaddrs));
487 DeletePidFile(me->pid_directory, "bareos-dir",
488 GetFirstPortHostOrder(me->DIRaddrs));
489 }
490 Scheduler::GetMainScheduler().Terminate();
491 TermJobServer();
492
493 if (runjob) { free(runjob); }
494 if (configfile != NULL) { free(configfile); }
495 if (debug_level > 5) { PrintMemoryPoolStats(); }
496 if (my_config) {
497 delete my_config;
498 my_config = NULL;
499 }
500
501 TermMsg(); /* Terminate message handler */
502 CleanupCrypto();
503 CloseMemoryPool(); /* release free memory in pool */
504
505 exit(sig);
506 }
507 } /* namespace directordaemon */
508
509 /**
510 * If we get here, we have received a SIGHUP, which means to reread our
511 * configuration file.
512 */
513 #if !defined(HAVE_WIN32)
SighandlerReloadConfig(int sig,siginfo_t * siginfo,void * ptr)514 extern "C" void SighandlerReloadConfig(int sig, siginfo_t* siginfo, void* ptr)
515 {
516 static bool is_reloading = false;
517
518 if (is_reloading) {
519 /*
520 * Note: don't use Jmsg here, as it could produce a race condition
521 * on multiple parallel reloads
522 */
523 Qmsg(NULL, M_ERROR, 0, _("Already reloading. Request ignored.\n"));
524 return;
525 }
526 is_reloading = true;
527 DoReloadConfig();
528 is_reloading = false;
529 }
530 #endif
531
InitSighandlerSighup()532 static bool InitSighandlerSighup()
533 {
534 bool retval = false;
535 #if !defined(HAVE_WIN32)
536 sigset_t block_mask;
537 struct sigaction action = {};
538
539 /*
540 * while handling SIGHUP signal,
541 * ignore further SIGHUP signals.
542 */
543 sigemptyset(&block_mask);
544 sigaddset(&block_mask, SIGHUP);
545
546 action.sa_sigaction = SighandlerReloadConfig;
547 action.sa_mask = block_mask;
548 action.sa_flags = SA_SIGINFO;
549 sigaction(SIGHUP, &action, NULL);
550
551 retval = true;
552 #endif
553 return retval;
554 }
555
556 namespace directordaemon {
DoReloadConfig()557 bool DoReloadConfig()
558 {
559 static bool is_reloading = false;
560 bool reloaded = false;
561 resource_table_reference prev_config;
562
563 if (is_reloading) {
564 /*
565 * Note: don't use Jmsg here, as it could produce a race condition
566 * on multiple parallel reloads
567 */
568 Qmsg(NULL, M_ERROR, 0, _("Already reloading. Request ignored.\n"));
569 return false;
570 }
571 is_reloading = true;
572
573 StopStatisticsThread();
574
575 LockJobs();
576 LockRes(my_config);
577
578 DbSqlPoolFlush();
579
580 prev_config.res_table = my_config->SaveResources();
581 prev_config.JobCount = 0;
582
583 Dmsg0(100, "Reloading config file\n");
584
585 my_config->err_type_ = M_ERROR;
586 my_config->ClearWarnings();
587 bool ok = my_config->ParseConfig();
588
589 if (!ok || !CheckResources() || !CheckCatalog(UPDATE_CATALOG)
590 || !InitializeSqlPooling()) {
591 Jmsg(NULL, M_ERROR, 0, _("Please correct the configuration in %s\n"),
592 my_config->get_base_config_path().c_str());
593 Jmsg(NULL, M_ERROR, 0, _("Resetting to previous configuration.\n"));
594
595 resource_table_reference temp_config;
596 temp_config.res_table = my_config->SaveResources();
597
598 int num_rcodes = my_config->r_last_ - my_config->r_first_ + 1;
599 for (int i = 0; i < num_rcodes; i++) {
600 // restore original config
601 my_config->res_head_[i] = prev_config.res_table[i];
602 }
603
604 // me is changed above by CheckResources()
605 me = (DirectorResource*)my_config->GetNextRes(R_DIRECTOR, NULL);
606 my_config->own_resource_ = me;
607
608 FreeSavedResources(&temp_config);
609 goto bail_out;
610
611 } else { // parse config ok
612
613 JobControlRecord* jcr;
614 int num_running_jobs = 0;
615 resource_table_reference* new_table = NULL;
616
617 Scheduler::GetMainScheduler().ClearQueue();
618 foreach_jcr (jcr) {
619 if (jcr->getJobType() != JT_SYSTEM) {
620 if (!new_table) {
621 new_table = (resource_table_reference*)malloc(
622 sizeof(resource_table_reference));
623 memcpy(new_table, &prev_config, sizeof(resource_table_reference));
624 }
625 new_table->JobCount++;
626 RegisterJobEndCallback(jcr, ReloadJobEndCb, (void*)new_table);
627 num_running_jobs++;
628 }
629 }
630 endeach_jcr(jcr);
631 reloaded = true;
632
633 SetWorkingDirectory(me->working_directory);
634 Dmsg0(10, "Director's configuration file reread.\n");
635
636 if (num_running_jobs > 0) {
637 if (!reload_table) { reload_table = new alist(10, not_owned_by_alist); }
638 reload_table->push(new_table);
639 } else { // no jobs running
640 FreeSavedResources(&prev_config);
641 }
642 StartStatisticsThread();
643 }
644
645 bail_out:
646 UnlockRes(my_config);
647 UnlockJobs();
648 is_reloading = false;
649 return reloaded;
650 }
651
652 } /* namespace directordaemon */
653
654 /*
655 * See if two storage definitions point to the same Storage Daemon.
656 *
657 * We compare:
658 * - address
659 * - SDport
660 * - password
661 */
IsSameStorageDaemon(StorageResource * store1,StorageResource * store2)662 static inline bool IsSameStorageDaemon(StorageResource* store1,
663 StorageResource* store2)
664 {
665 return store1->SDport == store2->SDport
666 && Bstrcasecmp(store1->address, store2->address)
667 && Bstrcasecmp(store1->password_.value, store2->password_.value);
668 }
669
670 /**
671 * Make a quick check to see that we have all the
672 * resources needed.
673 *
674 * **** FIXME **** this routine could be a lot more
675 * intelligent and comprehensive.
676 */
CheckResources()677 static bool CheckResources()
678 {
679 bool OK = true;
680 JobResource* job;
681 const std::string& configfile = my_config->get_base_config_path();
682
683 LockRes(my_config);
684
685 job = (JobResource*)my_config->GetNextRes(R_JOB, NULL);
686 me = (DirectorResource*)my_config->GetNextRes(R_DIRECTOR, NULL);
687 my_config->own_resource_ = me;
688 if (!me) {
689 Jmsg(NULL, M_FATAL, 0,
690 _("No Director resource defined in %s\n"
691 "Without that I don't know who I am :-(\n"),
692 configfile.c_str());
693 OK = false;
694 goto bail_out;
695 } else {
696 /*
697 * Sanity check.
698 */
699 if (me->MaxConsoleConnections > me->MaxConnections) {
700 me->MaxConnections = me->MaxConsoleConnections + 10;
701 }
702
703 my_config->omit_defaults_ = me->omit_defaults;
704 SetWorkingDirectory(me->working_directory);
705
706 /*
707 * See if message resource is specified.
708 */
709 if (!me->messages) {
710 me->messages = (MessagesResource*)my_config->GetNextRes(R_MSGS, NULL);
711 if (!me->messages) {
712 Jmsg(NULL, M_FATAL, 0, _("No Messages resource defined in %s\n"),
713 configfile.c_str());
714 OK = false;
715 goto bail_out;
716 }
717 }
718
719 /*
720 * When the user didn't force us we optimize for size.
721 */
722 if (!me->optimize_for_size && !me->optimize_for_speed) {
723 me->optimize_for_size = true;
724 } else if (me->optimize_for_size && me->optimize_for_speed) {
725 Jmsg(NULL, M_FATAL, 0,
726 _("Cannot optimize for speed and size define only one in %s\n"),
727 configfile.c_str());
728 OK = false;
729 goto bail_out;
730 }
731
732 if (my_config->GetNextRes(R_DIRECTOR, (BareosResource*)me) != NULL) {
733 Jmsg(NULL, M_FATAL, 0, _("Only one Director resource permitted in %s\n"),
734 configfile.c_str());
735 OK = false;
736 goto bail_out;
737 }
738
739 if (me->IsTlsConfigured()) {
740 if (!have_tls) {
741 Jmsg(NULL, M_FATAL, 0,
742 _("TLS required but not compiled into BAREOS.\n"));
743 OK = false;
744 goto bail_out;
745 }
746 }
747 }
748
749 if (!job) {
750 Jmsg(NULL, M_FATAL, 0, _("No Job records defined in %s\n"),
751 configfile.c_str());
752 OK = false;
753 goto bail_out;
754 }
755
756 if (!PopulateDefs()) {
757 OK = false;
758 goto bail_out;
759 }
760
761 /*
762 * Loop over Jobs
763 */
764 foreach_res (job, R_JOB) {
765 if (job->MaxFullConsolidations && job->JobType != JT_CONSOLIDATE) {
766 Jmsg(NULL, M_FATAL, 0,
767 _("MaxFullConsolidations configured in job %s which is not of job "
768 "type \"consolidate\" in file %s\n"),
769 job->resource_name_, configfile.c_str());
770 OK = false;
771 goto bail_out;
772 }
773
774 if (job->JobType != JT_BACKUP
775 && (job->AlwaysIncremental || job->AlwaysIncrementalJobRetention
776 || job->AlwaysIncrementalKeepNumber
777 || job->AlwaysIncrementalMaxFullAge)) {
778 Jmsg(NULL, M_FATAL, 0,
779 _("AlwaysIncremental configured in job %s which is not of job type "
780 "\"backup\" in file %s\n"),
781 job->resource_name_, configfile.c_str());
782 OK = false;
783 goto bail_out;
784 }
785 }
786
787 ConsoleResource* cons;
788 foreach_res (cons, R_CONSOLE) {
789 if (cons->IsTlsConfigured()) {
790 if (!have_tls) {
791 Jmsg(NULL, M_FATAL, 0,
792 _("TLS required but not configured in BAREOS.\n"));
793 OK = false;
794 goto bail_out;
795 }
796 }
797 }
798
799 me->subscriptions_used = 0;
800 ClientResource* client;
801 foreach_res (client, R_CLIENT) {
802 /*
803 * Count the number of clients
804 *
805 * Only used as indication not an enforced limit.
806 */
807 me->subscriptions_used++;
808
809 if (client->IsTlsConfigured()) {
810 if (!have_tls) {
811 Jmsg(NULL, M_FATAL, 0, _("TLS required but not configured.\n"));
812 OK = false;
813 goto bail_out;
814 }
815 }
816 }
817
818 StorageResource *store, *nstore;
819 foreach_res (store, R_STORAGE) {
820 if (store->IsTlsConfigured()) {
821 if (!have_tls) {
822 Jmsg(NULL, M_FATAL, 0, _("TLS required but not configured.\n"));
823 OK = false;
824 goto bail_out;
825 }
826 }
827
828 /*
829 * If we collect statistics on this SD make sure any other entry pointing to
830 * the same SD does not collect statistics otherwise we collect the same
831 * data multiple times.
832 */
833 if (store->collectstats) {
834 nstore = store;
835 while ((nstore = (StorageResource*)my_config->GetNextRes(
836 R_STORAGE, (BareosResource*)nstore))) {
837 if (IsSameStorageDaemon(store, nstore) && nstore->collectstats) {
838 nstore->collectstats = false;
839 Dmsg1(200,
840 _("Disabling collectstats for storage \"%s\""
841 " as other storage already collects from this SD.\n"),
842 nstore->resource_name_);
843 }
844 }
845 }
846 }
847
848 if (OK) {
849 CloseMsg(NULL); /* close temp message handler */
850 InitMsg(NULL, me->messages); /* open daemon message handler */
851 if (me->secure_erase_cmdline) {
852 SetSecureEraseCmdline(me->secure_erase_cmdline);
853 }
854 if (me->log_timestamp_format) {
855 SetLogTimestampFormat(me->log_timestamp_format);
856 }
857 }
858
859 bail_out:
860 UnlockRes(my_config);
861 return OK;
862 }
863
864 /**
865 * Initialize the sql pooling.
866 */
InitializeSqlPooling(void)867 static bool InitializeSqlPooling(void)
868 {
869 bool retval = true;
870 CatalogResource* catalog;
871
872 foreach_res (catalog, R_CATALOG) {
873 if (!db_sql_pool_initialize(
874 catalog->db_driver, catalog->db_name, catalog->db_user,
875 catalog->db_password.value, catalog->db_address, catalog->db_port,
876 catalog->db_socket, catalog->disable_batch_insert,
877 catalog->try_reconnect, catalog->exit_on_fatal,
878 catalog->pooling_min_connections, catalog->pooling_max_connections,
879 catalog->pooling_increment_connections,
880 catalog->pooling_idle_timeout, catalog->pooling_validate_timeout)) {
881 Jmsg(NULL, M_FATAL, 0,
882 _("Could not setup sql pooling for Catalog \"%s\", database "
883 "\"%s\".\n"),
884 catalog->resource_name_, catalog->db_name);
885 retval = false;
886 goto bail_out;
887 }
888 }
889
890 bail_out:
891 return retval;
892 }
893
PrepareJobToRun(const char * job_name)894 static JobControlRecord* PrepareJobToRun(const char* job_name)
895 {
896 JobResource* job
897 = static_cast<JobResource*>(my_config->GetResWithName(R_JOB, job_name));
898 if (!job) {
899 Emsg1(M_ERROR, 0, _("Job %s not found\n"), job_name);
900 return nullptr;
901 }
902 Dmsg1(5, "Found job_name %s\n", job_name);
903 JobControlRecord* jcr = NewDirectorJcr();
904 SetJcrDefaults(jcr, job);
905 return jcr;
906 }
907
CleanUpOldFiles()908 static void CleanUpOldFiles()
909 {
910 DIR* dp;
911 struct dirent* result;
912 #ifdef USE_READDIR_R
913 struct dirent* entry;
914 #endif
915 int rc, name_max;
916 int my_name_len = strlen(my_name);
917 int len = strlen(me->working_directory);
918 POOLMEM* cleanup = GetPoolMemory(PM_MESSAGE);
919 POOLMEM* basename = GetPoolMemory(PM_MESSAGE);
920 regex_t preg1{};
921 char prbuf[500];
922 BErrNo be;
923
924 /* Exclude spaces and look for .mail or .restore.xx.bsr files */
925 const char* pat1 = "^[^ ]+\\.(restore\\.[^ ]+\\.bsr|mail)$";
926
927 /* Setup working directory prefix */
928 PmStrcpy(basename, me->working_directory);
929 if (len > 0 && !IsPathSeparator(me->working_directory[len - 1])) {
930 PmStrcat(basename, "/");
931 }
932
933 /* Compile regex expressions */
934 rc = regcomp(&preg1, pat1, REG_EXTENDED);
935 if (rc != 0) {
936 regerror(rc, &preg1, prbuf, sizeof(prbuf));
937 Pmsg2(000, _("Could not compile regex pattern \"%s\" ERR=%s\n"), pat1,
938 prbuf);
939 goto get_out2;
940 }
941
942 name_max = pathconf(".", _PC_NAME_MAX);
943 if (name_max < 1024) { name_max = 1024; }
944
945 if (!(dp = opendir(me->working_directory))) {
946 BErrNo be;
947 Pmsg2(000, "Failed to open working dir %s for cleanup: ERR=%s\n",
948 me->working_directory, be.bstrerror());
949 goto get_out1;
950 return;
951 }
952
953 #ifdef USE_READDIR_R
954 entry = (struct dirent*)malloc(sizeof(struct dirent) + name_max + 1000);
955 while (1) {
956 if ((Readdir_r(dp, entry, &result) != 0) || (result == NULL)) {
957 #else
958 while (1) {
959 result = readdir(dp);
960 if (result == NULL) {
961 #endif
962
963 break;
964 }
965 /* Exclude any name with ., .., not my_name or containing a space */
966 if (strcmp(result->d_name, ".") == 0 || strcmp(result->d_name, "..") == 0
967 || strncmp(result->d_name, my_name, my_name_len) != 0) {
968 Dmsg1(500, "Skipped: %s\n", result->d_name);
969 continue;
970 }
971
972 /* Unlink files that match regexes */
973 if (regexec(&preg1, result->d_name, 0, NULL, 0) == 0) {
974 PmStrcpy(cleanup, basename);
975 PmStrcat(cleanup, result->d_name);
976 Dmsg1(100, "Unlink: %s\n", cleanup);
977 SecureErase(NULL, cleanup);
978 }
979 }
980
981 #ifdef USE_READDIR_R
982 free(entry);
983 #endif
984 closedir(dp);
985 /* Be careful to free up the correct resources */
986 get_out1:
987 regfree(&preg1);
988 get_out2:
989 FreePoolMemory(cleanup);
990 FreePoolMemory(basename);
991 }
992