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>
44 # define CLONE_NEWNS 0x00020000
47 #define LIBNAME "rpm-fake.so"
48 #define PLATFORM_FILE "/etc/rpm/platform"
50 #define INIT(FILE,FUNC) FUNC##_func = ((__typeof__(FUNC) *) (dlsym(FILE, #FUNC)))
51 #define DECLARE(FUNC) static __typeof__(FUNC) * FUNC##_func = 0
53 static bool is_initialized = false;
58 getAndClearEnv(char const *key, int dflt)
60 char *env = getenv(key);
63 if (env==0 || env[0]=='\0') res = dflt;
75 if (is_initialized) return;
77 #ifdef VC_ENABLE_API_LEGACY
79 extern void vc_init_internal_legacy(int ctx_rev, int ctx_number,
80 int ipv4_rev, int ipv4_number);
82 vc_init_internal_legacy(getAndClearEnv("RPM_FAKE_S_CONTEXT_REV", 0),
83 getAndClearEnv("RPM_FAKE_S_CONTEXT_NR", 280),
87 (void)getAndClearEnv("RPM_FAKE_S_CONTEXT_REV", 0);
88 (void)getAndClearEnv("RPM_FAKE_S_CONTEXT_NR", 280);
90 INIT(RTLD_NEXT, execv);
91 //INIT(RTLD_NEXT, open);
93 is_initialized = true;
99 char *env = getenv("LD_PRELOAD");
102 // the const <-> non-const assignment is not an issue since the following modifying operations
103 // will not be executed in the const-case
104 env = env ? env : "";
105 pos = strstr(env, LIBNAME);
108 char *end_pos = pos + sizeof(LIBNAME);
109 bool is_end = (end_pos[-1]=='\0');
113 start_pos = strrchr(env, ':');
114 if (start_pos==0) start_pos = env;
115 else if (!is_end) ++start_pos;
117 if (is_end) *start_pos = '\0';
118 else memmove(start_pos, end_pos, strlen(end_pos)+1);
122 printf("env='%s'\n", env);
125 if (*env=='\0') unsetenv("LD_PRELOAD");
129 execvWorker(char const *path, char * const argv[])
134 ctx = getAndClearEnv("RPM_FAKE_CTX", -1);
135 if ( (res=vc_new_s_context(ctx,
136 getAndClearEnv("RPM_FAKE_CAP", ~0x3404040f),
137 getAndClearEnv("RPM_FAKE_FLAGS", 0)))!=-1 &&
138 (res=execv_func(path, argv)!=-1) ) {}
151 removeNamespaceMountsChild(void *params_v)
153 struct ExecvParams * params = params_v;
154 char buf[strlen(params->mnts)+1], *ptr;
156 strcpy(buf, params->mnts);
157 ptr = strtok(buf, ":");
159 if (umount2(ptr, 0)==-1) {
160 // FIXME: What is the semantic for CLONE_NEWNS? Is it ok that mounts in
161 // chroots are visible only, when chroot is on /dev/root?
163 // For now, ignore any errors, but future versions should handle them.
167 ptr = strtok(0, ":");
170 unsetenv("RPM_FAKE_NAMESPACE_MOUNTS");
171 return execvWorker(params->path, params->argv);
175 removeNamespaceMounts(char const *path, char * const argv[])
177 char const * mnts = getenv("RPM_FAKE_NAMESPACE_MOUNTS");
179 if (mnts==0) return execvWorker(path, argv);
182 char buf[512 + 2*strlen(mnts)];
185 struct ExecvParams params;
191 // the rpmlib signal-handler is still active; use the default one to
192 // make wait4() working...
193 signal(SIGCHLD, SIG_DFL);
195 pid = clone(removeNamespaceMountsChild, buf+sizeof(buf)/2,
196 CLONE_NEWNS|SIGCHLD|CLONE_VFORK, ¶ms);
198 if (pid==-1) return -1;
199 while ((p=wait4(pid, &status, 0,0))==-1 &&
200 (errno==EINTR || errno==EAGAIN)) ;
202 if (p==-1) return -1;
204 if (WIFEXITED(status)) exit(WEXITSTATUS(status));
205 if (WIFSIGNALED(status)) kill(getpid(), WTERMSIG(status));
212 execv(char const *path, char * const argv[]) __THROW
216 return removeNamespaceMounts(path, argv);