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
)
162 len
= snprintf(buf
, sizeof(buf
), "config %s=tuntap,%s", guest
, host
);
163 if (len
< 0 || len
>= sizeof(buf
))
168 if (request(this, buf
, buf
, &len
) != 0)
170 DBG1("adding interface failed: %.*s", len
, buf
);
177 * Implementation of mconsole_t.del_iface.
179 static bool del_iface(private_mconsole_t
*this, char *guest
)
184 len
= snprintf(buf
, sizeof(buf
), "remove %s", guest
);
185 if (len
< 0 || len
>= sizeof(buf
))
189 if (request(this, buf
, buf
, &len
) != 0)
191 DBG1("removing interface failed: %.*s", len
, buf
);
198 * Poll until guest is ready
200 static bool wait_bootup(private_mconsole_t
*this)
209 res
= request(this, cmd
, buf
, &len
);
230 * Implementation of mconsole_t.destroy.
232 static void destroy(private_mconsole_t
*this)
234 close(this->console
);
240 * setup the mconsole notify connection and wait for its readyness
242 static bool wait_for_notify(private_mconsole_t
*this, char *nsock
)
244 struct sockaddr_un addr
;
245 mconsole_notify notify
;
248 this->notify
= socket(AF_UNIX
, SOCK_DGRAM
, 0);
249 if (this->notify
< 0)
251 DBG1("opening mconsole notify socket failed: %m");
254 memset(&addr
, 0, sizeof(addr
));
255 addr
.sun_family
= AF_UNIX
;
256 strncpy(addr
.sun_path
, nsock
, sizeof(addr
));
257 if (bind(this->notify
, (struct sockaddr
*)&addr
, sizeof(addr
)) < 0)
259 DBG1("binding mconsole notify socket to '%s' failed: %m", nsock
);
265 flags
= MSG_DONTWAIT
;
273 len
= recvfrom(this->notify
, ¬ify
, sizeof(notify
), flags
, NULL
, 0);
275 while (len
< 0 && (errno
== EINTR
|| errno
== EAGAIN
));
277 if (len
< 0 || len
>= sizeof(notify
))
279 DBG1("reading from mconsole notify socket failed: %m");
284 if (notify
.magic
!= MCONSOLE_MAGIC
||
285 notify
.version
!= MCONSOLE_VERSION
||
286 notify
.type
!= MCONSOLE_SOCKET
)
288 DBG1("received unexpected message from mconsole notify socket: %b",
289 ¬ify
, sizeof(notify
));
294 memset(&this->uml
, 0, sizeof(this->uml
));
295 this->uml
.sun_family
= AF_UNIX
;
296 strncpy(this->uml
.sun_path
, (char*)¬ify
.data
, sizeof(this->uml
.sun_path
));
301 * setup the mconsole console connection
303 static bool setup_console(private_mconsole_t
*this)
305 struct sockaddr_un addr
;
307 this->console
= socket(AF_UNIX
, SOCK_DGRAM
, 0);
308 if (this->console
< 0)
310 DBG1("opening mconsole socket failed: %m");
313 memset(&addr
, 0, sizeof(addr
));
314 addr
.sun_family
= AF_UNIX
;
315 snprintf(&addr
.sun_path
[1], sizeof(addr
.sun_path
), "%5d-%d",
316 getpid(), this->console
);
317 if (bind(this->console
, (struct sockaddr
*)&addr
, sizeof(addr
)) < 0)
319 DBG1("binding mconsole socket to '%s' failed: %m", &addr
.sun_path
[1]);
320 close(this->console
);
327 * create the mconsole instance
329 mconsole_t
*mconsole_create(char *notify
, void(*idle
)(void))
331 private_mconsole_t
*this = malloc_thing(private_mconsole_t
);
333 this->public.add_iface
= (bool(*)(mconsole_t
*, char *guest
, char *host
))add_iface
;
334 this->public.del_iface
= (bool(*)(mconsole_t
*, char *guest
))del_iface
;
335 this->public.destroy
= (void*)destroy
;
339 if (!wait_for_notify(this, notify
))
345 if (!setup_console(this))
354 if (!wait_bootup(this))
360 return &this->public;