2 * Copyright (C) 2008-2009 Tobias Brunner
3 * Copyright (C) 2007 Martin Willi
4 * HSR Hochschule fuer Technik Rapperswil
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the
8 * Free Software Foundation; either version 2 of the License, or (at your
9 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
11 * This program is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
13 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
19 #include <sys/types.h>
26 #include <utils/debug.h>
27 #include <collections/linked_list.h>
31 #define PERME (S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH)
32 #define GUEST_DIR "guests"
33 #define TEMPLATE_DIR "templates"
35 typedef struct private_dumm_t private_dumm_t
;
37 struct private_dumm_t
{
38 /** public dumm interface */
42 /** directory of guests */
44 /** directory of loaded template */
46 /** list of managed guests */
47 linked_list_t
*guests
;
48 /** list of managed bridges */
49 linked_list_t
*bridges
;
52 METHOD(dumm_t
, create_guest
, guest_t
*,
53 private_dumm_t
*this, char *name
, char *kernel
, char *master
, char *args
)
57 guest
= guest_create(this->guest_dir
, name
, kernel
, master
, args
);
60 this->guests
->insert_last(this->guests
, guest
);
65 METHOD(dumm_t
, create_guest_enumerator
, enumerator_t
*,
68 return this->guests
->create_enumerator(this->guests
);
71 METHOD(dumm_t
, delete_guest
, void,
72 private_dumm_t
*this, guest_t
*guest
)
74 if (this->guests
->remove(this->guests
, guest
, NULL
))
79 len
= snprintf(buf
, sizeof(buf
), "rm -Rf %s/%s",
80 this->guest_dir
, guest
->get_name(guest
));
81 guest
->destroy(guest
);
82 if (len
> 8 && len
< 512)
84 ignore_result(system(buf
));
89 METHOD(dumm_t
, create_bridge
, bridge_t
*,
90 private_dumm_t
*this, char *name
)
94 bridge
= bridge_create(name
);
97 this->bridges
->insert_last(this->bridges
, bridge
);
102 METHOD(dumm_t
, create_bridge_enumerator
, enumerator_t
*,
103 private_dumm_t
*this)
105 return this->bridges
->create_enumerator(this->bridges
);
108 METHOD(dumm_t
, delete_bridge
, void,
109 private_dumm_t
*this, bridge_t
*bridge
)
111 if (this->bridges
->remove(this->bridges
, bridge
, NULL
))
113 bridge
->destroy(bridge
);
117 METHOD(dumm_t
, add_overlay
, bool,
118 private_dumm_t
*this, char *dir
)
120 enumerator_t
*enumerator
;
127 if (strlen(dir
) > PATH_MAX
)
129 DBG1(DBG_LIB
, "overlay directory string '%s' is too long", dir
);
132 if (access(dir
, F_OK
) != 0)
134 if (!mkdir_p(dir
, PERME
))
136 DBG1(DBG_LIB
, "creating overlay directory '%s' failed: %m", dir
);
140 enumerator
= this->guests
->create_enumerator(this->guests
);
141 while (enumerator
->enumerate(enumerator
, (void**)&guest
))
143 char guest_dir
[PATH_MAX
];
144 int len
= snprintf(guest_dir
, sizeof(guest_dir
), "%s/%s", dir
,
145 guest
->get_name(guest
));
146 if (len
< 0 || len
>= sizeof(guest_dir
))
150 if (access(guest_dir
, F_OK
) != 0)
152 if (!mkdir_p(guest_dir
, PERME
))
154 DBG1(DBG_LIB
, "creating overlay directory for guest '%s' failed: %m",
155 guest
->get_name(guest
));
159 if (!guest
->add_overlay(guest
, guest_dir
))
164 enumerator
->destroy(enumerator
);
167 enumerator
->destroy(enumerator
);
168 this->public.del_overlay(&this->public, dir
);
172 METHOD(dumm_t
, del_overlay
, bool,
173 private_dumm_t
*this, char *dir
)
176 enumerator_t
*enumerator
;
179 enumerator
= this->guests
->create_enumerator(this->guests
);
180 while (enumerator
->enumerate(enumerator
, (void**)&guest
))
182 char guest_dir
[PATH_MAX
];
183 int len
= snprintf(guest_dir
, sizeof(guest_dir
), "%s/%s", dir
,
184 guest
->get_name(guest
));
185 if (len
< 0 || len
>= sizeof(guest_dir
))
189 ret
= guest
->del_overlay(guest
, guest_dir
) || ret
;
191 enumerator
->destroy(enumerator
);
195 METHOD(dumm_t
, pop_overlay
, bool,
196 private_dumm_t
*this)
199 enumerator_t
*enumerator
;
202 enumerator
= this->guests
->create_enumerator(this->guests
);
203 while (enumerator
->enumerate(enumerator
, (void**)&guest
))
205 ret
= guest
->pop_overlay(guest
) || ret
;
207 enumerator
->destroy(enumerator
);
212 * disable the currently enabled template
214 static void clear_template(private_dumm_t
*this)
218 del_overlay(this, this->template);
219 free(this->template);
220 this->template = NULL
;
224 METHOD(dumm_t
, load_template
, bool,
225 private_dumm_t
*this, char *name
)
227 clear_template(this);
232 if (strlen(name
) > PATH_MAX
)
234 DBG1(DBG_LIB
, "template name '%s' is too long", name
);
237 if (strchr(name
, '/') != NULL
)
239 DBG1(DBG_LIB
, "template name '%s' must not contain '/' characters", name
);
242 if (asprintf(&this->template, "%s/%s", TEMPLATE_DIR
, name
) < 0)
244 this->template = NULL
;
247 if (access(this->template, F_OK
) != 0)
249 if (!mkdir_p(this->template, PERME
))
251 DBG1(DBG_LIB
, "creating template directory '%s' failed: %m",
256 return add_overlay(this, this->template);
260 * Template directory enumerator
263 /** implements enumerator_t */
265 /** directory enumerator */
267 } template_enumerator_t
;
269 METHOD(enumerator_t
, template_enumerate
, bool,
270 template_enumerator_t
*this, va_list args
)
273 char *rel
, **template;
275 VA_ARGS_VGET(args
, template);
277 while (this->inner
->enumerate(this->inner
, &rel
, NULL
, &st
))
279 if (S_ISDIR(st
.st_mode
) && *rel
!= '.')
288 METHOD(enumerator_t
, template_enumerator_destroy
, void,
289 template_enumerator_t
*this)
291 this->inner
->destroy(this->inner
);
295 METHOD(dumm_t
, create_template_enumerator
, enumerator_t
*,
296 private_dumm_t
*this)
298 template_enumerator_t
*enumerator
;
301 .enumerate
= enumerator_enumerate_default
,
302 .venumerate
= _template_enumerate
,
303 .destroy
= (void*)_template_enumerator_destroy
,
305 .inner
= enumerator_create_directory(TEMPLATE_DIR
),
307 if (!enumerator
->inner
)
310 return enumerator_create_empty();
312 return &enumerator
->public;
315 METHOD(dumm_t
, destroy
, void,
316 private_dumm_t
*this)
318 enumerator_t
*enumerator
;
321 this->bridges
->destroy_offset(this->bridges
, offsetof(bridge_t
, destroy
));
323 enumerator
= this->guests
->create_enumerator(this->guests
);
324 while (enumerator
->enumerate(enumerator
, (void**)&guest
))
326 guest
->stop(guest
, NULL
);
328 enumerator
->destroy(enumerator
);
330 while (this->guests
->remove_last(this->guests
, (void**)&guest
) == SUCCESS
)
332 guest
->destroy(guest
);
334 this->guests
->destroy(this->guests
);
335 free(this->guest_dir
);
336 free(this->template);
342 * load all guests in our working dir
344 static void load_guests(private_dumm_t
*this)
350 dir
= opendir(this->guest_dir
);
356 while ((ent
= readdir(dir
)))
358 if (*ent
->d_name
== '.')
359 { /* skip ".", ".." and hidden files (such as ".svn") */
362 guest
= guest_load(this->guest_dir
, ent
->d_name
);
365 this->guests
->insert_last(this->guests
, guest
);
369 DBG1(DBG_LIB
, "loading guest in directory '%s' failed, skipped",
377 * create a dumm instance
379 dumm_t
*dumm_create(char *dir
)
382 private_dumm_t
*this;
386 .create_guest
= _create_guest
,
387 .create_guest_enumerator
= _create_guest_enumerator
,
388 .delete_guest
= _delete_guest
,
389 .create_bridge
= _create_bridge
,
390 .create_bridge_enumerator
= _create_bridge_enumerator
,
391 .delete_bridge
= _delete_bridge
,
392 .add_overlay
= _add_overlay
,
393 .del_overlay
= _del_overlay
,
394 .pop_overlay
= _pop_overlay
,
395 .load_template
= _load_template
,
396 .create_template_enumerator
= _create_template_enumerator
,
401 if (dir
&& *dir
== '/')
403 this->dir
= strdup(dir
);
407 if (getcwd(cwd
, sizeof(cwd
)) == NULL
)
414 if (asprintf(&this->dir
, "%s/%s", cwd
, dir
) < 0)
421 this->dir
= strdup(cwd
);
424 if (asprintf(&this->guest_dir
, "%s/%s", this->dir
, GUEST_DIR
) < 0)
426 this->guest_dir
= NULL
;
429 this->guests
= linked_list_create();
430 this->bridges
= linked_list_create();
432 if (this->dir
== NULL
|| this->guest_dir
== NULL
||
433 (mkdir(this->guest_dir
, PERME
) < 0 && errno
!= EEXIST
))
435 DBG1(DBG_LIB
, "creating guest directory '%s' failed: %m",
442 return &this->public;