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