Unify format of HSR copyright statements
[strongswan.git] / src / starter / invokecharon.c
1 /*
2 * Copyright (C) 2006 Martin Willi
3 * HSR Hochschule fuer Technik Rapperswil
4 *
5 * Copyright (C) 2001-2002 Mathieu Lafon
6 * Arkoon Network Security
7 *
8 * Ported from invokepluto.c to fit charons needs.
9 *
10 * This program is free software; you can redistribute it and/or modify it
11 * under the terms of the GNU General Public License as published by the
12 * Free Software Foundation; either version 2 of the License, or (at your
13 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
14 *
15 * This program is distributed in the hope that it will be useful, but
16 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
17 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
18 * for more details.
19 */
20
21 #include <sys/types.h>
22 #include <sys/stat.h>
23 #include <unistd.h>
24 #include <signal.h>
25 #include <string.h>
26 #include <stdlib.h>
27 #include <errno.h>
28
29 #include <library.h>
30 #include <utils/debug.h>
31
32 #include "confread.h"
33 #include "invokecharon.h"
34 #include "files.h"
35
36 static int _charon_pid = 0;
37 static int _stop_requested;
38
39 pid_t starter_charon_pid(void)
40 {
41 return _charon_pid;
42 }
43
44 void starter_charon_sigchild(pid_t pid, int status)
45 {
46 if (pid == _charon_pid)
47 {
48 _charon_pid = 0;
49 if (status == SS_RC_LIBSTRONGSWAN_INTEGRITY ||
50 status == SS_RC_DAEMON_INTEGRITY)
51 {
52 DBG1(DBG_APP, "%s has quit: integrity test of %s failed",
53 daemon_name, (status == 64) ? "libstrongswan" : daemon_name);
54 _stop_requested = 1;
55 }
56 else if (status == SS_RC_INITIALIZATION_FAILED)
57 {
58 DBG1(DBG_APP, "%s has quit: initialization failed", daemon_name);
59 _stop_requested = 1;
60 }
61 if (!_stop_requested)
62 {
63 DBG1(DBG_APP, "%s has died -- restart scheduled (%dsec)",
64 daemon_name, CHARON_RESTART_DELAY);
65 alarm(CHARON_RESTART_DELAY); // restart in 5 sec
66 }
67 unlink(pid_file);
68 }
69 }
70
71 int starter_stop_charon (void)
72 {
73 int i;
74 pid_t pid = _charon_pid;
75
76 if (pid)
77 {
78 _stop_requested = 1;
79
80 /* be more and more aggressive */
81 for (i = 0; i < 50 && (pid = _charon_pid) != 0; i++)
82 {
83 if (i == 0)
84 {
85 kill(pid, SIGINT);
86 }
87 else if (i < 40)
88 {
89 kill(pid, SIGTERM);
90 }
91 else if (i == 40)
92 {
93 kill(pid, SIGKILL);
94 DBG1(DBG_APP, "starter_stop_charon(): %s does not respond, sending KILL",
95 daemon_name);
96 }
97 else
98 {
99 kill(pid, SIGKILL);
100 }
101 usleep(200000); /* sleep for 200 ms */
102 }
103 if (_charon_pid == 0)
104 {
105 DBG1(DBG_APP, "%s stopped after %d ms", daemon_name, 200*i);
106 return 0;
107 }
108 DBG1(DBG_APP, "starter_stop_charon(): can't stop %s !!!", daemon_name);
109 return -1;
110 }
111 else
112 {
113 DBG1(DBG_APP, "stater_stop_charon(): %s was not started...", daemon_name);
114 }
115 return -1;
116 }
117
118
119 int starter_start_charon (starter_config_t *cfg, bool no_fork, bool attach_gdb)
120 {
121 struct stat stb;
122 int pid, i;
123 char buffer[BUF_LEN];
124 int argc = 1;
125 char *arg[] = {
126 cmd, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
127 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
128 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
129 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL
130 };
131
132 if (attach_gdb)
133 {
134 argc = 0;
135 arg[argc++] = "/usr/bin/gdb";
136 arg[argc++] = "--args";
137 arg[argc++] = cmd;
138 }
139 if (!no_fork)
140 {
141 arg[argc++] = "--use-syslog";
142 }
143
144 /* parse debug string */
145 {
146 int level;
147 char type[4];
148 char *pos = cfg->setup.charondebug;
149 char *buf_pos = buffer;
150
151 while (pos && sscanf(pos, "%3s %d,", type, &level) == 2)
152 {
153 snprintf(buf_pos, buffer + sizeof(buffer) - buf_pos, "--debug-%s", type);
154 arg[argc++] = buf_pos;
155 buf_pos += strlen(buf_pos) + 1;
156 if (buf_pos >= buffer + sizeof(buffer))
157 {
158 break;
159 }
160 snprintf(buf_pos, buffer + sizeof(buffer) - buf_pos, "%d", level);
161 arg[argc++] = buf_pos;
162 buf_pos += strlen(buf_pos) + 1;
163 if (buf_pos >= buffer + sizeof(buffer))
164 {
165 break;
166 }
167
168 /* get next */
169 pos = strchr(pos, ',');
170 if (pos)
171 {
172 pos++;
173 }
174 }
175 }
176
177 if (_charon_pid)
178 {
179 DBG1(DBG_APP, "starter_start_charon(): %s already started...",
180 daemon_name);
181 return -1;
182 }
183 else
184 {
185 unlink(CHARON_CTL_FILE);
186 _stop_requested = 0;
187
188 pid = fork();
189 switch (pid)
190 {
191 case -1:
192 DBG1(DBG_APP, "can't fork(): %s", strerror(errno));
193 return -1;
194 case 0:
195 /* child */
196 setsid();
197 closefrom(3);
198 sigprocmask(SIG_SETMASK, 0, NULL);
199 /* disable glibc's malloc checker, conflicts with leak detective */
200 setenv("MALLOC_CHECK_", "0", 1);
201 execv(arg[0], arg);
202 DBG1(DBG_APP, "can't execv(%s,...): %s", arg[0], strerror(errno));
203 exit(1);
204 default:
205 /* father */
206 _charon_pid = pid;
207 while (attach_gdb)
208 {
209 /* wait indefinitely if gdb is attached */
210 usleep(10000);
211 if (stat(pid_file, &stb) == 0)
212 {
213 return 0;
214 }
215 }
216 for (i = 0; i < 500 && _charon_pid; i++)
217 {
218 /* wait for charon for a maximum of 500 x 20 ms = 10 s */
219 usleep(20000);
220 if (stat(pid_file, &stb) == 0)
221 {
222 DBG1(DBG_APP, "%s (%d) started after %d ms", daemon_name,
223 _charon_pid, 20*(i+1));
224 return 0;
225 }
226 }
227 if (_charon_pid)
228 {
229 /* If charon is started but with no ctl file, stop it */
230 DBG1(DBG_APP, "%s too long to start... - kill kill",
231 daemon_name);
232 for (i = 0; i < 20 && (pid = _charon_pid) != 0; i++)
233 {
234 if (i == 0)
235 {
236 kill(pid, SIGINT);
237 }
238 else if (i < 10)
239 {
240 kill(pid, SIGTERM);
241 }
242 else
243 {
244 kill(pid, SIGKILL);
245 }
246 usleep(20000); /* sleep for 20 ms */
247 }
248 }
249 else
250 {
251 DBG1(DBG_APP, "%s refused to be started", daemon_name);
252 }
253 return -1;
254 }
255 }
256 return -1;
257 }