gentoo: use /var/run for new /run compatibility
[util-vserver.git] / src / vcontext.c
index 6cb76ef..b0923d5 100644 (file)
@@ -1,16 +1,16 @@
 // $Id$    --*- c -*--
 
 // Copyright (C) 2004-2006 Enrico Scholz <enrico.scholz@informatik.tu-chemnitz.de>
-//  
+//
 // This program is free software; you can redistribute it and/or modify
 // it under the terms of the GNU General Public License as published by
 // the Free Software Foundation; version 2 of the License.
-//  
+//
 // This program is distributed in the hope that it will be useful,
 // but WITHOUT ANY WARRANTY; without even the implied warranty of
 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 // GNU General Public License for more details.
-//  
+//
 // You should have received a copy of the GNU General Public License
 // along with this program; if not, write to the Free Software
 // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 #endif
 
 #include "util.h"
+#include "compat-pivot_root.h"
 #include "lib/internal.h"
 #include "lib_internal/jail.h"
 #include "lib_internal/sys_personality.h"
+#include "lib_internal/sys_unshare.h"
 
 #include <vserver.h>
 #include <getopt.h>
@@ -36,6 +38,7 @@
 #include <sys/types.h>
 #include <pwd.h>
 #include <grp.h>
+#include <sys/mount.h>
 
 #include <linux/personality.h>
 
 #define CMD_PERSTYPE           0x400e
 #define CMD_PERSFLAG           0x400f
 #define CMD_VLOGIN             0x4010
+#define CMD_PIVOT_ROOT         0x4011
+#define CMD_CLOSE_FD           0x4012
+
+
+#ifndef MNT_DETACH
+#define MNT_DETACH             0x0002
+#endif
 
 
 struct option const
@@ -90,9 +100,11 @@ CMDLINE_OPTIONS[] = {
   { "personality-type",  required_argument, 0, CMD_PERSTYPE },
   { "personality-flags", required_argument, 0, CMD_PERSFLAG },
   { "vlogin",       no_argument,        0, CMD_VLOGIN },
-#if 1  
+  { "pivot-root",   no_argument,        0, CMD_PIVOT_ROOT },
+  { "closefd",      no_argument,        0, CMD_CLOSE_FD },
+#if 1
   { "fakeinit",     no_argument,               0, CMD_INITPID },       // compatibility
-#endif  
+#endif
   { 0,0,0,0 },
 };
 
