#include <fcntl.h>
#include <signal.h>
#include <dirent.h>
+#include <termios.h>
#include <debug.h>
#include <utils/linked_list.h>
#define KERNEL_FILE "linux"
#define LOG_FILE "boot.log"
#define NOTIFY_FILE "notify"
+#define PTYS 0
typedef struct private_guest_t private_guest_t;
cowfs_t *cowfs;
/** mconsole to control running UML */
mconsole_t *mconsole;
+ /** pty consoles */
+ struct {
+ /** pty master fd */
+ int master;
+ /** pty slave fd */
+ int slave;
+ /** name of the pty */
+ char name[16];
+ /** currently in use */
+ bool occupied;
+ /** is valid */
+ bool valid;
+ } pty[PTYS];
/** list of interfaces attached to the guest */
linked_list_t *ifaces;
};
}
/**
+ * Implementation of get_t.close_console.
+ */
+static char* get_console(private_guest_t *this, int console)
+{
+ if (this->state == GUEST_RUNNING)
+ {
+ return this->mconsole->get_console_pts(this->mconsole, console);
+ }
+ return NULL;
+}
+
+/**
* Implementation of guest_t.stop.
*/
static void stop(private_guest_t *this)
args[i++] = write_arg(&pos, &left, "umid=%s", this->name);
args[i++] = write_arg(&pos, &left, "mem=%dM", this->mem);
args[i++] = write_arg(&pos, &left, "mconsole=notify:%s", notify);
- /*args[i++] = write_arg(&pos, &left, "con=pts");*/
- args[i++] = write_arg(&pos, &left, "con0=null,fd:%d", this->bootlog);
- //args[i++] = write_arg(&pos, &left, "con0=fd:0,fd:1");
- //args[i++] = write_arg(&pos, &left, "con1=null,null");
- args[i++] = write_arg(&pos, &left, "con2=null,null");
- args[i++] = write_arg(&pos, &left, "con3=null,null");
- args[i++] = write_arg(&pos, &left, "con4=null,null");
- args[i++] = write_arg(&pos, &left, "con5=null,null");
- args[i++] = write_arg(&pos, &left, "con6=null,null");
+ args[i++] = write_arg(&pos, &left, "con=pts");
+ args[i++] = write_arg(&pos, &left, "con0=none,fd:%d", this->bootlog);
args[i++] = NULL;
this->pid = fork();
stop(this);
return FALSE;
}
+
this->state = GUEST_RUNNING;
return TRUE;
}
*/
static void sigchild(private_guest_t *this)
{
+ int i;
+
if (this->state != GUEST_STOPPING)
{ /* collect zombie if uml crashed */
waitpid(this->pid, NULL, WNOHANG);
}
DESTROY_IF(this->mconsole);
this->mconsole = NULL;
+ for (i = 0; i < PTYS; i++)
+ {
+ if (this->pty[i].valid)
+ {
+ close(this->pty[i].master);
+ close(this->pty[i].slave);
+ }
+ }
this->state = GUEST_STOPPED;
}
this->public.create_iface_iterator = (iterator_t*(*)(guest_t*))create_iface_iterator;
this->public.start = (void*)start;
this->public.stop = (void*)stop;
+ this->public.get_console = (char*(*)(guest_t*,int))get_console;
this->public.set_scenario = (bool(*)(guest_t*, char *path))set_scenario;
this->public.sigchild = (void(*)(guest_t*))sigchild;
this->public.destroy = (void*)destroy;
-
+
if (*parent == '/' || getcwd(cwd, sizeof(cwd)) == NULL)
{
asprintf(&this->dirname, "%s/%s", parent, name);
bool (*stop) (guest_t *this);
/**
+ * @brief Get a console pts device.
+ *
+ * Every guest has 6 consoles, numbered from 1 to 6. These are associated
+ * to a unique pts device on the host.
+ *
+ * @param console console number to get (1-6)
+ * @return pts device file name, NULL if failed
+ */
+ char* (*get_console) (guest_t *this, int console);
+
+ /**
* @brief Create a new interface in the current scenario.
*
* @param name name of the interface in the guest
line = readline(prompt);
if (line == NULL)
{
- continue;
+ printf("quit\n");
+ dumm->destroy(dumm);
+ clear_history();
+ exit(0);
}
if (*line == '\0')
{
free(name);
}
+static void guest_console(guest_t *guest)
+{
+ int con;
+
+ for (con = 1; con <= 6; con++)
+ {
+ char *pts = guest->get_console(guest, con);
+ if (pts)
+ {
+ printf("%d: %s\n", con, pts);
+ free(pts);
+ }
+ }
+}
+
static void guest_menu(guest_t *guest)
{
while (TRUE)
{
if (guest->start(guest))
{
- printf("guest '%s' is booting\n", guest->get_name(guest));
+ printf("guest '%s' is running\n", guest->get_name(guest));
}
else
{
{
guest_delif_menu(guest);
}
+ else if (streq(line, "console"))
+ {
+ guest_console(guest);
+ }
else
{
- printf("back|start|stop|addif|delif\n");
+ printf("back|start|stop|addif|delif|console\n");
}
free(line);
}
* for more details.
*/
+#define _GNU_SOURCE
+
#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>
/**
* send a request to UML using mconsole
*/
-static bool request(private_mconsole_t *this, char *command)
+static int request(private_mconsole_t *this, char *command,
+ char buf[], size_t *size)
{
mconsole_request request;
mconsole_reply reply;
- bool first = TRUE, good = TRUE;
- int len;
+ int len, total = 0;
memset(&request, 0, sizeof(request));
request.magic = MCONSOLE_MAGIC;
request.version = MCONSOLE_VERSION;
request.len = min(strlen(command), sizeof(reply.data) - 1);
strncpy(request.data, command, request.len);
+ *buf = '\0';
+ (*size)--;
if (sendto(this->console, &request, sizeof(request), 0,
(struct sockaddr*)&this->uml, sizeof(this->uml)) < 0)
{
- DBG1("sending mconsole command to UML failed: %m");
- return FALSE;
+ snprintf(buf, *size, "sending mconsole command to UML failed: %m");
+ return -1;
}
do
{
- len = recvfrom(this->console, &reply, sizeof(reply), 0, NULL, 0);
+ len = recv(this->console, &reply, sizeof(reply), 0);
if (len < 0)
{
- DBG1("receiving from mconsole failed: %m");
- return FALSE;
+ snprintf(buf, *size, "receiving from mconsole failed: %m");
+ return -1;
}
- if (first && reply.err)
+ if (len > 0)
{
- good = FALSE;
- DBG1("received error from UML mconsole: %s", reply.data);
+ strncat(buf, reply.data, min(reply.len, *size - total));
+ total += reply.len;
}
- first = FALSE;
}
while (reply.more);
- return good;
+
+ *size = total;
+ return reply.err;
}
/**
{
return FALSE;
}
- return request(this, buf);
+ len = sizeof(buf);
+ if (request(this, buf, buf, &len) != 0)
+ {
+ DBG1("adding interface failed: %.*s", len, buf);
+ return FALSE;
+ }
+ return TRUE;
}
/**
{
return FALSE;
}
- return request(this, buf);
+ if (request(this, buf, buf, &len) != 0)
+ {
+ DBG1("removing interface failed: %.*s", len, buf);
+ return FALSE;
+ }
+ return TRUE;
+}
+
+/**
+ * Implementation of mconsole_t.get_console_pts.
+ */
+static char* get_console_pts(private_mconsole_t *this, int con)
+{
+ char buf[128];
+ char *pos;
+ int len;
+
+ len = snprintf(buf, sizeof(buf), "config con%d", con);
+ if (len < 0 || len >= sizeof(buf))
+ {
+ return NULL;
+ }
+ len = sizeof(buf);
+ if (request(this, buf, buf, &len) != 0)
+ {
+ DBG1("getting console pts failed: %.*s", len, buf);
+ return NULL;
+ }
+ pos = memchr(buf, ':', len);
+ if (pos == NULL)
+ {
+ return NULL;
+ }
+ pos++;
+ return strndup(pos, len - (pos - buf));
}
/**
this->public.add_iface = (bool(*)(mconsole_t*, char *guest, char *host))add_iface;
this->public.del_iface = (bool(*)(mconsole_t*, char *guest))del_iface;
+ this->public.get_console_pts = (char*(*)(mconsole_t*, int con))get_console_pts;
this->public.destroy = (void*)destroy;
if (!wait_for_notify(this, notify))
bool (*del_iface)(mconsole_t *this, char *guest);
/**
+ * @brief Get the pts device file assigned to a console.
+ *
+ * @param con console number in guest
+ * @return allocated device string
+ */
+ char* (*get_console_pts)(mconsole_t *this, int con);
+
+ /**
* @brief Destroy the mconsole instance
*/
void (*destroy) (mconsole_t *this);