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.
36 #include <sys/mount.h>
40 #include <sys/types.h>
43 #define LIBNAME "rpm-fake.so"
44 #define PLATFORM_FILE "/etc/rpm/platform"
46 #define INIT(FILE,FUNC) FUNC##_func = ((__typeof__(FUNC) *) (dlsym(FILE, #FUNC)))
47 #define DECLARE(FUNC) static __typeof__(FUNC) * FUNC##_func = 0
49 static bool is_initialized = false;
54 getAndClearEnv(char const *key, int dflt)
56 char *env = getenv(key);
59 if (env==0 || env[0]=='\0') res = dflt;
71 if (is_initialized) return;
73 #ifdef VC_ENABLE_API_LEGACY
75 extern void vc_init_internal_legacy(int ctx_rev, int ctx_number,
76 int ipv4_rev, int ipv4_number);
78 vc_init_internal_legacy(getAndClearEnv("RPM_FAKE_S_CONTEXT_REV", 0),
79 getAndClearEnv("RPM_FAKE_S_CONTEXT_NR", 280),
83 (void)getAndClearEnv("RPM_FAKE_S_CONTEXT_REV", 0);
84 (void)getAndClearEnv("RPM_FAKE_S_CONTEXT_NR", 280);
86 INIT(RTLD_NEXT, execv);
87 //INIT(RTLD_NEXT, open);
89 is_initialized = true;
95 char *env = getenv("LD_PRELOAD");
98 // the const <-> non-const assignment is not an issue since the following modifying operations
99 // will not be executed in the const-case
100 env = env ? env : "";
101 pos = strstr(env, LIBNAME);
104 char *end_pos = pos + sizeof(LIBNAME);
105 bool is_end = (end_pos[-1]=='\0');
109 start_pos = strrchr(env, ':');
110 if (start_pos==0) start_pos = env;
111 else if (!is_end) ++start_pos;
113 if (is_end) *start_pos = '\0';
114 else memmove(start_pos, end_pos, strlen(end_pos)+1);
118 printf("env='%s'\n", env);
121 if (*env=='\0') unsetenv("LD_PRELOAD");
125 execvWorker(char const *path, char * const argv[])
130 ctx = getAndClearEnv("RPM_FAKE_CTX", -1);
131 if ( (res=vc_new_s_context(ctx,
132 getAndClearEnv("RPM_FAKE_CAP", ~0x3404040f),
133 getAndClearEnv("RPM_FAKE_FLAGS", 0)))!=-1 &&
134 (res=execv_func(path, argv)!=-1) ) {}
147 removeNamespaceMountsChild(void *params_v)
149 struct ExecvParams * params = params_v;
150 char buf[strlen(params->mnts)+1], *ptr;
152 strcpy(buf, params->mnts);
153 ptr = strtok(buf, ":");
155 if (umount2(ptr, 0)==-1) {
156 // FIXME: What is the semantic for CLONE_NEWNS? Is it ok that mounts in
157 // chroots are visible only, when chroot is on /dev/root?
159 // For now, ignore any errors, but future versions should handle them.
163 ptr = strtok(0, ":");
166 unsetenv("RPM_FAKE_NAMESPACE_MOUNTS");
167 return execvWorker(params->path, params->argv);
171 removeNamespaceMounts(char const *path, char * const argv[])
173 char const * mnts = getenv("RPM_FAKE_NAMESPACE_MOUNTS");
175 if (mnts==0) return execvWorker(path, argv);
178 char buf[512 + 2*strlen(mnts)];
181 struct ExecvParams params = {
187 // the rpmlib signal-handler is still active; use the default one to
188 // make wait4() working...
189 signal(SIGCHLD, SIG_DFL);
191 pid_t pid = clone(removeNamespaceMountsChild, buf+sizeof(buf)/2,
192 CLONE_NEWNS|SIGCHLD|CLONE_VFORK, ¶ms);
194 if (pid==-1) return -1;
195 while ((p=wait4(pid, &status, 0,0))==-1 &&
196 (errno==EINTR || errno==EAGAIN)) ;
198 if (p==-1) return -1;
200 if (WIFEXITED(status)) exit(WEXITSTATUS(status));
201 if (WIFSIGNALED(status)) kill(getpid(), WTERMSIG(status));
208 execv(char const *path, char * const argv[]) __THROW
212 return removeNamespaceMounts(path, argv);