2 * Copyright (C) 2006-2012 Tobias Brunner
3 * Copyright (C) 2005-2013 Martin Willi
4 * Copyright (C) 2006 Daniel Roethlisberger
5 * Copyright (C) 2005 Jan Hutter
6 * Hochschule fuer Technik Rapperswil
8 * This program is free software; you can redistribute it and/or modify it
9 * under the terms of the GNU General Public License as published by the
10 * Free Software Foundation; either version 2 of the License, or (at your
11 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
13 * This program is distributed in the hope that it will be useful, but
14 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
15 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
20 #define _POSIX_PTHREAD_SEMANTICS /* for two param sigwait on OpenSolaris */
22 #undef _POSIX_PTHREAD_SEMANTICS
24 #include <sys/types.h>
25 #include <sys/utsname.h>
32 #include <utils/backtrace.h>
33 #include <threading/thread.h>
35 #include "cmd/cmd_options.h"
38 * Loglevel configuration
40 static level_t levels
[DBG_MAX
];
43 * hook in library for debugging messages
45 extern void (*dbg
) (debug_t group
, level_t level
, char *fmt
, ...);
48 * Logging hook for library logs, using stderr output
50 static void dbg_stderr(debug_t group
, level_t level
, char *fmt
, ...)
57 fprintf(stderr
, "00[%N] ", debug_names
, group
);
58 vfprintf(stderr
, fmt
, args
);
59 fprintf(stderr
, "\n");
65 * Run the daemon and handle unix signals
71 /* handle SIGINT, SIGHUP ans SIGTERM in this handler */
73 sigaddset(&set
, SIGINT
);
74 sigaddset(&set
, SIGHUP
);
75 sigaddset(&set
, SIGTERM
);
76 sigprocmask(SIG_BLOCK
, &set
, NULL
);
83 error
= sigwait(&set
, &sig
);
86 DBG1(DBG_DMN
, "error %d while waiting for a signal", error
);
93 DBG1(DBG_DMN
, "signal of type SIGHUP received. Reloading "
95 if (lib
->settings
->load_files(lib
->settings
, NULL
, FALSE
))
97 charon
->load_loggers(charon
, levels
, TRUE
);
98 lib
->plugins
->reload(lib
->plugins
, NULL
);
102 DBG1(DBG_DMN
, "reloading config failed, keeping old");
108 DBG1(DBG_DMN
, "signal of type SIGINT received. Shutting down");
109 charon
->bus
->alert(charon
->bus
, ALERT_SHUTDOWN_SIGNAL
, sig
);
114 DBG1(DBG_DMN
, "signal of type SIGTERM received. Shutting down");
115 charon
->bus
->alert(charon
->bus
, ALERT_SHUTDOWN_SIGNAL
, sig
);
120 DBG1(DBG_DMN
, "unknown signal %d received. Ignored", sig
);
130 static bool lookup_uid_gid()
133 if (!charon
->caps
->resolve_uid(charon
->caps
, IPSEC_USER
))
139 if (!charon
->caps
->resolve_gid(charon
->caps
, IPSEC_GROUP
))
148 * Handle SIGSEGV/SIGILL signals raised by threads
150 static void segv_handler(int signal
)
152 backtrace_t
*backtrace
;
154 DBG1(DBG_DMN
, "thread %u received %d", thread_current_id(), signal
);
155 backtrace
= backtrace_create(2);
156 backtrace
->log(backtrace
, stderr
, TRUE
);
157 backtrace
->destroy(backtrace
);
159 DBG1(DBG_DMN
, "killing ourself, received critical signal");
164 * Print command line usage and exit
166 static void usage(FILE *out
, char *msg
, char *binary
)
168 int i
, pre
, post
, padto
= 0, spacing
= 2;
170 for (i
= 0; i
< CMD_OPT_COUNT
; i
++)
172 padto
= max(padto
, strlen(cmd_options
[i
].name
) +
173 strlen(cmd_options
[i
].arg
));
179 fprintf(out
, "%s\n", msg
);
181 fprintf(out
, "Usage: %s\n", binary
);
182 for (i
= 0; i
< CMD_OPT_COUNT
; i
++)
184 switch (cmd_options
[i
].has_arg
)
186 case required_argument
:
190 case optional_argument
:
199 fprintf(out
, " --%s %c%s%c %-*s%s\n",
201 pre
, cmd_options
[i
].arg
, post
,
202 padto
- strlen(cmd_options
[i
].name
) - strlen(cmd_options
[i
].arg
), "",
203 cmd_options
[i
].desc
);
208 * Handle command line options
210 static void handle_arguments(int argc
, char *argv
[])
214 struct option long_opts
[CMD_OPT_COUNT
+ 1] = {};
217 for (i
= 0; i
< CMD_OPT_COUNT
; i
++)
219 long_opts
[i
].name
= cmd_options
[i
].name
;
220 long_opts
[i
].val
= cmd_options
[i
].id
;
221 long_opts
[i
].has_arg
= cmd_options
[i
].has_arg
;
224 switch (getopt_long(argc
, argv
, "", long_opts
, NULL
))
229 usage(stdout
, NULL
, argv
[0]);
231 case CMD_OPT_VERSION
:
232 printf("%s, strongSwan %s\n", "charon-cmd", VERSION
);
235 usage(stderr
, NULL
, argv
[0]);
243 * Main function, starts the daemon.
245 int main(int argc
, char *argv
[])
247 struct sigaction action
;
248 struct utsname utsname
;
252 atexit(library_deinit
);
253 if (!library_init(NULL
))
255 exit(SS_RC_LIBSTRONGSWAN_INTEGRITY
);
259 if (!lib
->integrity
->check_file(lib
->integrity
, "charon-cmd", argv
[0]))
261 exit(SS_RC_DAEMON_INTEGRITY
);
264 atexit(libhydra_deinit
);
265 if (!libhydra_init("charon-cmd"))
267 exit(SS_RC_INITIALIZATION_FAILED
);
269 atexit(libcharon_deinit
);
270 if (!libcharon_init("charon-cmd"))
272 exit(SS_RC_INITIALIZATION_FAILED
);
274 for (group
= 0; group
< DBG_MAX
; group
++)
276 levels
[group
] = LEVEL_CTRL
;
279 handle_arguments(argc
, argv
);
281 if (!lookup_uid_gid())
283 exit(SS_RC_INITIALIZATION_FAILED
);
285 charon
->load_loggers(charon
, levels
, TRUE
);
287 if (uname(&utsname
) != 0)
289 memset(&utsname
, 0, sizeof(utsname
));
291 DBG1(DBG_DMN
, "Starting charon-cmd IKE client (strongSwan %s, %s %s, %s)",
292 VERSION
, utsname
.sysname
, utsname
.release
, utsname
.machine
);
294 if (!charon
->initialize(charon
,
295 lib
->settings
->get_str(lib
->settings
, "charon-cmd.load", PLUGINS
)))
297 exit(SS_RC_INITIALIZATION_FAILED
);
299 if (!charon
->caps
->drop(charon
->caps
))
301 exit(SS_RC_INITIALIZATION_FAILED
);
304 /* add handler for SEGV and ILL,
305 * INT, TERM and HUP are handled by sigwait() in run() */
306 action
.sa_handler
= segv_handler
;
308 sigemptyset(&action
.sa_mask
);
309 sigaddset(&action
.sa_mask
, SIGINT
);
310 sigaddset(&action
.sa_mask
, SIGTERM
);
311 sigaddset(&action
.sa_mask
, SIGHUP
);
312 sigaction(SIGSEGV
, &action
, NULL
);
313 sigaction(SIGILL
, &action
, NULL
);
314 sigaction(SIGBUS
, &action
, NULL
);
315 action
.sa_handler
= SIG_IGN
;
316 sigaction(SIGPIPE
, &action
, NULL
);
318 pthread_sigmask(SIG_SETMASK
, &action
.sa_mask
, NULL
);
320 /* start daemon with thread-pool */
321 charon
->start(charon
);
322 /* wait for signal */