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>
23 #include <sys/types.h>
28 #include <utils/linked_list.h>
34 typedef struct private_guest_t private_guest_t
;
36 struct private_guest_t
{
37 /** implemented public interface */
39 /** name of the guest */
41 /** kernel to boot for guest */
43 /** read only master filesystem guest uses */
45 /** amount of memory for guest, in MB */
47 /** pid of guest child process */
49 /** log file for console 0 */
51 /** mconsole to control running UML */
53 /** list of interfaces attached to the guest */
54 linked_list_t
*ifaces
;
58 * Implementation of guest_t.get_name.
60 static char* get_name(private_guest_t
*this)
66 * Implementation of guest_t.create_iface.
68 static iface_t
* create_iface(private_guest_t
*this, char *name
)
75 DBG1("guest '%s' not running, unable to add interface", this->name
);
79 iterator
= this->ifaces
->create_iterator(this->ifaces
, TRUE
);
80 while (iterator
->iterate(iterator
, (void**)&iface
))
82 if (streq(name
, iface
->get_guest(iface
)))
84 DBG1("guest '%s' already has an interface '%s'", this->name
, name
);
85 iterator
->destroy(iterator
);
89 iterator
->destroy(iterator
);
91 iface
= iface_create(name
, this->mconsole
);
94 this->ifaces
->insert_last(this->ifaces
, iface
);
100 * Implementation of guest_t.create_iface_iterator.
102 static iterator_t
* create_iface_iterator(private_guest_t
*this)
104 return this->ifaces
->create_iterator(this->ifaces
, TRUE
);
108 * write format string to a buffer, and advance buffer position
110 static char* write_arg(char **pos
, size_t *left
, char *format
, ...)
116 va_start(args
, format
);
117 len
= vsnprintf(*pos
, *left
, format
, args
);
130 * Implementation of guest_t.start.
132 static bool start(private_guest_t
*this)
139 size_t left
= sizeof(buf
);
141 args
[i
++] = this->kernel
;
142 args
[i
++] = write_arg(&pos
, &left
, "root=/dev/root");
143 args
[i
++] = write_arg(&pos
, &left
, "rootfstype=hostfs");
144 args
[i
++] = write_arg(&pos
, &left
, "rootflags=%s/%s/%s",
145 getcwd(cwd
, sizeof(cwd
)), MOUNT_DIR
, this->name
);
146 args
[i
++] = write_arg(&pos
, &left
, "uml_dir=%s/%s", RUN_DIR
, this->name
);
147 args
[i
++] = write_arg(&pos
, &left
, "umid=%s", this->name
);
148 args
[i
++] = write_arg(&pos
, &left
, "mem=%dM", this->mem
);
149 /*args[i++] = write_arg(&pos, &left, "con=pts");*/
150 args
[i
++] = write_arg(&pos
, &left
, "con0=null,fd:%d", this->bootlog
);
151 args
[i
++] = write_arg(&pos
, &left
, "con1=fd:0,fd:1");
152 args
[i
++] = write_arg(&pos
, &left
, "con3=null,null");
153 args
[i
++] = write_arg(&pos
, &left
, "con4=null,null");
154 args
[i
++] = write_arg(&pos
, &left
, "con5=null,null");
155 args
[i
++] = write_arg(&pos
, &left
, "con6=null,null");
162 dup2(open("/dev/null", 0), 0);
163 dup2(open("/dev/null", 0), 1);
164 dup2(open("/dev/null", 0), 2);
165 execvp(args
[0], args
);
166 DBG1("starting UML kernel '%s' failed", args
[0]);
175 snprintf(buf
, sizeof(buf
), "%s/%s/%s/mconsole", RUN_DIR
, this->name
, this->name
);
176 this->mconsole
= mconsole_create(buf
);
177 if (this->mconsole
== NULL
)
179 DBG1("opening mconsole at '%s' failed, stopping guest", buf
);
180 kill(this->pid
, SIGINT
);
188 * Implementation of guest_t.stop.
190 static void stop(private_guest_t
*this)
194 kill(this->pid
, SIGINT
);
200 * Check if directory exists, create otherwise
202 static bool makedir(char *dir
, char *name
)
208 len
= snprintf(buf
, sizeof(buf
), "%s/%s", dir
, name
);
209 if (len
< 0 || len
>= sizeof(buf
))
213 if (stat(buf
, &st
) != 0)
215 return mkdir(buf
, S_IRWXU
) == 0;
217 return S_ISDIR(st
.st_mode
);
221 * umount the union filesystem
223 static bool umount_unionfs(char *name
)
228 len
= snprintf(cmd
, sizeof(cmd
), "fusermount -u %s/%s", MOUNT_DIR
, name
);
229 if (len
< 0 || len
>= sizeof(cmd
))
233 if (system(cmd
) != 0)
235 DBG1("unmounting guest unionfs for %s failed", name
);
242 * mount the union filesystem
244 static bool mount_unionfs(char *name
, char *master
)
249 len
= snprintf(cmd
, sizeof(cmd
), "unionfs %s/%s:%s %s/%s",
250 HOST_DIR
, name
, master
, MOUNT_DIR
, name
);
251 if (len
< 0 || len
>= sizeof(cmd
))
255 if (system(cmd
) != 0)
257 DBG1("mounting guest unionfs for %s using '%s' failed", name
, cmd
);
264 * open logfile for boot messages
266 static int open_bootlog(char *name
)
272 len
= snprintf(blg
, sizeof(blg
), "%s/%s/boot.log", RUN_DIR
, name
);
273 if (len
< 0 || len
>= sizeof(blg
))
277 fd
= open(blg
, O_WRONLY
| O_CREAT
, S_IRUSR
| S_IWUSR
);
280 DBG1("opening bootlog '%s' for %s failed, using stdout", blg
, name
);
287 * Implementation of guest_t.destroy.
289 static void destroy(private_guest_t
*this)
292 umount_unionfs(this->name
);
293 this->ifaces
->destroy_offset(this->ifaces
, offsetof(iface_t
, destroy
));
294 DESTROY_IF(this->mconsole
);
302 * create the guest instance, including required dirs and mounts
304 guest_t
*guest_create(char *name
, char *kernel
, char *master
, int mem
)
306 private_guest_t
*this = malloc_thing(private_guest_t
);
308 this->public.get_name
= (void*)get_name
;
309 this->public.create_iface
= (iface_t
*(*)(guest_t
*,char*))create_iface
;
310 this->public.create_iface_iterator
= (iterator_t
*(*)(guest_t
*))create_iface_iterator
;
311 this->public.start
= (void*)start
;
312 this->public.stop
= (void*)stop
;
313 this->public.destroy
= (void*)destroy
;
315 if (!makedir(HOST_DIR
, name
) || !makedir(MOUNT_DIR
, name
) ||
316 !makedir(RUN_DIR
, name
) || !mount_unionfs(name
, master
))
322 this->name
= strdup(name
);
323 this->kernel
= strdup(kernel
);
324 this->master
= strdup(master
);
327 this->bootlog
= open_bootlog(name
);
328 this->mconsole
= NULL
;
329 this->ifaces
= linked_list_create();
331 return &this->public;