2 * Copyright (C) 2007 Martin Willi
3 * Hochschule fuer Technik Rapperswil
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>.
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
18 #include <sys/types.h>
29 #define PERME (S_IRWXU | S_IRWXG)
30 #define GUEST_DIR "guests"
31 #define TEMPLATE_DIR "templates"
32 #define TEMPLATE_DIR_DIR "diff"
35 * instances of dumm, used to deliver signals
37 static linked_list_t
*instances
= NULL
;
39 typedef struct private_dumm_t private_dumm_t
;
41 struct private_dumm_t
{
42 /** public dumm interface */
46 /** directory of guests */
48 /** directory of templates */
50 /** directory of loaded 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 */
61 * Implementation of dumm_t.create_guest.
63 static guest_t
* create_guest(private_dumm_t
*this, char *name
, char *kernel
,
64 char *master
, int mem
)
68 guest
= guest_create(this->guest_dir
, name
, kernel
, master
, mem
);
71 this->guests
->insert_last(this->guests
, guest
);
77 * Implementation of dumm_t.create_guest_iterator.
79 static iterator_t
* create_guest_iterator(private_dumm_t
*this)
81 return this->guests
->create_iterator(this->guests
, TRUE
);
85 * Implementation of dumm_t.create_bridge.
87 static bridge_t
* create_bridge(private_dumm_t
*this, char *name
)
91 bridge
= bridge_create(name
);
94 this->bridges
->insert_last(this->bridges
, bridge
);
100 * Implementation of dumm_t.create_bridge_iterator.
102 static iterator_t
* create_bridge_iterator(private_dumm_t
*this)
104 return this->bridges
->create_iterator(this->bridges
, TRUE
);
108 * disable the currently enabled template
110 static void clear_template(private_dumm_t
*this)
112 iterator_t
*iterator
, *ifaces
;
116 free(this->template);
117 this->template = NULL
;
119 iterator
= this->guests
->create_iterator(this->guests
, TRUE
);
120 while (iterator
->iterate(iterator
, (void**)&guest
))
122 guest
->load_template(guest
, NULL
);
123 ifaces
= guest
->create_iface_iterator(guest
);
124 while (ifaces
->iterate(ifaces
, (void**)&iface
))
126 ifaces
->remove(ifaces
);
127 iface
->destroy(iface
);
129 ifaces
->destroy(ifaces
);
131 iterator
->destroy(iterator
);
135 * Implementation of dumm_t.load_template.
137 static bool load_template(private_dumm_t
*this, char *name
)
139 iterator_t
*iterator
;
144 clear_template(this);
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
))
159 if (access(this->template, F_OK
) != 0)
160 { /* does not exist, create template */
161 if (mkdir(this->template, PERME
) != 0)
163 DBG1("creating template directory '%s' failed: %m", this->template);
166 if (mkdir(dir
, PERME
) != 0)
168 DBG1("creating template overlay directory '%s' failed: %m", dir
);
172 iterator
= this->guests
->create_iterator(this->guests
, TRUE
);
173 while (iterator
->iterate(iterator
, (void**)&guest
))
175 if (!guest
->load_template(guest
, dir
))
177 iterator
->destroy(iterator
);
178 clear_template(this);
182 iterator
->destroy(iterator
);
189 void signal_handler(int sig
, siginfo_t
*info
, void *ucontext
)
193 switch (info
->si_code
)
199 private_dumm_t
*this;
201 iterator_t
*iterator
, *guests
;
203 iterator
= instances
->create_iterator(instances
, TRUE
);
204 while (iterator
->iterate(iterator
, (void**)&this))
206 if (this->destroying
)
210 guests
= this->guests
->create_iterator(this->guests
, TRUE
);
211 while (guests
->iterate(guests
, (void**)&guest
))
213 if (guest
->get_pid(guest
) == info
->si_pid
)
215 guest
->sigchild(guest
);
219 guests
->destroy(guests
);
221 iterator
->destroy(iterator
);
229 /* SIGHUP is currently just ignored */
233 * add a dumm instance
235 static void add_instance(private_dumm_t
*this)
237 if (instances
== NULL
)
239 struct sigaction action
;
241 instances
= linked_list_create();
243 memset(&action
, 0, sizeof(action
));
244 action
.sa_sigaction
= signal_handler
;
245 action
.sa_flags
= SA_SIGINFO
;
247 if (sigaction(SIGCHLD
, &action
, NULL
) != 0 ||
248 sigaction(SIGHUP
, &action
, NULL
) != 0)
250 DBG1("installing signal handler failed!");
253 instances
->insert_last(instances
, this);
257 * remove a dumm instance
259 static void remove_instance(private_dumm_t
*this)
261 iterator_t
*iterator
;
262 private_dumm_t
*current
;
264 iterator
= instances
->create_iterator(instances
, TRUE
);
265 while (iterator
->iterate(iterator
, (void**)¤t
))
269 iterator
->remove(iterator
);
273 iterator
->destroy(iterator
);
274 if (instances
->get_count(instances
) == 0)
276 instances
->destroy(instances
);
282 * Implementation of dumm_t.destroy
284 static void destroy(private_dumm_t
*this)
286 iterator_t
*iterator
;
289 this->bridges
->destroy_offset(this->bridges
, offsetof(bridge_t
, destroy
));
291 iterator
= this->guests
->create_iterator(this->guests
, TRUE
);
292 while (iterator
->iterate(iterator
, (void**)&guest
))
296 iterator
->destroy(iterator
);
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);
304 remove_instance(this);
309 * load all guests in our working dir
311 static void load_guests(private_dumm_t
*this)
317 dir
= opendir(this->guest_dir
);
323 while ((ent
= readdir(dir
)))
325 if (streq(ent
->d_name
, ".") || streq(ent
->d_name
, ".."))
329 guest
= guest_load(this->guest_dir
, ent
->d_name
);
332 DBG1("loaded guest '%s'", ent
->d_name
);
333 this->guests
->insert_last(this->guests
, guest
);
337 DBG1("loading guest in directory '%s' failed, skipped", ent
->d_name
);
344 * create a dumm instance
346 dumm_t
*dumm_create(char *dir
)
349 private_dumm_t
*this = malloc_thing(private_dumm_t
);
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
;
358 this->destroying
= FALSE
;
359 if (*dir
== '/' || getcwd(cwd
, sizeof(cwd
)) == 0)
361 this->dir
= strdup(dir
);
365 asprintf(&this->dir
, "%s/%s", cwd
, dir
);
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();
375 if (mkdir(this->guest_dir
, PERME
) < 0 && errno
!= EEXIST
)
377 DBG1("creating guest directory '%s' failed: %m", this->guest_dir
);
381 if (mkdir(this->template_dir
, PERME
) < 0 && errno
!= EEXIST
)
383 DBG1("creating template directory '%s' failed: %m", this->template_dir
);
389 return &this->public;