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, char *command
,
92 char buf
[], size_t *size
)
94 mconsole_request request
;
96 int len
, total
= 0, flags
= 0;
98 memset(&request
, 0, sizeof(request
));
99 request
.magic
= MCONSOLE_MAGIC
;
100 request
.version
= MCONSOLE_VERSION
;
101 request
.len
= min(strlen(command
), sizeof(reply
.data
) - 1);
102 strncpy(request
.data
, command
, request
.len
);
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 snprintf(buf
, *size
, "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 snprintf(buf
, *size
, "receiving from mconsole failed: %m");
144 strncat(buf
, reply
.data
, min(reply
.len
, *size
- total
));
155 * Implementation of mconsole_t.add_iface.
157 static bool add_iface(private_mconsole_t
*this, char *guest
, char *host
)
159 char in
[128], out
[128];
162 len
= snprintf(in
, sizeof(in
), "config %s=tuntap,%s", guest
, host
);
163 if (len
< 0 || len
>= sizeof(in
))
170 if (request(this, in
, out
, &len
) == 0)
174 usleep(10000 * tries
);
176 DBG1("adding interface failed: %.*s", len
, out
);
181 * Implementation of mconsole_t.del_iface.
183 static bool del_iface(private_mconsole_t
*this, char *guest
)
188 len
= snprintf(buf
, sizeof(buf
), "remove %s", guest
);
189 if (len
< 0 || len
>= sizeof(buf
))
193 if (request(this, buf
, buf
, &len
) != 0)
201 * Poll until guest is ready
203 static bool wait_bootup(private_mconsole_t
*this)
211 res
= request(this, "config eth9=mcast", buf
, &len
);
218 while (request(this, "remove eth9", buf
, &len
) != 0)
236 * Implementation of mconsole_t.destroy.
238 static void destroy(private_mconsole_t
*this)
240 close(this->console
);
246 * setup the mconsole notify connection and wait for its readyness
248 static bool wait_for_notify(private_mconsole_t
*this, char *nsock
)
250 struct sockaddr_un addr
;
251 mconsole_notify notify
;
254 this->notify
= socket(AF_UNIX
, SOCK_DGRAM
, 0);
255 if (this->notify
< 0)
257 DBG1("opening mconsole notify socket failed: %m");
260 memset(&addr
, 0, sizeof(addr
));
261 addr
.sun_family
= AF_UNIX
;
262 strncpy(addr
.sun_path
, nsock
, sizeof(addr
));
263 if (bind(this->notify
, (struct sockaddr
*)&addr
, sizeof(addr
)) < 0)
265 DBG1("binding mconsole notify socket to '%s' failed: %m", nsock
);
271 flags
= MSG_DONTWAIT
;
279 len
= recvfrom(this->notify
, ¬ify
, sizeof(notify
), flags
, NULL
, 0);
281 while (len
< 0 && (errno
== EINTR
|| errno
== EAGAIN
));
283 if (len
< 0 || len
>= sizeof(notify
))
285 DBG1("reading from mconsole notify socket failed: %m");
290 if (notify
.magic
!= MCONSOLE_MAGIC
||
291 notify
.version
!= MCONSOLE_VERSION
||
292 notify
.type
!= MCONSOLE_SOCKET
)
294 DBG1("received unexpected message from mconsole notify socket: %b",
295 ¬ify
, sizeof(notify
));
300 memset(&this->uml
, 0, sizeof(this->uml
));
301 this->uml
.sun_family
= AF_UNIX
;
302 strncpy(this->uml
.sun_path
, (char*)¬ify
.data
, sizeof(this->uml
.sun_path
));
307 * setup the mconsole console connection
309 static bool setup_console(private_mconsole_t
*this)
311 struct sockaddr_un addr
;
313 this->console
= socket(AF_UNIX
, SOCK_DGRAM
, 0);
314 if (this->console
< 0)
316 DBG1("opening mconsole socket failed: %m");
319 memset(&addr
, 0, sizeof(addr
));
320 addr
.sun_family
= AF_UNIX
;
321 snprintf(&addr
.sun_path
[1], sizeof(addr
.sun_path
), "%5d-%d",
322 getpid(), this->console
);
323 if (bind(this->console
, (struct sockaddr
*)&addr
, sizeof(addr
)) < 0)
325 DBG1("binding mconsole socket to '%s' failed: %m", &addr
.sun_path
[1]);
326 close(this->console
);
333 * create the mconsole instance
335 mconsole_t
*mconsole_create(char *notify
, void(*idle
)(void))
337 private_mconsole_t
*this = malloc_thing(private_mconsole_t
);
339 this->public.add_iface
= (bool(*)(mconsole_t
*, char *guest
, char *host
))add_iface
;
340 this->public.del_iface
= (bool(*)(mconsole_t
*, char *guest
))del_iface
;
341 this->public.destroy
= (void*)destroy
;
345 if (!wait_for_notify(this, notify
))
351 if (!setup_console(this))
360 if (!wait_bootup(this))
366 return &this->public;