From: Sapan Bhatia Date: Tue, 27 Jan 2009 15:54:32 +0000 (+0000) Subject: Support scripts for Trellis X-Git-Url: http://git.onelab.eu/?p=linux-2.6.git;a=commitdiff_plain;h=fbd84cf4cc33611563712b0bb2bfbb02bc5c76e4 Support scripts for Trellis --- diff --git a/support/chpid.c b/support/chpid.c new file mode 100644 index 000000000..ccc06cdd5 --- /dev/null +++ b/support/chpid.c @@ -0,0 +1,475 @@ +/* gcc -Wall -O2 -g chpid.c -o chpid */ +#define _XOPEN_SOURCE +#define _XOPEN_SOURCE_EXTENDED +#define _SVID_SOURCE +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifndef MNT_FORCE +#define MNT_FORCE 0x00000001 /* Attempt to forcibily umount */ +#endif /* MNT_FORCE */ +#ifndef MNT_DETACH +#define MNT_DETACH 0x00000002 /* Just detach from the tree */ +#endif /* MNT_DETACH */ +#ifndef MNT_EXPIRE +#define MNT_EXPIRE 0x00000004 /* Mark for expiry */ +#endif /* MNT_EXPIRE */ + +#ifndef MS_MOVE +#define MS_MOVE 8192 +#endif +#ifndef MS_REC +#define MS_REC 16384 +#endif + +#ifdef OLD +# ifndef CLONE_NPSPACE +# define CLONE_NPSPACE 0x04000000 /* New process space */ +# endif +# ifndef CLONE_NSYSVIPC +# define CLONE_NSYSVIPC 0x08000000 /* New sysvipc space */ +# endif +# ifndef CLONE_NHOST +# define CLONE_NHOST 0x10000000 /* New networking host context (lo, hostname, etc) */ +# endif +# ifndef CLONE_NDEV +# define CLONE_NDEV 0x20000000 /* New hash of devices I can touch */ +# endif +# ifndef CLONE_NUSERS +# define CLONE_NUSERS 0x40000000 /* New users */ +# endif +# ifndef CLONE_NTIME +# define CLONE_NTIME 0x80000000 /* New time context??? */ +# endif +# ifndef CLONE_NS_NOSUID +# define CLONE_NS_NOSUID 0x00001000 /* Force MNT_NOSUID on all mounts in the namespace */ +# endif +#endif + +#ifndef CLONE_NEWUTS +#define CLONE_NEWUTS 0x04000000 /* New uts namespace (uname) */ +#endif +#ifndef CLONE_NEWIPC +#define CLONE_NEWIPC 0x08000000 /* New sysvipc namespace */ +#endif +#ifndef CLONE_NEWUID +#define CLONE_NEWUID 0x10000000 /* New users */ +#endif +#ifndef CLONE_NEWNET +#define CLONE_NEWNET 0x40000000 /* New network namespace (lo, device, names sockets, etc) */ +#endif +#ifndef CLONE_NEWPID +#define CLONE_NEWPID 0x80000000 /* New process space */ +#endif +#ifndef CLONE_NEWTIME +#define CLONE_NEWTIME 0x40000000 /* New time context??? */ +#endif +#ifndef CLONE_NEWDEV +#define CLONE_NEWDEV 0x00001000 /* New has of devices I can touch */ +#endif + + +#ifndef PROC_SUPER_MAGIC +#define PROC_SUPER_MAGIC 0x9fa0 +#endif /* PROC_SUPER_MAGIC */ + +struct user_desc; +static pid_t raw_clone(int flags, void *child_stack, + int *parent_tidptr, struct user_desc *newtls, int *child_tidptr) +{ + return syscall(__NR_clone, flags, child_stack, parent_tidptr, newtls, child_tidptr); +} + +static int raw_pivot_root(const char *new_root, const char *old_root) +{ + return syscall(__NR_pivot_root, new_root, old_root); +} + +static void (*my_exit)(int status) = exit; + +static void die(char *fmt, ...) +{ + va_list ap; + va_start(ap, fmt); + vfprintf(stderr, fmt, ap); + va_end(ap); + fflush(stderr); + fflush(stdout); + my_exit(1); +} + +static void *xmalloc(size_t size) +{ + void *ptr; + ptr = malloc(size); + if (!ptr) die("malloc of %d bytes failed: %s\n", size, strerror(errno)); + return ptr; +} + +static void umount_buffer(char *line) +{ + char *next, *mnt, *end, *type; + int result; + if (!line || !*line) + return; + next = strchr(line, '\n'); + *next++ = '0'; + type = line; + mnt = strchr(line, ' '); + *mnt++ = '\0'; + end = strchr(mnt, ' '); + *end = '\0'; + umount_buffer(next); + +#if 0 + /* For debugging list what I am unounting */ + write(STDOUT_FILENO, mnt, strlen(mnt)); + write(STDOUT_FILENO, "\n", 1); +#endif + + if (strcmp(type, "rootfs")) + return; + result = umount2(mnt, MNT_DETACH); + if (result < 0) + die("umount of '%s' failed: %d: %s\n", + mnt, errno, strerror(errno)); +} + +static void umount_all(void) +{ + static const char mounts[] = "/proc/self/mounts"; + char *buf; + ssize_t bufsz, bytes; + int fd, result; + buf = NULL; + bufsz = 4096; + + /* Temporarily mount /proc at / so I know I have it */ + result = mount("proc", "/proc", "proc", 0, NULL); + if (result < 0) + die("mount of proc failed: %d: %s\n", + errno, strerror(errno)); +#if 0 + DIR *dir; + struct dirent *entry; + dir = opendir("/"); + while((entry = readdir(dir)) != NULL) { + write(STDOUT_FILENO, entry->d_name, strlen(entry->d_name)); + write(STDOUT_FILENO, "\n", 1); + } + closedir(dir); +#endif + fd = open(mounts, O_RDONLY); + if (fd < 0) + die("open of %s failed: %d: %s\n", + mounts, errno, strerror(errno)); + + /* Read in all of the mount points */ + do { + buf = xmalloc(bufsz); + result = lseek(fd, 0, SEEK_SET); + if (result != 0) + die("lseek failed: %d:%s\n", + errno, strerror(errno)); + bytes = read(fd, buf, bufsz); + if (bytes < 0) + die("Read of %s failed: %d:%s\n", + mounts, errno, strerror(errno)); + if (bytes != bufsz) { + /* Terminate the buffer */ + buf[bytes] = '\0'; + } else { + /* Free the buffer and try again */ + free(buf); + buf = NULL; + bufsz <<= 1; + } + } while(!buf); + /* Be good and close the file descriptor */ + result = close(fd); + if (result < 0) + fprintf(stderr, "close of %s failed: %d:%s\n", + mounts, errno, strerror(errno)); + +#if 0 + /* For debugging print the list of mounts */ + write(STDOUT_FILENO, buf, bufsz); + write(STDOUT_FILENO, "\n\n", 2); +#endif + + umount_buffer(buf); +} + +int main(int argc, char **argv, char **envp) +{ + pid_t pid; + int status; + struct rlimit rlim; + int clone_flags; + char **cmd_argv, *shell_argv[2]; + char *root = "/", *old = "/mnt"; + char *label = "none"; + int i; + int tty, tty_force; + + tty = 0; + tty_force = 0; + clone_flags = SIGCHLD; + + for (i = 1; (i < argc) && (argv[i][0] == '-'); i++) { + if (strcmp(argv[i], "--") == 0) { + break; + } + else if (((argc - i) >= 2) && (strcmp(argv[i], "-r") == 0)) { + clone_flags |= CLONE_NEWNS; + root = argv[i + 1]; + i++; + } + else if (((argc - i) >= 2) && (strcmp(argv[i], "-o") == 0)) { + old = argv[i + 1]; + i++; + } + else if (((argc - i) >= 2) && (strcmp(argv[i], "-l") == 0)) { + clone_flags |= CLONE_NEWNS; + label = argv[i + 1]; + i++; + } + else if (strcmp(argv[i], "-m") == 0) { + clone_flags |= CLONE_NEWNS; + } + else if (strcmp(argv[i], "-h") == 0) { + clone_flags |= CLONE_NEWUTS; + } + else if (strcmp(argv[i], "-i") == 0) { + clone_flags |= CLONE_NEWIPC; + } + else if (strcmp(argv[i], "-n") == 0) { + clone_flags |= CLONE_NEWNET; + } + else if (strcmp(argv[i], "-p") == 0) { + clone_flags |= CLONE_NEWPID; + } + else if (strcmp(argv[i], "-u") == 0) { + clone_flags |= CLONE_NEWUID; + } + else if (strcmp(argv[i], "-d") == 0) { + clone_flags |= CLONE_NEWDEV; + } + else if (strcmp(argv[i], "-t") == 0) { + clone_flags |= CLONE_NEWTIME; + } + else if (strcmp(argv[i], "--tty") == 0) { + tty = 1; + } + else if (strcmp(argv[i], "--tty-force") == 0) { + tty = 1; tty_force = 1; + } + else { + die("Bad argument %s\n", argv[i]); + } + } + cmd_argv = argv + i; + if (cmd_argv[0] == NULL) { + cmd_argv = shell_argv; + shell_argv[0] = getenv("SHELL"); + shell_argv[1] = NULL; + } + if (cmd_argv[0] == NULL) { + die("No command specified\n"); + } +#if 1 + fprintf(stderr, "cmd_argv: %s\n", cmd_argv[0]); +#endif + if (root[0] != '/') { + die("root path: '%s' not absolute\n", root); + } + if (old[0] != '/') { + die("old path: '%s' not absolute\n", old); + } + +#if 0 + status = getrlimit(RLIMIT_NPROC, &rlim); + if (status < 0) { + fprintf(stderr, "getrlimit RLIMIT_NPROC failed: %s\n", + strerror(errno)); + exit(1); + } + fprintf(stderr, "RLIMIT_NPROC: %llu %llu\n", + (unsigned long long)rlim.rlim_cur, (unsigned long long)rlim.rlim_max); +#endif +#if 0 + rlim.rlim_cur = 256; + status = setrlimit(RLIMIT_NPROC, &rlim); + if (status < 0) { + fprintf(stderr, "setrlimit RLIMIT_NPROC %lu %lu failed: %s\n", + (unsigned long)rlim.rlim_cur, (unsigned long)rlim.rlim_max, + strerror(errno)); + exit(2); + } +#endif + printf("Clone flags: %lx\n", clone_flags); + pid = raw_clone(clone_flags, NULL, NULL, NULL, NULL); + if (pid < 0) { + fprintf(stderr, "clone_failed: pid: %d %d:%s\n", + pid, errno, strerror(errno)); + exit(2); + } + if (pid == 0) { + /* In the child */ + int result; + my_exit = _exit; + + /* FIXME allocate a process inside for controlling the new process space */ + if (clone_flags & CLONE_NEWPID) { + fprintf(stderr, "pid: %d, ppid: %d pgrp: %d sid: %d\n", + getpid(), getppid(), getpgid(0), getsid(0)); + /* If CLONE_NEWPID isn't implemented exit */ + if (getpid() != 1) + die("CLONE_NEWPID not implemented\n"); + } + + if (clone_flags & CLONE_NEWNS) { + struct statfs stfs; +#if 0 + if (strcmp(root, "/") != 0) { + /* FIXME find a way to remove unreachable filesystems + * from the namespace. + */ + result = chdir(root); + if (result < 0) + die("chdir to '%s' failed: %d:%s\n", + root, errno, strerror(errno)); + /* Convert the current working directory into a mount point */ + result = mount(".", ".", NULL, MS_BIND | MS_REC, NULL); + if (result < 0) + die("bind of '%s' failed: %d: %s\n", + root, errno, strerror(errno)); + /* Update the current working directory */ + result = chdir(root); + if (result < 0) + die("chdir to '%s' failed: %d:%s\n", + ".", errno, strerror(errno)); + result = mount(".", "/", NULL, MS_MOVE, NULL); + if (result < 0) + die("mount of '%s' failed: %d:%s\n", + root, errno, strerror(errno)); + result = chroot("."); + if (result < 0) + die("chroot to '%s' failed: %d:%s\n", + root, errno, strerror(errno)); + } +#endif +#if 1 + if (strcmp(root, "/") != 0) { + char put_old[PATH_MAX]; + result = snprintf(put_old, sizeof(put_old), "%s%s", root, old); + if (result >= sizeof(put_old)) + die("path name to long\n"); + if (result < 0) + die("snprintf failed: %d:%s\n", + errno, strerror(errno)); + + /* Ensure I have a mount point at the directory I want to export */ + result = mount(root, root, NULL, MS_BIND | MS_REC, NULL); + if (result < 0) + die("bind of '%s' failed: %d:%s\n", + root, errno, strerror(errno)); + + /* Switch the mount points */ + result = raw_pivot_root(root, put_old); + if (result < 0) + die("pivot_root('%s', '%s') failed: %d:%s\n", + root, put_old, errno, strerror(errno)); + + /* Unmount all of the old mounts */ + result = umount2(old, MNT_DETACH); + if (result < 0) + die("umount2 of '%s' failed: %d:%s\n", + put_old, errno, strerror(errno)); + } +#endif + + result = statfs("/proc", &stfs); + if ((result == 0) && (stfs.f_type == PROC_SUPER_MAGIC)) { + printf ("Umounting proc\n"); + /* Unmount and remount proc so it reflects the new pid space */ + result = umount2("/proc", MNT_DETACH); + if (result < 0) + die("umount failed: %d:%s\n", errno, strerror(errno)); + + result = mount(label, "/proc", "proc", 0, NULL); + if (result < 0) + die("mount failed: %d:%s\n", + errno, strerror(errno)); + } + } + if (tty) { + pid_t sid, pgrp; + sid = setsid(); + if (sid < 0) + die("setsid failed: %d:%s\n", + errno, strerror(errno)); + fprintf(stderr, "pid: %d, ppid: %d pgrp: %d sid: %d\n", + getpid(), getppid(), getpgid(0), getsid(0)); + + result = ioctl(STDIN_FILENO, TIOCSCTTY, tty_force); + if (result < 0) + die("tiocsctty failed: %d:%s\n", + errno, strerror(errno)); + + pgrp = tcgetpgrp(STDIN_FILENO); + + fprintf(stderr, "pgrp: %d\n", pgrp); + + fprintf(stderr, "pid: %d, ppid: %d pgrp: %d sid: %d\n", + getpid(), getppid(), getpgid(0), getsid(0)); + + } + result = execve(cmd_argv[0], cmd_argv, envp); + die("execve of %s failed: %d:%s\n", + cmd_argv[0], errno, strerror(errno)); + } + /* In the parent */ + fprintf(stderr, "child pid: %d\n", pid); + pid = waitpid(pid, &status, 0); + fprintf(stderr, "pid: %d exited status: %d\n", + pid, status); + if (pid < 0) { + fprintf(stderr, "waitpid failed: %d %s\n", + errno, strerror(errno)); + exit(9); + } + if (pid == 0) { + fprintf(stderr, "waitpid returned no pid!\n"); + exit(10); + } + if (WIFEXITED(status)) { + fprintf(stderr, "pid: %d exited: %d\n", + pid, WEXITSTATUS(status)); + } + if (WIFSIGNALED(status)) { + fprintf(stderr, "pid: %d exited with a uncaught signal: %d %s\n", + pid, WTERMSIG(status), strsignal(WTERMSIG(status))); + } + if (WIFSTOPPED(status)) { + fprintf(stderr, "pid: %d stopped with signal: %d\n", + pid, WSTOPSIG(status)); + } + return 0; +} diff --git a/support/enter_admin.c b/support/enter_admin.c new file mode 100644 index 000000000..fdbfe2cdd --- /dev/null +++ b/support/enter_admin.c @@ -0,0 +1,88 @@ +/* enter_admin.c Vsys script to switch a vserver into admin mode in which it has access + * to the Internet. Install in /vsys and invoke as echo $$ > /vsys/enter_admin.in + * from within the slice. + * 3/21/2008 Sapan Bhatia + */ + +#include +#include +#include +#include +#include + +#ifndef CLONE_NEWNET +#define CLONE_NEWNET 0x40000000 /* New network namespace (lo, device, names sockets, etc) */ +#endif + +#define __NR_set_space 327 +#define PATHLEN 1024 + +int set_space(int pid, int id, int toggle, unsigned long unshare_flags) { + return syscall(__NR_set_space, pid, id, toggle, unshare_flags); +} + +int get_slice_xid(char *slice_name) { + char slicepath[PATHLEN]; + FILE *fp; + int xid; + snprintf(slicepath, sizeof(slicepath), "/etc/vservers/%s/context", + slice_name); + + if ((fp = fopen(slicepath, "r")) == NULL) { + printf("Could not open %s\n", slicepath); + return -1; + } + + if (fscanf(fp, "%d", &xid)==0) { + printf("Could not read ctx file\n"); + return -1; + } + + fclose (fp); + return xid; +} + +int verify_ownership(int pid, int arg_xid) { + char procpath[PATHLEN]; + FILE *fp; + int xid; + snprintf(procpath, sizeof(procpath), "/proc/%d/vinfo", pid); + + if ((fp = fopen(procpath, "r")) == NULL) { + printf("Could not open %s\n", procpath); + return -1; + } + + if (fscanf(fp, "XID: %d", &xid)==0) { + printf("Could not read ctx file\n"); + return -1; + } + + fclose (fp); + return (arg_xid==xid); + +} + +int main(int argc, char *argv[]) { + int xid; + int pid; + + if (argc < 1) { + printf("Slice name missing. Was I invoked by vsys?\n"); + exit(1); + } + + scanf("%d",&pid); + + if ((xid = get_slice_xid(argv[1]))==-1) { + printf("Could not get xid for slice %s\n",argv[1]); + exit(1); + } + + if (!verify_ownership(pid, xid)) { + printf("Does xid %d really own %d?\n",xid,pid); + exit(1); + } + + set_space(pid, xid, 0, CLONE_NEWNET); +} diff --git a/support/enter_topo.c b/support/enter_topo.c new file mode 100644 index 000000000..18cfdcb85 --- /dev/null +++ b/support/enter_topo.c @@ -0,0 +1,88 @@ +/* enter_topo.c Vsys script to switch a vserver into experiment mode in which it has access + * to the Topology. Install in /vsys and invoke as echo $$ > /vsys/enter_topo.in + * from within the slice. + * 3/21/2008 Sapan Bhatia + */ + +#include +#include +#include +#include +#include + +#ifndef CLONE_NEWNET +#define CLONE_NEWNET 0x40000000 /* New network namespace (lo, device, names sockets, etc) */ +#endif + +#define __NR_set_space 327 +#define PATHLEN 1024 + +int set_space(int pid, int id, int toggle, unsigned long unshare_flags) { + return syscall(__NR_set_space, pid, id, toggle, unshare_flags); +} + +int get_slice_xid(char *slice_name) { + char slicepath[PATHLEN]; + FILE *fp; + int xid; + snprintf(slicepath, sizeof(slicepath), "/etc/vservers/%s/context", + slice_name); + + if ((fp = fopen(slicepath, "r")) == NULL) { + printf("Could not open %s\n", slicepath); + return -1; + } + + if (fscanf(fp, "%d", &xid)==0) { + printf("Could not read ctx file\n"); + return -1; + } + + fclose (fp); + return xid; +} + +int verify_ownership(int pid, int arg_xid) { + char procpath[PATHLEN]; + FILE *fp; + int xid; + snprintf(procpath, sizeof(procpath), "/proc/%d/vinfo", pid); + + if ((fp = fopen(procpath, "r")) == NULL) { + printf("Could not open %s\n", procpath); + return -1; + } + + if (fscanf(fp, "XID: %d", &xid)==0) { + printf("Could not read ctx file\n"); + return -1; + } + + fclose (fp); + return (arg_xid==xid); + +} + +int main(int argc, char *argv[]) { + int xid; + int pid; + + if (argc < 1) { + printf("Slice name missing. Was I invoked by vsys?\n"); + exit(1); + } + + scanf("%d",&pid); + + if ((xid = get_slice_xid(argv[1]))==-1) { + printf("Could not get xid for slice %s\n",argv[1]); + exit(1); + } + + if (!verify_ownership(pid, xid)) { + printf("Does xid %d really own %d?\n",xid,pid); + exit(1); + } + + set_space(pid, xid, 1, CLONE_NEWNET); +}