3 // Copyright (C) 2003 Enrico Scholz <enrico.scholz@informatik.tu-chemnitz.de>
5 // This program is free software; you can redistribute it and/or modify
6 // it under the terms of the GNU General Public License as published by
7 // the Free Software Foundation; version 2 of the License.
9 // This program is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 // GNU General Public License for more details.
14 // You should have received a copy of the GNU General Public License
15 // along with this program; if not, write to the Free Software
16 // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
31 #include <asm/unistd.h>
34 #include <sys/mount.h>
38 #include <sys/types.h>
41 #define LIBNAME "rpm-fake.so"
42 #define PLATFORM_FILE "/etc/rpm/platform"
44 #define INIT(FILE,FUNC) FUNC##_func = ((__typeof__(FUNC) *) (dlsym(FILE, #FUNC)))
45 #define DECLARE(FUNC) static __typeof__(FUNC) * FUNC##_func = 0
47 static bool is_initialized = false;
51 static int def_NR_new_s_context = 259;
52 #undef __NR_new_s_context
53 static int __NR_new_s_context_rev0;
54 static int __NR_new_s_context_rev1;
56 static int new_s_context_rev0(int, int, int);
57 static int new_s_context_rev1(int, int *, int, int);
59 _syscall3(int, new_s_context_rev0, int, newctx, int, remove_cap, int, flags)
60 _syscall4(int, new_s_context_rev1, int, nbctx, int *, ctxs, int, remove_cap, int, flags)
63 new_s_context(int rev,
64 int nbctx, int *ctxs, int remove_cap, int flags)
74 case 0 : ctx = -1; break;
75 case 1 : ctx = ctxs[0]; break;
76 default : errno = EINVAL; return -1;
79 ret = new_s_context_rev0(ctx, remove_cap, flags);
85 ret = new_s_context_rev1(nbctx, ctxs, remove_cap, flags);
89 errno = EINVAL; return -1;
96 initVserverSyscalls(int s_context_NR)
98 int nr = (s_context_NR!=-1) ? s_context_NR : def_NR_new_s_context;
100 __NR_new_s_context_rev0 = __NR_new_s_context_rev1 = nr;
104 getAndClearEnv(char const *key, int dflt)
106 char *env = getenv(key);
109 if (env==0 || env[0]=='\0') res = dflt;
121 if (is_initialized) return;
123 initVserverSyscalls(getAndClearEnv("RPM_FAKE_S_CONTEXT_NR", -1));
124 INIT(RTLD_NEXT, execv);
125 //INIT(RTLD_NEXT, open);
127 is_initialized = true;
133 char *env = getenv("LD_PRELOAD");
136 // the const <-> non-const assignment is not an issue since the following modifying operations
137 // will not be executed in the const-case
138 env = env ? env : "";
139 pos = strstr(env, LIBNAME);
142 char *end_pos = pos + sizeof(LIBNAME);
143 bool is_end = (end_pos[-1]=='\0');
147 start_pos = strrchr(env, ':');
148 if (start_pos==0) start_pos = env;
149 else if (!is_end) ++start_pos;
151 if (is_end) *start_pos = '\0';
152 else memmove(start_pos, end_pos, strlen(end_pos)+1);
156 printf("env='%s'\n", env);
159 if (*env=='\0') unsetenv("LD_PRELOAD");
163 execvWorker(char const *path, char * const argv[])
168 ctx = getAndClearEnv("RPM_FAKE_CTX", -1);
169 if ( (res=new_s_context(getAndClearEnv("RPM_FAKE_S_CONTEXT_REV", 0),
172 getAndClearEnv("RPM_FAKE_CAP", ~0x3404040f),
173 getAndClearEnv("RPM_FAKE_FLAGS", 0)))!=-1 &&
174 (res=execv_func(path, argv)!=-1) ) {}
187 removeNamespaceMountsChild(void *params_v)
189 struct ExecvParams * params = params_v;
190 char buf[strlen(params->mnts)+1], *ptr;
192 strcpy(buf, params->mnts);
193 ptr = strtok(buf, ":");
195 if (umount2(ptr, 0)==-1) {
196 // FIXME: What is the semantic for CLONE_NEWNS? Is it ok that mounts in
197 // chroots are visible only, when chroot is on /dev/root?
199 // For now, ignore any errors, but future versions should handle them.
203 ptr = strtok(0, ":");
206 unsetenv("RPM_FAKE_NAMESPACE_MOUNTS");
207 return execvWorker(params->path, params->argv);
211 removeNamespaceMounts(char const *path, char * const argv[])
213 char const * mnts = getenv("RPM_FAKE_NAMESPACE_MOUNTS");
215 if (mnts==0) return execvWorker(path, argv);
218 char buf[512 + 2*strlen(mnts)];
221 struct ExecvParams params = {
227 pid_t pid = clone(removeNamespaceMountsChild, buf+sizeof(buf)/2,
228 CLONE_NEWNS|SIGCHLD|CLONE_VFORK, ¶ms);
230 if (pid==-1) return -1;
231 while ((p=waitpid(pid, &status, 0))==-1 &&
232 (errno==EINTR || errno==EAGAIN)) ;
233 if (p==-1) return -1;
235 if (WIFEXITED(status)) exit(WEXITSTATUS(status));
236 if (WIFSIGNALED(status)) kill(getpid(), WTERMSIG(status));
243 execv(char const *path, char * const argv[]) __THROW
247 return removeNamespaceMounts(path, argv);