2 * Copyright (C) 2007 Martin Willi
3 * Hochschule fuer Technik Rapperswil
4 * Copyright (C) 2001-2004 Jeff Dike
6 * Based on the "uml_mconsole" utility from Jeff Dike.
8 * This program is free software; you can redistribute it and/or modify it
9 * under the terms of the GNU General Public License as published by the
10 * Free Software Foundation; either version 2 of the License, or (at your
11 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
13 * This program is distributed in the hope that it will be useful, but
14 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
15 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
21 #include <sys/types.h>
24 #include <sys/socket.h>
32 #define MCONSOLE_MAGIC 0xcafebabe
33 #define MCONSOLE_VERSION 2
34 #define MCONSOLE_MAX_DATA 512
36 typedef struct private_mconsole_t private_mconsole_t
;
38 struct private_mconsole_t
{
39 /** public interface */
41 /** mconsole socket */
45 /** address of uml socket */
46 struct sockaddr_un uml
;
52 * mconsole message format from "arch/um/include/mconsole.h"
54 typedef struct mconsole_request mconsole_request
;
55 /** mconsole request message */
56 struct mconsole_request
{
60 char data
[MCONSOLE_MAX_DATA
];
64 typedef struct mconsole_reply mconsole_reply
;
65 /** mconsole reply message */
66 struct mconsole_reply
{
70 char data
[MCONSOLE_MAX_DATA
];
73 typedef struct mconsole_notify mconsole_notify
;
74 /** mconsole notify message */
75 struct mconsole_notify
{
85 char data
[MCONSOLE_MAX_DATA
];
89 * send a request to UML using mconsole
91 static int request(private_mconsole_t
*this, void(*cb
)(void*,char*,size_t),
92 void *data
, char *command
, ...)
94 mconsole_request request
;
99 memset(&request
, 0, sizeof(request
));
100 request
.magic
= MCONSOLE_MAGIC
;
101 request
.version
= MCONSOLE_VERSION
;
102 va_start(args
, command
);
103 request
.len
= vsnprintf(request
.data
, sizeof(request
.data
), command
, args
);
108 flags
= MSG_DONTWAIT
;
116 len
= sendto(this->console
, &request
, sizeof(request
), flags
,
117 (struct sockaddr
*)&this->uml
, sizeof(this->uml
));
119 while (len
< 0 && (errno
== EINTR
|| errno
== EAGAIN
));
123 DBG1(DBG_LIB
, "sending mconsole command to UML failed: %m");
128 len
= recv(this->console
, &reply
, sizeof(reply
), flags
);
129 if (len
< 0 && (errno
== EINTR
|| errno
== EAGAIN
))
139 DBG1(DBG_LIB
, "receiving from mconsole failed: %m");
146 cb(data
, reply
.data
, reply
.len
);
150 if (reply
.len
&& *reply
.data
)
152 DBG1(DBG_LIB
, "received mconsole error %d: %.*s",
153 reply
.err
, reply
.len
, reply
.data
);
165 * ignore error message
167 static void ignore(void *data
, char *buf
, size_t len
)
172 * Implementation of mconsole_t.add_iface.
174 static bool add_iface(private_mconsole_t
*this, char *guest
, char *host
)
180 if (request(this, ignore
, NULL
, "config %s=tuntap,%s", guest
, host
) == 0)
184 usleep(10000 * tries
* tries
);
190 * Implementation of mconsole_t.del_iface.
192 static bool del_iface(private_mconsole_t
*this, char *guest
)
194 if (request(this, NULL
, NULL
, "remove %s", guest
) != 0)
202 * Implementation of mconsole_t.exec
204 static int exec(private_mconsole_t
*this, void(*cb
)(void*,char*,size_t),
205 void *data
, char *cmd
)
207 return request(this, cb
, data
, "%s", cmd
);
211 * Poll until guest is ready
213 static void wait_bootup(private_mconsole_t
*this)
215 /* wait for init process to appear */
216 while (request(this, ignore
, NULL
, "exec ps -p 1 > /dev/null"))
227 * Implementation of mconsole_t.destroy.
229 static void destroy(private_mconsole_t
*this)
231 close(this->console
);
237 * setup the mconsole notify connection and wait for its readiness
239 static bool wait_for_notify(private_mconsole_t
*this, char *nsock
)
241 struct sockaddr_un addr
;
242 mconsole_notify notify
;
245 this->notify
= socket(AF_UNIX
, SOCK_DGRAM
, 0);
246 if (this->notify
< 0)
248 DBG1(DBG_LIB
, "opening mconsole notify socket failed: %m");
251 memset(&addr
, 0, sizeof(addr
));
252 addr
.sun_family
= AF_UNIX
;
253 strncpy(addr
.sun_path
, nsock
, sizeof(addr
.sun_path
));
254 if (bind(this->notify
, (struct sockaddr
*)&addr
, sizeof(addr
)) < 0)
256 DBG1(DBG_LIB
, "binding mconsole notify socket to '%s' failed: %m",
263 flags
= MSG_DONTWAIT
;
271 len
= recvfrom(this->notify
, ¬ify
, sizeof(notify
), flags
, NULL
, 0);
273 while (len
< 0 && (errno
== EINTR
|| errno
== EAGAIN
));
275 if (len
< 0 || len
>= sizeof(notify
))
277 DBG1(DBG_LIB
, "reading from mconsole notify socket failed: %m");
282 if (notify
.magic
!= MCONSOLE_MAGIC
||
283 notify
.version
!= MCONSOLE_VERSION
||
284 notify
.type
!= MCONSOLE_SOCKET
)
286 DBG1(DBG_LIB
, "received unexpected message from mconsole notify"
287 " socket: %b", ¬ify
, sizeof(notify
));
292 memset(&this->uml
, 0, sizeof(this->uml
));
293 this->uml
.sun_family
= AF_UNIX
;
294 strncpy(this->uml
.sun_path
, (char*)¬ify
.data
, sizeof(this->uml
.sun_path
));
299 * setup the mconsole console connection
301 static bool setup_console(private_mconsole_t
*this)
303 struct sockaddr_un addr
;
305 this->console
= socket(AF_UNIX
, SOCK_DGRAM
, 0);
306 if (this->console
< 0)
308 DBG1(DBG_LIB
, "opening mconsole socket failed: %m");
311 memset(&addr
, 0, sizeof(addr
));
312 addr
.sun_family
= AF_UNIX
;
313 snprintf(&addr
.sun_path
[1], sizeof(addr
.sun_path
)-1, "%5d-%d",
314 getpid(), this->console
);
315 if (bind(this->console
, (struct sockaddr
*)&addr
, sizeof(addr
)) < 0)
317 DBG1(DBG_LIB
, "binding mconsole socket to '%s' failed: %m",
319 close(this->console
);
326 * create the mconsole instance
328 mconsole_t
*mconsole_create(char *notify
, void(*idle
)(void))
330 private_mconsole_t
*this = malloc_thing(private_mconsole_t
);
332 this->public.add_iface
= (bool(*)(mconsole_t
*, char *guest
, char *host
))add_iface
;
333 this->public.del_iface
= (bool(*)(mconsole_t
*, char *guest
))del_iface
;
334 this->public.exec
= (int(*)(mconsole_t
*, void(*cb
)(void*,char*,size_t), void *data
, char *cmd
))exec
;
335 this->public.destroy
= (void*)destroy
;
339 if (!wait_for_notify(this, notify
))
345 if (!setup_console(this))
356 return &this->public;