use '$CONFDIR/.defaults/run.rev' instead of '$PKGSTATEREVDIR'
[util-vserver.git] / util-vserver / src / rpm-fake.c
index ffd26ef..71706f2 100644 (file)
@@ -19,6 +19,9 @@
 #ifdef HAVE_CONFIG_H
 #  include <config.h>
 #endif
+#include "compat.h"
+
+#include <vserver.h>
 
 #include <dlfcn.h>
 #include <stdlib.h>
@@ -28,7 +31,6 @@
 #include <string.h>
 #include <stdbool.h>
 #include <errno.h>
-#include <asm/unistd.h>
 #include <fcntl.h>
 #include <stdarg.h>
 #include <sys/mount.h>
 #include <sys/types.h>
 #include <sys/wait.h>
 
+#ifndef CLONE_NEWNS
+#  define CLONE_NEWNS  0x00020000
+#endif
+
 #define LIBNAME                "rpm-fake.so"
 #define PLATFORM_FILE  "/etc/rpm/platform"
 
-#define INIT(FILE,FUNC)        FUNC##_func = dlsym(FILE, #FUNC)
+#define INIT(FILE,FUNC)        FUNC##_func = ((__typeof__(FUNC) *) (dlsym(FILE, #FUNC)))
 #define DECLARE(FUNC)  static __typeof__(FUNC) *       FUNC##_func = 0
 
 static bool            is_initialized = false;
 DECLARE(execv);
   //DECLARE(open);
 