@@ -110,6 +122,8 @@ struct Arguments {
     uint_least32_t     personality_type;
     int                        verbosity;
     bool               do_chroot;
+    bool               do_pivot_root;
+    bool               do_close_fd;
     char const *       uid;
     xid_t              xid;
     char const *       sync_sock;
@@ -154,6 +168,7 @@ showHelp(int fd, char const *cmd, int res)
            "                    ...  use <message> as synchronization message; by\n"
            "                         default, 'ok' will be used\n"
            "    --vlogin        ...  enable terminal proxy\n"
+           "    --closefd       ...  close all open file descriptors >2\n"
            "\n"
            "'vcontext --create' exits with code 254 iff the context exists already.\n"
            "\n"
@@ -195,7 +210,7 @@ connectExternalSync(char const *filename)
 {
   int                  fd;
   struct sockaddr_un   addr;
-  
+
   if (filename==0) return -1;
 
   ENSC_INIT_UNIX_SOCK(addr, filename);
@@ -227,7 +242,7 @@ static void
 doExternalSync(int fd, char const *msg)
 {
   char         c;
-  
+
   if (fd==-1) return;
 
   if (msg) EsendAll(fd, msg, strlen(msg));
@@ -246,23 +261,32 @@ doit(struct Arguments const *args, int argc, char *argv[])
 {
   int                  p[2][2];
   pid_t                        pid = initSync(p, args->do_disconnect);
-  
+
   if (pid==0) {
     xid_t                      xid;
     int                                ext_sync_fd = connectExternalSync(args->sync_sock);
 
-    doSyncStage0(p, args->do_disconnect);  
-    
+    doSyncStage0(p, args->do_disconnect);
+
+    if (args->do_close_fd) {
+      int fd;
+      for (fd = 3; fd < sysconf(_SC_OPEN_MAX); fd++) {
+       if (fd == ext_sync_fd)
+         continue;
+       close(fd);
+      }
+    }
+
     if (args->do_create) {
-      xid = vc_ctx_create(args->xid);
+      xid = vc_ctx_create(args->xid, NULL);
       if (xid==VC_NOCTX) {
        switch (errno) {
          case EEXIST   :
            if (!args->is_silentexist)
-             perror(ENSC_WRAPPERS_PREFIX "vc_create_context()");
+             perror(ENSC_WRAPPERS_PREFIX "vc_ctx_create()");
            return 254;
          default       :
-           perror(ENSC_WRAPPERS_PREFIX "vc_create_context()");
+           perror(ENSC_WRAPPERS_PREFIX "vc_ctx_create()");
            return wrapper_exit_code;
        }
       }
@@ -274,15 +298,45 @@ doit(struct Arguments const *args, int argc, char *argv[])
     if (args->do_chroot) {
       Echroot(".");
       if (args->set_namespace) {
-       if (args->do_migrateself)  Evc_set_namespace();
-       else if (args->do_migrate) Evc_enter_namespace(xid);
+       if (args->do_migrateself)  Evc_set_namespace(xid, CLONE_NEWNS|CLONE_FS, 0);
+       else if (args->do_migrate) Evc_enter_namespace(xid, CLONE_NEWNS|CLONE_FS, 0);
+      }
+    }
+    else if (args->do_pivot_root) {
+      if (vc_enter_namespace(xid, CLONE_NEWNS | CLONE_FS, 1) == -1) {
+       bool existed = false;
+       if (sys_unshare(CLONE_NEWNS) == -1) {
+         perror(ENSC_WRAPPERS_PREFIX "unshare(NEWNS)");
+         return wrapper_exit_code;
+       }
+       if (mkdir("./.oldroot", 0700) == -1) {
+         if (errno == EEXIST)
+           existed = true;
+         else {
+           perror(ENSC_WRAPPERS_PREFIX "mkdir()");
+           return wrapper_exit_code;
+         }
+       }
+       if (pivot_root(".", "./.oldroot") == -1) {
+         perror(ENSC_WRAPPERS_PREFIX "pivot_root()");
+         return wrapper_exit_code;
+       }
+       if (umount2("/.oldroot", MNT_DETACH) == -1) {
+         perror(ENSC_WRAPPERS_PREFIX "umount2()");
+         return wrapper_exit_code;
+       }
+       if (!existed && rmdir("/.oldroot") == -1) {
+         perror(ENSC_WRAPPERS_PREFIX "rmdir()");
+         return wrapper_exit_code;
+       }
+       Evc_set_namespace(xid, CLONE_NEWNS | CLONE_FS, 1);
       }
     }
 
     setFlags(args, xid);
 
     if (args->do_migrate && !args->do_migrateself)
-      Evc_ctx_migrate(xid);
+      Evc_ctx_migrate(xid, 0);
 
     if (args->uid != NULL) {
       uid_t uid = 0;
@@ -327,6 +381,7 @@ doit(struct Arguments const *args, int argc, char *argv[])
     doExternalSync(ext_sync_fd, args->sync_msg);
     doSyncStage1(p, args->do_disconnect);
     DPRINTF("doit: pid=%u, ppid=%u\n", getpid(), getppid());
+
     if (!args->do_vlogin)
       execvp (argv[optind],argv+optind);
     else
@@ -338,7 +393,7 @@ doit(struct Arguments const *args, int argc, char *argv[])
   }
 
   assert(args->do_disconnect);
-    
+
   waitOnSync(pid, p, args->xid!=VC_DYNAMIC_XID && args->do_migrate);
   return EXIT_SUCCESS;
 }
@@ -380,6 +435,7 @@ int main (int argc, char *argv[])
     .do_disconnect     = false,
     .do_endsetup       = false,
     .do_vlogin         = false,
+    .do_close_fd       = false,
     .is_initpid        = false,
     .is_silentexist    = false,
     .set_namespace     = false,
@@ -390,11 +446,11 @@ int main (int argc, char *argv[])
     .personality_flags = 0,
     .sync_msg          = "ok",
   };
-  
+
   while (1) {
     int                c = getopt_long(argc, argv, "+", CMDLINE_OPTIONS, 0);
     if (c==-1) break;
-    
+
     switch (c) {
       case CMD_HELP            :  showHelp(1, argv[0], 0);
       case CMD_VERSION         :  showVersion();
@@ -405,8 +461,10 @@ int main (int argc, char *argv[])
       case CMD_VLOGIN          :  args.do_vlogin      = true;   break;
       case CMD_INITPID         :  args.is_initpid     = true;   break;
       case CMD_CHROOT          :  args.do_chroot      = true;   break;
+      case CMD_PIVOT_ROOT      :  args.do_pivot_root  = true;   break;
       case CMD_NAMESPACE       :  args.set_namespace  = true;   break;
       case CMD_SILENTEXIST     :  args.is_silentexist = true;   break;
+      case CMD_CLOSE_FD                :  args.do_close_fd    = true;   break;
       case CMD_SYNCSOCK                :  args.sync_sock      = optarg; break;
       case CMD_SYNCMSG         :  args.sync_msg       = optarg; break;
       case CMD_UID             :  args.uid            = optarg; break;
@@ -433,10 +491,10 @@ int main (int argc, char *argv[])
   }
 
   signal(SIGCHLD, SIG_DFL);
-  
+
   if (args.do_migrateself)
     args.xid = Evc_get_task_xid(0);
-  
+
   if (!args.do_create && !args.do_migrate)
     WRITE_MSG(2, "Neither '--create' nor '--migrate' specified; try '--help' for more information\n");
   else if (args.do_create  &&  args.do_migrate)