prototype of irdumm - interactive ruby shell for dumm
[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 #include <utils/linked_list.h>
27
28 #include "dumm.h"
29
30 #define PERME (S_IRWXU | S_IRWXG)
31 #define GUEST_DIR "guests"
32 #define TEMPLATE_DIR "templates"
33 #define TEMPLATE_DIR_DIR "diff"
34
35 typedef struct private_dumm_t private_dumm_t;
36
37 struct private_dumm_t {
38 /** public dumm interface */
39 dumm_t public;
40 /** working dir */
41 char *dir;
42 /** directory of guests */
43 char *guest_dir;
44 /** directory of templates */
45 char *template_dir;
46 /** directory of loaded template */
47 char *template;
48 /** list of managed guests */
49 linked_list_t *guests;
50 /** list of managed bridges */
51 linked_list_t *bridges;
52 };
53
54 /**
55 * Implementation of dumm_t.create_guest.
56 */
57 static guest_t* create_guest(private_dumm_t *this, char *name, char *kernel,
58 char *master, int mem)
59 {
60 guest_t *guest;
61
62 guest = guest_create(this->guest_dir, name, kernel, master, mem);
63 if (guest)
64 {
65 this->guests->insert_last(this->guests, guest);
66 }
67 return guest;
68 }
69
70 /**
71 * Implementation of dumm_t.create_guest_enumerator.
72 */
73 static enumerator_t* create_guest_enumerator(private_dumm_t *this)
74 {
75 return this->guests->create_enumerator(this->guests);
76 }
77
78 /**
79 * Implementation of dumm_t.delete_guest.
80 */
81 static void delete_guest(private_dumm_t *this, guest_t *guest)
82 {
83 if (this->guests->remove(this->guests, guest, NULL))
84 {
85 char buf[512];
86 int len;
87
88 len = snprintf(buf, sizeof(buf), "rm -Rf %s/%s",
89 this->guest_dir, guest->get_name(guest));
90 guest->destroy(guest);
91 if (len > 8 && len < 512)
92 {
93 system(buf);
94 }
95 }
96 }
97
98 /**
99 * Implementation of dumm_t.create_bridge.
100 */
101 static bridge_t* create_bridge(private_dumm_t *this, char *name)
102 {
103 bridge_t *bridge;
104
105 bridge = bridge_create(name);
106 if (bridge)
107 {
108 this->bridges->insert_last(this->bridges, bridge);
109 }
110 return bridge;
111 }
112
113 /**
114 * Implementation of dumm_t.create_bridge_enumerator.
115 */
116 static enumerator_t* create_bridge_enumerator(private_dumm_t *this)
117 {
118 return this->bridges->create_enumerator(this->bridges);
119 }
120
121 /**
122 * Implementation of dumm_t.delete_bridge.
123 */
124 static void delete_bridge(private_dumm_t *this, bridge_t *bridge)
125 {
126 if (this->bridges->remove(this->bridges, bridge, NULL))
127 {
128 bridge->destroy(bridge);
129 }
130 }
131
132 /**
133 * disable the currently enabled template
134 */
135 static void clear_template(private_dumm_t *this)
136 {
137 enumerator_t *enumerator;
138 guest_t *guest;
139
140 free(this->template);
141 this->template = NULL;
142
143 enumerator = this->guests->create_enumerator(this->guests);
144 while (enumerator->enumerate(enumerator, (void**)&guest))
145 {
146 guest->load_template(guest, NULL);
147 }
148 enumerator->destroy(enumerator);
149 }
150
151 /**
152 * Implementation of dumm_t.load_template.
153 */
154 static bool load_template(private_dumm_t *this, char *name)
155 {
156 enumerator_t *enumerator;
157 guest_t *guest;
158 char dir[PATH_MAX];
159 size_t len;
160
161 clear_template(this);
162
163 if (name == NULL)
164 {
165 return TRUE;
166 }
167
168 free(this->template);
169 asprintf(&this->template, "%s/%s", this->template_dir, name);
170 len = snprintf(dir, sizeof(dir), "%s/%s", this->template, TEMPLATE_DIR_DIR);
171 if (len < 0 || len >= sizeof(dir))
172 {
173 return FALSE;
174 }
175
176 if (access(this->template, F_OK) != 0)
177 { /* does not exist, create template */
178 if (mkdir(this->template, PERME) != 0)
179 {
180 DBG1("creating template directory '%s' failed: %m", this->template);
181 return FALSE;
182 }
183 if (mkdir(dir, PERME) != 0)
184 {
185 DBG1("creating template overlay directory '%s' failed: %m", dir);
186 return FALSE;
187 }
188 }
189 enumerator = this->guests->create_enumerator(this->guests);
190 while (enumerator->enumerate(enumerator, (void**)&guest))
191 {
192 if (!guest->load_template(guest, dir))
193 {
194 enumerator->destroy(enumerator);
195 clear_template(this);
196 return FALSE;
197 }
198 }
199 enumerator->destroy(enumerator);
200 return TRUE;
201 }
202
203 /**
204 * Implementation of dumm_t.destroy
205 */
206 static void destroy(private_dumm_t *this)
207 {
208 enumerator_t *enumerator;
209 guest_t *guest;
210
211 this->bridges->destroy_offset(this->bridges, offsetof(bridge_t, destroy));
212
213 enumerator = this->guests->create_enumerator(this->guests);
214 while (enumerator->enumerate(enumerator, (void**)&guest))
215 {
216 guest->stop(guest, NULL);
217 }
218 enumerator->destroy(enumerator);
219
220 while (this->guests->remove_last(this->guests, (void**)&guest) == SUCCESS)
221 {
222 guest->destroy(guest);
223 }
224 this->guests->destroy(this->guests);
225 free(this->guest_dir);
226 free(this->template_dir);
227 free(this->template);
228 free(this->dir);
229 free(this);
230 }
231
232 /**
233 * load all guests in our working dir
234 */
235 static void load_guests(private_dumm_t *this)
236 {
237 DIR *dir;
238 struct dirent *ent;
239 guest_t *guest;
240
241 dir = opendir(this->guest_dir);
242 if (dir == NULL)
243 {
244 return;
245 }
246
247 while ((ent = readdir(dir)))
248 {
249 if (streq(ent->d_name, ".") || streq(ent->d_name, ".."))
250 {
251 continue;
252 }
253 guest = guest_load(this->guest_dir, ent->d_name);
254 if (guest)
255 {
256 this->guests->insert_last(this->guests, guest);
257 }
258 else
259 {
260 DBG1("loading guest in directory '%s' failed, skipped", ent->d_name);
261 }
262 }
263 closedir(dir);
264 }
265
266 /**
267 * create a dumm instance
268 */
269 dumm_t *dumm_create(char *dir)
270 {
271 char cwd[PATH_MAX];
272 private_dumm_t *this = malloc_thing(private_dumm_t);
273
274 this->public.create_guest = (guest_t*(*)(dumm_t*,char*,char*,char*,int))create_guest;
275 this->public.create_guest_enumerator = (enumerator_t*(*)(dumm_t*))create_guest_enumerator;
276 this->public.delete_guest = (void(*)(dumm_t*,guest_t*))delete_guest;
277 this->public.create_bridge = (bridge_t*(*)(dumm_t*, char *name))create_bridge;
278 this->public.create_bridge_enumerator = (enumerator_t*(*)(dumm_t*))create_bridge_enumerator;
279 this->public.delete_bridge = (void(*)(dumm_t*,bridge_t*))delete_bridge;
280 this->public.load_template = (bool(*)(dumm_t*, char *name))load_template;
281 this->public.destroy = (void(*)(dumm_t*))destroy;
282
283 if (dir && *dir == '/')
284 {
285 this->dir = strdup(dir);
286 }
287 else
288 {
289 if (getcwd(cwd, sizeof(cwd)) == NULL)
290 {
291 free(this);
292 return NULL;
293 }
294 if (dir)
295 {
296 asprintf(&this->dir, "%s/%s", cwd, dir);
297 }
298 else
299 {
300 this->dir = strdup(cwd);
301 }
302 }
303 this->template = NULL;
304 asprintf(&this->guest_dir, "%s/%s", this->dir, GUEST_DIR);
305 asprintf(&this->template_dir, "%s/%s", this->dir, TEMPLATE_DIR);
306 this->guests = linked_list_create();
307 this->bridges = linked_list_create();
308
309 if (mkdir(this->guest_dir, PERME) < 0 && errno != EEXIST)
310 {
311 DBG1("creating guest directory '%s' failed: %m", this->guest_dir);
312 destroy(this);
313 return NULL;
314 }
315 if (mkdir(this->template_dir, PERME) < 0 && errno != EEXIST)
316 {
317 DBG1("creating template directory '%s' failed: %m", this->template_dir);
318 destroy(this);
319 return NULL;
320 }
321
322 load_guests(this);
323 return &this->public;
324 }
325