-static int def_NR_new_s_context = 259;
-#undef __NR_new_s_context
-static int __NR_new_s_context_rev0;
-static int __NR_new_s_context_rev1;
-
-static int new_s_context_rev0(int, int, int);
-static int new_s_context_rev1(int, int *, int, int);
-
-_syscall3(int, new_s_context_rev0, int, newctx,              int, remove_cap, int, flags)
-_syscall4(int, new_s_context_rev1, int, nbctx,  int *, ctxs, int, remove_cap, int, flags)
-
-static int
-new_s_context(int rev,
-             int nbctx,  int *ctxs, int remove_cap, int flags)
-{
-  int          ret;
-  
-  switch (rev) {
-    case 0     :
-    {
-      int      ctx;
-      
-      switch (nbctx) {
-       case 0  :  ctx = -1;      break;
-       case 1  :  ctx = ctxs[0]; break;
-       default :  errno = EINVAL; return -1;
-      }
-
-      ret = new_s_context_rev0(ctx, remove_cap, flags);
-
-      break;
-    }
-
-    case 1     :
-      ret = new_s_context_rev1(nbctx, ctxs, remove_cap, flags);
-      break;
-
-    default    :
-      errno = EINVAL; return -1;
-  }
-
-  return ret;
-}
-
-static void
-initVserverSyscalls(int s_context_NR)
-{
-  int  nr = (s_context_NR!=-1) ? s_context_NR : def_NR_new_s_context;
-
-  __NR_new_s_context_rev0 = __NR_new_s_context_rev1 = nr;
-}
-
 static int
 getAndClearEnv(char const *key, int dflt)
 {
-  char *env = getenv(key);
+  char         *env = getenv(key);
   int          res;
 
   if (env==0 || env[0]=='\0') res = dflt;
@@ -120,7 +74,19 @@ initLib()
 {
   if (is_initialized) return;
 
-  initVserverSyscalls(getAndClearEnv("RPM_FAKE_S_CONTEXT_NR", -1));
+#ifdef VC_ENABLE_API_LEGACY
+  {
+    extern void vc_init_internal_legacy(int ctx_rev, int ctx_number,
+                                       int ipv4_rev, int ipv4_number);
+  
+    vc_init_internal_legacy(getAndClearEnv("RPM_FAKE_S_CONTEXT_REV", 0),
+                           getAndClearEnv("RPM_FAKE_S_CONTEXT_NR",  280),
+                           3, 281);
+  }
+#else
+  (void)getAndClearEnv("RPM_FAKE_S_CONTEXT_REV", 0);
+  (void)getAndClearEnv("RPM_FAKE_S_CONTEXT_NR",  280);
+#endif  
   INIT(RTLD_NEXT, execv);
     //INIT(RTLD_NEXT, open);
 
@@ -142,7 +108,7 @@ fixPreloadEnv()
     char       *end_pos = pos + sizeof(LIBNAME);
     bool       is_end = (end_pos[-1]=='\0');
     char       *start_pos;
-    
+
     end_pos[-1] = '\0';
     start_pos   = strrchr(env, ':');
     if (start_pos==0) start_pos = env;
@@ -165,15 +131,11 @@ execvWorker(char const *path, char * const argv[])
   int          res;
   int          ctx;
 
-  printf("+execvWorker\n");
   ctx = getAndClearEnv("RPM_FAKE_CTX",  -1);
-  if ( (res=new_s_context(getAndClearEnv("RPM_FAKE_S_CONTEXT_REV", 0),
-                         ctx==-1 ? 0 : 1,
-                         &ctx,
-                         getAndClearEnv("RPM_FAKE_CAP",  ~0x3404040f),
-                         getAndClearEnv("RPM_FAKE_FLAGS", 0)))!=-1 &&
+  if ( (res=vc_new_s_context(ctx,
+                            getAndClearEnv("RPM_FAKE_CAP",  ~0x3404040f),
+                            getAndClearEnv("RPM_FAKE_FLAGS", 0)))!=-1 &&
        (res=execv_func(path, argv)!=-1) ) {}
-  printf("-execvWorker -> res=%u, err=%s\n",res,strerror(errno));
 
   return res;
 }
@@ -194,10 +156,14 @@ removeNamespaceMountsChild(void *params_v)
   strcpy(buf, params->mnts);
   ptr = strtok(buf, ":");
   while (ptr) {
-    system("cat /proc/mounts");
-    system("pstree -h");
-    system("ls -l /proc/self/ /proc/self/fd/ /var/lib /var/lib/rpm/");
-    if (umount2(ptr, 0)==-1) { dprintf(2, "ptr='%s' -> ", ptr); perror("umount2()"); return -1; }
+    if (umount2(ptr, 0)==-1) {
+       // FIXME: What is the semantic for CLONE_NEWNS? Is it ok that mounts in
+       // chroots are visible only, when chroot is on /dev/root?
+       //
+       // For now, ignore any errors, but future versions should handle them.
+
+       //return -1;
+    }
     ptr = strtok(0, ":");
   }
 
@@ -210,37 +176,30 @@ removeNamespaceMounts(char const *path, char * const argv[])
 {
   char const * mnts = getenv("RPM_FAKE_NAMESPACE_MOUNTS");
 
-  printf("mnts='%s'\n", mnts);
   if (mnts==0) return execvWorker(path, argv);
 
   {
-    printf("l=%u\n", __LINE__);
-    char       buf[512 + 2*strlen(mnts)];
-    int                status;
-    pid_t      p;
-    struct ExecvParams         params = {
-      .path = path,
-      .argv = argv,
-      .mnts = mnts,
-    };
-    
-    printf("l=%u\n", __LINE__);
-
-    
-    system("mount -t proc none /proc");
-    system("cat /proc/mounts");
-      //system("pstree -h");
-    system("ls -l /proc/self/ /proc/self/fd/ /var/lib /var/lib/rpm/");
-    pid_t      pid = clone(removeNamespaceMountsChild, buf+sizeof(buf)/2,
-                           CLONE_NEWNS|SIGCHLD|CLONE_VFORK, &params);
-
-    printf("l=%u\n", __LINE__);
+    char                       buf[512 + 2*strlen(mnts)];
+    int                                status;
+    pid_t                      p, pid;
+    struct ExecvParams         params;
+
+    params.path = path;
+    params.argv = argv;
+    params.mnts = mnts;
+
+      // the rpmlib signal-handler is still active; use the default one to
+      // make wait4() working...
+    signal(SIGCHLD, SIG_DFL);
+
+    pid = clone(removeNamespaceMountsChild, buf+sizeof(buf)/2,
+               CLONE_NEWNS|SIGCHLD|CLONE_VFORK, &params);
+
     if (pid==-1) return -1;
-    while ((p=waitpid(pid, &status, 0))==-1 &&
+    while ((p=wait4(pid, &status, 0,0))==-1 &&
           (errno==EINTR || errno==EAGAIN)) ;
-    if (p==-1)   return -1;
 
-    printf("removeNamespaceMountsChild() -> status=%u\n", status);
+    if (p==-1)   return -1;
 
     if (WIFEXITED(status))   exit(WEXITSTATUS(status));
     if (WIFSIGNALED(status)) kill(getpid(), WTERMSIG(status));