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 INIT(RTLD_NEXT, execv);
74 //INIT(RTLD_NEXT, open);
76 is_initialized = true;
82 char *env = getenv("LD_PRELOAD");
85 // the const <-> non-const assignment is not an issue since the following modifying operations
86 // will not be executed in the const-case
88 pos = strstr(env, LIBNAME);
91 char *end_pos = pos + sizeof(LIBNAME);
92 bool is_end = (end_pos[-1]=='\0');
96 start_pos = strrchr(env, ':');
97 if (start_pos==0) start_pos = env;
98 else if (!is_end) ++start_pos;
100 if (is_end) *start_pos = '\0';
101 else memmove(start_pos, end_pos, strlen(end_pos)+1);
105 printf("env='%s'\n", env);
108 if (*env=='\0') unsetenv("LD_PRELOAD");
112 execvWorker(char const *path, char * const argv[])
117 ctx = getAndClearEnv("RPM_FAKE_CTX", -1);
118 if ( (res=vc_new_s_context(ctx,
119 getAndClearEnv("RPM_FAKE_CAP", ~0x3404040f),
120 getAndClearEnv("RPM_FAKE_FLAGS", 0)))!=-1 &&
121 (res=execv_func(path, argv)!=-1) ) {}
134 removeNamespaceMountsChild(void *params_v)
136 struct ExecvParams * params = params_v;
137 char buf[strlen(params->mnts)+1], *ptr;
139 strcpy(buf, params->mnts);
140 ptr = strtok(buf, ":");
142 if (umount2(ptr, 0)==-1) {
143 // FIXME: What is the semantic for CLONE_NEWNS? Is it ok that mounts in
144 // chroots are visible only, when chroot is on /dev/root?
146 // For now, ignore any errors, but future versions should handle them.
150 ptr = strtok(0, ":");
153 unsetenv("RPM_FAKE_NAMESPACE_MOUNTS");
154 return execvWorker(params->path, params->argv);
158 removeNamespaceMounts(char const *path, char * const argv[])
160 char const * mnts = getenv("RPM_FAKE_NAMESPACE_MOUNTS");
162 if (mnts==0) return execvWorker(path, argv);
165 char buf[512 + 2*strlen(mnts)];
168 struct ExecvParams params = {
174 // the rpmlib signal-handler is still active; use the default one to
175 // make wait4() working...
176 signal(SIGCHLD, SIG_DFL);
178 pid_t pid = clone(removeNamespaceMountsChild, buf+sizeof(buf)/2,
179 CLONE_NEWNS|SIGCHLD|CLONE_VFORK, ¶ms);
181 if (pid==-1) return -1;
182 while ((p=wait4(pid, &status, 0,0))==-1 &&
183 (errno==EINTR || errno==EAGAIN)) ;
185 if (p==-1) return -1;
187 if (WIFEXITED(status)) exit(WEXITSTATUS(status));
188 if (WIFSIGNALED(status)) kill(getpid(), WTERMSIG(status));
195 execv(char const *path, char * const argv[]) __THROW
199 return removeNamespaceMounts(path, argv);