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
, (int)reply
.len
, reply
.data
);
165 * ignore error message
167 static void ignore(void *data
, char *buf
, size_t len
)
171 METHOD(mconsole_t
, add_iface
, bool,
172 private_mconsole_t
*this, char *guest
, char *host
)
178 if (request(this, ignore
, NULL
, "config %s=tuntap,%s", guest
, host
) == 0)
182 usleep(10000 * tries
* tries
);
187 METHOD(mconsole_t
, del_iface
, bool,
188 private_mconsole_t
*this, char *guest
)
190 if (request(this, NULL
, NULL
, "remove %s", guest
) != 0)
197 METHOD(mconsole_t
, exec
, int,
198 private_mconsole_t
*this, void(*cb
)(void*,char*,size_t), void *data
,
201 return request(this, cb
, data
, "%s", cmd
);
205 * Poll until guest is ready
207 static void wait_bootup(private_mconsole_t
*this)
209 /* wait for init process to appear */
210 while (request(this, ignore
, NULL
, "exec ps -p 1 > /dev/null"))
220 METHOD(mconsole_t
, destroy
, void,
221 private_mconsole_t
*this)
223 close(this->console
);
229 * setup the mconsole notify connection and wait for its readiness
231 static bool wait_for_notify(private_mconsole_t
*this, char *nsock
)
233 struct sockaddr_un addr
;
234 mconsole_notify notify
;
237 this->notify
= socket(AF_UNIX
, SOCK_DGRAM
, 0);
238 if (this->notify
< 0)
240 DBG1(DBG_LIB
, "opening mconsole notify socket failed: %m");
243 memset(&addr
, 0, sizeof(addr
));
244 addr
.sun_family
= AF_UNIX
;
245 strncpy(addr
.sun_path
, nsock
, sizeof(addr
.sun_path
));
246 if (bind(this->notify
, (struct sockaddr
*)&addr
, sizeof(addr
)) < 0)
248 DBG1(DBG_LIB
, "binding mconsole notify socket to '%s' failed: %m",
255 flags
= MSG_DONTWAIT
;
263 len
= recvfrom(this->notify
, ¬ify
, sizeof(notify
), flags
, NULL
, 0);
265 while (len
< 0 && (errno
== EINTR
|| errno
== EAGAIN
));
267 if (len
< 0 || len
>= sizeof(notify
))
269 DBG1(DBG_LIB
, "reading from mconsole notify socket failed: %m");
274 if (notify
.magic
!= MCONSOLE_MAGIC
||
275 notify
.version
!= MCONSOLE_VERSION
||
276 notify
.type
!= MCONSOLE_SOCKET
)
278 DBG1(DBG_LIB
, "received unexpected message from mconsole notify"
279 " socket: %b", ¬ify
, sizeof(notify
));
284 memset(&this->uml
, 0, sizeof(this->uml
));
285 this->uml
.sun_family
= AF_UNIX
;
286 strncpy(this->uml
.sun_path
, (char*)¬ify
.data
, sizeof(this->uml
.sun_path
));
291 * setup the mconsole console connection
293 static bool setup_console(private_mconsole_t
*this)
295 struct sockaddr_un addr
;
297 this->console
= socket(AF_UNIX
, SOCK_DGRAM
, 0);
298 if (this->console
< 0)
300 DBG1(DBG_LIB
, "opening mconsole socket failed: %m");
303 memset(&addr
, 0, sizeof(addr
));
304 addr
.sun_family
= AF_UNIX
;
305 snprintf(&addr
.sun_path
[1], sizeof(addr
.sun_path
)-1, "%5d-%d",
306 getpid(), this->console
);
307 if (bind(this->console
, (struct sockaddr
*)&addr
, sizeof(addr
)) < 0)
309 DBG1(DBG_LIB
, "binding mconsole socket to '%s' failed: %m",
311 close(this->console
);
318 * create the mconsole instance
320 mconsole_t
*mconsole_create(char *notify
, void(*idle
)(void))
322 private_mconsole_t
*this;
326 .add_iface
= _add_iface
,
327 .del_iface
= _del_iface
,
334 if (!wait_for_notify(this, notify
))
340 if (!setup_console(this))
351 return &this->public;