Skip to content

Commit 6e4f423

Browse files
committed
Daemon skeleton for event driven cfengine
Signed-off-by: Victor Moene <victor.moene@northern.tech>
1 parent 9c0a20c commit 6e4f423

2 files changed

Lines changed: 250 additions & 2 deletions

File tree

cf-watchd/cf-watchd.c

Lines changed: 249 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,255 @@
11
#include <stdio.h>
2+
#include <unistd.h>
23

3-
int main()
4+
#include <exec_tools.h>
5+
#include <signals.h>
6+
#include <generic_agent.h>
7+
#include <logging.h>
8+
#include <eval_context.h>
9+
#include <cleanup.h>
10+
#include <man.h>
11+
#include <known_dirs.h>
12+
13+
14+
static GenericAgentConfig *CheckOpts(int argc, char **argv);
15+
static void WatchStart();
16+
17+
/*****************************************************************************/
18+
/* Globals */
19+
/*****************************************************************************/
20+
21+
int NO_FORK = false;
22+
23+
/*******************************************************************/
24+
/* Command line options */
25+
/*******************************************************************/
26+
27+
28+
static const char *const CF_WATCHD_SHORT_DESCRIPTION =
29+
"event watching daemon for CFEngine";
30+
31+
static const char *const CF_WATCHD_MANPAGE_LONG_DESCRIPTION =
32+
"cf-watchd is the event watching and reacting daemon for CFEngine. It watches specific events defined in the policy "
33+
"and runs policy code on reaction to these events.";
34+
35+
static const Component COMPONENT =
36+
{
37+
.name = "cf-watchd",
38+
.website = CF_WEBSITE,
39+
.copyright = CF_COPYRIGHT
40+
};
41+
42+
static const struct option OPTIONS[] =
43+
{
44+
{"help", no_argument, 0, 'h'},
45+
{"debug", no_argument, 0, 'd'},
46+
{"verbose", no_argument, 0, 'v'},
47+
{"version", no_argument, 0, 'V'},
48+
{"no-lock", no_argument, 0, 'K'},
49+
{"file", required_argument, 0, 'f'},
50+
{"log-level", required_argument, 0, 'g'},
51+
{"inform", no_argument, 0, 'I'},
52+
{"no-fork", no_argument, 0, 'F'},
53+
{"color", optional_argument, 0, 'C'},
54+
{"timestamp", no_argument, 0, 'l'},
55+
/* Only long option for the rest */
56+
{"ignore-preferred-augments", no_argument, 0, 0},
57+
{NULL, 0, 0, '\0'}
58+
};
59+
60+
static const char *const HINTS[] =
461
{
5-
printf("Hello world!\n");
62+
"Print the help message",
63+
"Enable debugging output",
64+
"Output verbose information about the behaviour of cf-watchd",
65+
"Output the version of the software",
66+
"Ignore system lock",
67+
"Specify an alternative input file than the default. This option is overridden by FILE if supplied as argument.",
68+
"Specify how detailed logs should be. Possible values: 'error', 'warning', 'notice', 'info', 'verbose', 'debug'",
69+
"Print basic information about changes made to the system, i.e. promises repaired",
70+
"Run process in foreground, not as a daemon",
71+
"Enable colorized output. Possible values: 'always', 'auto', 'never'. If option is used, the default value is 'auto'",
72+
"Log timestamps on each line of log output",
73+
"Ignore def_preferred.json file in favor of def.json",
74+
NULL
75+
};
76+
77+
/*****************************************************************************/
78+
79+
int main(int argc, char **argv)
80+
{
81+
GenericAgentConfig *config = CheckOpts(argc, argv);
82+
EvalContext *ctx = EvalContextNew();
83+
GenericAgentConfigApply(ctx, config);
84+
85+
pid_t existing_pid = ReadPID("cf-watchd.pid");
86+
if ((existing_pid != -1) && (kill(existing_pid, 0) == 0))
87+
{
88+
Log(LOG_LEVEL_ERR, "Another instance of cf-watchd is already running, terminating");
89+
return 1;
90+
}
91+
92+
#ifdef __MINGW32__
93+
94+
if (!NO_FORK)
95+
{
96+
Log(LOG_LEVEL_VERBOSE, "Windows does not support starting processes in the background - starting in foreground");
97+
}
98+
99+
#else /* !__MINGW32__ */
100+
101+
if ((!NO_FORK) && (fork() != 0))
102+
{
103+
Log(LOG_LEVEL_INFO, "cf-watchd: starting");
104+
_exit(EXIT_SUCCESS);
105+
}
106+
107+
if (!NO_FORK)
108+
{
109+
ActAsDaemon();
110+
}
111+
112+
#endif /* !__MINGW32__ */
113+
114+
115+
umask(077);
116+
WritePID("cf-watchd.pid");
117+
118+
signal(SIGINT, HandleSignalsForDaemon);
119+
signal(SIGTERM, HandleSignalsForDaemon);
120+
signal(SIGBUS, HandleSignalsForDaemon);
121+
signal(SIGHUP, HandleSignalsForDaemon);
122+
signal(SIGPIPE, SIG_IGN);
123+
signal(SIGUSR1, HandleSignalsForDaemon);
124+
signal(SIGUSR2, HandleSignalsForDaemon);
125+
126+
WatchStart();
127+
128+
GenericAgentFinalize(ctx, config);
129+
CallCleanupFunctions();
130+
6131
return 0;
7132
}
8133

