hyperStart source code

The files under src directory is the codes of hyperStart,
use autogen.sh && configure && make to generate hyper-initrd.img,
this image will be used to start hyper instance.

Signed-off-by: Gao feng <feng@hyper.sh>
This commit is contained in:
Gao feng
2015-05-25 14:47:03 +08:00
committed by Gao feng
parent 4782098723
commit 6dc013fc59
28 changed files with 6841 additions and 0 deletions
+37
View File
@@ -0,0 +1,37 @@
*#*#
*.#*#
*.a
*.o
*.orig
*.rej
.#*
.git
.deps
init
build/hyper_daemon
build/hyper-initrd.img
build/root/*
build/daemon
build/.*
src/.*
Makefile
Makefile.in
cscope.files
cscope.in.out
cscope.out
cscope.po.out
stamp-h
stamp-h.in
stamp-h1
/config.h
/config.h.in
/config.log
/config.status
/configure
/aclocal.m4
/autoscan.log
/autom4te.cache
/compile
/depcomp
/install-sh
/missing
+1
View File
@@ -0,0 +1 @@
SUBDIRS=src build
+2
View File
@@ -0,0 +1,2 @@
The init task for hyper.
exec ./autogen.sh to compile hyperinit
Executable
+64
View File
@@ -0,0 +1,64 @@
#!/bin/sh
srcdir=`dirname $0`
test -z "$srcdir" && srcidr=.
cd $srcdir
DIE=0
test -f src/init.c || {
echo
echo "You must run this script in the top-level hyperint drectory."
echo
DIE=1
}
(autoconf --version) < /dev/null > /dev/null 2>&1 || {
echo
echo "You must have autoconf installed to generate the hyperinit."
echo
DIE=1
}
(autoheader --version) < /dev/null > /dev/null 2>&1 || {
echo
echo "You must have autoheader installed to generate the hypernit."
echo
DIE=1
}
(automake --version) < /dev/null > /dev/null 2>&1 || {
echo
echo "You must have automake installed to generate the hypernit."
echo
DIE=1
}
(autoreconf --version) < /dev/null > /dev/null 2>&1 || {
echo
echo "You must have autoreconf installed to generate the hypernit."
echo
DIE=1
}
if test "$DIE" -eq 1; then
exit 1
fi
echo
echo "Generating build-system with:"
echo " aclocal: $(aclocal --version | head -1)"
echo " autoconf: $(autoconf --version | head -1)"
echo " autoheader: $(autoheader --version | head -1)"
echo " automake: $(automake --version | head -1)"
echo
rm -rf autom4te.cache
aclocal
autoconf
autoheader
automake --add-missing
echo
echo "type '$srcdir/configure' and 'make' to compile hyperinit."
echo
+4
View File
@@ -0,0 +1,4 @@
bin_PROGRAMS=hyper_daemon
hyper_daemon_SOURCES=hyper_daemon.c ../src/net.c
all-local:
bash ./make-initrd.sh
+168
View File
@@ -0,0 +1,168 @@
#define _GNU_SOURCE
#include <stdio.h>
#include <sys/socket.h>
#include <linux/un.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include "../src/hyper.h"
#include "../src/net.h"
int test_sendmsg(int fd, unsigned int type, unsigned int len, char *message)
{
uint8_t buf[4096];
/* send hyper info to guest */
hyper_set_be32(buf, type);
len += 8;
fprintf(stdout, "type is %u, len is %u\n", type, len);
hyper_set_be32(buf + 4, len);
if (message)
memcpy(buf + 8, message, len - 8);
if (write(fd, buf, len) != len) {
fprintf(stderr, "send SETDVM MESSAGE failed\n");
return -1;
}
fprintf(stdout, "finish sending\n");
return 0;
}
int test_sendmsg_from_file(int fd, unsigned int type, char *file)
{
int file_fd = open(file, O_RDONLY);
uint8_t buf[4096];
unsigned int len = 0;
if (file_fd < 0) {
perror("fail to open file");
return -1;
}
while (len < 4096) {
int size = read(file_fd, buf + len, sizeof(buf) - len);
fprintf(stdout, "read %d data\n", size);
if (size < 0) {
perror("fail to read data");
return -1;
} else if (size == 0) {
/* buf[len] = '\0';*/
fprintf(stdout, "get buf %s, call sendmsg\n", buf);
test_sendmsg(fd, type, len, (char *)buf);
break;
}
len += size;
}
close(file_fd);
if (read(fd, buf, 8) != 8) {
fprintf(stderr, "read response failed\n");
return -1;
}
type = hyper_get_be32(buf);
if (type != ACK) {
fprintf(stderr, "incorrect type %d\n", type);
return -1;
}
return 0;
}
int main(int argc, char *argv[])
{
int sock, fd = -1;
struct sockaddr_un addr;
uint8_t buf[8];
unsigned int type;
unlink("/tmp/hyper.sock");
sock = socket(AF_UNIX, SOCK_STREAM|SOCK_CLOEXEC, 0);
if (sock == -1) {
perror("create unix socket failed");
return -1;
}
addr.sun_family = AF_UNIX;
strncpy(addr.sun_path, "/tmp/hyper.sock", UNIX_PATH_MAX);
addr.sun_path[UNIX_PATH_MAX - 1] = '\0';
if (bind(sock, ((struct sockaddr *) &addr), sizeof(addr)) == -1) {
perror("bind failed");
goto out;
}
if (listen(sock, 1) == -1) {
perror("bind failed");
goto out;
}
while (fd == -1)
fd = accept4(sock, NULL, NULL, SOCK_CLOEXEC);
fprintf(stdout, "connected\n");
if (read(fd, buf, 8) != 8) {
fprintf(stderr, "read failed, buf %s\n", buf);
goto out1;
}
type = hyper_get_be32(buf);
fprintf(stdout, "get type %d\n", type);
if (type != READY) {
fprintf(stderr, "incorrect type %d\n", type);
goto out1;
}
fprintf(stdout, "get length %d\n", hyper_get_be32(buf + 4));
/* test_sendmsg_from_file(fd, SETDVM, "sethyper.json"); */
if (test_sendmsg_from_file(fd, STARTPOD, "startpod.json") < 0) {
fprintf(stderr, "send startpod message failed\n");
goto out1;
}
if (test_sendmsg_from_file(fd, EXECCMD, "execcmd.json") < 0) {
fprintf(stderr, "send execcmd message failed\n");
goto out1;
}
if (test_sendmsg(fd, STOPPOD, 0, NULL) < 0) {
fprintf(stderr, "send stoppod message failed\n");
goto out1;
}
if (read(fd, buf, 8) != 8) {
fprintf(stderr, "read response failed\n");
return -1;
}
type = hyper_get_be32(buf);
if (type != ACK) {
fprintf(stderr, "incorrect type %d\n", type);
return -1;
}
if (read(fd, buf, 8) != 8) {
fprintf(stderr, "read response failed\n");
return -1;
}
out1:
close(fd);
out:
close(sock);
return 0;
}
BIN
View File
Binary file not shown.
+1691
View File
File diff suppressed because it is too large Load Diff
+21
View File
@@ -0,0 +1,21 @@
#!/bin/bash
rm -rf root
mkdir root
cp ../src/init ./root
ldd ./root/init | while read line
do
arr=(${line// / })
for lib in ${arr[@]}
do
if [ "${lib:0:1}" = "/" ]; then
dir=root`dirname $lib`
mkdir -p "${dir}"
cp -f $lib $dir
fi
done
done
cd ./root && find . | cpio -H newc -o | gzip -9 > ../hyper-initrd.img
+67
View File
@@ -0,0 +1,67 @@
# -*- Autoconf -*-
# Process this file with autoconf to produce a configure script.
AC_PREREQ([2.69])
AC_INIT([dvminit], [0.1], [list@getdvm.org])
AM_INIT_AUTOMAKE([-Wall -Werror foreign subdir-objects])
AC_CONFIG_SRCDIR([src/init.c])
AC_CONFIG_HEADERS([config.h])
# Checks for programs.
AC_PROG_CC
# Checks for libraries.
# Checks for header files.
AC_CHECK_HEADERS([arpa/inet.h fcntl.h limits.h stddef.h stdint.h stdlib.h string.h sys/mount.h sys/socket.h unistd.h],
[headers_found=yes],
[headers_found=no])
if test "x$headers_found" != "xyes"; then
AC_MSG_ERROR(Unable to find necessary headers)
fi
# Checks for typedefs, structures, and compiler characteristics.
AC_C_INLINE
AC_TYPE_PID_T
AC_TYPE_SIZE_T
AC_TYPE_UINT32_T
AC_TYPE_UINT8_T
# Checks for library functions.
AC_FUNC_FORK
AC_CHECK_FUNCS([dup2 memmove memset mkdir setenv socket strchr strdup strrchr strtoul], [fail=0], [fail=1])
if test "$fail" = "1" ; then
AC_MSG_ERROR(Unable to find necessary functions)
fi
AC_ARG_WITH([ttys],
[AS_HELP_STRING([--with-ttys],
[use pci serial device as container tty])],
[],[with_ttys=yes])
if test "x$with_ttys" != "xno" ; then
AC_DEFINE_UNQUOTED([WITH_TTYS], 1, [where use pci serial device as container tty])
fi
AM_CONDITIONAL([WITH_TTYS], [test "x$with_ttys" != "xno"])
AC_CONFIG_FILES([
Makefile
src/Makefile
build/Makefile
])
AC_OUTPUT
AC_MSG_RESULT([
${PACKAGE} ${VERSION}
prefix: ${prefix}
with-ttys: ${with_ttys}
compiler: ${CC}
cflags: ${CFLAGS}
suid cflags: ${SUID_CFLAGS}
ldflags: ${LDFLAGS}
suid ldflags: ${SUID_LDFLAGS}
])
+3
View File
@@ -0,0 +1,3 @@
AM_CFLAGS = -Wall
bin_PROGRAMS=init
init_SOURCES=init.c jsmn.c net.c util.c parse.c container.c exec.c event.c
+546
View File
@@ -0,0 +1,546 @@
#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <sched.h>
#include <string.h>
#include <sys/mount.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <unistd.h>
#include <mntent.h>
#include <signal.h>
#include <errno.h>
#include <fcntl.h>
#include <dirent.h>
#include "hyper.h"
static int container_setup_env(struct hyper_container *container)
{
int i;
struct env *env;
for (i = 0; i < container->envs_num; i++) {
env = &container->envs[i];
setenv(env->env, env->value, 1);
}
return 0;
}
static int container_setup_volume(struct hyper_container *container)
{
int i;
char dev[512], path[512];
struct volume *vol;
for (i = 0; i < container->vols_num; i++) {
vol = &container->vols[i];
sprintf(dev, "/.oldroot/dev/%s", vol->device);
sprintf(path, "/tmp/%s", vol->mountpoint);
fprintf(stdout, "mount %s to %s\n", dev, vol->mountpoint);
if (hyper_mkdir(path) < 0 || hyper_mkdir(vol->mountpoint) < 0) {
fprintf(stdout, "mountpoint %s\n", vol->mountpoint);
perror("create volume dir failed");
continue;
}
if (mount(dev, path, vol->fstype, 0, NULL) < 0) {
perror("mount volume device faled");
continue;
}
if (mount(path, vol->mountpoint, NULL, MS_BIND, NULL) < 0) {
perror("mount volume device faled");
continue;
}
if (vol->readonly &&
mount(path, vol->mountpoint, NULL, MS_BIND | MS_REMOUNT | MS_RDONLY, NULL) < 0)
perror("mount fsmap faled");
umount(path);
}
return 0;
}
static void container_unmount_oldroot(char *path)
{
FILE *mtab;
struct mntent *mnt;
char *mntlist[128];
int i;
int n = 0;
char *filesys;
mtab = setmntent("/proc/mounts", "r");
if (mtab == NULL) {
fprintf(stderr, "cannot open /proc/mount");
return;
}
while (n < 128 && (mnt = getmntent(mtab))) {
if (strncmp(mnt->mnt_dir, path, strlen(path)))
continue;
mntlist[n++] = strdup(mnt->mnt_dir);
}
endmntent(mtab);
for (i = n - 1; i >= 0; i--) {
filesys = mntlist[i];
fprintf(stdout, "umount %s\n", filesys);
if (umount(mntlist[i]) < 0 && umount2(mntlist[i],
MNT_DETACH) < 0) {
fprintf(stdout, "umount %s: %s failed\n",
filesys, strerror(errno));
}
}
}
static int container_setup_mount(struct hyper_container *container)
{
int i, fd;
char src[512];
struct fsmap *map;
if (mount("proc", "/proc", "proc", 0, NULL) < 0 ||
mount("sysfs", "/sys", "sysfs", 0, NULL) < 0 ||
mount("devtmpfs", "/dev", "devtmpfs", 0, NULL) < 0) {
perror("mount basic filesystem for container failed");
return -1;
}
if (hyper_mkdir("/dev/pts") < 0) {
fprintf(stderr, "create /dev/pts failed\n");
return -1;
}
if (sprintf(src, "/.oldroot/tmp/hyper/%s/devpts", container->id) < 0) {
fprintf(stderr, "get container devpts failed\n");
return -1;
}
if (mount(src, "/dev/pts/", NULL, MS_BIND, NULL) < 0) {
perror("move pts to /dev/pts failed");
return -1;
}
unlink("/dev/ptmx");
link("/dev/pts/ptmx", "/dev/ptmx");
for (i = 0; i < container->maps_num; i++) {
struct stat st;
map = &container->maps[i];
sprintf(src, "/.oldroot/tmp/hyper/shared/%s", map->source);
fprintf(stdout, "mount %s to %s\n", src, map->path);
stat(src, &st);
if (st.st_mode & S_IFDIR) {
if (hyper_mkdir(map->path) < 0) {
perror("create map dir failed");
continue;
}
} else {
fd = open(map->path, O_CREAT|O_WRONLY, 0755);
if (fd < 0) {
perror("create map file failed");
continue;
}
close(fd);
}
if (mount(src, map->path, NULL, MS_BIND, NULL) < 0) {
perror("mount fsmap faled");
continue;
}
if (map->readonly == 0)
continue;
if (mount(src, map->path, NULL, MS_BIND | MS_REMOUNT | MS_RDONLY, NULL) < 0)
perror("mount fsmap faled");
}
return 0;
}
static int container_setup_workdir(struct hyper_container *container)
{
if (container->workdir && chdir(container->workdir) < 0) {
perror("change work directory failed");
return -1;
}
return 0;
}
static int container_setup_tty(int fd, struct hyper_container *container)
{
return hyper_dup_exec_tty(fd, &container->exec);
}
static int hyper_list_dir(char *path)
{
struct dirent **list;
struct dirent *dir;
int i, num;
fprintf(stdout, "list %s\n", path);
num = scandir(path, &list, NULL, NULL);
if (num < 0) {
perror("scan path failed");
return -1;
}
for (i = 0; i < num; i++) {
dir = list[i];
fprintf(stdout, "%s get %s\n", path, dir->d_name);
}
free(list);
return 0;
}
static int hyper_rescan_scsi(void)
{
struct dirent **list;
struct dirent *dir;
int fd = -1, i, num;
char path[256];
num = scandir("/sys/class/scsi_host/", &list, NULL, NULL);
if (num < 0) {
perror("scan /sys/calss/virtio-ports/ failed");
return -1;
}
memset(path, 0, sizeof(path));
for (i = 0; i < num; i++) {
dir = list[i];
if (dir->d_name[0] == '.')
continue;
if (snprintf(path, sizeof(path), "/sys/class/scsi_host/%s/scan",
dir->d_name) < 0) {
fprintf(stderr, "get scsi host device %s path failed\n",
dir->d_name);
continue;
}
fprintf(stdout, "path %s\n", path);
fd = open(path, O_WRONLY);
if (fd < 0) {
perror("open path failed");
continue;
}
if (write(fd, "- - - \n", 7) < 0)
perror("write to scan failed");
close(fd);
}
fprintf(stdout, "finish scan scsi\n");
return 0;
free(list);
}
struct hyper_container_arg {
struct hyper_container *c;
int pipe[2];
};
static int hyper_container_init(void *data)
{
struct hyper_container_arg *arg = data;
struct hyper_container *container = arg->c;
char root[512], oldroot[512];
fprintf(stdout, "%s in\n", __func__);
if (container->exec.argv == NULL) {
fprintf(stdout, "no cmd!\n");
goto fail;
}
if (hyper_rescan_scsi() < 0) {
fprintf(stdout, "rescan scsi failed\n");
goto fail;
}
if (container_setup_env(container) < 0) {
fprintf(stdout, "setup env failed\n");
goto fail;
}
if (mount("", "/", NULL, MS_SLAVE|MS_REC, NULL) < 0) {
perror("mount SLAVE failed");
goto fail;
}
if (mount("", "/", NULL, MS_PRIVATE|MS_REC, NULL) < 0) {
perror("mount PRIVATE failed");
goto fail;
}
sprintf(root, "/tmp/hyper/%s/root/", container->id);
if (hyper_mkdir(root) < 0) {
perror("make root directroy failed");
goto fail;
}
fprintf(stdout, "container root directory %s\n", root);
if (container->fstype) {
char dev[128];
sprintf(dev, "/dev/%s", container->image);
fprintf(stdout, "device %s\n", dev);
if (mount(dev, root, container->fstype, 0, NULL) < 0) {
perror("mount device failed");
goto fail;
}
} else {
char path[512];
sprintf(path, "/tmp/hyper/shared/%s/", container->image);
fprintf(stdout, "src directory %s\n", path);
if (mount(path, root, NULL, MS_BIND, NULL) < 0) {
perror("mount src dir failed");
goto fail;
}
}
fprintf(stdout, "root directory for container is %s/%s, init task %s\n",
root, container->rootfs, container->exec.argv[0]);
hyper_list_dir(root);
sprintf(oldroot, "%s/%s/.oldroot", root, container->rootfs);
if (hyper_mkdir(oldroot) < 0) {
perror("make oldroot directroy failed");
goto fail;
}
if (mount("/", oldroot, NULL, MS_BIND|MS_REC, NULL) < 0) {
perror("bind oldroot failed");
goto fail;
}
/* reuse oldroot array */
sprintf(oldroot, "%s/%s/", root, container->rootfs);
/* pivot_root won't work, see
* Documention/filesystem/ramfs-rootfs-initramfs.txt */
chroot(oldroot);
chdir("/");
if (container_setup_volume(container) < 0) {
fprintf(stderr, "container sets up voulme failed\n");
goto fail;
}
if (container_setup_mount(container) < 0) {
fprintf(stderr, "container sets up mount ns failed\n");
goto fail;
}
if (container_setup_workdir(container) < 0) {
fprintf(stderr, "container sets up work directory failed\n");
goto fail;
}
container_unmount_oldroot("/.oldroot");
fflush(stdout);
if (container_setup_tty(arg->pipe[1], container) < 0) {
fprintf(stdout, "setup tty failed\n");
goto fail;
}
close(arg->pipe[0]);
close(arg->pipe[1]);
execvp(container->exec.argv[0], container->exec.argv);
_exit(-1);
fail:
container->exec.code = -1;
hyper_send_type_block(arg->pipe[1], ERROR, 0);
_exit(-1);
}
int hyper_start_container(struct hyper_container *container)
{
int stacksize = getpagesize() * 4;
void *stack = malloc(stacksize);
struct hyper_container_arg arg = {
.c = container,
};
int flags = CLONE_NEWNS | SIGCHLD;
uint32_t type;
int pid;
if (container->image == NULL || container->exec.argv == NULL) {
fprintf(stdout, "container root image %s, argv %p\n",
container->image, container->exec.argv);
goto fail;
}
if (socketpair(PF_UNIX, SOCK_STREAM, 0, arg.pipe) < 0) {
perror("create pipe between pod init execcmd failed");
goto fail;
}
pid = clone(hyper_container_init, stack + stacksize, flags, &arg);
free(stack);
if (pid < 0) {
perror("create child process failed");
goto fail;
}
/* wait for ready message */
if (hyper_get_type_block(arg.pipe[0], &type) < 0 || type != READY) {
fprintf(stdout, "wait for container started failed\n");
goto fail;
}
close(arg.pipe[0]);
close(arg.pipe[1]);
container->exec.pid = pid;
fprintf(stdout, "container %s init pid is %d\n", container->id, pid);
return 0;
fail:
fprintf(stdout, "container %s init exit code %d\n", container->id, -1);
container->exec.code = -1;
return -1;
}
int hyper_start_containers(struct hyper_pod *pod)
{
int i;
/* mount new proc directory */
if (umount("/proc") < 0) {
perror("umount proc filesystem failed\n");
return -1;
}
if (mount("proc", "/proc", "proc", 0, NULL) < 0) {
perror("mount proc filesystem failed\n");
return -1;
}
if (sethostname(pod->hostname, strlen(pod->hostname)) < 0) {
perror("set host name failed");
return -1;
}
for (i = 0; i < pod->c_num; i++)
hyper_start_container(&pod->c[i]);
return 0;
}
int hyper_restart_containers(struct hyper_pod *pod)
{
int i;
struct hyper_container *c;
for (i = 0; i < pod->c_num; i++) {
c = &pod->c[i];
if (hyper_start_container(c) < 0) {
fprintf(stderr, "restart container %s failed\n", c->id);
hyper_send_type(pod->ctl.fd, ERROR);
return -1;
}
}
if (hyper_send_type(pod->ctl.fd, ACK) < 0)
return -1;
return 0;
}
struct hyper_container *hyper_find_container(struct hyper_pod *pod, char *id)
{
int i;
struct hyper_container *container;
for (i = 0; i < pod->c_num; i++) {
container = &pod->c[i];
if (strlen(container->id) != strlen(id))
continue;
if (strncmp(container->id, id, strlen(id)))
continue;
return container;
}
return NULL;
}
void hyper_cleanup_container(struct hyper_pod *pod)
{
int i, j;
struct hyper_container *c;
struct volume *vol;
struct env *env;
struct fsmap *map;
char root[512];
for (i = 0; i < pod->c_num; i++) {
c = &pod->c[i];
sprintf(root, "/tmp/hyper/%s/devpts/", c->id);
if (umount(root) < 0 && umount2(root, MNT_DETACH))
perror("umount devpts failed");
free(c->id);
free(c->rootfs);
free(c->image);
free(c->workdir);
free(c->fstype);
for (j = 0; j < c->vols_num; j++) {
vol = &(c->vols[j]);
free(vol->device);
free(vol->mountpoint);
free(vol->fstype);
}
free(c->vols);
for (j = 0; j < c->envs_num; j++) {
env = &(c->envs[j]);
free(env->env);
free(env->value);
}
free(c->envs);
for (j = 0; j < c->maps_num; j++) {
map = &(c->maps[j]);
free(map->source);
free(map->path);
}
free(c->maps);
}
free(pod->c);
pod->c = NULL;
pod->c_num = 0;
}
+47
View File
@@ -0,0 +1,47 @@
#ifndef _CONTAINER_H_
#define _CONTAINER_H_
#include "exec.h"
struct env {
char *env;
char *value;
};
struct volume {
char *device;
char *mountpoint;
char *fstype;
int readonly;
};
struct fsmap {
char *source;
char *path;
int readonly;
};
struct hyper_container {
char *id;
char *rootfs;
char *image;
char *workdir;
char *fstype;
struct volume *vols;
struct env *envs;
struct fsmap *maps;
int vols_num;
int envs_num;
int maps_num;
uint32_t code;
struct hyper_exec exec;
};
struct hyper_pod;
int hyper_start_containers(struct hyper_pod *pod);
struct hyper_container *hyper_find_container(struct hyper_pod *pod, char *id);
int hyper_restart_containers(struct hyper_pod *pod);
void hyper_cleanup_container(struct hyper_pod *pod);
#endif
+91
View File
@@ -0,0 +1,91 @@
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <fcntl.h>
#include <unistd.h>
#include "util.h"
#include "event.h"
void hyper_reset_event(struct hyper_event *de)
{
free(de->buf.data);
de->buf.data = NULL;
memset(de, 0, sizeof(*de));
}
int hyper_init_event(struct hyper_event *de,
struct hyper_event_ops *ops,
uint32_t size, int to, void *arg)
{
struct hyper_buf *buf = &de->buf;
memset(buf, 0, sizeof(*buf));
de->ops = ops;
de->ptr = arg;
de->to = to;
buf->size = size;
if (size) {
buf->data = malloc(size);
if (buf->data == NULL) {
fprintf(stderr, "allocate data for event failed\n");
return -1;
}
}
return 0;
}
int hyper_add_event(int efd, struct hyper_event *de)
{
struct epoll_event event = {
.events = EPOLLIN,
.data.ptr = de,
};
if (hyper_setfd_nonblock(de->fd) < 0) {
perror("set fd nonblock failed");
return -1;
}
fprintf(stdout, "%s add event fd %d, %p\n", __func__, de->fd, de->ops);
if (epoll_ctl(efd, EPOLL_CTL_ADD, de->fd, &event) < 0) {
perror("epoll_ctl fd failed");
return -1;
}
return 0;
}
void hyper_event_hup(struct hyper_event *de, int efd)
{
if (epoll_ctl(efd, EPOLL_CTL_DEL, de->fd, NULL) < 0)
perror("epoll_ctl del epoll event failed");
close(de->fd);
hyper_reset_event(de);
}
int hyper_handle_event(int efd, struct epoll_event *event)
{
struct hyper_event *de = event->data.ptr;
if (event->events & EPOLLHUP) {
fprintf(stdout, "%s event EPOLLHUP, de %p, fd %d, %p\n",
__func__, de, de->fd, de->ops);
if (de->ops->hup)
de->ops->hup(de, efd);
return 0;
} else if (event->events & EPOLLIN) {
return de->ops->read(de);
} else if (event->events & EPOLLERR) {
fprintf(stderr, "get epoll err of not epool in event\n");
return -1;
}
fprintf(stdout, "%s get unknown event %d\n", __func__, event->events);
return -1;
}
+36
View File
@@ -0,0 +1,36 @@
#ifndef _EVENT_H
#define _EVENT_H
#include <inttypes.h>
#include <sys/epoll.h>
struct hyper_event;
struct hyper_event_ops {
int (*read)(struct hyper_event *e);
int (*getlen)(struct hyper_event *e, uint32_t *len);
int (*handle)(struct hyper_event *e, uint32_t len);
void (*hup)(struct hyper_event *e, int efd);
};
struct hyper_buf {
uint32_t get;
uint32_t size;
uint8_t *data;
};
struct hyper_event {
int fd;
int to;
struct hyper_buf buf;
struct hyper_event_ops *ops;
void *ptr;
};
int hyper_add_event(int efd, struct hyper_event *de);
int hyper_init_event(struct hyper_event *de, struct hyper_event_ops *ops,
uint32_t size, int to, void *arg);
int hyper_handle_event(int efd, struct epoll_event *event);
void hyper_reset_event(struct hyper_event *de);
void hyper_event_hup(struct hyper_event *de, int efd);
#endif
+558
View File
@@ -0,0 +1,558 @@
#define _GNU_SOURCE
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/epoll.h>
#include <sys/ioctl.h>
#include <sched.h>
#include <errno.h>
#include <string.h>
#include <fcntl.h>
#include <inttypes.h>
#include "hyper.h"
#include "util.h"
#include "parse.h"
static int pts_loop(struct hyper_event *de)
{
int size = 0;
uint8_t buf[512];
uint8_t seq[12];
struct hyper_exec *exec = container_of(de, struct hyper_exec, e);
fprintf(stdout, "%s\n", __func__);
while (1) {
size = read(de->fd, buf, sizeof(buf));
if (size <= 0) {
if (errno == EINTR)
continue;
if (errno == EAGAIN || errno == EIO)
break;
perror("fail to read tty fd");
return -1;
}
hyper_set_be64(seq, exec->seq);
hyper_set_be32(seq + 8, size + 12);
if (hyper_send_data(de->to, seq, 12) < 0)
continue;
hyper_send_data(de->to, buf, size);
}
return 0;
}
struct hyper_event_ops pts_ops = {
.read = pts_loop,
.hup = hyper_event_hup,
};
int hyper_setup_exec_tty(struct hyper_exec *e)
{
int unlock = 0;
char ptmx[512], path[512];
if (e->seq == 0)
return 0;
if (e->id) {
if (sprintf(path, "/tmp/hyper/%s/devpts/", e->id) < 0) {
fprintf(stderr, "get ptmx path failed\n");
return -1;
}
} else {
if (sprintf(path, "/dev/pts/") < 0) {
fprintf(stderr, "get ptmx path failed\n");
return -1;
}
}
if (sprintf(ptmx, "%s/ptmx", path) < 0) {
fprintf(stderr, "get ptmx path failed\n");
return -1;
}
e->e.fd = open(ptmx, O_RDWR | O_NOCTTY | O_NONBLOCK | O_CLOEXEC);
if (e->e.fd < 0) {
perror("open ptmx device for execcmd failed");
return -1;
}
if (ioctl(e->e.fd, TIOCSPTLCK, &unlock) < 0) {
perror("ioctl unlock ptmx device failed");
return -1;
}
if (ioctl(e->e.fd, TIOCGPTN, &e->ptyno) < 0) {
perror("ioctl get execcmd pty device failed");
return -1;
}
if (sprintf(ptmx, "%s/%d", path, e->ptyno) < 0) {
fprintf(stderr, "get ptmx path failed\n");
return -1;
}
e->pty = strdup(ptmx);
fprintf(stdout, "get pty device for exec %s\n", e->pty);
return 0;
}
int hyper_dup_exec_tty(int to, struct hyper_exec *e)
{
int fd;
char pty[128];
setsid();
if (e->seq) {
if (sprintf(pty, "/dev/pts/%d", e->ptyno) < 0) {
perror("get pts device name failed");
return -1;
}
} else {
if (sprintf(pty, "/dev/null") < 0) {
perror("get pts device name failed");
return -1;
}
}
fprintf(stdout, "setup pty device %s for exec\n", pty);
fd = open(pty, O_RDWR | O_NOCTTY);
if (fd < 0) {
perror("open pty device for execcmd failed");
return -1;
}
if (ioctl(fd, TIOCSCTTY, NULL) < 0) {
perror("ioctl pty device for execcmd failed");
return -1;
}
if (hyper_send_type_block(to, READY, 0) < 0) {
fprintf(stderr, "send ready message to hyper init failed\n");
return -1;
}
fflush(stdout);
if (dup2(fd, STDIN_FILENO) < 0) {
perror("dup tty device to stdin failed");
close(fd);
return -1;
}
if (dup2(fd, STDOUT_FILENO) < 0) {
perror("dup tty device to stdout failed");
close(fd);
return -1;
}
if (dup2(fd, STDERR_FILENO) < 0) {
perror("dup tty device to stderr failed");
close(fd);
return -1;
}
close(fd);
return 0;
}
int hyper_exec_in_container(struct hyper_pod *pod,
struct hyper_exec *exec)
{
global_exec = exec;
if (hyper_send_type_block(ctl.ctl.fd, EXECCMD, 1) < 0) {
global_exec = NULL;
fprintf(stderr, "tell pod init EXECCMD failed\n");
return -1;
}
list_add_tail(&exec->list, &pod->ce_head);
if (exec->seq == 0)
return 0;
fprintf(stdout, "init container exec pts event %p, ops %p, fd %d\n",
&exec->e, &pts_ops, exec->e.fd);
if (hyper_init_event(&exec->e, &pts_ops, 0, ctl.tty.fd, NULL) < 0 ||
hyper_add_event(ctl.efd, &exec->e) < 0) {
fprintf(stderr, "add pts master event failed\n");
return -1;
}
return 0;
}
int hyper_request_restart_containers(struct hyper_pod *pod)
{
int i;
struct hyper_exec *exec;
pod->code = 0;
pod->remains = pod->c_num;
for (i = 0; i < pod->c_num; i++) {
exec = &pod->c[i].exec;
if (hyper_setup_exec_tty(exec) < 0) {
fprintf(stdout, "restart setup container tty failed\n");
return -1;
}
}
if (hyper_send_type_block(ctl.ctl.fd, RESTARTCONTAINER, 1) < 0) {
fprintf(stderr, "tell container init RESTARTCONTAINER failed\n");
return -1;
}
for (i = 0; i < pod->c_num; i++) {
exec = &pod->c[i].exec;
list_add_tail(&exec->list, &pod->ce_head);
if (exec->seq == 0)
continue;
if (hyper_init_event(&exec->e, &pts_ops, 0, ctl.tty.fd, NULL) < 0 ||
hyper_add_event(ctl.efd, &exec->e) < 0) {
fprintf(stderr, "add pts master event failed\n");
return -1;
}
}
return 0;
}
int hyper_exec_cmd(char *json, int length)
{
struct hyper_exec *exec;
struct hyper_pod *pod = &global_pod;
int pid, pipe[2];
fprintf(stdout, "call hyper_exec_cmd, json %s, len %d\n", json, length);
exec = hyper_parse_execcmd(json, length);
if (exec == NULL) {
fprintf(stderr, "parse exec cmd failed\n");
return -1;
}
if (exec->argv == NULL) {
fprintf(stderr, "cmd is %p, seq %" PRIu64 ", container %s\n",
exec->argv, exec->seq, exec->id);
return -1;
}
if (hyper_setup_exec_tty(exec) < 0) {
fprintf(stderr, "setup exec tty failed\n");
return -1;
}
if (exec->id) {
if (hyper_exec_in_container(pod, exec) < 0) {
fprintf(stderr, "notify container exec failed\n");
return -1;
}
return 0;
}
if (socketpair(PF_UNIX, SOCK_STREAM, 0, pipe) < 0) {
perror("create pipe between pod init execcmd failed");
return -1;
}
pid = fork();
if (pid < 0) {
fprintf(stderr, "fork failed\n");
return -1;
} else if (pid > 0) {
uint32_t type;
if (hyper_get_type_block(pipe[0], &type) < 0 || type != READY) {
fprintf(stderr, "hyper init doesn't get execcmd ready message\n");
return -1;
}
close(pipe[0]);
close(pipe[1]);
fprintf(stdout, "hyper init get ready message\n");
exec->pid = pid;
fprintf(stdout, "create exec cmd %s pid %d\n", exec->argv[0], pid);
list_add_tail(&exec->list, &pod->pe_head);
if (exec->seq == 0)
return 0;
fprintf(stdout, "init pod exec pts event %p, ops %p, fd %d\n",
&exec->e, &pts_ops, exec->e.fd);
if (hyper_init_event(&exec->e, &pts_ops, 0, ctl.tty.fd, NULL) < 0 ||
hyper_add_event(ctl.efd, &exec->e) < 0) {
fprintf(stderr, "add pts master event failed\n");
return -1;
}
return 0;
}
if (hyper_dup_exec_tty(pipe[1], exec) < 0) {
fprintf(stderr, "dup pts to exec stdio failed\n");
_exit(-1);
}
close(pipe[0]);
close(pipe[1]);
if (execvp(exec->argv[0], exec->argv) < 0) {
perror("exec failed");
_exit(-1);
}
_exit(0);
}
int hyper_container_execcmd(struct hyper_pod *pod)
{
struct hyper_exec *exec = global_exec;
struct hyper_container *container = NULL;
int fd, pid, sock = pod->ctl.fd;
char root[512]; int pipe[2];
global_exec = NULL;
container = hyper_find_container(pod, exec->id);
if (container == NULL) {
fprintf(stderr, "can not find container %s\n", exec->id);
return -1;
}
if (sprintf(root, "/tmp/hyper/%s/devpts/", exec->id) < 0) {
fprintf(stderr, "get container %s pts path failed\n", exec->id);
return -1;
}
if (socketpair(PF_UNIX, SOCK_STREAM, 0, pipe) < 0) {
perror("create pipe between pod init execcmd failed");
return -1;
}
pid = fork();
if (pid < 0) {
fprintf(stderr, "container init fork failed\n");
return -1;
} else if (pid > 0) {
uint32_t type;
if (hyper_get_type_block(pipe[0], &type) < 0 || type != READY) {
fprintf(stderr, "pod init get execcmd ready message failed\n");
hyper_send_type_block(sock, ERROR, 0);
return 0;
}
close(pipe[0]);
close(pipe[1]);
fprintf(stdout, "pod init get ready message\n");
exec->pid = pid;
fprintf(stdout, "create exec cmd %s pid %d\n", exec->argv[0], pid);
if (hyper_send_type_block(sock, ACK, 0) < 0)
return -1;
return 0;
}
close(pipe[0]);
sprintf(root, "/proc/%d/ns/mnt", container->exec.pid);
fprintf(stdout, "container %s, init pid %d\n",
exec->id, container->exec.pid);
fd = open(root, O_RDONLY);
if (fd < 0) {
perror("fail to open container mnt ns\n");
goto fail;
}
if (setns(fd, CLONE_NEWNS) < 0) {
perror("enter mnt ns failed");
goto fail;
}
close(fd);
sprintf(root, "/tmp/hyper/%s/root/%s/",
container->id, container->rootfs);
fprintf(stdout, "root directory for container is %s, exec %s\n",
root, exec->argv[0]);
/* TODO: wait for container finishing setup root */
if (chroot(root) < 0) {
perror("chroot for exec command failed");
goto fail;
}
chdir("/");
if (hyper_dup_exec_tty(pipe[1], exec)) {
fprintf(stderr, "dup pts to stdio failed\n");
goto fail;
}
close(pipe[1]);
if (execvp(exec->argv[0], exec->argv) < 0)
perror("exec failed");
_exit(-1);
fail:
hyper_send_type_block(pipe[1], ERROR, 0);
_exit(-1);
}
int hyper_release_exec(struct hyper_exec *exec,
struct hyper_pod *pod)
{
int i;
close(exec->e.fd);
free(exec->pty);
list_del_init(&exec->list);
fprintf(stdout, "%s exit code %" PRIu8"\n", __func__, exec->code);
if (exec->init) {
fprintf(stdout, "%s container init exited, type %d, remains %d, policy %d\n",
__func__, pod->type, pod->remains, pod->policy);
/* stop pod, should not restart container */
if (pod->type == STOPPOD)
return 0;
if (exec->code)
pod->code = exec->code;
if (--pod->remains > 0)
return 0;
/* should shutdown? */
if (pod->policy == POLICY_NEVER ||
((pod->policy == POLICY_ONFAILURE) && pod->code == 0)) {
hyper_shutdown(pod);
return 0;
}
if (hyper_request_restart_containers(pod) < 0) {
fprintf(stderr, "restart container failed\n");
return -1;
}
return 0;
}
free(exec->id);
for (i = 0; i < exec->argc; i++) {
fprintf(stdout, "argv %d %s\n", i, exec->argv[i]);
free(exec->argv[i]);
}
free(exec->argv);
free(exec);
return 0;
}
struct hyper_exec *hyper_find_exec_by_pid(struct list_head *head, int pid)
{
struct hyper_exec *exec;
list_for_each_entry(exec, head, list) {
fprintf(stdout, "exec pid %d, pid %d\n", exec->pid, pid);
if (exec->pid != pid)
continue;
return exec;
}
return NULL;
}
struct hyper_exec *hyper_find_exec_by_seq(struct hyper_pod *pod, uint64_t seq)
{
struct hyper_exec *exec;
list_for_each_entry(exec, &pod->ce_head, list) {
fprintf(stdout, "container exec seq %" PRIu64 ", seq %" PRIu64 "\n",
exec->seq, seq);
if (exec->seq != seq)
continue;
return exec;
}
list_for_each_entry(exec, &pod->pe_head, list) {
fprintf(stdout, "pod exec seq %" PRIu64 ", seq %" PRIu64 "\n",
exec->seq, seq);
if (exec->seq != seq)
continue;
return exec;
}
return NULL;
}
int hyper_send_exec_eof(int to, struct hyper_pod *pod,
struct list_head *head, int pid,
uint8_t code)
{
struct hyper_exec *exec;
uint8_t seq[12];
exec = hyper_find_exec_by_pid(head, pid);
if (exec == NULL) {
fprintf(stdout, "can not find exec whose pid is %d\n",
pid);
return 0;
}
fprintf(stdout, "%s exec pid %d, seq %" PRIu64 ", container %s\n",
__func__, exec->pid, exec->seq, exec->id ? exec->id : "pod");
exec->code = code;
if (exec->seq == 0)
goto out;
hyper_set_be64(seq, exec->seq);
hyper_set_be32(seq + 8, 12);
if (hyper_send_data(to, seq, 12) < 0) {
fprintf(stderr, "pod signal_loop send finishcmd failed\n");
return -1;
}
out:
hyper_release_exec(exec, pod);
return 0;
}
void hyper_cleanup_exec(struct hyper_pod *pod)
{
struct hyper_exec *exec, *next;
list_for_each_entry_safe(exec, next, &pod->ce_head, list) {
fprintf(stdout, "cleanup container exec seq %" PRIu64 "\n", exec->seq);
hyper_release_exec(exec, pod);
}
}
+36
View File
@@ -0,0 +1,36 @@
#ifndef _EXEC_H
#define _EXEC_H
#include "list.h"
#include "event.h"
struct hyper_exec {
struct list_head list;
struct hyper_event e;
char *id;
char *pty;
char **argv;
int argc;
uint64_t seq;
int pid;
int ptyno;
int init;
uint8_t code;
};
struct hyper_pod;
int hyper_exec_cmd(char *json, int length);
int hyper_release_exec(struct hyper_exec *, struct hyper_pod *);
int hyper_container_execcmd(struct hyper_pod *pod);
int hyper_setup_exec_tty(struct hyper_exec *e);
int hyper_dup_exec_tty(int fd, struct hyper_exec *e);
struct hyper_exec *hyper_find_exec_by_pid(struct list_head *head, int pid);
struct hyper_exec *hyper_find_exec_by_seq(struct hyper_pod *pod, uint64_t seq);
int hyper_send_exec_eof(int to, struct hyper_pod *pod,
struct list_head *head, int pid,
uint8_t code);
void hyper_cleanup_exec(struct hyper_pod *pod);
extern struct hyper_event_ops pts_ops;
#endif
+80
View File
@@ -0,0 +1,80 @@
#ifndef _DVM_H_
#define _DVM_H_
#include <stdint.h>
#include "net.h"
#include "list.h"
#include "exec.h"
#include "event.h"
#include "container.h"
enum {
SETDVM,
STARTPOD,
GETPOD,
STOPPOD,
DESTROYPOD,
RESTARTCONTAINER,
EXECCMD,
FINISHCMD,
READY,
ACK,
ERROR,
WINSIZE,
PING,
FINISH,
};
enum {
POLICY_NEVER,
POLICY_ALWAYS,
POLICY_ONFAILURE,
};
struct hyper_pod {
struct hyper_container *c;
struct hyper_interface *iface;
struct hyper_route *rt;
struct list_head pe_head;
struct list_head ce_head;
char *hostname;
char *tag;
char *channel;
int init_pid;
uint32_t c_num;
uint32_t i_num;
uint32_t r_num;
uint32_t e_num;
uint32_t type;
uint32_t code;
uint32_t remains;
uint8_t policy;
int efd;
struct hyper_event sig;
struct hyper_event ctl;
};
struct hyper_win_size {
char *tty;
int row;
int column;
uint64_t seq;
};
struct hyper_ctl {
int efd;
struct hyper_event sig;
struct hyper_event tty;
struct hyper_event chan;
struct hyper_event ctl;
};
int hyper_mkdir(char *hyper_path);
int hyper_open_serial(char *tty);
struct hyper_container *hyper_find_container(struct hyper_pod *pod, char *id);
extern struct hyper_pod global_pod;
extern struct hyper_ctl ctl;
extern struct hyper_exec *global_exec;
#endif
+1025
View File
File diff suppressed because it is too large Load Diff
+321
View File
@@ -0,0 +1,321 @@
#include <stdlib.h>
#include "jsmn.h"
/**
* Allocates a fresh unused token from the token pull.
*/
static jsmntok_t *jsmn_alloc_token(jsmn_parser *parser,
jsmntok_t *tokens,
size_t num_tokens)
{
jsmntok_t *tok;
if (parser->toknext >= num_tokens)
return NULL;
tok = &tokens[parser->toknext++];
tok->start = tok->end = -1;
tok->size = 0;
#ifdef JSMN_PARENT_LINKS
tok->parent = -1;
#endif
return tok;
}
/**
* Fills token type and boundaries.
*/
static void jsmn_fill_token(jsmntok_t *token, jsmntype_t type,
int start, int end)
{
token->type = type;
token->start = start;
token->end = end;
token->size = 0;
}
/**
* Fills next available token with JSON primitive.
*/
static jsmnerr_t jsmn_parse_primitive(jsmn_parser *parser, const char *js,
size_t len, jsmntok_t *tokens,
size_t num_tokens) {
jsmntok_t *token;
int start;
start = parser->pos;
for (; parser->pos < len && js[parser->pos] != '\0'; parser->pos++) {
switch (js[parser->pos]) {
#ifndef JSMN_STRICT
/* In strict mode primitive must be followed by "," or "}" or "]" */
case ':':
#endif
case '\t': case '\r': case '\n': case ' ':
case ',': case ']': case '}':
goto found;
}
if (js[parser->pos] < 32 || js[parser->pos] >= 127) {
parser->pos = start;
return JSMN_ERROR_INVAL;
}
}
#ifdef JSMN_STRICT
/* In strict mode primitive must be followed by a comma/object/array */
parser->pos = start;
return JSMN_ERROR_PART;
#endif
found:
if (tokens == NULL) {
parser->pos--;
return 0;
}
token = jsmn_alloc_token(parser, tokens, num_tokens);
if (token == NULL) {
parser->pos = start;
return JSMN_ERROR_NOMEM;
}
jsmn_fill_token(token, JSMN_PRIMITIVE, start, parser->pos);
#ifdef JSMN_PARENT_LINKS
token->parent = parser->toksuper;
#endif
parser->pos--;
return 0;
}
/**
* Filsl next token with JSON string.
*/
static jsmnerr_t jsmn_parse_string(jsmn_parser *parser, const char *js,
size_t len, jsmntok_t *tokens,
size_t num_tokens)
{
jsmntok_t *token;
int start = parser->pos;
parser->pos++;
/* Skip starting quote */
for (; parser->pos < len && js[parser->pos] != '\0'; parser->pos++) {
char c = js[parser->pos];
/* Quote: end of string */
if (c == '\"') {
if (tokens == NULL)
return 0;
token = jsmn_alloc_token(parser, tokens, num_tokens);
if (token == NULL) {
parser->pos = start;
return JSMN_ERROR_NOMEM;
}
jsmn_fill_token(token, JSMN_STRING, start+1, parser->pos);
#ifdef JSMN_PARENT_LINKS
token->parent = parser->toksuper;
#endif
return 0;
}
/* Backslash: Quoted symbol expected */
if (c == '\\' && parser->pos + 1 < len) {
int i;
parser->pos++;
switch (js[parser->pos]) {
/* Allowed escaped symbols */
case '\"': case '/': case '\\': case 'b':
case 'f': case 'r': case 'n': case 't':
break;
/* Allows escaped symbol \uXXXX */
case 'u':
parser->pos++;
for (i = 0; i < 4 && parser->pos < len && js[parser->pos] != '\0'; i++) {
/* If it isn't a hex character we have an error */
if (!((js[parser->pos] >= 48 && js[parser->pos] <= 57) || /* 0-9 */
(js[parser->pos] >= 65 && js[parser->pos] <= 70) || /* A-F */
(js[parser->pos] >= 97 && js[parser->pos] <= 102))) { /* a-f */
parser->pos = start;
return JSMN_ERROR_INVAL;
}
parser->pos++;
}
parser->pos--;
break;
/* Unexpected symbol */
default:
parser->pos = start;
return JSMN_ERROR_INVAL;
}
}
}
parser->pos = start;
return JSMN_ERROR_PART;
}
/**
* Parse JSON string and fill tokens.
*/
jsmnerr_t jsmn_parse(jsmn_parser *parser, const char *js, size_t len,
jsmntok_t *tokens, unsigned int num_tokens)
{
jsmnerr_t r;
int i;
jsmntok_t *token;
int count = 0;
for (; parser->pos < len && js[parser->pos] != '\0'; parser->pos++) {
char c;
jsmntype_t type;
c = js[parser->pos];
switch (c) {
case '{': case '[':
count++;
if (tokens == NULL)
break;
token = jsmn_alloc_token(parser, tokens, num_tokens);
if (token == NULL)
return JSMN_ERROR_NOMEM;
if (parser->toksuper != -1) {
tokens[parser->toksuper].size++;
#ifdef JSMN_PARENT_LINKS
token->parent = parser->toksuper;
#endif
}
token->type = (c == '{' ? JSMN_OBJECT : JSMN_ARRAY);
token->start = parser->pos;
parser->toksuper = parser->toknext - 1;
break;
case '}': case ']':
if (tokens == NULL)
break;
type = (c == '}' ? JSMN_OBJECT : JSMN_ARRAY);
#ifdef JSMN_PARENT_LINKS
if (parser->toknext < 1)
return JSMN_ERROR_INVAL;
token = &tokens[parser->toknext - 1];
for (;;) {
if (token->start != -1 && token->end == -1) {
if (token->type != type)
return JSMN_ERROR_INVAL;
token->end = parser->pos + 1;
parser->toksuper = token->parent;
break;
}
if (token->parent == -1)
break;
token = &tokens[token->parent];
}
#else
for (i = parser->toknext - 1; i >= 0; i--) {
token = &tokens[i];
if (token->start != -1 && token->end == -1) {
if (token->type != type)
return JSMN_ERROR_INVAL;
parser->toksuper = -1;
token->end = parser->pos + 1;
break;
}
}
/* Error if unmatched closing bracket */
if (i == -1)
return JSMN_ERROR_INVAL;
for (; i >= 0; i--) {
token = &tokens[i];
if (token->start != -1 && token->end == -1) {
parser->toksuper = i;
break;
}
}
#endif
break;
case '\"':
r = jsmn_parse_string(parser, js, len, tokens, num_tokens);
if (r < 0)
return r;
count++;
if (parser->toksuper != -1 && tokens != NULL)
tokens[parser->toksuper].size++;
break;
case '\t': case '\r': case '\n': case ' ':
break;
case ':':
parser->toksuper = parser->toknext - 1;
break;
case ',':
if (tokens != NULL &&
tokens[parser->toksuper].type != JSMN_ARRAY &&
tokens[parser->toksuper].type != JSMN_OBJECT) {
#ifdef JSMN_PARENT_LINKS
parser->toksuper = tokens[parser->toksuper].parent;
#else
for (i = parser->toknext - 1; i >= 0; i--) {
if (tokens[i].type == JSMN_ARRAY || tokens[i].type == JSMN_OBJECT) {
if (tokens[i].start != -1 && tokens[i].end == -1) {
parser->toksuper = i;
break;
}
}
}
#endif
}
break;
#ifdef JSMN_STRICT
/* In strict mode primitives are: numbers and booleans */
case '-': case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':
case 't': case 'f': case 'n':
/* And they must not be keys of the object */
if (tokens != NULL) {
jsmntok_t *t = &tokens[parser->toksuper];
if (t->type == JSMN_OBJECT ||
(t->type == JSMN_STRING && t->size != 0))
return JSMN_ERROR_INVAL;
}
#else
/* In non-strict mode every unquoted value is a primitive */
default:
#endif
r = jsmn_parse_primitive(parser, js, len, tokens, num_tokens);
if (r < 0)
return r;
count++;
if (parser->toksuper != -1 && tokens != NULL)
tokens[parser->toksuper].size++;
break;
#ifdef JSMN_STRICT
/* Unexpected char in strict mode */
default:
return JSMN_ERROR_INVAL;
#endif
}
}
for (i = parser->toknext - 1; i >= 0; i--) {
/* Unmatched opened object or array */
if (tokens[i].start != -1 && tokens[i].end == -1)
return JSMN_ERROR_PART;
}
return count;
}
/**
* Creates a new parser based over a given buffer with an array of tokens
* available.
*/
void jsmn_init(jsmn_parser *parser)
{
parser->pos = 0;
parser->toknext = 0;
parser->toksuper = -1;
}
+67
View File
@@ -0,0 +1,67 @@
#ifndef __JSMN_H_
#define __JSMN_H_
#include <stddef.h>
/**
* JSON type identifier. Basic types are:
* o Object
* o Array
* o String
* o Other primitive: number, boolean (true/false) or null
*/
typedef enum {
JSMN_PRIMITIVE = 0,
JSMN_OBJECT = 1,
JSMN_ARRAY = 2,
JSMN_STRING = 3
} jsmntype_t;
typedef enum {
/* Not enough tokens were provided */
JSMN_ERROR_NOMEM = -1,
/* Invalid character inside JSON string */
JSMN_ERROR_INVAL = -2,
/* The string is not a full JSON packet, more bytes expected */
JSMN_ERROR_PART = -3
} jsmnerr_t;
/**
* JSON token description.
* @param type type (object, array, string etc.)
* @param start start position in JSON data string
* @param end end position in JSON data string
*/
typedef struct {
jsmntype_t type;
int start;
int end;
int size;
#ifdef JSMN_PARENT_LINKS
int parent;
#endif
} jsmntok_t;
/**
* JSON parser. Contains an array of token blocks available. Also stores
* the string being parsed now and current position in that string
*/
typedef struct {
unsigned int pos; /* offset in the JSON string */
unsigned int toknext; /* next token to allocate */
int toksuper; /* superior token node, e.g parent object or array */
} jsmn_parser;
/**
* Create JSON parser over an array of tokens
*/
void jsmn_init(jsmn_parser *parser);
/**
* Run JSON parser. It parses a JSON data string into and array of tokens, each describing
* a single JSON object.
*/
jsmnerr_t jsmn_parse(jsmn_parser *parser, const char *js, size_t len,
jsmntok_t *tokens, unsigned int num_tokens);
#endif /* __JSMN_H_ */
+191
View File
@@ -0,0 +1,191 @@
#ifndef _LIST_H_
#define _LIST_H_
#include <stddef.h>
/*
* Simple doubly linked list implementation.
*
* Some of the internal functions ("__xxx") are useful when
* manipulating whole lists rather than single entries, as
* sometimes we already know the next/prev entries and we can
* generate better code by using them directly rather than
* using the generic single-entry routines.
*/
/**
* container_of - cast a member of a structure out to the containing structure
* @ptr: the pointer to the member.
* @type: the type of the container struct this is embedded in.
* @member: the name of the member within the struct.
*
*/
#define container_of(ptr, type, member) ({ \
const typeof(((type *)0)->member) * __mptr = (ptr); \
(type *)((char *)__mptr - offsetof(type, member)); })
struct list_head {
struct list_head *next, *prev;
};
#define LIST_HEAD_INIT(name) { &(name), &(name) }
#define LIST_HEAD(name) \
struct list_head name = LIST_HEAD_INIT(name)
static inline void INIT_LIST_HEAD(struct list_head *list)
{
list->next = list;
list->prev = list;
}
static inline void __list_add(struct list_head *new,
struct list_head *prev,
struct list_head *next)
{
next->prev = new;
new->next = next;
new->prev = prev;
prev->next = new;
}
/**
* list_add - add a new entry
* @new: new entry to be added
* @head: list head to add it after
*
* Insert a new entry after the specified head.
* This is good for implementing stacks.
*/
static inline void list_add(struct list_head *new, struct list_head *head)
{
__list_add(new, head, head->next);
}
/**
* list_add_tail - add a new entry
* @new: new entry to be added
* @head: list head to add it before
*
* Insert a new entry before the specified head.
* This is useful for implementing queues.
*/
static inline void list_add_tail(struct list_head *new, struct list_head *head)
{
__list_add(new, head->prev, head);
}
/*
* Delete a list entry by making the prev/next entries
* point to each other.
*
* This is only for internal list manipulation where we know
* the prev/next entries already!
*/
static inline void __list_del(struct list_head *prev, struct list_head *next)
{
next->prev = prev;
prev->next = next;
}
/**
* list_del - deletes entry from list.
* @entry: the element to delete from the list.
* Note: list_empty() on entry does not return true after this, the entry is
* in an undefined state.
*/
static inline void list_del(struct list_head *entry)
{
__list_del(entry->prev, entry->next);
}
/**
* list_del_init - deletes entry from list and reinitialize it.
* @entry: the element to delete from the list.
*/
static inline void list_del_init(struct list_head *entry)
{
list_del(entry);
INIT_LIST_HEAD(entry);
}
/**
* list_empty - tests whether a list is empty
* @head: the list to test.
*/
static inline int list_empty(const struct list_head *head)
{
return head->next == head;
}
/**
* list_entry - get the struct for this entry
* @ptr: the &struct list_head pointer.
* @type: the type of the struct this is embedded in.
* @member: the name of the list_head within the struct.
*/
#define list_entry(ptr, type, member) \
container_of(ptr, type, member)
/**
* list_for_each - iterate over a list
* @pos: the &struct list_head to use as a loop cursor.
* @head: the head for your list.
*/
#define list_for_each(pos, head) \
for (pos = (head)->next; pos != (head); pos = pos->next)
/**
* list_first_entry - get the first element from a list
* @ptr: the list head to take the element from.
* @type: the type of the struct this is embedded in.
* @member: the name of the list_head within the struct.
*
* Note, that list is expected to be not empty.
*/
#define list_first_entry(ptr, type, member) \
list_entry((ptr)->next, type, member)
/**
* list_last_entry - get the last element from a list
* @ptr: the list head to take the element from.
* @type: the type of the struct this is embedded in.
* @member: the name of the list_head within the struct.
*
* Note, that list is expected to be not empty.
*/
#define list_last_entry(ptr, type, member) \
list_entry((ptr)->prev, type, member)
/**
* list_next_entry - get the next element in list
* @pos: the type * to cursor
* @member: the name of the list_head within the struct.
*/
#define list_next_entry(pos, member) \
list_entry((pos)->member.next, typeof(*(pos)), member)
/**
* list_for_each_entry - iterate over list of given type
* @pos: the type * to use as a loop cursor.
* @head: the head for your list.
* @member: the name of the list_head within the struct.
*/
#define list_for_each_entry(pos, head, member) \
for (pos = list_first_entry(head, typeof(*pos), member); \
&pos->member != (head); \
pos = list_next_entry(pos, member))
/**
* list_for_each_entry_safe - iterate over list of given type safe against removal of list entry
* @pos: the type * to use as a loop cursor.
* @n: another type * to use as temporary storage
* @head: the head for your list.
* @member: the name of the list_head within the struct.
*/
#define list_for_each_entry_safe(pos, n, head, member) \
for (pos = list_first_entry(head, typeof(*pos), member), \
n = list_next_entry(pos, member); \
&pos->member != (head); \
pos = n, n = list_next_entry(n, member))
#endif
+793
View File
@@ -0,0 +1,793 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <limits.h>
#include <errno.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <fcntl.h>
#include "hyper.h"
void hyper_set_be32(uint8_t *buf, uint32_t val)
{
buf[0] = val >> 24;
buf[1] = val >> 16;
buf[2] = val >> 8;
buf[3] = val;
}
uint32_t hyper_get_be32(uint8_t *buf)
{
return buf[0] << 24 | buf[1] << 16 | buf[2] << 8 | buf[3];
}
void hyper_set_be64(uint8_t *buf, uint64_t val)
{
hyper_set_be32(buf, val >> 32);
hyper_set_be32(buf + 4, val);
}
uint64_t hyper_get_be64(uint8_t *buf)
{
uint64_t v;
v = (uint64_t) hyper_get_be32(buf) << 32;
v |= hyper_get_be32(buf + 4);
return v;
}
int hyper_send_data(int fd, uint8_t *data, uint32_t len)
{
int length = 0, size;
while (length < len) {
size = write(fd, data + length, len - length);
if (size <= 0) {
if (errno == EINTR)
continue;
/* EAGAIN means unblock and the peer of virtio-ports is disappear */
if (errno == EAGAIN)
return 0;
perror("send hyper data failed");
return -1;
}
length += size;
}
return 0;
}
int hyper_send_msg(int fd, uint32_t type, uint32_t len,
uint8_t *message)
{
uint8_t buf[8];
fprintf(stdout, "hyper send type %d, len %d\n", type, len);
hyper_set_be32(buf, type);
hyper_set_be32(buf + 4, len + 8);
if (hyper_send_data(fd, buf, 8) < 0)
return -1;
if (message && hyper_send_data(fd, message, len) < 0)
return -1;
return 0;
}
int hyper_send_type(int fd, uint32_t type)
{
return hyper_send_msg(fd, type, 0, NULL);
}
int hyper_get_type_block(int fd, uint32_t *type)
{
int len = 0, size;
uint8_t buf[8];
while (len < 8) {
size = read(fd, buf + len, 8 - len);
if (size <= 0) {
if (errno == EINTR)
continue;
perror("wait for ack failed");
return -1;
}
len += size;
}
*type = hyper_get_be32(buf);
return 0;
}
int hyper_send_type_block(int fd, uint32_t type, int need_ack)
{
int ret = 0, flags;
uint32_t t;
flags = fcntl(fd, F_GETFL, 0);
if (flags < 0) {
fprintf(stderr, "get fd flag failed\n");
return -1;
}
if (fcntl(fd, F_SETFL, flags & ~O_NONBLOCK) < 0) {
perror("set fd BLOCK failed");
return -1;
}
ret = hyper_send_msg(fd, type, 0, NULL);
if (ret < 0)
goto out;
if (need_ack == 0)
goto out;
ret = hyper_get_type_block(fd, &t);
if (ret < 0) {
fprintf(stderr, "can not get type\n");
goto out;
}
fprintf(stdout, "get type %" PRIu32"\n", type);
if (t != ACK)
ret = -1;
out:
if (fcntl(fd, F_SETFL, flags | O_NONBLOCK) < 0) {
perror("set fd BLOCK failed");
return -1;
}
return ret;
}
static int get_addr_ipv4(uint8_t *ap, const char *cp)
{
int i;
for (i = 0; i < 4; i++) {
unsigned long n;
char *endp;
n = strtoul(cp, &endp, 0);
if (n > 255)
return -1; /* bogus network value */
if (endp == cp) /* no digits */
return -1;
ap[i] = n;
if (*endp == '\0')
break;
if (i == 3 || *endp != '.')
return -1; /* extra characters */
cp = endp + 1;
}
return 1;
}
static int addattr_l(struct nlmsghdr *n, int maxlen, int type, void *data, int alen)
{
int len = RTA_LENGTH(alen);
struct rtattr *rta;
if (NLMSG_ALIGN(n->nlmsg_len) + len > maxlen)
return -1;
rta = (struct rtattr *)(((char *)n) + NLMSG_ALIGN(n->nlmsg_len));
rta->rta_type = type;
rta->rta_len = len;
memcpy(RTA_DATA(rta), data, alen);
n->nlmsg_len = NLMSG_ALIGN(n->nlmsg_len) + len;
return 0;
}
static int hyper_get_ifindex(char *nic)
{
int fd, ifindex = -1;
char path[512], buf[4];
fprintf(stdout, "net device %s\n", nic);
sprintf(path, "/sys/class/net/%s/ifindex", nic);
fprintf(stdout, "net device sys path is %s\n", path);
fd = open(path, O_RDONLY);
if (fd < 0) {
perror("can not open file");
return -1;
}
memset(buf, 0, sizeof(buf));
if (read(fd, buf, sizeof(buf)) <= 0) {
perror("can read open file");
goto out;
}
ifindex = atoi(buf);
fprintf(stdout, "get ifindex %d\n", ifindex);
out:
close(fd);
return ifindex;
}
static int netlink_open(struct rtnl_handle *rth)
{
memset(rth, 0, sizeof(*rth));
rth->fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
if (rth->fd < 0) {
perror("cannot open netlink socket");
return -1;
}
rth->local.nl_family = AF_NETLINK;
rth->local.nl_groups = 0;
if (bind(rth->fd, (struct sockaddr *)&rth->local, sizeof(rth->local)) < 0) {
perror("cannot bind netlink socket");
goto out;
}
rth->seq = 0;
return 0;
out:
close(rth->fd);
return -1;
}
static void netlink_close(struct rtnl_handle *rth)
{
if (rth->fd > 0)
close(rth->fd);
rth->fd = -1;
}
static int rtnl_talk(struct rtnl_handle *rtnl,
struct nlmsghdr *n, pid_t peer,
unsigned groups, struct nlmsghdr *answer)
{
int status;
struct sockaddr_nl nladdr;
struct iovec iov = { (void *)n, n->nlmsg_len };
struct msghdr msg = { (void *)&nladdr, sizeof(nladdr), &iov, 1, NULL, 0, 0 };
memset(&nladdr, 0, sizeof(nladdr));
nladdr.nl_family = AF_NETLINK;
nladdr.nl_pid = peer;
nladdr.nl_groups = groups;
n->nlmsg_seq = ++rtnl->seq;
if (answer == NULL)
n->nlmsg_flags |= NLM_F_ACK;
status = sendmsg(rtnl->fd, &msg, 0);
if (status < 0)
return -1;
return 0;
}
static int hyper_up_nic(struct rtnl_handle *rth, int ifindex)
{
struct {
struct nlmsghdr n;
struct ifinfomsg i;
char buf[1024];
} req;
memset(&req, 0, sizeof(req));
req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg));
req.n.nlmsg_flags = NLM_F_REQUEST;
req.n.nlmsg_type = RTM_NEWLINK;
req.i.ifi_family = AF_UNSPEC;
req.i.ifi_change |= IFF_UP;
req.i.ifi_flags |= IFF_UP;
req.i.ifi_index = ifindex;
if (rtnl_talk(rth, &req.n, 0, 0, NULL) < 0)
return -1;
return 0;
}
static int hyper_remove_nic(char *device)
{
char path[256], real[128];
int fd;
sprintf(path, "/sys/class/net/%s", device);
if (readlink(path, real, 128) < 0) {
perror("fail to read link directory");
return -1;
}
sprintf(path, "/sys/%s/../../../remove", real + 5);
fprintf(stdout, "get net sys path %s\n", path);
fd = open(path, O_WRONLY);
if (fd < 0) {
perror("open file failed");
return -1;
}
if (write(fd, "1\n", 2) < 0) {
perror("write 1 to file failed");
close(fd);
return 1;
}
close(fd);
return 0;
}
static int hyper_down_nic(struct rtnl_handle *rth, int ifindex)
{
struct {
struct nlmsghdr n;
struct ifinfomsg i;
char buf[1024];
} req;
memset(&req, 0, sizeof(req));
req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg));
req.n.nlmsg_flags = NLM_F_REQUEST;
req.n.nlmsg_type = RTM_NEWLINK;
req.i.ifi_family = AF_UNSPEC;
req.i.ifi_change |= IFF_UP;
req.i.ifi_flags &= ~IFF_UP;
req.i.ifi_index = ifindex;
if (rtnl_talk(rth, &req.n, 0, 0, NULL) < 0)
return -1;
return 0;
}
static int mask2bits(uint32_t netmask)
{
unsigned bits = 0;
uint32_t mask = ntohl(netmask);
uint32_t host = ~mask;
/* a valid netmask must be 2^n - 1 */
if ((host & (host + 1)) != 0)
return -1;
for (; mask; mask <<= 1)
++bits;
return bits;
}
static int get_netmask(unsigned *val, const char *addr)
{
char *ptr;
unsigned long res;
uint32_t data;
int b;
res = strtoul(addr, &ptr, 0);
if (!ptr || ptr == addr || *ptr)
goto get_addr;
if (res == ULONG_MAX && errno == ERANGE)
goto get_addr;
if (res > UINT_MAX)
goto get_addr;
*val = res;
return 0;
get_addr:
if (get_addr_ipv4((uint8_t *)&data, addr) <= 0)
return -1;
b = mask2bits(data);
if (b < 0)
return -1;
*val = b;
return 0;
}
static int hyper_setup_route(struct rtnl_handle *rth,
struct hyper_route *rt)
{
uint32_t data;
struct {
struct nlmsghdr n;
struct rtmsg r;
char buf[1024];
} req;
if (!rt->dst) {
fprintf(stderr, "route dest is null\n");
return -1;
}
memset(&req, 0, sizeof(req));
req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg));
req.n.nlmsg_flags = NLM_F_CREATE | NLM_F_EXCL | NLM_F_REQUEST;
req.n.nlmsg_type = RTM_NEWROUTE;
req.r.rtm_family = AF_INET;
req.r.rtm_table = RT_TABLE_MAIN;
req.r.rtm_scope = RT_SCOPE_UNIVERSE;
req.r.rtm_type = RTN_UNICAST;
req.r.rtm_protocol = RTPROT_BOOT;
req.r.rtm_dst_len = 0;
if (rt->gw) {
if (get_addr_ipv4((uint8_t *)&data, rt->gw) <= 0) {
fprintf(stderr, "get gw failed\n");
return -1;
}
if (addattr_l(&req.n, sizeof(req), RTA_GATEWAY, &data, 4)) {
fprintf(stderr, "setup gateway attr failed\n");
return -1;
}
}
if (rt->device) {
rt->ifindex = hyper_get_ifindex(rt->device);
if (addattr_l(&req.n, sizeof(req), RTA_OIF, &rt->ifindex, 4)) {
fprintf(stderr, "setup oif attr failed\n");
return -1;
}
}
if (strcmp(rt->dst, "default") && strcmp(rt->dst, "any") && strcmp(rt->dst, "all")) {
unsigned mask;
char *slash = strchr(rt->dst, '/');
req.r.rtm_dst_len = 32;
if (slash)
*slash = 0;
if (get_addr_ipv4((uint8_t *)&data, rt->dst) <= 0) {
fprintf(stderr, "get dst failed\n");
return -1;
}
if (addattr_l(&req.n, sizeof(req), RTA_DST, &data, 4)) {
fprintf(stderr, "setup gateway attr failed\n");
return -1;
}
if (slash) {
if (get_netmask(&mask, slash + 1) < 0) {
fprintf(stderr, "get netmask failed\n");
return -1;
}
req.r.rtm_dst_len = mask;
*slash = '/';
}
}
if (rtnl_talk(rth, &req.n, 0, 0, NULL) < 0) {
fprintf(stderr, "rtnl talk failed\n");
return -1;
}
return 0;
}
static int hyper_cleanup_route(struct rtnl_handle *rth, struct hyper_route *rt)
{
uint32_t data;
struct {
struct nlmsghdr n;
struct rtmsg r;
char buf[1024];
} req;
if (!rt->dst) {
fprintf(stderr, "route dest is null\n");
return -1;
}
memset(&req, 0, sizeof(req));
req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg));
req.n.nlmsg_flags = NLM_F_REQUEST;
req.n.nlmsg_type = RTM_DELROUTE;
req.r.rtm_family = AF_INET;
req.r.rtm_table = RT_TABLE_MAIN;
req.r.rtm_scope = RT_SCOPE_UNIVERSE;
req.r.rtm_type = RTN_UNICAST;
req.r.rtm_protocol = RTPROT_BOOT;
req.r.rtm_dst_len = 0;
if (rt->gw) {
if (get_addr_ipv4((uint8_t *)&data, rt->gw) <= 0) {
fprintf(stderr, "get gw failed\n");
return -1;
}
if (addattr_l(&req.n, sizeof(req), RTA_GATEWAY, &data, 4)) {
fprintf(stderr, "setup gateway attr failed\n");
return -1;
}
}
if (rt->device) {
if (addattr_l(&req.n, sizeof(req), RTA_OIF, &rt->ifindex, 4)) {
fprintf(stderr, "setup oif attr failed\n");
return -1;
}
}
if (strcmp(rt->dst, "default") && strcmp(rt->dst, "any") && strcmp(rt->dst, "all")) {
unsigned mask;
char *slash = strchr(rt->dst, '/');
req.r.rtm_dst_len = 32;
if (slash)
*slash = 0;
if (get_addr_ipv4((uint8_t *)&data, rt->dst) <= 0) {
fprintf(stderr, "get dst failed\n");
return -1;
}
if (addattr_l(&req.n, sizeof(req), RTA_DST, &data, 4)) {
fprintf(stderr, "setup gateway attr failed\n");
return -1;
}
if (slash) {
if (get_netmask(&mask, slash + 1) < 0) {
fprintf(stderr, "get netmask failed\n");
return -1;
}
req.r.rtm_dst_len = mask;
*slash = '/';
}
}
if (rtnl_talk(rth, &req.n, 0, 0, NULL) < 0) {
fprintf(stderr, "rtnl talk failed\n");
return -1;
}
return 0;
}
static int hyper_setup_interface(struct rtnl_handle *rth,
struct hyper_interface *iface)
{
uint8_t data[4];
unsigned mask;
struct {
struct nlmsghdr n;
struct ifaddrmsg ifa;
char buf[256];
} req;
if (!(iface->device && iface->ipaddr && iface->mask)) {
fprintf(stderr, "interface information incorrect\n");
return -1;
}
memset(&req, 0, sizeof(req));
req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifaddrmsg));
req.n.nlmsg_flags = NLM_F_REQUEST | NLM_F_CREATE | NLM_F_EXCL;
req.n.nlmsg_type = RTM_NEWADDR;
req.ifa.ifa_family = AF_INET;
iface->ifindex = hyper_get_ifindex(iface->device);
req.ifa.ifa_index = iface->ifindex;
req.ifa.ifa_scope = 0;
if (get_addr_ipv4((uint8_t *)&data, iface->ipaddr) <= 0) {
fprintf(stderr, "get addr failed\n");
return -1;
}
if (addattr_l(&req.n, sizeof(req), IFA_LOCAL, &data, 4)) {
fprintf(stderr, "setup attr failed\n");
return -1;
}
if (get_netmask(&mask, iface->mask) < 0) {
fprintf(stderr, "get netamsk failed\n");
return -1;
}
req.ifa.ifa_prefixlen = mask;
fprintf(stdout, "interface get netamsk %d %s\n", req.ifa.ifa_prefixlen, iface->mask);
if (rtnl_talk(rth, &req.n, 0, 0, NULL) < 0) {
perror("rtnl_talk failed");
return -1;
}
if (hyper_up_nic(rth, iface->ifindex) < 0) {
fprintf(stderr, "up device %d failed\n", iface->ifindex);
return -1;
}
return 0;
}
static int hyper_cleanup_interface(struct rtnl_handle *rth,
struct hyper_interface *iface)
{
uint8_t data[4];
unsigned mask;
struct {
struct nlmsghdr n;
struct ifaddrmsg ifa;
char buf[256];
} req;
if (!(iface->device && iface->ipaddr && iface->mask)) {
fprintf(stderr, "interface information incorrect\n");
return -1;
}
memset(&req, 0, sizeof(req));
req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifaddrmsg));
req.n.nlmsg_flags = NLM_F_REQUEST;
req.n.nlmsg_type = RTM_DELADDR;
req.ifa.ifa_family = AF_INET;
req.ifa.ifa_index = iface->ifindex;
req.ifa.ifa_scope = 0;
if (get_addr_ipv4((uint8_t *)&data, iface->ipaddr) <= 0) {
fprintf(stderr, "get addr failed\n");
return -1;
}
if (addattr_l(&req.n, sizeof(req), IFA_LOCAL, &data, 4)) {
fprintf(stderr, "setup attr failed\n");
return -1;
}
if (get_netmask(&mask, iface->mask) < 0) {
fprintf(stderr, "get netamsk failed\n");
return -1;
}
req.ifa.ifa_prefixlen = mask;
fprintf(stdout, "interface get netamsk %d %s\n", req.ifa.ifa_prefixlen, iface->mask);
if (rtnl_talk(rth, &req.n, 0, 0, NULL) < 0) {
perror("rtnl_talk failed");
return -1;
}
if (hyper_down_nic(rth, iface->ifindex) < 0) {
fprintf(stderr, "up device %d failed\n", iface->ifindex);
return -1;
}
if (hyper_remove_nic(iface->device) < 0) {
fprintf(stderr, "remove device %s failed\n", iface->device);
return -1;
}
return 0;
}
int hyper_rescan(void)
{
int fd = open("/sys/bus/pci/rescan", O_WRONLY);
if (fd < 0) {
perror("can not open rescan file");
return -1;
}
if (write(fd, "1\n", 2) < 0) {
perror("can not open rescan file");
close(fd);
return -1;
}
fprintf(stdout, "finish rescan\n");
close(fd);
return 0;
}
int hyper_setup_network(struct hyper_pod *pod)
{
int i, ret = 0;
struct hyper_interface *iface;
struct hyper_route *rt;
struct rtnl_handle rth;
if (hyper_rescan() < 0)
return -1;
if (netlink_open(&rth) < 0)
return -1;
for (i = 0; i < pod->i_num; i++) {
iface = &pod->iface[i];
ret = hyper_setup_interface(&rth, iface);
if (ret < 0) {
fprintf(stderr, "link up device %s failed\n", iface->device);
goto out;
}
}
ret = hyper_up_nic(&rth, 1);
if (ret < 0) {
fprintf(stderr, "link up lo device failed\n");
goto out;
}
for (i = 0; i < pod->r_num; i++) {
rt = &pod->rt[i];
ret = hyper_setup_route(&rth, rt);
if (ret < 0) {
fprintf(stderr, "setup route failed\n");
goto out;
}
}
out:
netlink_close(&rth);
return ret;
}
void hyper_cleanup_network(struct hyper_pod *pod)
{
int i;
struct rtnl_handle rth;
struct hyper_interface *iface;
struct hyper_route *rt;
if (netlink_open(&rth) < 0) {
fprintf(stdout, "open netlink failed\n");
return;
}
for (i = 0; i < pod->r_num; i++) {
rt = &pod->rt[i];
if (hyper_cleanup_route(&rth, rt) < 0)
fprintf(stderr, "cleanup route failed\n");
free(rt->dst);
free(rt->gw);
free(rt->device);
}
free(pod->rt);
pod->rt = NULL;
pod->r_num = 0;
for (i = 0; i < pod->i_num; i++) {
iface = &pod->iface[i];
if (hyper_cleanup_interface(&rth, iface) < 0)
fprintf(stderr, "link down device %s failed\n", iface->device);
free(iface->device);
free(iface->ipaddr);
free(iface->mask);
}
free(pod->iface);
pod->iface = NULL;
pod->i_num = 0;
netlink_close(&rth);
}
+57
View File
@@ -0,0 +1,57 @@
#ifndef _NET_H_
#define _NET_H_
#include <stdio.h>
#include <ctype.h>
#include <stdint.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <linux/if.h>
#include <linux/netlink.h>
#include <linux/rtnetlink.h>
struct rtnl_handle {
int fd;
struct sockaddr_nl local;
struct sockaddr_nl peer;
__u32 seq;
__u32 dump;
};
typedef struct {
__u8 family;
__u8 bytelen;
__s16 bitlen;
__u32 flags;
__u32 data[8];
} inet_prefix;
struct hyper_interface {
char *device;
int ifindex;
char *ipaddr;
char *mask;
};
struct hyper_route {
char *dst;
char *gw;
char *device;
int ifindex;
};
struct hyper_pod;
int hyper_rescan(void);
void hyper_set_be32(uint8_t *buf, uint32_t val);
uint32_t hyper_get_be32(uint8_t *buf);
void hyper_set_be64(uint8_t *buf, uint64_t val);
uint64_t hyper_get_be64(uint8_t *buf);
int hyper_setup_network(struct hyper_pod *pod);
void hyper_cleanup_network(struct hyper_pod *pod);
int hyper_get_type_block(int fd, uint32_t *type);
int hyper_send_type(int fd, uint32_t type);
int hyper_send_type_block(int fd, uint32_t type, int need_ack);
int hyper_send_msg(int fd, uint32_t type, uint32_t len,
uint8_t *message);
int hyper_send_data(int fd, uint8_t *data, uint32_t len);
#endif
+605
View File
@@ -0,0 +1,605 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <inttypes.h>
#include "list.h"
#include "parse.h"
char *json_token_str(char *js, jsmntok_t *t)
{
js[t->end] = '\0';
return js + t->start;
}
int json_token_int(char *js, jsmntok_t *t)
{
return strtol(json_token_str(js, t), 0, 10);
}
uint64_t json_token_ll(char *js, jsmntok_t *t)
{
return strtoll(json_token_str(js, t), 0, 10);
}
int json_token_streq(char *js, jsmntok_t *t, char *s)
{
return (strncmp(js + t->start, s, t->end - t->start) == 0 &&
strlen(s) == (size_t)(t->end - t->start));
}
static int container_parse_cmd(struct hyper_container *c, char *json, jsmntok_t *toks)
{
int i = 1, j;
if (toks[i].type != JSMN_ARRAY) {
fprintf(stdout, "cmd need array");
return -1;
}
c->exec.argc = toks[i].size;
c->exec.argv = calloc(c->exec.argc + 1, sizeof(*c->exec.argv));
c->exec.argv[c->exec.argc] = NULL;
for (j = 0; j < c->exec.argc; j++) {
i++;
c->exec.argv[j] = strdup(json_token_str(json, &toks[i]));
fprintf(stdout, "container init arg %d %s\n", j, c->exec.argv[j]);
}
return i;
}
static int container_parse_volumes(struct hyper_container *c, char *json, jsmntok_t *toks)
{
int i = 1, j;
if (toks[i].type != JSMN_ARRAY) {
fprintf(stdout, "volume need array\n");
return -1;
}
c->vols_num = toks[i].size;
fprintf(stdout, "volumes num %d\n", c->vols_num);
c->vols = calloc(c->vols_num, sizeof(*c->vols));
for (j = 0; j < c->vols_num; j++) {
int i_volume, next_volume;
i++;
if (toks[i].type != JSMN_OBJECT) {
fprintf(stdout, "volume array need object\n");
return -1;
}
next_volume = toks[i].size;
for (i_volume = 0; i_volume < next_volume; i_volume++) {
i++;
if (json_token_streq(json, &toks[i], "device")) {
c->vols[j].device =
strdup(json_token_str(json, &toks[++i]));
fprintf(stdout, "volume %d device %s\n", j, c->vols[j].device);
} else if (json_token_streq(json, &toks[i], "mount")) {
c->vols[j].mountpoint =
strdup(json_token_str(json, &toks[++i]));
fprintf(stdout, "volume %d mp %s\n", j, c->vols[j].mountpoint);
} else if (json_token_streq(json, &toks[i], "fstype")) {
c->vols[j].fstype =
strdup(json_token_str(json, &toks[++i]));
fprintf(stdout, "volume %d fstype %s\n", j, c->vols[j].fstype);
} else if (json_token_streq(json, &toks[i], "readOnly")) {
if (!json_token_streq(json, &toks[++i], "false"))
c->vols[j].readonly = 1;
fprintf(stdout, "volume %d readonly %d\n", j, c->vols[j].readonly);
} else {
fprintf(stdout, "in voulmes incorrect %s\n", json_token_str(json, &toks[i]));
}
}
}
return i;
}
static int container_parse_fsmap(struct hyper_container *c, char *json, jsmntok_t *toks)
{
int i = 1, j;
if (toks[i].type != JSMN_ARRAY) {
fprintf(stdout, "envs need array\n");
return -1;
}
c->maps_num = toks[i].size;
fprintf(stdout, "fsmap num %d\n", c->maps_num);
c->maps = calloc(c->maps_num, sizeof(*c->maps));
for (j = 0; j < c->maps_num; j++) {
int i_map, next_map;
i++;
if (toks[i].type != JSMN_OBJECT) {
fprintf(stdout, "fsmap array need object\n");
return -1;
}
next_map = toks[i].size;
for (i_map = 0; i_map < next_map; i_map++) {
i++;
if (json_token_streq(json, &toks[i], "source")) {
c->maps[j].source =
strdup(json_token_str(json, &toks[++i]));
fprintf(stdout, "maps %d source %s\n", j, c->maps[j].source);
} else if (json_token_streq(json, &toks[i], "path")) {
c->maps[j].path =
strdup(json_token_str(json, &toks[++i]));
fprintf(stdout, "maps %d path %s\n", j, c->maps[j].path);
} else if (json_token_streq(json, &toks[i], "readOnly")) {
if (!json_token_streq(json, &toks[++i], "false"))
c->maps[j].readonly = 1;
fprintf(stdout, "maps %d readonly %d\n", j, c->maps[j].readonly);
} else {
fprintf(stdout, "in maps incorrect %s\n",
json_token_str(json, &toks[i]));
}
}
}
return i;
}
static int container_parse_envs(struct hyper_container *c, char *json, jsmntok_t *toks)
{
int i = 1, j;
if (toks[i].type != JSMN_ARRAY) {
fprintf(stdout, "encs need array\n");
return -1;
}
c->envs_num = toks[i].size;
fprintf(stdout, "envs num %d\n", c->envs_num);
c->envs = calloc(c->envs_num, sizeof(*c->envs));
for (j = 0; j < c->envs_num; j++) {
int i_env, next_env;
i++;
if (toks[i].type != JSMN_OBJECT) {
fprintf(stdout, "env array need object\n");
return -1;
}
next_env = toks[i].size;
for (i_env = 0; i_env < next_env; i_env++) {
i++;
if (json_token_streq(json, &toks[i], "env")) {
c->envs[j].env =
strdup(json_token_str(json, &toks[++i]));
fprintf(stdout, "envs %d env %s\n", j, c->envs[j].env);
} else if (json_token_streq(json, &toks[i], "value")) {
c->envs[j].value =
strdup(json_token_str(json, &toks[++i]));
fprintf(stdout, "envs %d value %s\n", j, c->envs[j].value);
} else {
fprintf(stdout, "in envs incorrect %s\n", json_token_str(json, &toks[i]));
}
}
}
return i;
}
static int hyper_parse_container(struct hyper_pod *pod, struct hyper_container *c,
char *json, jsmntok_t *toks)
{
int i = 1, j, next, next_container;
jsmntok_t *t;
if (toks[i].type != JSMN_OBJECT) {
fprintf(stderr, "format incorrect\n");
return -1;
}
c->exec.init = 1;
c->exec.code = -1;
next_container = toks[i].size;
fprintf(stdout, "next container %d\n", next_container);
for (j = 0; j < next_container; j++) {
i++;
t = &toks[i];
fprintf(stdout, "%d name %s\n", i, json_token_str(json, t));
if (json_token_streq(json, t, "id") && t->size == 1) {
i++;
c->id = strdup(json_token_str(json, &toks[i]));
c->exec.id = strdup(c->id);
fprintf(stdout, "container id %s\n", c->id);
} else if (json_token_streq(json, t, "cmd") && t->size == 1) {
next = container_parse_cmd(c, json, &toks[i]);
if (next < 0)
return -1;
i += next;
} else if (json_token_streq(json, t, "rootfs") && t->size == 1) {
i++;
c->rootfs = strdup(json_token_str(json, &toks[i]));
fprintf(stdout, "container rootfs %s\n", c->rootfs);
} else if (json_token_streq(json, t, "tty") && t->size == 1) {
i++;
c->exec.seq = json_token_ll(json, &toks[i]);
fprintf(stdout, "container seq %" PRIu64 "\n", c->exec.seq);
} else if (json_token_streq(json, t, "workdir") && t->size == 1) {
i++;
c->workdir = strdup(json_token_str(json, &toks[i]));
fprintf(stdout, "container workdir %s\n", c->workdir);
} else if (json_token_streq(json, t, "image") && t->size == 1) {
i++;
c->image = strdup(json_token_str(json, &toks[i]));
fprintf(stdout, "container image %s\n", c->image);
} else if (json_token_streq(json, t, "fstype") && t->size == 1) {
i++;
c->fstype = strdup(json_token_str(json, &toks[i]));
fprintf(stdout, "container fstype %s\n", c->fstype);
} else if (json_token_streq(json, t, "volumes") && t->size == 1) {
next = container_parse_volumes(c, json, &toks[i]);
if (next < 0)
return -1;
i += next;
} else if (json_token_streq(json, t, "fsmap") && t->size == 1) {
next = container_parse_fsmap(c, json, &toks[i]);
if (next < 0)
return -1;
i += next;
} else if (json_token_streq(json, t, "envs") && t->size == 1) {
next = container_parse_envs(c, json, &toks[i]);
if (next < 0)
return -1;
i += next;
} else if (json_token_streq(json, t, "restartPolicy") && t->size == 1) {
i++;
/*
if (json_token_streq(json, &toks[i], "always") && t->size == 1)
c->exec.flags = POLICY_ALWAYS;
else if (json_token_streq(json, &toks[i], "onFailure") && t->size == 1)
c->exec.flags = POLICY_ONFAILURE;
else
c->exec.flags = POLICY_NEVER;
*/
fprintf(stdout, "restartPolicy %s\n", json_token_str(json, &toks[i]));
}
}
return i;
}
static int hyper_parse_containers(struct hyper_pod *pod, char *json, jsmntok_t *toks)
{
int i = 1, j, next;
if (toks[i].type != JSMN_ARRAY) {
fprintf(stdout, "format incorrect\n");
return -1;
}
pod->remains = pod->c_num = toks[i].size;
fprintf(stdout, "container count %d\n", pod->c_num);
pod->c = calloc(pod->c_num, sizeof(*pod->c));
if (pod->c == NULL) {
fprintf(stdout, "alloc memory for container failed\n");
return -1;
}
for (j = 0; j < pod->c_num; j++) {
next = hyper_parse_container(pod, &pod->c[j], json, toks + i);
if (next < 0)
return -1;
i += next;
}
return i;
}
static int hyper_parse_interfaces(struct hyper_pod *pod, char *json, jsmntok_t *toks)
{
int i = 1, j, next_if;
struct hyper_interface *iface;
if (toks[i].type != JSMN_ARRAY) {
fprintf(stdout, "interfaces need array\n");
return -1;
}
pod->i_num = toks[i].size;
fprintf(stdout, "network interfaces num %d\n", pod->i_num);
pod->iface = calloc(pod->i_num, sizeof(*iface));
for (j = 0; j < pod->i_num; j++) {
int i_if;
iface = &pod->iface[j];
i++;
if (toks[i].type != JSMN_OBJECT) {
fprintf(stdout, "network array need object\n");
return -1;
}
next_if = toks[i].size;
for (i_if = 0; i_if < next_if; i_if++) {
i++;
if (json_token_streq(json, &toks[i], "device")) {
iface->device = strdup(json_token_str(json, &toks[++i]));
fprintf(stdout, "net device is %s\n", iface->device);
} else if (json_token_streq(json, &toks[i], "ipAddress")) {
iface->ipaddr = strdup(json_token_str(json, &toks[++i]));
fprintf(stdout, "net ipaddress is %s\n", iface->ipaddr);
} else if (json_token_streq(json, &toks[i], "netMask")) {
iface->mask = strdup(json_token_str(json, &toks[++i]));
fprintf(stdout, "net mask is %s\n", iface->mask);
}
}
}
return i;
}
static int hyper_parse_routes(struct hyper_pod *pod, char *json, jsmntok_t *toks)
{
int i = 1, j, next_rt;
struct hyper_route *rt;
if (toks[i].type != JSMN_ARRAY) {
fprintf(stdout, "routes need array\n");
return -1;
}
pod->r_num = toks[i].size;
fprintf(stdout, "network routes num %d\n", pod->r_num);
pod->rt = calloc(pod->r_num, sizeof(*rt));
for (j = 0; j < pod->r_num; j++) {
int i_rt;
rt = &pod->rt[j];
i++;
if (toks[i].type != JSMN_OBJECT) {
fprintf(stdout, "routes array need object\n");
return -1;
}
next_rt = toks[i].size;
for (i_rt = 0; i_rt < next_rt; i_rt++) {
i++;
if (json_token_streq(json, &toks[i], "dest")) {
rt->dst = strdup(json_token_str(json, &toks[++i]));
fprintf(stdout, "route %d dest is %s\n", j, rt->dst);
} else if (json_token_streq(json, &toks[i], "gateway")) {
rt->gw = strdup(json_token_str(json, &toks[++i]));
fprintf(stdout, "route %d gateway is %s\n", j, rt->gw);
} else if (json_token_streq(json, &toks[i], "device")) {
rt->device = strdup(json_token_str(json, &toks[++i]));
fprintf(stdout, "route %d device is %s\n", j, rt->device);
}
}
}
return i;
}
int hyper_parse_pod(struct hyper_pod *pod, char *json, int length)
{
int i, n, next = -1;
jsmn_parser p;
int toks_num = 100;
jsmntok_t *toks = NULL;
realloc:
toks = realloc(toks, toks_num * sizeof(jsmntok_t));
fprintf(stdout, "call hyper_start_pod, json %s, len %d\n", json, length);
jsmn_init(&p);
n = jsmn_parse(&p, json, length, toks, toks_num);
if (n < 0) {
fprintf(stdout, "jsmn parse failed, n is %d\n", n);
if (n == JSMN_ERROR_NOMEM) {
toks_num *= 2;
goto realloc;
}
goto out;
}
pod->policy = POLICY_NEVER;
fprintf(stdout, "jsmn parse successed, n is %d\n", n);
next = 0;
for (i = 0; i < n; i++) {
jsmntok_t *t = &toks[i];
fprintf(stdout, "token %d, type is %d, size is %d\n", i, t->type, t->size);
if (t->type != JSMN_STRING)
continue;
if (json_token_streq(json, t, "containers") && t->size == 1) {
next = hyper_parse_containers(pod, json, t);
if (next < 0)
goto out;
i += next;
} else if (json_token_streq(json, t, "interfaces") && t->size == 1) {
next = hyper_parse_interfaces(pod, json, t);
if (next < 0)
goto out;
i += next;
} else if (json_token_streq(json, t, "routes") && t->size == 1) {
next = hyper_parse_routes(pod, json, t);
if (next < 0)
goto out;
i += next;
} else if (json_token_streq(json, t, "socket") && t->size == 1) {
pod->channel = strdup(json_token_str(json, &toks[++i]));
fprintf(stdout, "channel is %s\n", pod->channel);
} else if (json_token_streq(json, t, "shareDir") && t->size == 1) {
pod->tag = strdup(json_token_str(json, &toks[++i]));
fprintf(stdout, "9p tag is %s\n", pod->tag);
} else if (json_token_streq(json, t, "hostname") && t->size == 1) {
pod->hostname = strdup(json_token_str(json, &toks[++i]));
fprintf(stdout, "hostname is %s\n", pod->hostname);
} else if (json_token_streq(json, t, "restartPolicy") && t->size == 1) {
i++;
if (json_token_streq(json, &toks[i], "always") && t->size == 1)
pod->policy = POLICY_ALWAYS;
else if (json_token_streq(json, &toks[i], "onFailure") && t->size == 1)
pod->policy = POLICY_ONFAILURE;
fprintf(stdout, "restartPolicy is %" PRIu8 "\n", pod->policy);
}
}
out:
free(toks);
return next;
}
int hyper_parse_winsize(struct hyper_win_size *ws, char *json, int length)
{
int i, n, ret = 0;
jsmn_parser p;
int toks_num = 10;
jsmntok_t *toks = NULL;
realloc:
toks = realloc(toks, toks_num * sizeof(jsmntok_t));
jsmn_init(&p);
n = jsmn_parse(&p, json, length, toks, toks_num);
if (n < 0) {
fprintf(stdout, "jsmn parse failed, n is %d\n", n);
if (n == JSMN_ERROR_NOMEM) {
toks_num *= 2;
goto realloc;
}
goto fail;
}
for (i = 0; i < n; i++) {
jsmntok_t *t = &toks[i];
if (t->type != JSMN_STRING)
continue;
if (i++ == n)
goto fail;
if (json_token_streq(json, t, "tty")) {
if (toks[i].type != JSMN_STRING)
goto fail;
ws->tty = strdup(json_token_str(json, &toks[i]));
} else if (json_token_streq(json, t, "seq")) {
if (toks[i].type != JSMN_PRIMITIVE)
goto fail;
ws->seq = json_token_ll(json, &toks[i]);
} else if (json_token_streq(json, t, "row")) {
if (toks[i].type != JSMN_PRIMITIVE)
goto fail;
ws->row = json_token_int(json, &toks[i]);
} else if (json_token_streq(json, t, "column")) {
if (toks[i].type != JSMN_PRIMITIVE)
goto fail;
ws->column = json_token_int(json, &toks[i]);
}
}
out:
free(toks);
return ret;
fail:
ret = -1;
goto out;
}
struct hyper_exec *hyper_parse_execcmd(char *json, int length)
{
int i, j, n, has_seq = 0;
struct hyper_exec *exec = NULL;
char **argv = NULL;
jsmn_parser p;
int toks_num = 10;
jsmntok_t *toks = NULL;
realloc:
toks = realloc(toks, toks_num * sizeof(jsmntok_t));
jsmn_init(&p);
n = jsmn_parse(&p, json, length, toks, toks_num);
if (n < 0) {
fprintf(stdout, "jsmn parse failed, n is %d\n", n);
if (n == JSMN_ERROR_NOMEM) {
toks_num *= 2;
goto realloc;
}
goto out;
}
exec = calloc(1, sizeof(*exec));
if (exec == NULL)
goto out;
INIT_LIST_HEAD(&exec->list);
for (i = 0, j = 0; i < n; i++) {
jsmntok_t *t = &toks[i];
if (t->type != JSMN_STRING)
continue;
if (json_token_streq(json, t, "container")) {
if (i++ == n)
goto fail;
exec->id = strdup(json_token_str(json, &toks[i]));
fprintf(stdout, "get container %s\n", exec->id);
} else if (json_token_streq(json, t, "seq")) {
if (i++ == n)
goto fail;
has_seq = 1;
exec->seq = json_token_ll(json, &toks[i]);
fprintf(stdout, "get seq %"PRIu64"\n", exec->seq);
} else if (json_token_streq(json, t, "cmd")) {
if (i++ == n)
goto fail;
if (toks[i].type != JSMN_ARRAY) {
fprintf(stdout, "execcmd need array\n");
goto fail;
}
exec->argc = toks[i].size;
argv = calloc(exec->argc + 1, sizeof(*argv));
argv[exec->argc] = NULL;
} else if (j < exec->argc) {
argv[j++] = strdup(json_token_str(json, &toks[i]));
fprintf(stdout, "argv %d, %s\n", j - 1, argv[j - 1]);
}
}
if (!has_seq) {
fprintf(stderr, "execcmd format error, has no seq\n");
goto fail;
}
exec->argv = argv;
out:
free(toks);
return exec;
fail:
free(exec->id);
for (i = 0; i < exec->argc; i++)
free(argv[i]);
free(exec->argv);
free(exec);
exec = NULL;
goto out;
}
+13
View File
@@ -0,0 +1,13 @@
#ifndef _DVM_JSON_H_
#define _DVM_JSON_H_
#include "hyper.h"
#include "jsmn.h"
int hyper_parse_pod(struct hyper_pod *pod, char *json, int length);
struct hyper_exec *hyper_parse_execcmd(char *json, int length);
char *json_token_str(char *js, jsmntok_t *t);
int json_token_streq(char *js, jsmntok_t *t, char *s);
int hyper_parse_winsize(struct hyper_win_size *ws, char *json, int length);
#endif
+300
View File
@@ -0,0 +1,300 @@
#include <sys/types.h>
#include <sys/stat.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <dirent.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <signal.h>
#include <ctype.h>
#include <mntent.h>
#include <sys/mount.h>
#include <sys/reboot.h>
#include <linux/reboot.h>
#include "net.h"
#include "util.h"
char *read_cmdline(void)
{
return NULL;
}
int hyper_mkdir(char *hyper_path)
{
struct stat st;
char *p, *path = strdup(hyper_path);
if (path == NULL) {
errno = ENOMEM;
return -1;
}
fprintf(stdout, "create directory %s\n", path);
if (stat(path, &st) >= 0) {
if (S_ISDIR(st.st_mode))
return 0;
errno = ENOTDIR;
return -1;
}
if (errno != ENOENT)
return -1;
p = strrchr(path, '/');
if (p == NULL) {
errno = EINVAL;
return -1;
}
if (p != path) {
*p = '\0';
if (hyper_mkdir(path) < 0)
return -1;
*p = '/';
}
if (mkdir(path, 0755) < 0 && errno != EEXIST)
return -1;
return 0;
}
int hyper_open_channel(char *channel, int mode)
{
struct dirent **list;
struct dirent *dir;
int fd = -1, i, num;
char path[256], name[128];
num = scandir("/sys/class/virtio-ports/", &list, NULL, NULL);
if (num < 0) {
perror("scan /sys/calss/virtio-ports/ failed");
return -1;
}
memset(path, 0, sizeof(path));
for (i = 0; i < num; i++) {
dir = list[i];
if (dir->d_name[0] == '.')
continue;
if (snprintf(path, sizeof(path), "/sys/class/virtio-ports/%s/name", dir->d_name) < 0) {
fprintf(stderr, "get channel device %s path failed\n", dir->d_name);
continue;
}
fd = open(path, O_RDONLY);
memset(name, 0, sizeof(name));
if (fd < 0 || read(fd, name, sizeof(name)) < 0)
continue;
close(fd);
fd = -1;
if (strncmp(name, channel, strlen(channel))) {
fprintf(stderr, "channel %s, directory %s\n", channel, name);
continue;
}
if (snprintf(path, sizeof(path), "/dev/%s", dir->d_name) < 0) {
fprintf(stderr, "get channel device %s path failed\n", dir->d_name);
continue;
}
fprintf(stdout, "open hyper channel %s\n", path);
fd = open(path, O_RDWR | O_CLOEXEC | mode);
if (fd < 0)
perror("fail to open channel deice");
break;
}
free(list);
return fd;
}
int hyper_open_serial_dev(char *tty)
{
int fd = open(tty, O_RDWR | O_CLOEXEC | O_NOCTTY);
if (fd < 0) {
perror("fail to open tty device");
return -1;
}
return fd;
}
int hyper_open_serial(char *tty)
{
char path[256];
memset(path, 0, sizeof(path));
if (snprintf(path, sizeof(path), "/dev/%s", tty) < 0) {
fprintf(stderr, "get channel device %s path failed\n", tty);
return -1;
}
fprintf(stdout, "open hyper tty %s\n", path);
return hyper_open_serial_dev(path);
}
int hyper_setfd_cloexec(int fd)
{
int flags = fcntl(fd, F_GETFD);
if (flags < 0) {
perror("fcntl F_GETFD failed");
return -1;
}
if (fcntl(fd, F_SETFD, flags | FD_CLOEXEC) < 0) {
perror("fcntl F_SETFD failed");
return -1;
}
return 0;
}
int hyper_setfd_block(int fd)
{
int flags = fcntl(fd, F_GETFL);
if (flags < 0) {
perror("fcntl F_GETFL failed");
return -1;
}
if (fcntl(fd, F_SETFL, flags & ~O_NONBLOCK) < 0) {
perror("fcntl F_SETFD failed");
return -1;
}
return 0;
}
int hyper_setfd_nonblock(int fd)
{
int flags = fcntl(fd, F_GETFL);
if (flags < 0) {
perror("fcntl F_GETFL failed");
return -1;
}
if (fcntl(fd, F_SETFL, flags | O_NONBLOCK) < 0) {
perror("fcntl F_SETFD failed");
return -1;
}
return 0;
}
void hyper_unmount_all(void)
{
FILE *mtab;
struct mntent *mnt;
char *mntlist[128];
int i, n = 0;
char *filesys;
mtab = setmntent("/proc/mounts", "r");
if (mtab == NULL) {
fprintf(stderr, "cannot open /proc/mount");
return;
}
while (n < 128) {
mnt = getmntent(mtab);
if (mnt == NULL)
break;
if (strcmp(mnt->mnt_type, "devtmpfs") == 0 ||
strcmp(mnt->mnt_type, "proc") == 0 ||
strcmp(mnt->mnt_type, "sysfs") == 0 ||
strcmp(mnt->mnt_type, "ramfs") == 0 ||
strcmp(mnt->mnt_type, "tmpfs") == 0 ||
strcmp(mnt->mnt_type, "rootfs") == 0 ||
strcmp(mnt->mnt_type, "devpts") == 0)
continue;
mntlist[n++] = strdup(mnt->mnt_dir);
}
endmntent(mtab);
for (i = n - 1; i >= 0; i--) {
filesys = mntlist[i];
fprintf(stdout, "umount %s\n", filesys);
if ((umount(mntlist[i]) < 0) && (umount2(mntlist[i], MNT_DETACH) < 0)) {
fprintf(stdout, ("umount %s: %s failed\n"),
filesys, strerror(errno));
}
}
sync();
}
void hyper_kill_all(void)
{
int npids = 0;
int index = 0;
int pid;
DIR *dp;
struct dirent *de;
pid_t *pids = NULL;
dp = opendir("/proc");
if (dp == NULL)
return;
while ((de = readdir(dp)) && de != NULL) {
if (!isdigit(de->d_name[0]))
continue;
pid = atoi(de->d_name);
if (pid == 1)
continue;
if (index <= npids) {
pids = realloc(pids, npids + 16384);
if (pids == NULL)
return;
npids += 16384;
}
pids[index++] = pid;
}
fprintf(stdout, "Sending SIGTERM\n");
for (--index; index >= 0; --index) {
fprintf(stdout, "kill process %d\n", pids[index]);
kill(pids[index], SIGTERM);
}
free(pids);
closedir(dp);
}
void hyper_shutdown(struct hyper_pod *pod)
{
int i;
uint8_t *data = calloc(pod->c_num, 4);
for (i = 0; i < pod->c_num; i++)
hyper_set_be32(data + (i * 4), pod->c[i].exec.code);
hyper_send_msg(ctl.chan.fd, FINISH, pod->c_num * 4, data);
hyper_unmount_all();
hyper_kill_all();
reboot(LINUX_REBOOT_CMD_POWER_OFF);
}
+17
View File
@@ -0,0 +1,17 @@
#ifndef _UTIL_H_
#define _UTIL_H_
#include "hyper.h"
char *read_cmdline(void);
int hyper_mkdir(char *path);
int hyper_open_channel(char *channel, int mode);
int hyper_open_serial_dev(char *tty);
int hyper_open_serial(char *tty);
int hyper_setfd_cloexec(int fd);
int hyper_setfd_block(int fd);
int hyper_setfd_nonblock(int fd);
void hyper_shutdown(struct hyper_pod *pod);
void hyper_kill_all(void);
void hyper_unmount_all(void);
#endif