completed pkcs7 parsing methods
[strongswan.git] / src / dumm / dumm.c
1 /*
2 * Copyright (C) 2007 Martin Willi
3 * Hochschule fuer Technik Rapperswil
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License as published by the
7 * Free Software Foundation; either version 2 of the License, or (at your
8 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
9 *
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
12 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
13 * for more details.
14 */
15
16 #define _GNU_SOURCE
17
18 #include <sys/types.h>
19 #include <sys/stat.h>
20 #include <unistd.h>
21 #include <stdio.h>
22 #include <dirent.h>
23 #include <errno.h>
24
25 #include <debug.h>
26
27 #include "dumm.h"
28
29 #define PERME (S_IRWXU | S_IRWXG)
30 #define GUEST_DIR "guests"
31 #define TEMPLATE_DIR "templates"
32 #define TEMPLATE_DIR_DIR "diff"
33
34 /**
35 * instances of dumm, used to deliver signals
36 */
37 static linked_list_t *instances = NULL;
38
39 typedef struct private_dumm_t private_dumm_t;
40
41 struct private_dumm_t {
42 /** public dumm interface */
43 dumm_t public;
44 /** working dir */
45 char *dir;
46 /** directory of guests */
47 char *guest_dir;
48 /** directory of templates */
49 char *template_dir;
50 /** directory of loaded template */
51 char *template;
52 /** list of managed guests */
53 linked_list_t *guests;
54 /** list of managed bridges */
55 linked_list_t *bridges;
56 /** do not catch signals if we are destroying */
57 bool destroying;
58 };
59
60 /**
61 * Implementation of dumm_t.create_guest.
62 */
63 static guest_t* create_guest(private_dumm_t *this, char *name, char *kernel,
64 char *master, int mem)
65 {
66 guest_t *guest;
67
68 guest = guest_create(this->guest_dir, name, kernel, master, mem);
69 if (guest)
70 {
71 this->guests->insert_last(this->guests, guest);
72 }
73 return guest;
74 }
75
76 /**
77 * Implementation of dumm_t.create_guest_iterator.
78 */
79 static iterator_t* create_guest_iterator(private_dumm_t *this)
80 {
81 return this->guests->create_iterator(this->guests, TRUE);
82 }
83
84 /**
85 * Implementation of dumm_t.create_bridge.
86 */
87 static bridge_t* create_bridge(private_dumm_t *this, char *name)
88 {
89 bridge_t *bridge;
90
91 bridge = bridge_create(name);
92 if (bridge)
93 {
94 this->bridges->insert_last(this->bridges, bridge);
95 }
96 return bridge;
97 }
98
99 /**
100 * Implementation of dumm_t.create_bridge_iterator.
101 */
102 static iterator_t* create_bridge_iterator(private_dumm_t *this)
103 {
104 return this->bridges->create_iterator(this->bridges, TRUE);
105 }
106
107 /**
108 * disable the currently enabled template
109 */
110 static void clear_template(private_dumm_t *this)
111 {
112 iterator_t *iterator, *ifaces;
113 guest_t *guest;
114 iface_t *iface;
115
116 free(this->template);
117 this->template = NULL;
118
119 iterator = this->guests->create_iterator(this->guests, TRUE);
120 while (iterator->iterate(iterator, (void**)&guest))
121 {
122 guest->load_template(guest, NULL);
123 ifaces = guest->create_iface_iterator(guest);
124 while (ifaces->iterate(ifaces, (void**)&iface))
125 {
126 ifaces->remove(ifaces);
127 iface->destroy(iface);
128 }
129 ifaces->destroy(ifaces);
130 }
131 iterator->destroy(iterator);
132 }
133
134 /**
135 * Implementation of dumm_t.load_template.
136 */
137 static bool load_template(private_dumm_t *this, char *name)
138 {
139 iterator_t *iterator;
140 guest_t *guest;
141 char dir[PATH_MAX];
142 size_t len;
143
144 clear_template(this);
145
146 if (name == NULL)
147 {
148 return TRUE;
149 }
150
151 free(this->template);
152 asprintf(&this->template, "%s/%s", this->template_dir, name);
153 len = snprintf(dir, sizeof(dir), "%s/%s", this->template, TEMPLATE_DIR_DIR);
154 if (len < 0 || len >= sizeof(dir))
155 {
156 return FALSE;
157 }
158
159 if (access(this->template, F_OK) != 0)
160 { /* does not exist, create template */
161 if (mkdir(this->template, PERME) != 0)
162 {
163 DBG1("creating template directory '%s' failed: %m", this->template);
164 return FALSE;
165 }
166 if (mkdir(dir, PERME) != 0)
167 {
168 DBG1("creating template overlay directory '%s' failed: %m", dir);
169 return FALSE;
170 }
171 }
172 iterator = this->guests->create_iterator(this->guests, TRUE);
173 while (iterator->iterate(iterator, (void**)&guest))
174 {
175 if (!guest->load_template(guest, dir))
176 {
177 iterator->destroy(iterator);
178 clear_template(this);
179 return FALSE;
180 }
181 }
182 iterator->destroy(iterator);
183 return TRUE;
184 }
185
186 /**
187 * signal handler
188 */
189 void signal_handler(int sig, siginfo_t *info, void *ucontext)
190 {
191 if (sig == SIGCHLD)
192 {
193 switch (info->si_code)
194 {
195 case CLD_EXITED:
196 case CLD_KILLED:
197 case CLD_DUMPED:
198 {
199 private_dumm_t *this;
200 guest_t *guest;
201 iterator_t *iterator, *guests;
202
203 iterator = instances->create_iterator(instances, TRUE);
204 while (iterator->iterate(iterator, (void**)&this))
205 {
206 if (this->destroying)
207 {
208 continue;
209 }
210 guests = this->guests->create_iterator(this->guests, TRUE);
211 while (guests->iterate(guests, (void**)&guest))
212 {
213 if (guest->get_pid(guest) == info->si_pid)
214 {
215 guest->sigchild(guest);
216 break;
217 }
218 }
219 guests->destroy(guests);
220 }
221 iterator->destroy(iterator);
222 break;
223 }
224 default:
225 break;
226 }
227
228 }
229 /* SIGHUP is currently just ignored */
230 }
231
232 /**
233 * add a dumm instance
234 */
235 static void add_instance(private_dumm_t *this)
236 {
237 if (instances == NULL)
238 {
239 struct sigaction action;
240
241 instances = linked_list_create();
242
243 memset(&action, 0, sizeof(action));
244 action.sa_sigaction = signal_handler;
245 action.sa_flags = SA_SIGINFO;
246
247 if (sigaction(SIGCHLD, &action, NULL) != 0 ||
248 sigaction(SIGHUP, &action, NULL) != 0)
249 {
250 DBG1("installing signal handler failed!");
251 }
252 }
253 instances->insert_last(instances, this);
254 }
255
256 /**
257 * remove a dumm instance
258 */
259 static void remove_instance(private_dumm_t *this)
260 {
261 iterator_t *iterator;
262 private_dumm_t *current;
263
264 iterator = instances->create_iterator(instances, TRUE);
265 while (iterator->iterate(iterator, (void**)&current))
266 {
267 if (current == this)
268 {
269 iterator->remove(iterator);
270 break;
271 }
272 }
273 iterator->destroy(iterator);
274 if (instances->get_count(instances) == 0)
275 {
276 instances->destroy(instances);
277 instances = NULL;
278 }
279 }
280
281 /**
282 * Implementation of dumm_t.destroy
283 */
284 static void destroy(private_dumm_t *this)
285 {
286 iterator_t *iterator;
287 guest_t *guest;
288
289 this->bridges->destroy_offset(this->bridges, offsetof(bridge_t, destroy));
290
291 iterator = this->guests->create_iterator(this->guests, TRUE);
292 while (iterator->iterate(iterator, (void**)&guest))
293 {
294 guest->stop(guest);
295 }
296 iterator->destroy(iterator);
297
298 this->destroying = TRUE;
299 this->guests->destroy_offset(this->guests, offsetof(guest_t, destroy));
300 free(this->guest_dir);
301 free(this->template_dir);
302 free(this->template);
303 free(this->dir);
304 remove_instance(this);
305 free(this);
306 }
307
308 /**
309 * load all guests in our working dir
310 */
311 static void load_guests(private_dumm_t *this)
312 {
313 DIR *dir;
314 struct dirent *ent;
315 guest_t *guest;
316
317 dir = opendir(this->guest_dir);
318 if (dir == NULL)
319 {
320 return;
321 }
322
323 while ((ent = readdir(dir)))
324 {
325 if (streq(ent->d_name, ".") || streq(ent->d_name, ".."))
326 {
327 continue;
328 }
329 guest = guest_load(this->guest_dir, ent->d_name);
330 if (guest)
331 {
332 DBG1("loaded guest '%s'", ent->d_name);
333 this->guests->insert_last(this->guests, guest);
334 }
335 else
336 {
337 DBG1("loading guest in directory '%s' failed, skipped", ent->d_name);
338 }
339 }
340 closedir(dir);
341 }
342
343 /**
344 * create a dumm instance
345 */
346 dumm_t *dumm_create(char *dir)
347 {
348 char cwd[PATH_MAX];
349 private_dumm_t *this = malloc_thing(private_dumm_t);
350
351 this->public.create_guest = (guest_t*(*)(dumm_t*,char*,char*,char*,int))create_guest;
352 this->public.create_guest_iterator = (iterator_t*(*)(dumm_t*))create_guest_iterator;
353 this->public.create_bridge = (bridge_t*(*)(dumm_t*, char *name))create_bridge;
354 this->public.create_bridge_iterator = (iterator_t*(*)(dumm_t*))create_bridge_iterator;
355 this->public.load_template = (bool(*)(dumm_t*, char *name))load_template;
356 this->public.destroy = (void(*)(dumm_t*))destroy;
357
358 this->destroying = FALSE;
359 if (*dir == '/' || getcwd(cwd, sizeof(cwd)) == 0)
360 {
361 this->dir = strdup(dir);
362 }
363 else
364 {
365 asprintf(&this->dir, "%s/%s", cwd, dir);
366 }
367 this->template = NULL;
368 asprintf(&this->guest_dir, "%s/%s", this->dir, GUEST_DIR);
369 asprintf(&this->template_dir, "%s/%s", this->dir, TEMPLATE_DIR);
370 this->guests = linked_list_create();
371 this->bridges = linked_list_create();
372
373 add_instance(this);
374
375 if (mkdir(this->guest_dir, PERME) < 0 && errno != EEXIST)
376 {
377 DBG1("creating guest directory '%s' failed: %m", this->guest_dir);
378 destroy(this);
379 return NULL;
380 }
381 if (mkdir(this->template_dir, PERME) < 0 && errno != EEXIST)
382 {
383 DBG1("creating template directory '%s' failed: %m", this->template_dir);
384 destroy(this);
385 return NULL;
386 }
387
388 load_guests(this);
389 return &this->public;
390 }
391