"Fossies" - the Fresh Open Source Software Archive

Member "cfengine-3.15.4/cf-execd/cf-execd.c" (7 Jun 2021, 21816 Bytes) of package /linux/misc/cfengine-3.15.4.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "cf-execd.c" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 3.15.3_vs_3.15.4.

    1 /*
    2   Copyright 2019 Northern.tech AS
    3 
    4   This file is part of CFEngine 3 - written and maintained by Northern.tech AS.
    5 
    6   This program is free software; you can redistribute it and/or modify it
    7   under the terms of the GNU General Public License as published by the
    8   Free Software Foundation; version 3.
    9 
   10   This program is distributed in the hope that it will be useful,
   11   but WITHOUT ANY WARRANTY; without even the implied warranty of
   12   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   13   GNU General Public License for more details.
   14 
   15   You should have received a copy of the GNU General Public License
   16   along with this program; if not, write to the Free Software
   17   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA
   18 
   19   To the extent this program is licensed as part of the Enterprise
   20   versions of CFEngine, the applicable Commercial Open Source License
   21   (COSL) may apply to this file if you as a licensee so wish it. See
   22   included file COSL.txt.
   23 */
   24 
   25 #include <cf-execd.h>
   26 
   27 #include <cf-execd-runner.h>
   28 #include <item_lib.h>
   29 #include <known_dirs.h>
   30 #include <man.h>
   31 #include <ornaments.h>
   32 #include <exec_tools.h>
   33 #include <signals.h>
   34 #include <processes_select.h>
   35 #include <bootstrap.h>
   36 #include <policy_server.h>
   37 #include <sysinfo.h>
   38 #include <timeout.h>
   39 #include <time_classes.h>
   40 #include <loading.h>
   41 #include <printsize.h>
   42 #include <cleanup.h>
   43 #include <repair.h>
   44 #include <dbm_api.h>            /* CheckDBRepairFlagFile() */
   45 #include <string_lib.h>
   46 
   47 #include <cf-windows-functions.h>
   48 
   49 #define CF_EXEC_IFELAPSED 0
   50 #define CF_EXEC_EXPIREAFTER 1
   51 
   52 static bool PERFORM_DB_CHECK = false;
   53 static int NO_FORK = false; /* GLOBAL_A */
   54 static int ONCE = false; /* GLOBAL_A */
   55 static int WINSERVICE = true; /* GLOBAL_A */
   56 
   57 static pthread_attr_t threads_attrs; /* GLOBAL_T, initialized by pthread_attr_init */
   58 
   59 /*******************************************************************/
   60 
   61 static GenericAgentConfig *CheckOpts(int argc, char **argv);
   62 
   63 void ThisAgentInit(void);
   64 static bool ScheduleRun(EvalContext *ctx, Policy **policy, GenericAgentConfig *config,
   65                         ExecdConfig **execd_config, ExecConfig **exec_config);
   66 #ifndef __MINGW32__
   67 static void Apoptosis(void);
   68 #endif
   69 
   70 static bool LocalExecInThread(const ExecConfig *config);
   71 
   72 /*******************************************************************/
   73 /* Command line options                                            */
   74 /*******************************************************************/
   75 
   76 static const char *const CF_EXECD_SHORT_DESCRIPTION =
   77     "scheduling daemon for cf-agent";
   78 
   79 static const char *const CF_EXECD_MANPAGE_LONG_DESCRIPTION =
   80     "cf-execd is the scheduling daemon for cf-agent. It runs cf-agent locally according to a schedule specified in "
   81     "policy code (executor control body). After a cf-agent run is completed, cf-execd gathers output from cf-agent, "
   82     "and may be configured to email the output to a specified address. It may also be configured to splay (randomize) the "
   83     "execution schedule to prevent synchronized cf-agent runs across a network. "
   84     "Note: this daemon reloads it's config when the SIGHUP signal is received.";
   85 
   86 static const struct option OPTIONS[] =
   87 {
   88     {"help", no_argument, 0, 'h'},
   89     {"debug", no_argument, 0, 'd'},
   90     {"verbose", no_argument, 0, 'v'},
   91     {"dry-run", no_argument, 0, 'n'},
   92     {"version", no_argument, 0, 'V'},
   93     {"file", required_argument, 0, 'f'},
   94     {"define", required_argument, 0, 'D'},
   95     {"negate", required_argument, 0, 'N'},
   96     {"no-lock", no_argument, 0, 'K'},
   97     {"inform", no_argument, 0, 'I'},
   98     {"diagnostic", no_argument, 0, 'x'},
   99     {"log-level", required_argument, 0, 'g'},
  100     {"no-fork", no_argument, 0, 'F'},
  101     {"once", no_argument, 0, 'O'},
  102     {"no-winsrv", no_argument, 0, 'W'},
  103     {"ld-library-path", required_argument, 0, 'L'},
  104     {"color", optional_argument, 0, 'C'},
  105     {"timestamp", no_argument, 0, 'l'},
  106     {"skip-db-check", optional_argument, 0, 0 },
  107     {NULL, 0, 0, '\0'}
  108 };
  109 
  110 static const char *const HINTS[] =
  111 {
  112     "Print the help message",
  113     "Enable debugging output",
  114     "Output verbose information about the behaviour of cf-execd",
  115     "All talk and no action mode - make no changes, only inform of promises not kept",
  116     "Output the version of the software",
  117     "Specify an alternative input file than the default. This option is overridden by FILE if supplied as argument.",
  118     "Define a list of comma separated classes to be defined at the start of execution",
  119     "Define a list of comma separated classes to be undefined at the start of execution",
  120     "Ignore locking constraints during execution (ifelapsed/expireafter) if \"too soon\" to run",
  121     "Print basic information about changes made to the system, i.e. promises repaired",
  122     "Activate internal diagnostics (developers only)",
  123     "Specify how detailed logs should be. Possible values: 'error', 'warning', 'notice', 'info', 'verbose', 'debug'",
  124     "Run as a foreground processes (do not fork)",
  125     "Run once and then exit (implies no-fork)",
  126     "Do not run as a service on windows - use this when running from a command shell (CFEngine Nova only)",
  127     "Set the internal value of LD_LIBRARY_PATH for child processes",
  128     "Enable colorized output. Possible values: 'always', 'auto', 'never'. If option is used, the default value is 'auto'",
  129     "Log timestamps on each line of log output",
  130     "Do not run database integrity checks and repairs at startup",
  131     NULL
  132 };
  133 
  134 /*****************************************************************************/
  135 
  136 int main(int argc, char *argv[])
  137 {
  138     GenericAgentConfig *config = CheckOpts(argc, argv);
  139     bool force_repair = CheckDBRepairFlagFile();
  140     if (force_repair || PERFORM_DB_CHECK)
  141     {
  142         repair_lmdb_default(force_repair);
  143     }
  144 
  145     EvalContext *ctx = EvalContextNew();
  146     GenericAgentConfigApply(ctx, config);
  147 
  148     const char *program_invocation_name = argv[0];
  149     const char *last_dir_sep = strrchr(program_invocation_name, FILE_SEPARATOR);
  150     const char *program_name = (last_dir_sep != NULL ? last_dir_sep + 1 : program_invocation_name);
  151     GenericAgentDiscoverContext(ctx, config, program_name);
  152 
  153     Policy *policy = SelectAndLoadPolicy(config, ctx, false, false);
  154 
  155     if (!policy)
  156     {
  157         Log(LOG_LEVEL_ERR, "Error reading CFEngine policy. Exiting...");
  158         DoCleanupAndExit(EXIT_FAILURE);
  159     }
  160 
  161     GenericAgentPostLoadInit(ctx);
  162     ThisAgentInit();
  163 
  164     ExecConfig *exec_config = ExecConfigNew(!ONCE, ctx, policy);
  165     ExecdConfig *execd_config = ExecdConfigNew(ctx, policy);
  166     SetFacility(execd_config->log_facility);
  167 
  168 #ifdef __MINGW32__
  169     if (WINSERVICE)
  170     {
  171         NovaWin_StartExecService();
  172     }
  173     else
  174 #endif /* __MINGW32__ */
  175     {
  176         StartServer(ctx, policy, config, &execd_config, &exec_config);
  177     }
  178 
  179     GenericAgentFinalize(ctx, config);
  180     ExecConfigDestroy(exec_config);
  181     ExecdConfigDestroy(execd_config);
  182     CallCleanupFunctions();
  183     return 0;
  184 }
  185 
  186 /*****************************************************************************/
  187 /* Level 1                                                                   */
  188 /*****************************************************************************/
  189 
  190 static GenericAgentConfig *CheckOpts(int argc, char **argv)
  191 {
  192     extern char *optarg;
  193     int c;
  194 
  195     GenericAgentConfig *config = GenericAgentConfigNewDefault(AGENT_TYPE_EXECUTOR, GetTTYInteractive());
  196 
  197 
  198     int longopt_idx;
  199     while ((c = getopt_long(argc, argv, "dvnKIf:g:D:N:VxL:hFOV1gMWC::l",
  200                             OPTIONS, &longopt_idx))
  201            != -1)
  202     {
  203         switch (c)
  204         {
  205         case 'f':
  206             GenericAgentConfigSetInputFile(config, GetInputDir(), optarg);
  207             MINUSF = true;
  208             break;
  209 
  210         case 'd':
  211             LogSetGlobalLevel(LOG_LEVEL_DEBUG);
  212             break;
  213 
  214         case 'K':
  215             config->ignore_locks = true;
  216             break;
  217 
  218         case 'D':
  219             {
  220                 StringSet *defined_classes = StringSetFromString(optarg, ',');
  221                 if (! config->heap_soft)
  222                 {
  223                     config->heap_soft = defined_classes;
  224                 }
  225                 else
  226                 {
  227                     StringSetJoin(config->heap_soft, defined_classes, xstrdup);
  228                     StringSetDestroy(defined_classes);
  229                 }
  230             }
  231             break;
  232 
  233         case 'N':
  234             {
  235                 StringSet *negated_classes = StringSetFromString(optarg, ',');
  236                 if (! config->heap_negated)
  237                 {
  238                     config->heap_negated = negated_classes;
  239                 }
  240                 else
  241                 {
  242                     StringSetJoin(config->heap_negated, negated_classes, xstrdup);
  243                     StringSetDestroy(negated_classes);
  244                 }
  245             }
  246             break;
  247 
  248         case 'I':
  249             LogSetGlobalLevel(LOG_LEVEL_INFO);
  250             break;
  251 
  252         case 'v':
  253             LogSetGlobalLevel(LOG_LEVEL_VERBOSE);
  254             NO_FORK = true; // TODO: really?
  255             break;
  256 
  257         case 'g':
  258             LogSetGlobalLevelArgOrExit(optarg);
  259             break;
  260 
  261         case 'n':
  262             DONTDO = true;
  263             config->ignore_locks = true;
  264             break;
  265 
  266         case 'L':
  267             {
  268                 Log(LOG_LEVEL_VERBOSE, "Setting 'LD_LIBRARY_PATH=%s'", optarg);
  269                 setenv_wrapper("LD_LIBRARY_PATH", optarg, 1);
  270                 break;
  271             }
  272         case 'W':
  273             WINSERVICE = false;
  274             break;
  275 
  276         case 'F':
  277             NO_FORK = true;
  278             break;
  279 
  280         case 'O':
  281             ONCE = true;
  282             NO_FORK = true;
  283             break;
  284 
  285         case 'V':
  286         {
  287             Writer *w = FileWriter(stdout);
  288             GenericAgentWriteVersion(w);
  289             FileWriterDetach(w);
  290         }
  291         DoCleanupAndExit(EXIT_SUCCESS);
  292 
  293         case 'h':
  294         {
  295             Writer *w = FileWriter(stdout);
  296             WriterWriteHelp(w, "cf-execd", OPTIONS, HINTS, NULL, false, true);
  297             FileWriterDetach(w);
  298         }
  299         DoCleanupAndExit(EXIT_SUCCESS);
  300 
  301         case 'M':
  302         {
  303             Writer *out = FileWriter(stdout);
  304             ManPageWrite(out, "cf-execd", time(NULL),
  305                          CF_EXECD_SHORT_DESCRIPTION,
  306                          CF_EXECD_MANPAGE_LONG_DESCRIPTION,
  307                          OPTIONS, HINTS,
  308                          NULL, false,
  309                          true);
  310             FileWriterDetach(out);
  311             DoCleanupAndExit(EXIT_SUCCESS);
  312         }
  313 
  314         case 'x':
  315             Log(LOG_LEVEL_ERR, "Self-diagnostic functionality is retired.");
  316             DoCleanupAndExit(EXIT_SUCCESS);
  317 
  318         case 'C':
  319             if (!GenericAgentConfigParseColor(config, optarg))
  320             {
  321                 DoCleanupAndExit(EXIT_FAILURE);
  322             }
  323             break;
  324 
  325         case 'l':
  326             LoggingEnableTimestamps(true);
  327             break;
  328 
  329         case 0:
  330         {
  331             const char *const option_name = OPTIONS[longopt_idx].name;
  332             if (StringEqual(option_name, "skip-db-check"))
  333             {
  334                 if (optarg == NULL)
  335                 {
  336                     PERFORM_DB_CHECK = false; // Skip (no arg), check = false
  337                 }
  338                 else if (StringEqual_IgnoreCase(optarg, "yes"))
  339                 {
  340                     PERFORM_DB_CHECK = false; // Skip = yes, check = false
  341                 }
  342                 else if (StringEqual_IgnoreCase(optarg, "no"))
  343                 {
  344                     PERFORM_DB_CHECK = true; // Skip = no, check = true
  345                 }
  346                 else
  347                 {
  348                     Log(LOG_LEVEL_ERR,
  349                         "Invalid argument for --skip-db-check(yes/no): '%s'",
  350                         optarg);
  351                     DoCleanupAndExit(EXIT_FAILURE);
  352                 }
  353             }
  354             break;
  355         }
  356         default:
  357         {
  358             Writer *w = FileWriter(stdout);
  359             WriterWriteHelp(w, "cf-execd", OPTIONS, HINTS, NULL, false, true);
  360             FileWriterDetach(w);
  361         }
  362         DoCleanupAndExit(EXIT_FAILURE);
  363 
  364         }
  365     }
  366 
  367     if (!GenericAgentConfigParseArguments(config, argc - optind, argv + optind))
  368     {
  369         Log(LOG_LEVEL_ERR, "Too many arguments");
  370         DoCleanupAndExit(EXIT_FAILURE);
  371     }
  372 
  373     return config;
  374 }
  375 
  376 /*****************************************************************************/
  377 
  378 void ThisAgentInit(void)
  379 {
  380     umask(077);
  381 }
  382 
  383 /*****************************************************************************/
  384 
  385 // msg should include exactly one reference to unsigned int.
  386 static unsigned int MaybeSleepLog(LogLevel level, const char *msg, unsigned int seconds)
  387 {
  388     if (IsPendingTermination())
  389     {
  390         return seconds;
  391     }
  392 
  393     Log(level, msg, seconds);
  394 
  395     return sleep(seconds);
  396 }
  397 
  398 /*****************************************************************************/
  399 
  400 /* Might be called back from NovaWin_StartExecService */
  401 void StartServer(EvalContext *ctx, Policy *policy, GenericAgentConfig *config, ExecdConfig **execd_config, ExecConfig **exec_config)
  402 {
  403     pthread_attr_init(&threads_attrs);
  404     pthread_attr_setdetachstate(&threads_attrs, PTHREAD_CREATE_DETACHED);
  405     pthread_attr_setstacksize(&threads_attrs, (size_t)2048*1024);
  406 
  407     Banner("Starting executor");
  408 
  409 #ifndef __MINGW32__
  410     if (!ONCE)
  411     {
  412         /* Kill previous instances of cf-execd if those are still running */
  413         Apoptosis();
  414     }
  415 
  416     time_t now = time(NULL);
  417     if ((!NO_FORK) && (fork() != 0))
  418     {
  419         Log(LOG_LEVEL_INFO, "cf-execd starting %.24s", ctime(&now));
  420         _exit(EXIT_SUCCESS);
  421     }
  422 
  423     if (!NO_FORK)
  424     {
  425         ActAsDaemon();
  426     }
  427 
  428 #else  /* __MINGW32__ */
  429 
  430     if (!NO_FORK)
  431     {
  432         Log(LOG_LEVEL_VERBOSE, "Windows does not support starting processes in the background - starting in foreground");
  433     }
  434 
  435 #endif
  436 
  437     WritePID("cf-execd.pid");
  438     signal(SIGINT, HandleSignalsForDaemon);
  439     signal(SIGTERM, HandleSignalsForDaemon);
  440     signal(SIGBUS, HandleSignalsForDaemon);
  441     signal(SIGHUP, HandleSignalsForDaemon);
  442     signal(SIGPIPE, SIG_IGN);
  443     signal(SIGUSR1, HandleSignalsForDaemon);
  444     signal(SIGUSR2, HandleSignalsForDaemon);
  445 
  446     umask(077);
  447 
  448     if (ONCE)
  449     {
  450         LocalExec(*exec_config);
  451         CloseLog();
  452     }
  453     else
  454     {
  455         while (!IsPendingTermination())
  456         {
  457             if (ScheduleRun(ctx, &policy, config, execd_config, exec_config))
  458             {
  459                 MaybeSleepLog(LOG_LEVEL_VERBOSE,
  460                               "Sleeping for splaytime %u seconds",
  461                               (*execd_config)->splay_time);
  462 
  463                 // We are sleeping both above and inside ScheduleRun(), so make
  464                 // sure a terminating signal did not arrive during that time.
  465                 if (IsPendingTermination())
  466                 {
  467                     break;
  468                 }
  469 
  470                 if (!LocalExecInThread(*exec_config))
  471                 {
  472                     Log(LOG_LEVEL_INFO,
  473                         "Unable to run agent in thread, falling back to blocking execution");
  474                     LocalExec(*exec_config);
  475                 }
  476             }
  477         }
  478     }
  479     PolicyDestroy(policy);
  480 }
  481 
  482 /*****************************************************************************/
  483 
  484 static void Thread_AllSignalsBlock(void)
  485 {
  486 #ifndef __MINGW32__
  487     sigset_t sigmask;
  488     sigfillset(&sigmask);
  489     int ret = pthread_sigmask(SIG_SETMASK, &sigmask, NULL);
  490     if (ret != 0)
  491     {
  492         Log(LOG_LEVEL_ERR,
  493             "Unable to block signals in child thread,"
  494             " killing cf-execd might fail (pthread_sigmask: %s)",
  495             GetErrorStr());
  496     }
  497 #endif
  498 }
  499 
  500 static void Thread_AllSignalsUnblock(void)
  501 {
  502 #ifndef __MINGW32__
  503     sigset_t sigmask;
  504     sigemptyset(&sigmask);
  505     int ret = pthread_sigmask(SIG_SETMASK, &sigmask, NULL);
  506     if (ret != 0)
  507     {
  508         Log(LOG_LEVEL_ERR,
  509             "Unable to unblock signals again (pthread_sigmask: %s)",
  510             GetErrorStr());
  511     }
  512 #endif
  513 }
  514 
  515 static void *LocalExecThread(void *param)
  516 {
  517     ExecConfig *config = (ExecConfig *) param;
  518     LocalExec(config);
  519     ExecConfigDestroy(config);
  520 
  521     Log(LOG_LEVEL_VERBOSE, "Finished exec_command execution, terminating thread");
  522     return NULL;
  523 }
  524 
  525 static bool LocalExecInThread(const ExecConfig *config)
  526 {
  527     ExecConfig *thread_config = ExecConfigCopy(config);
  528     pthread_t tid;
  529 
  530     Log(LOG_LEVEL_VERBOSE, "Spawning thread for exec_command execution");
  531 
  532     /* ENT-3147: Block all signals so that child thread inherits it and
  533      * signals get only delivered to the main thread. Unblock all signals
  534      * right after thread has been spawned. */
  535     Thread_AllSignalsBlock();
  536 
  537     int ret = pthread_create(&tid, &threads_attrs, LocalExecThread, thread_config);
  538 
  539     Thread_AllSignalsUnblock();
  540 
  541     if (ret != 0)
  542     {
  543         ExecConfigDestroy(thread_config);
  544         Log(LOG_LEVEL_ERR, "Failed to create thread (pthread_create: %s)",
  545             GetErrorStr());
  546         return false;
  547     }
  548 
  549     return true;
  550 }
  551 
  552 #ifndef __MINGW32__
  553 
  554 static void Apoptosis(void)
  555 {
  556     char promiser_buf[CF_SMALLBUF];
  557     snprintf(promiser_buf, sizeof(promiser_buf), "%s%ccf-execd",
  558              GetBinDir(), FILE_SEPARATOR);
  559 
  560     if (LoadProcessTable())
  561     {
  562         char myuid[PRINTSIZE(unsigned)];
  563         xsnprintf(myuid, sizeof(myuid), "%u", (unsigned) getuid());
  564 
  565         Rlist *owners = NULL;
  566         RlistPrepend(&owners, myuid, RVAL_TYPE_SCALAR);
  567 
  568         ProcessSelect process_select = PROCESS_SELECT_INIT;
  569         process_select.owner = owners;
  570         process_select.process_result = "process_owner";
  571 
  572         Item *killlist = SelectProcesses(promiser_buf, &(process_select), true);
  573         RlistDestroy(owners);
  574 
  575         for (Item *ip = killlist; ip != NULL; ip = ip->next)
  576         {
  577             pid_t pid = ip->counter;
  578 
  579             if (pid != getpid() && kill(pid, SIGTERM) < 0)
  580             {
  581                 if (errno == ESRCH)
  582                 {
  583                     /* That's ok, process exited voluntarily */
  584                 }
  585                 else
  586                 {
  587                     Log(LOG_LEVEL_ERR, "Unable to kill stale cf-execd process pid=%d. (kill: %s)",
  588                         (int)pid, GetErrorStr());
  589                 }
  590             }
  591         }
  592     }
  593 
  594     ClearProcessTable();
  595 
  596     Log(LOG_LEVEL_VERBOSE, "Pruning complete");
  597 }
  598 
  599 #endif
  600 
  601 typedef enum
  602 {
  603     RELOAD_ENVIRONMENT,
  604     RELOAD_FULL
  605 } Reload;
  606 
  607 static Reload CheckNewPromises(GenericAgentConfig *config)
  608 {
  609     Log(LOG_LEVEL_DEBUG, "Checking file updates for input file '%s'", config->input_file);
  610 
  611     time_t validated_at = ReadTimestampFromPolicyValidatedFile(config, NULL);
  612 
  613     bool reload_config = false;
  614 
  615     if (config->agent_specific.daemon.last_validated_at < validated_at)
  616     {
  617         Log(LOG_LEVEL_VERBOSE, "New promises detected...");
  618         reload_config = true;
  619     }
  620     if (ReloadConfigRequested())
  621     {
  622         Log(LOG_LEVEL_VERBOSE, "Force reload of inputs files...");
  623         reload_config = true;
  624     }
  625 
  626     if (reload_config)
  627     {
  628         ClearRequestReloadConfig();
  629 
  630         /* Rereading policies now, so update timestamp. */
  631         config->agent_specific.daemon.last_validated_at = validated_at;
  632 
  633         if (GenericAgentArePromisesValid(config))
  634         {
  635             return RELOAD_FULL;
  636         }
  637         else
  638         {
  639             Log(LOG_LEVEL_INFO, "New promises file contains syntax errors -- ignoring");
  640         }
  641     }
  642     else
  643     {
  644         Log(LOG_LEVEL_DEBUG, "No new promises found");
  645     }
  646 
  647     return RELOAD_ENVIRONMENT;
  648 }
  649 
  650 static bool ScheduleRun(EvalContext *ctx, Policy **policy, GenericAgentConfig *config,
  651                         ExecdConfig **execd_config, ExecConfig **exec_config)
  652 {
  653     /* 1 Minute resolution is enough */
  654     MaybeSleepLog(LOG_LEVEL_VERBOSE, "Sleeping for pulse time %u seconds...", CFPULSETIME);
  655 
  656     /*
  657      * FIXME: this logic duplicates the one from cf-serverd.c. Unify ASAP.
  658      */
  659 
  660     if (CheckNewPromises(config) == RELOAD_FULL)
  661     {
  662         /* Full reload */
  663 
  664         Log(LOG_LEVEL_INFO, "Re-reading promise file '%s'", config->input_file);
  665 
  666         EvalContextClear(ctx);
  667 
  668         strcpy(VDOMAIN, "undefined.domain");
  669 
  670         PolicyDestroy(*policy);
  671         *policy = NULL;
  672 
  673         EvalContextSetPolicyServerFromFile(ctx, GetWorkDir());
  674         UpdateLastPolicyUpdateTime(ctx);
  675 
  676         DetectEnvironment(ctx);
  677         GenericAgentDiscoverContext(ctx, config, NULL);
  678 
  679         EvalContextClassPutHard(ctx, CF_AGENTTYPES[AGENT_TYPE_EXECUTOR], "cfe_internal,source=agent");
  680 
  681         time_t t = SetReferenceTime();
  682         UpdateTimeClasses(ctx, t);
  683 
  684         GenericAgentConfigSetBundleSequence(config, NULL);
  685 
  686         *policy = LoadPolicy(ctx, config);
  687         ExecConfigDestroy(*exec_config);
  688         ExecdConfigDestroy(*execd_config);
  689 
  690         *exec_config = ExecConfigNew(!ONCE, ctx, *policy);
  691         *execd_config = ExecdConfigNew(ctx, *policy);
  692 
  693         SetFacility((*execd_config)->log_facility);
  694     }
  695     else
  696     {
  697         /* Environment reload */
  698 
  699         EvalContextClear(ctx);
  700 
  701         DetectEnvironment(ctx);
  702 
  703         time_t t = SetReferenceTime();
  704         UpdateTimeClasses(ctx, t);
  705     }
  706 
  707     {
  708         StringSetIterator it = StringSetIteratorInit((*execd_config)->schedule);
  709         const char *time_context = NULL;
  710         while ((time_context = StringSetIteratorNext(&it)))
  711         {
  712             if (IsDefinedClass(ctx, time_context))
  713             {
  714                 Log(LOG_LEVEL_VERBOSE, "Waking up the agent at %s ~ %s", ctime(&CFSTARTTIME), time_context);
  715                 return true;
  716             }
  717         }
  718     }
  719 
  720     Log(LOG_LEVEL_VERBOSE, "Nothing to do at %s", ctime(&CFSTARTTIME));
  721     return false;
  722 }