checked in first draft of "Dynamic Uml Mesh Modeler"
[strongswan.git] / src / dumm / guest.c
1 #define _GNU_SOURCE
2
3 #include <sys/types.h>
4 #include <sys/stat.h>
5 #include <unistd.h>
6 #include <stdio.h>
7 #include <sys/uio.h>
8 #include <sys/types.h>
9 #include <fcntl.h>
10 #include <signal.h>
11
12 #include <debug.h>
13
14 #include "dumm.h"
15 #include "guest.h"
16
17 typedef struct private_guest_t private_guest_t;
18
19 struct private_guest_t {
20 guest_t public;
21 char *name;
22 char *kernel;
23 char *master;
24 int mem;
25 int pid;
26 int bootlog;
27 };
28
29 static char* get_name(private_guest_t *this)
30 {
31 return this->name;
32 }
33
34 static char* write_arg(char **pos, size_t *left, char *format, ...)
35 {
36 size_t len;
37 char *res = NULL;
38 va_list args;
39
40 va_start(args, format);
41 len = vsnprintf(*pos, *left, format, args);
42 va_end(args);
43 if (len < *left)
44 {
45 res = *pos;
46 len++;
47 *pos += len + 1;
48 *left -= len + 1;
49 }
50 return res;
51 }
52
53 static bool start(private_guest_t *this)
54 {
55 char buf[1024];
56 char cwd[512];
57 char *pos = buf;
58 char *args[16];
59 int i = 0;
60 size_t left = sizeof(buf);
61
62 args[i++] = this->kernel;
63 args[i++] = write_arg(&pos, &left, "root=/dev/root");
64 args[i++] = write_arg(&pos, &left, "rootfstype=hostfs");
65 args[i++] = write_arg(&pos, &left, "rootflags=%s/%s/%s",
66 getcwd(cwd, sizeof(cwd)), MOUNT_DIR, this->name);
67 args[i++] = write_arg(&pos, &left, "uml_dir=%s/%s", RUN_DIR, this->name);
68 args[i++] = write_arg(&pos, &left, "umid=%s", this->name);
69 args[i++] = write_arg(&pos, &left, "mem=%dM", this->mem);
70 //args[i++] = write_arg(&pos, &left, "con=pts");
71 args[i++] = write_arg(&pos, &left, "con0=null,fd:%d", this->bootlog);
72 args[i++] = write_arg(&pos, &left, "con1=fd:0,fd:1");
73 args[i++] = write_arg(&pos, &left, "con3=null,null");
74 args[i++] = write_arg(&pos, &left, "con4=null,null");
75 args[i++] = write_arg(&pos, &left, "con5=null,null");
76 args[i++] = write_arg(&pos, &left, "con6=null,null");
77 args[i++] = NULL;
78
79 this->pid = fork();
80 switch (this->pid)
81 {
82 case 0: /* child, */
83 dup2(open("/dev/null", 0), 0);
84 dup2(open("/dev/null", 0), 1);
85 dup2(open("/dev/null", 0), 2);
86 execvp(args[0], args);
87 exit(1);
88 case -1:
89 this->pid = 0;
90 return FALSE;
91 default:
92 return TRUE;
93 }
94 }
95
96 static void stop(private_guest_t *this)
97 {
98 if (this->pid)
99 {
100 kill(this->pid, SIGINT);
101 this->pid = 0;
102 }
103 }
104
105 /**
106 * create a directory
107 */
108 static bool makedir(char *dir, char *name)
109 {
110 struct stat st;
111 char buf[256];
112 size_t len;
113
114 len = snprintf(buf, sizeof(buf), "%s/%s", dir, name);
115 if (len < 0 || len >= sizeof(buf))
116 {
117 return FALSE;
118 }
119 if (stat(buf, &st) != 0)
120 {
121 return mkdir(buf, S_IRWXU) == 0;
122 }
123 return S_ISDIR(st.st_mode);
124 }
125
126 /**
127 * umount the union filesystem
128 */
129 static bool umount_unionfs(char *name)
130 {
131 char cmd[128];
132 size_t len;
133
134 len = snprintf(cmd, sizeof(cmd), "fusermount -u %s/%s", MOUNT_DIR, name);
135 if (len < 0 || len >= sizeof(cmd))
136 {
137 return FALSE;
138 }
139 if (system(cmd) != 0)
140 {
141 return FALSE;
142 }
143 return TRUE;
144 }
145
146 /**
147 * mount the union filesystem
148 */
149 static bool mount_unionfs(char *name, char *master)
150 {
151 char cmd[256];
152 size_t len;
153
154 /* mount unionfs */
155 len = snprintf(cmd, sizeof(cmd), "unionfs %s/%s:%s %s/%s",
156 HOST_DIR, name, master, MOUNT_DIR, name);
157 if (len < 0 || len >= sizeof(cmd))
158 {
159 return FALSE;
160 }
161 if (system(cmd) != 0)
162 {
163 DBG1("mounting unionfs using '%s' failed.", cmd);
164 return FALSE;
165 }
166 return TRUE;
167 }
168
169 /**
170 * open logfile for boot messages
171 */
172 static int open_bootlog(char *name)
173 {
174 char blg[256];
175 size_t len;
176 int fd;
177
178 len = snprintf(blg, sizeof(blg), "%s/%s/boot.log", RUN_DIR, name);
179 if (len < 0 || len >= sizeof(blg))
180 {
181 return 1;
182 }
183 fd = open(blg, O_WRONLY | O_CREAT, S_IRUSR | S_IWUSR);
184 if (fd == -1)
185 {
186 return 1;
187 }
188 return fd;
189 }
190
191 /**
192 * stop guest, unmount mounts
193 */
194 static void destroy(private_guest_t *this)
195 {
196 stop(this);
197 umount_unionfs(this->name);
198 free(this->name);
199 free(this->kernel);
200 free(this->master);
201 free(this);
202 }
203
204 /**
205 * create the guest instance, including required dirs and mounts
206 */
207 guest_t *guest_create(char *name, char *kernel, char *master, int mem)
208 {
209 private_guest_t *this = malloc_thing(private_guest_t);
210
211 this->public.get_name = (void*)get_name;
212 this->public.start = (void*)start;
213 this->public.stop = (void*)stop;
214 this->public.destroy = (void*)destroy;
215
216 if (!makedir(HOST_DIR, name) || !makedir(MOUNT_DIR, name) ||
217 !makedir(RUN_DIR, name))
218 {
219 DBG1("creating guest directories for %s failed failed.", name);
220 free(this);
221 return NULL;
222 }
223
224 if (!mount_unionfs(name, master))
225 {
226 DBG1("mounting guest unionfs for %s failed.", name);
227 free(this);
228 return NULL;
229 }
230
231 this->name = strdup(name);
232 this->kernel = strdup(kernel);
233 this->master = strdup(master);
234 this->mem = mem;
235 this->pid = 0;
236 this->bootlog = open_bootlog(name);
237
238 return &this->public;
239 }
240