134+
static GenericAgentConfig *CheckOpts(int argc, char **argv)
135+
{
136+
extern char *optarg;
137+
int c;
138+
GenericAgentConfig *config = GenericAgentConfigNewDefault(AGENT_TYPE_WATCH, GetTTYInteractive());
139+
140+
int longopt_idx;
141+
while ((c = getopt_long(argc, argv, "dvIf:g:VSKMFhC::l",
142+
OPTIONS, &longopt_idx)) != -1)
143+
{
144+
switch (c)
145+
{
146+
case 'f':
147+
GenericAgentConfigSetInputFile(config, GetInputDir(), optarg);
148+
MINUSF = true;
149+
break;
150+
151+
case 'd':
152+
LogSetGlobalLevel(LOG_LEVEL_DEBUG);
153+
NO_FORK = true;
154+
break;
155+
156+
case 'K':
157+
config->ignore_locks = true;
158+
break;
159+
160+
case 'I':
161+
LogSetGlobalLevel(LOG_LEVEL_INFO);
162+
break;
163+
164+
case 'v':
165+
LogSetGlobalLevel(LOG_LEVEL_VERBOSE);
166+
NO_FORK = true;
167+
break;
168+
169+
case 'g':
170+
LogSetGlobalLevelArgOrExit(optarg);
171+
break;
172+
173+
case 'F':
174+
NO_FORK = true;
175+
break;
176+
177+
case 'V':
178+
{
179+
Writer *w = FileWriter(stdout);
180+
GenericAgentWriteVersion(w);
181+
FileWriterDetach(w);
182+
}
183+
DoCleanupAndExit(EXIT_SUCCESS);
184+
185+
case 'h':
186+
{
187+
Writer *w = FileWriter(stdout);
188+
WriterWriteHelp(w, &COMPONENT, OPTIONS, HINTS, NULL, false, true);
189+
FileWriterDetach(w);
190+
}
191+
DoCleanupAndExit(EXIT_SUCCESS);
192+
193+
case 'M':
194+
{
195+
Writer *out = FileWriter(stdout);
196+
ManPageWrite(out, "cf-watchd", time(NULL),
197+
CF_WATCHD_SHORT_DESCRIPTION,
198+
CF_WATCHD_MANPAGE_LONG_DESCRIPTION,
199+
OPTIONS, HINTS,
200+
NULL, false,
201+
true);
202+
FileWriterDetach(out);
203+
DoCleanupAndExit(EXIT_SUCCESS);
204+
}
205+
206+
case 'C':
207+
if (!GenericAgentConfigParseColor(config, optarg))
208+
{
209+
DoCleanupAndExit(EXIT_FAILURE);
210+
}
211+
break;
212+
213+
case 'l':
214+
LoggingEnableTimestamps(true);
215+
break;
216+
217+
/* long options only */
218+
case 0:
219+
{
220+
const char *const option_name = OPTIONS[longopt_idx].name;
221+
if (StringEqual(option_name, "ignore-preferred-augments"))
222+
{
223+
config->ignore_preferred_augments = true;
224+
}
225+
break;
226+
}
227+
228+
default:
229+
{
230+
Writer *w = FileWriter(stdout);
231+
WriterWriteHelp(w, &COMPONENT, OPTIONS, HINTS, NULL, false, true);
232+
FileWriterDetach(w);
233+
}
234+
DoCleanupAndExit(EXIT_FAILURE);
235+
}
236+
}
237+
238+
if (!GenericAgentConfigParseArguments(config, argc - optind, argv + optind))
239+
{
240+
Log(LOG_LEVEL_ERR, "Too many arguments");
241+
DoCleanupAndExit(EXIT_FAILURE);
242+
}
243+
244+
return config;
245+
}
246+
247+
static void WatchStart()
248+
{
249+
for (int i = 0; !IsPendingTermination(); i++)
250+
{
251+
/* Do something */
252+
Log(LOG_LEVEL_INFO, "cf-watchd: %d", i);
253+
sleep(1);
254+
}
255+
}

libpromises/cf3.defs.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -409,6 +409,7 @@ typedef enum
409409
AGENT_TYPE_RUNAGENT,
410410
AGENT_TYPE_KEYGEN,
411411
AGENT_TYPE_HUB,
412+
AGENT_TYPE_WATCH,
412413
AGENT_TYPE_NOAGENT
413414
} AgentType;
414415

0 commit comments

Comments
 (0)