cowfs is bootable now!
[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 <unistd.h>
20 #include <stdio.h>
21 #include <dirent.h>
22
23 #include <debug.h>
24
25 #include "dumm.h"
26
27 /**
28 * instances of dumm, used to deliver signals
29 */
30 static linked_list_t *instances = NULL;
31
32 typedef struct private_dumm_t private_dumm_t;
33
34 struct private_dumm_t {
35 /** public dumm interface */
36 dumm_t public;
37 /** working dir */
38 char *dir;
39 /** list of managed guests */
40 linked_list_t *guests;
41 /** list of managed bridges */
42 linked_list_t *bridges;
43 /** do not catch signals if we are destroying */
44 bool destroying;
45 };
46
47 /**
48 * Implementation of dumm_t.create_guest.
49 */
50 static guest_t* create_guest(private_dumm_t *this, char *name, char *kernel,
51 char *master, int mem)
52 {
53 guest_t *guest;
54
55 guest = guest_create(this->dir, name, kernel, master, mem);
56 if (guest)
57 {
58 this->guests->insert_last(this->guests, guest);
59 }
60 return guest;
61 }
62
63 /**
64 * Implementation of dumm_t.create_guest_iterator.
65 */
66 static iterator_t* create_guest_iterator(private_dumm_t *this)
67 {
68 return this->guests->create_iterator(this->guests, TRUE);
69 }
70
71 /**
72 * Implementation of dumm_t.create_bridge.
73 */
74 static bridge_t* create_bridge(private_dumm_t *this, char *name)
75 {
76 bridge_t *bridge;
77
78 bridge = bridge_create(name);
79 if (bridge)
80 {
81 this->bridges->insert_last(this->bridges, bridge);
82 }
83 return bridge;
84 }
85
86 /**
87 * Implementation of dumm_t.create_bridge_iterator.
88 */
89 static iterator_t* create_bridge_iterator(private_dumm_t *this)
90 {
91 return this->bridges->create_iterator(this->bridges, TRUE);
92 }
93
94 /**
95 * signal handler
96 */
97 void signal_handler(int sig, siginfo_t *info, void *ucontext)
98 {
99 if (sig == SIGCHLD)
100 {
101 switch (info->si_code)
102 {
103 case CLD_EXITED:
104 case CLD_KILLED:
105 case CLD_DUMPED:
106 {
107 private_dumm_t *this;
108 guest_t *guest;
109 iterator_t *iterator, *guests;
110
111 iterator = instances->create_iterator(instances, TRUE);
112 while (iterator->iterate(iterator, (void**)&this))
113 {
114 if (this->destroying)
115 {
116 continue;
117 }
118 guests = this->guests->create_iterator(this->guests, TRUE);
119 while (guests->iterate(guests, (void**)&guest))
120 {
121 if (guest->get_pid(guest) == info->si_pid)
122 {
123 guest->sigchild(guest);
124 break;
125 }
126 }
127 guests->destroy(guests);
128 }
129 iterator->destroy(iterator);
130 break;
131 }
132 default:
133 break;
134 }
135
136 }
137 /* SIGHUP is currently just ignored */
138 }
139
140 /**
141 * add a dumm instance
142 */
143 static void add_instance(private_dumm_t *this)
144 {
145 if (instances == NULL)
146 {
147 struct sigaction action;
148
149 instances = linked_list_create();
150
151 memset(&action, 0, sizeof(action));
152 action.sa_sigaction = signal_handler;
153 action.sa_flags = SA_SIGINFO;
154
155 if (sigaction(SIGCHLD, &action, NULL) != 0 ||
156 sigaction(SIGHUP, &action, NULL) != 0)
157 {
158 DBG1("installing signal handler failed!");
159 }
160 }
161 instances->insert_last(instances, this);
162 }
163
164 /**
165 * remove a dumm instance
166 */
167 static void remove_instance(private_dumm_t *this)
168 {
169 iterator_t *iterator;
170 private_dumm_t *current;
171
172 iterator = instances->create_iterator(instances, TRUE);
173 while (iterator->iterate(iterator, (void**)&current))
174 {
175 if (current == this)
176 {
177 iterator->remove(iterator);
178 break;
179 }
180 }
181 iterator->destroy(iterator);
182 if (instances->get_count(instances) == 0)
183 {
184 instances->destroy(instances);
185 instances = NULL;
186 }
187 }
188
189 /**
190 * Implementation of dumm_t.destroy
191 */
192 static void destroy(private_dumm_t *this)
193 {
194 iterator_t *iterator;
195 guest_t *guest;
196
197 this->bridges->destroy_offset(this->bridges, offsetof(bridge_t, destroy));
198
199 iterator = this->guests->create_iterator(this->guests, TRUE);
200 while (iterator->iterate(iterator, (void**)&guest))
201 {
202 guest->stop(guest);
203 }
204 iterator->destroy(iterator);
205
206 this->destroying = TRUE;
207 this->guests->destroy_offset(this->guests, offsetof(guest_t, destroy));
208 free(this->dir);
209 remove_instance(this);
210 free(this);
211 }
212
213 /**
214 * load all guests in our working dir
215 */
216 static void load_guests(private_dumm_t *this)
217 {
218 DIR *dir;
219 struct dirent *ent;
220 guest_t *guest;
221
222 dir = opendir(this->dir);
223 if (dir == NULL)
224 {
225 return;
226 }
227
228 while ((ent = readdir(dir)))
229 {
230 if (streq(ent->d_name, ".") || streq(ent->d_name, ".."))
231 {
232 continue;
233 }
234 guest = guest_load(this->dir, ent->d_name);
235 if (guest)
236 {
237 this->guests->insert_last(this->guests, guest);
238 }
239 else
240 {
241 DBG1("loading guest in directory '%s' failed, skipped", ent->d_name);
242 }
243 }
244 closedir(dir);
245 }
246
247 /**
248 * create a dumm instance
249 */
250 dumm_t *dumm_create(char *dir)
251 {
252 char cwd[PATH_MAX];
253 private_dumm_t *this = malloc_thing(private_dumm_t);
254
255 this->public.create_guest = (guest_t*(*)(dumm_t*,char*,char*,char*,int))create_guest;
256 this->public.create_guest_iterator = (iterator_t*(*)(dumm_t*))create_guest_iterator;
257 this->public.create_bridge = (bridge_t*(*)(dumm_t*, char *name))create_bridge;
258 this->public.create_bridge_iterator = (iterator_t*(*)(dumm_t*))create_bridge_iterator;
259 this->public.destroy = (void(*)(dumm_t*))destroy;
260
261 this->destroying = FALSE;
262 if (*dir == '/' || getcwd(cwd, sizeof(cwd)) == 0)
263 {
264 this->dir = strdup(dir);
265 }
266 else
267 {
268 asprintf(&this->dir, "%s/%s", cwd, dir);
269 }
270 this->guests = linked_list_create();
271 this->bridges = linked_list_create();
272
273 add_instance(this);
274
275 load_guests(this);
276 return &this->public;
277 }
278