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