mirror of
https://github.com/clearlinux/hyperstart.git
synced 2026-08-18 20:05:48 +00:00
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:
+37
@@ -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
|
||||
@@ -0,0 +1 @@
|
||||
SUBDIRS=src build
|
||||
@@ -0,0 +1,2 @@
|
||||
The init task for hyper.
|
||||
exec ./autogen.sh to compile hyperinit
|
||||
Executable
+64
@@ -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
|
||||
@@ -0,0 +1,4 @@
|
||||
bin_PROGRAMS=hyper_daemon
|
||||
hyper_daemon_SOURCES=hyper_daemon.c ../src/net.c
|
||||
all-local:
|
||||
bash ./make-initrd.sh
|
||||
@@ -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;
|
||||
}
|
||||
Binary file not shown.
+1691
File diff suppressed because it is too large
Load Diff
Executable
+21
@@ -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
|
||||
@@ -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}
|
||||
])
|
||||
@@ -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
@@ -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;
|
||||
}
|
||||
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
File diff suppressed because it is too large
Load Diff
+321
@@ -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
@@ -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
@@ -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
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
|
||||
Reference in New Issue
Block a user