mirror of
https://github.com/clearlinux/kvmtool.git
synced 2026-06-16 02:15:47 +00:00
kvm tools: Introduce 'kvm setup' command
This patch implements 'kvm setup' command that can be used to setup a guest filesystem that shares system libraries and binaries from host filesystem in read-only mode. You can setup a new shared rootfs guest with: ./kvm setup -n default and launch it with: ./kvm run --9p /,hostfs -p "init=virt/init" -d ~/.kvm-tools/default/ We want to teach 'kvm run' to be able to launch guest filesystems by name in the future. Furthermore, 'kvm run' should setup a 'default' filesystem and use it by default unless the user specifies otherwise. Cc: Asias He <asias.hejun@gmail.com> Cc: Cyrill Gorcunov <gorcunov@gmail.com> Cc: Ingo Molnar <mingo@elte.hu> Cc: Sasha Levin <levinsasha928@gmail.com> Signed-off-by: Pekka Enberg <penberg@kernel.org>
This commit is contained in:
committed by
Will Deacon
parent
06f4810348
commit
282113fd51
@@ -6,4 +6,5 @@ tags
|
||||
include/common-cmds.h
|
||||
tests/boot/boot_test.iso
|
||||
tests/boot/rootfs/
|
||||
guest/init
|
||||
KVMTOOLS-VERSION-FILE
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
kvm-setup(1)
|
||||
================
|
||||
|
||||
NAME
|
||||
----
|
||||
kvm-setup - Setup a new virtual machine
|
||||
|
||||
SYNOPSIS
|
||||
--------
|
||||
[verse]
|
||||
'kvm setup <name>'
|
||||
|
||||
DESCRIPTION
|
||||
-----------
|
||||
The command setups a virtual machine.
|
||||
@@ -20,6 +20,8 @@ TAGS := ctags
|
||||
|
||||
PROGRAM := kvm
|
||||
|
||||
GUEST_INIT := guest/init
|
||||
|
||||
OBJS += builtin-balloon.o
|
||||
OBJS += builtin-debug.o
|
||||
OBJS += builtin-help.o
|
||||
@@ -28,6 +30,7 @@ OBJS += builtin-stat.o
|
||||
OBJS += builtin-pause.o
|
||||
OBJS += builtin-resume.o
|
||||
OBJS += builtin-run.o
|
||||
OBJS += builtin-setup.o
|
||||
OBJS += builtin-stop.o
|
||||
OBJS += builtin-version.o
|
||||
OBJS += cpuid.o
|
||||
@@ -159,7 +162,7 @@ WARNINGS += -Wunused-result
|
||||
|
||||
CFLAGS += $(WARNINGS)
|
||||
|
||||
all: $(PROGRAM)
|
||||
all: $(PROGRAM) $(GUEST_INIT)
|
||||
|
||||
KVMTOOLS-VERSION-FILE:
|
||||
@$(SHELL_PATH) util/KVMTOOLS-VERSION-GEN $(OUTPUT)
|
||||
@@ -169,6 +172,10 @@ $(PROGRAM): $(DEPS) $(OBJS)
|
||||
$(E) " LINK " $@
|
||||
$(Q) $(CC) $(OBJS) $(LIBS) -o $@
|
||||
|
||||
$(GUEST_INIT): guest/init.c
|
||||
$(E) " LINK " $@
|
||||
$(Q) $(CC) -static guest/init.c -o $@
|
||||
|
||||
$(DEPS):
|
||||
|
||||
%.d: %.c
|
||||
@@ -240,7 +247,7 @@ clean:
|
||||
$(Q) rm -f bios/bios-rom.h
|
||||
$(Q) rm -f tests/boot/boot_test.iso
|
||||
$(Q) rm -rf tests/boot/rootfs/
|
||||
$(Q) rm -f $(DEPS) $(OBJS) $(PROGRAM)
|
||||
$(Q) rm -f $(DEPS) $(OBJS) $(PROGRAM) $(GUEST_INIT)
|
||||
$(Q) rm -f cscope.*
|
||||
$(Q) rm -f $(KVM_INCLUDE)/common-cmds.h
|
||||
$(Q) rm -f KVMTOOLS-VERSION-FILE
|
||||
|
||||
+185
@@ -0,0 +1,185 @@
|
||||
#include <kvm/util.h>
|
||||
#include <kvm/kvm-cmd.h>
|
||||
#include <kvm/builtin-setup.h>
|
||||
#include <kvm/kvm.h>
|
||||
#include <kvm/parse-options.h>
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <limits.h>
|
||||
#include <signal.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <stdio.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/stat.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
#define KVM_PID_FILE_PATH "/.kvm-tools/"
|
||||
#define HOME_DIR getenv("HOME")
|
||||
|
||||
static const char *instance_name;
|
||||
|
||||
static const char * const setup_usage[] = {
|
||||
"kvm setup [-n name]",
|
||||
NULL
|
||||
};
|
||||
|
||||
static const struct option setup_options[] = {
|
||||
OPT_GROUP("General options:"),
|
||||
OPT_STRING('n', "name", &instance_name, "name", "Instance name"),
|
||||
OPT_END()
|
||||
};
|
||||
|
||||
static void parse_setup_options(int argc, const char **argv)
|
||||
{
|
||||
while (argc != 0) {
|
||||
argc = parse_options(argc, argv, setup_options, setup_usage,
|
||||
PARSE_OPT_STOP_AT_NON_OPTION);
|
||||
if (argc != 0)
|
||||
kvm_setup_help();
|
||||
}
|
||||
}
|
||||
|
||||
void kvm_setup_help(void)
|
||||
{
|
||||
usage_with_options(setup_usage, setup_options);
|
||||
}
|
||||
|
||||
static int copy_file(const char *from, const char *to)
|
||||
{
|
||||
int in_fd, out_fd;
|
||||
void *src, *dst;
|
||||
struct stat st;
|
||||
int err = -1;
|
||||
|
||||
in_fd = open(from, O_RDONLY);
|
||||
if (in_fd < 0)
|
||||
return err;
|
||||
|
||||
if (fstat(in_fd, &st) < 0)
|
||||
goto error_close_in;
|
||||
|
||||
out_fd = open(to, O_RDWR | O_CREAT | O_TRUNC, st.st_mode & (S_IRWXU|S_IRWXG|S_IRWXO));
|
||||
if (out_fd < 0)
|
||||
goto error_close_in;
|
||||
|
||||
src = mmap(NULL, st.st_size, PROT_READ, MAP_SHARED, in_fd, 0);
|
||||
if (src == MAP_FAILED)
|
||||
goto error_close_out;
|
||||
|
||||
if (ftruncate(out_fd, st.st_size) < 0)
|
||||
goto error_munmap_src;
|
||||
|
||||
dst = mmap(NULL, st.st_size, PROT_READ|PROT_WRITE, MAP_SHARED, out_fd, 0);
|
||||
if (dst == MAP_FAILED)
|
||||
goto error_munmap_src;
|
||||
|
||||
memcpy(dst, src, st.st_size);
|
||||
|
||||
if (fsync(out_fd) < 0)
|
||||
goto error_munmap_dst;
|
||||
|
||||
err = 0;
|
||||
|
||||
error_munmap_dst:
|
||||
munmap(dst, st.st_size);
|
||||
error_munmap_src:
|
||||
munmap(src, st.st_size);
|
||||
error_close_out:
|
||||
close(out_fd);
|
||||
error_close_in:
|
||||
close(in_fd);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static const char *guestfs_dirs[] = {
|
||||
"/dev",
|
||||
"/etc",
|
||||
"/home",
|
||||
"/host",
|
||||
"/proc",
|
||||
"/root",
|
||||
"/sys",
|
||||
"/var",
|
||||
"/var/lib",
|
||||
"/virt",
|
||||
};
|
||||
|
||||
static const char *guestfs_symlinks[] = {
|
||||
"/bin",
|
||||
"/lib",
|
||||
"/lib64",
|
||||
"/sbin",
|
||||
"/usr",
|
||||
};
|
||||
|
||||
static int copy_init(const char *guestfs_name)
|
||||
{
|
||||
char path[PATH_MAX];
|
||||
|
||||
snprintf(path, PATH_MAX, "%s%s%s/virt/init", HOME_DIR, KVM_PID_FILE_PATH, guestfs_name);
|
||||
|
||||
return copy_file("guest/init", path);
|
||||
}
|
||||
|
||||
static int make_guestfs_symlink(const char *guestfs_name, const char *path)
|
||||
{
|
||||
char target[PATH_MAX];
|
||||
char name[PATH_MAX];
|
||||
|
||||
snprintf(name, PATH_MAX, "%s%s%s%s", HOME_DIR, KVM_PID_FILE_PATH, guestfs_name, path);
|
||||
|
||||
snprintf(target, PATH_MAX, "/host%s", path);
|
||||
|
||||
return symlink(target, name);
|
||||
}
|
||||
|
||||
static void make_dir(const char *dir)
|
||||
{
|
||||
char name[PATH_MAX];
|
||||
|
||||
snprintf(name, PATH_MAX, "%s%s%s", HOME_DIR, KVM_PID_FILE_PATH, dir);
|
||||
|
||||
mkdir(name, 0777);
|
||||
}
|
||||
|
||||
static void make_guestfs_dir(const char *guestfs_name, const char *dir)
|
||||
{
|
||||
char name[PATH_MAX];
|
||||
|
||||
snprintf(name, PATH_MAX, "%s%s", guestfs_name, dir);
|
||||
|
||||
make_dir(name);
|
||||
}
|
||||
|
||||
static int do_setup(const char *guestfs_name)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
make_dir(guestfs_name);
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(guestfs_dirs); i++)
|
||||
make_guestfs_dir(guestfs_name, guestfs_dirs[i]);
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(guestfs_symlinks); i++) {
|
||||
make_guestfs_symlink(guestfs_name, guestfs_symlinks[i]);
|
||||
}
|
||||
|
||||
return copy_init(guestfs_name);
|
||||
}
|
||||
|
||||
int kvm_cmd_setup(int argc, const char **argv, const char *prefix)
|
||||
{
|
||||
parse_setup_options(argc, argv);
|
||||
|
||||
if (instance_name == NULL)
|
||||
kvm_setup_help();
|
||||
|
||||
return do_setup(instance_name);
|
||||
}
|
||||
@@ -3,6 +3,7 @@
|
||||
# command name category [deprecated] [common]
|
||||
#
|
||||
kvm-run mainporcelain common
|
||||
kvm-setup mainporcelain common
|
||||
kvm-pause common
|
||||
kvm-resume common
|
||||
kvm-version common
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
* This is a simple init for shared rootfs guests. It brings up critical
|
||||
* mountpoints and then launches /bin/sh.
|
||||
*/
|
||||
#include <sys/mount.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
|
||||
static int run_process(char *filename)
|
||||
{
|
||||
char *new_argv[] = { filename, NULL };
|
||||
char *new_env[] = { NULL };
|
||||
|
||||
return execve(filename, new_argv, new_env);
|
||||
}
|
||||
|
||||
static void do_mounts(void)
|
||||
{
|
||||
mount("hostfs", "/host", "9p", MS_RDONLY, "trans=virtio,version=9p2000.L");
|
||||
mount("", "/sys", "sysfs", 0, NULL);
|
||||
mount("proc", "/proc", "proc", 0, NULL);
|
||||
mount("devtmpfs", "/dev", "devtmpfs", 0, NULL);
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
puts("Mounting...");
|
||||
|
||||
do_mounts();
|
||||
|
||||
puts("Starting '/bin/sh'...");
|
||||
|
||||
run_process("/bin/sh");
|
||||
|
||||
printf("Init failed: %s\n", strerror(errno));
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
#ifndef KVM__SETUP_H
|
||||
#define KVM__SETUP_H
|
||||
|
||||
int kvm_cmd_setup(int argc, const char **argv, const char *prefix);
|
||||
void kvm_setup_help(void);
|
||||
|
||||
#endif
|
||||
@@ -11,6 +11,7 @@
|
||||
#include "kvm/builtin-balloon.h"
|
||||
#include "kvm/builtin-list.h"
|
||||
#include "kvm/builtin-version.h"
|
||||
#include "kvm/builtin-setup.h"
|
||||
#include "kvm/builtin-stop.h"
|
||||
#include "kvm/builtin-stat.h"
|
||||
#include "kvm/builtin-help.h"
|
||||
@@ -29,6 +30,7 @@ struct cmd_struct kvm_commands[] = {
|
||||
{ "stop", kvm_cmd_stop, kvm_stop_help, 0 },
|
||||
{ "stat", kvm_cmd_stat, kvm_stat_help, 0 },
|
||||
{ "help", kvm_cmd_help, NULL, 0 },
|
||||
{ "setup", kvm_cmd_setup, kvm_setup_help, 0 },
|
||||
{ "run", kvm_cmd_run, kvm_run_help, 0 },
|
||||
{ NULL, NULL, NULL, 0 },
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user