small signed/unsigned fixes for pedantic warning setups
[util-vserver.git] / util-vserver / src / rpm-fake.c
1 // $Id$    --*- c++ -*--
2
3 // Copyright (C) 2003 Enrico Scholz <enrico.scholz@informatik.tu-chemnitz.de>
4 //  
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.
8 //  
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.
13 //  
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.
17 //  
18
19 #ifdef HAVE_CONFIG_H
20 #  include <config.h>
21 #endif
22 #include "compat.h"
23
24 #include <vserver.h>
25
26 #include <dlfcn.h>
27 #include <stdlib.h>
28 #include <stdint.h>
29 #include <stdio.h>
30 #include <unistd.h>
31 #include <string.h>
32 #include <stdbool.h>
33 #include <errno.h>
34 #include <fcntl.h>
35 #include <stdarg.h>
36 #include <sys/mount.h>
37 #include <linux/fs.h>
38 #include <sched.h>
39 #include <signal.h>
40 #include <sys/types.h>
41 #include <sys/wait.h>
42
43 #define LIBNAME         "rpm-fake.so"
44 #define PLATFORM_FILE   "/etc/rpm/platform"
45
46 #define INIT(FILE,FUNC) FUNC##_func = ((__typeof__(FUNC) *) (dlsym(FILE, #FUNC)))
47 #define DECLARE(FUNC)   static __typeof__(FUNC) *       FUNC##_func = 0
48
49 static bool             is_initialized = false;
50 DECLARE(execv);
51   //DECLARE(open);
52
53 static int
54 getAndClearEnv(char const *key, int dflt)
55 {
56   char          *env = getenv(key);
57   int           res;
58
59   if (env==0 || env[0]=='\0') res = dflt;
60   else {
61     res = atoi(env);
62     unsetenv(key);
63   }
64
65   return res;
66 }
67
68 static void
69 initLib()
70 {
71   if (is_initialized) return;
72
73 #ifdef VC_ENABLE_API_LEGACY
74   {
75     extern void vc_init_internal_legacy(int ctx_rev, int ctx_number,
76                                         int ipv4_rev, int ipv4_number);
77   
78     vc_init_internal_legacy(getAndClearEnv("RPM_FAKE_S_CONTEXT_REV", 0),
79                             getAndClearEnv("RPM_FAKE_S_CONTEXT_NR",  280),
80                             3, 281);
81   }
82 #else
83   (void)getAndClearEnv("RPM_FAKE_S_CONTEXT_REV", 0);
84   (void)getAndClearEnv("RPM_FAKE_S_CONTEXT_NR",  280);
85 #endif  
86   INIT(RTLD_NEXT, execv);
87     //INIT(RTLD_NEXT, open);
88
89   is_initialized = true;
90 }
91
92 static void
93 fixPreloadEnv()
94 {
95   char                  *env = getenv("LD_PRELOAD");
96   char                  *pos;
97
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);
102
103   if (pos!=0) {
104     char        *end_pos = pos + sizeof(LIBNAME);
105     bool        is_end = (end_pos[-1]=='\0');
106     char        *start_pos;
107
108     end_pos[-1] = '\0';
109     start_pos   = strrchr(env, ':');
110     if (start_pos==0) start_pos = env;
111     else if (!is_end) ++start_pos;
112
113     if (is_end) *start_pos = '\0';
114     else        memmove(start_pos, end_pos, strlen(end_pos)+1);
115   }
116
117 #ifdef DEBUG
118   printf("env='%s'\n", env);
119 #endif
120
121   if (*env=='\0') unsetenv("LD_PRELOAD");
122 }
123
124 static int
125 execvWorker(char const *path, char * const argv[])
126 {
127   int           res;
128   int           ctx;
129
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) ) {}
135
136   return res;
137 }
138
139 struct ExecvParams
140 {
141     char const *        path;
142     char * const *      argv;
143     char const *        mnts;
144 };
145
146 static int
147 removeNamespaceMountsChild(void *params_v)
148 {
149   struct ExecvParams *  params = params_v;
150   char                  buf[strlen(params->mnts)+1], *ptr;
151
152   strcpy(buf, params->mnts);
153   ptr = strtok(buf, ":");
154   while (ptr) {
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?
158         //
159         // For now, ignore any errors, but future versions should handle them.
160
161         //return -1;
162     }
163     ptr = strtok(0, ":");
164   }
165
166   unsetenv("RPM_FAKE_NAMESPACE_MOUNTS");
167   return execvWorker(params->path, params->argv);
168 }
169
170 static int
171 removeNamespaceMounts(char const *path, char * const argv[])
172 {
173   char const *  mnts = getenv("RPM_FAKE_NAMESPACE_MOUNTS");
174
175   if (mnts==0) return execvWorker(path, argv);
176
177   {
178     char        buf[512 + 2*strlen(mnts)];
179     int         status;
180     pid_t       p;
181     struct ExecvParams          params = {
182       .path = path,
183       .argv = argv,
184       .mnts = mnts,
185     };
186
187       // the rpmlib signal-handler is still active; use the default one to
188       // make wait4() working...
189     signal(SIGCHLD, SIG_DFL);
190
191     pid_t       pid = clone(removeNamespaceMountsChild, buf+sizeof(buf)/2,
192                             CLONE_NEWNS|SIGCHLD|CLONE_VFORK, &params);
193
194     if (pid==-1) return -1;
195     while ((p=wait4(pid, &status, 0,0))==-1 &&
196            (errno==EINTR || errno==EAGAIN)) ;
197
198     if (p==-1)   return -1;
199
200     if (WIFEXITED(status))   exit(WEXITSTATUS(status));
201     if (WIFSIGNALED(status)) kill(getpid(), WTERMSIG(status));
202
203     return -1;
204   }
205 }
206
207 int
208 execv(char const *path, char * const argv[]) __THROW
209 {
210   initLib();
211   fixPreloadEnv();
212   return removeNamespaceMounts(path, argv);
213 }