summaryrefslogtreecommitdiffstats
path: root/fakechroot-2.9-cmdsubst.patch
blob: 0d40cd73d5ebfcf9e90eed543f9d6ce5373387c1 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
Index: test/cmd-subst-pwd.sh
===================================================================
--- test/cmd-subst-pwd.sh	(revision 0)
+++ test/cmd-subst-pwd.sh	(revision 0)
@@ -0,0 +1,3 @@
+#!/bin/sh
+
+echo substituted

Property changes on: test/cmd-subst-pwd.sh
___________________________________________________________________
Added: svn:executable
   + *

Index: test/cmd-subst.t
===================================================================
--- test/cmd-subst.t	(revision 0)
+++ test/cmd-subst.t	(revision 0)
@@ -0,0 +1,37 @@
+#!/bin/sh
+
+. ./tap.sh
+
+plan 5
+
+rm -rf testtree
+
+./testtree.sh testtree
+test "`cat testtree/CHROOT`" = "testtree" || not
+ok "testtree"
+
+t=`./fakechroot.sh testtree /bin/pwd`
+test "$t" = "/" || not
+ok "fakechroot pwd is /"
+
+export FAKECHROOT_CMD_SUBST="/bin/pwd=$(pwd)/cmd-subst-pwd.sh"
+
+t=`./fakechroot.sh testtree /bin/pwd`
+test "$t" = "substituted" || not
+ok "fakechroot substituted pwd (1)"
+
+export FAKECHROOT_CMD_SUBST="/no/file=foo:/bin/pwd=$(pwd)/cmd-subst-pwd.sh"
+
+t=`./fakechroot.sh testtree /bin/pwd`
+test "$t" = "substituted" || not
+ok "fakechroot substituted pwd (2)"
+
+export FAKECHROOT_CMD_SUBST="/no/file=foo:/other/file=bar"
+
+t=`./fakechroot.sh testtree /bin/pwd`
+test "$t" = "/" || not
+ok "fakechroot not substituted pwd is /"
+
+rm -rf testtree
+
+end

Property changes on: test/cmd-subst.t
___________________________________________________________________
Added: svn:executable
   + *

Index: test/Makefile.am
===================================================================
--- test/Makefile.am	(revision 323)
+++ test/Makefile.am	(working copy)
@@ -1,6 +1,6 @@
 SUBDIRS = src
 
-TESTS = chroot.t escape-nested-chroot.t pwd.t touch.t
+TESTS = chroot.t cmd-subst.t escape-nested-chroot.t pwd.t touch.t
 
 suffix =
 
Index: src/libfakechroot.c
===================================================================
--- src/libfakechroot.c	(revision 323)
+++ src/libfakechroot.c	(working copy)
@@ -1467,7 +1467,38 @@
     return execve (path, argv, environ);
 }
 
+/* Parse the FAKECHROOT_CMD_SUBST environment variable (the first
+ * parameter) and if there is a match with filename, return the
+ * substitution in cmd_subst.  Returns non-zero if there was a match.
+ *
+ * FAKECHROOT_CMD_SUBST=cmd=subst:cmd=subst:...
+ */
+static int
+try_cmd_subst (char *env, const char *filename, char *cmd_subst)
+{
+    int len = strlen (filename), len2;
+    char *p;
 
+    if (env == NULL) return 0;
+
+    do {
+	p = strchrnul (env, ':');
+
+	if (strncmp (env, filename, len) == 0 && env[len] == '=') {
+	    len2 = p - &env[len+1];
+	    if (len2 >= FAKECHROOT_MAXPATH)
+		len2 = FAKECHROOT_MAXPATH - 1;
+	    strncpy (cmd_subst, &env[len+1], len2);
+	    cmd_subst[len2] = '\0';
+	    return 1;
+	}
+
+	env = p;
+    } while (*env++ != '\0');
+
+    return 0;
+}
+
 /* #include <unistd.h> */
 int execve (const char *filename, char *const argv [], char *const envp[])
 {
@@ -1479,32 +1510,16 @@
     char *env;
     char tmp[FAKECHROOT_MAXPATH], newfilename[FAKECHROOT_MAXPATH], argv0[FAKECHROOT_MAXPATH];
     char *ptr;
-    unsigned int i, j, n, len;
+    unsigned int i, j, n, len, r, newenvppos;
     size_t sizeenvp;
     char c;
     char *fakechroot_path, *fakechroot_ptr, fakechroot_buf[FAKECHROOT_MAXPATH];
     char *envkey[] = { "FAKECHROOT", "FAKECHROOT_BASE",
                        "FAKECHROOT_VERSION", "FAKECHROOT_EXCLUDE_PATH",
+                       "FAKECHROOT_CMD_SUBST",
                        "LD_LIBRARY_PATH", "LD_PRELOAD" };
+    const int nr_envkey = sizeof envkey / sizeof envkey[0];
 
-    strncpy(argv0, filename, FAKECHROOT_MAXPATH);
-
-    expand_chroot_path(filename, fakechroot_path, fakechroot_ptr, fakechroot_buf);
-    strcpy(tmp, filename);
-    filename = tmp;
-
-    if ((file = open(filename, O_RDONLY)) == -1) {
-        errno = ENOENT;
-        return -1;
-    }
-
-    i = read(file, hashbang, FAKECHROOT_MAXPATH-2);
-    close(file);
-    if (i == -1) {
-        errno = ENOENT;
-        return -1;
-    }
-
     if (next_execve == NULL) fakechroot_init();
 
     /* Scan envp and check its size */
@@ -1514,39 +1529,69 @@
     }
 
     /* Copy envp to newenvp */
-    newenvp = malloc( sizeenvp * sizeof (char *) + sizeof(envkey) );
+    newenvp = malloc( (sizeenvp + 1) * sizeof (char *) );
     if (newenvp == NULL) {
         errno = ENOMEM;
         return -1;
     }
-    for (ep = envp, i = 0; *ep != NULL; ++ep) {
-        for (j = 0; j < sizeof (envkey) / sizeof (char *); j++) {
+    for (ep = envp, newenvppos = 0; *ep != NULL; ++ep) {
+        for (j = 0; j < nr_envkey; j++) {
             len = strlen (envkey[j]);
             if (strncmp (*ep, envkey[j], len) == 0 && (*ep)[len] == '=')
                 goto skip;
         }
-        newenvp[i] = *ep;
-        i++;
+        newenvp[newenvppos] = *ep;
+        newenvppos++;
     skip: ;
     }
+    newenvp[newenvppos] = NULL;
 
+    strncpy(argv0, filename, FAKECHROOT_MAXPATH);
+
+    r = try_cmd_subst (getenv ("FAKECHROOT_CMD_SUBST"), filename, tmp);
+    if (r) {
+        filename = tmp;
+
+        /* FAKECHROOT_CMD_SUBST escapes the chroot.  newenvp here does
+         * not contain LD_PRELOAD and the other special environment
+         * variables.
+         */
+        return next_execve(filename, argv, newenvp);
+    }
+
+    expand_chroot_path(filename, fakechroot_path, fakechroot_ptr, fakechroot_buf);
+    strcpy(tmp, filename);
+    filename = tmp;
+
+    if ((file = open(filename, O_RDONLY)) == -1) {
+        errno = ENOENT;
+        return -1;
+    }
+
+    i = read(file, hashbang, FAKECHROOT_MAXPATH-2);
+    close(file);
+    if (i == -1) {
+        errno = ENOENT;
+        return -1;
+    }
+
     /* Add our variables to newenvp */
-    newenvp = realloc( newenvp, i * sizeof(char *) + sizeof(envkey) );
+    newenvp = realloc( newenvp, (newenvppos + nr_envkey + 1) * sizeof(char *) );
     if (newenvp == NULL) {
         errno = ENOMEM;
         return -1;
     }
-    for (j = 0; j < sizeof(envkey) / sizeof(char *); j++) {
+    for (j = 0; j < nr_envkey; j++) {
         env = getenv(envkey[j]);
         if (env != NULL) {
-            newenvp[i] = malloc(strlen(envkey[j]) + strlen(env) + 3);
-            strcpy(newenvp[i], envkey[j]);
-            strcat(newenvp[i], "=");
-            strcat(newenvp[i], env);
-            i++;
+            newenvp[newenvppos] = malloc(strlen(envkey[j]) + strlen(env) + 3);
+            strcpy(newenvp[newenvppos], envkey[j]);
+            strcat(newenvp[newenvppos], "=");
+            strcat(newenvp[newenvppos], env);
+            newenvppos++;
         }
     }
-    newenvp[i] = NULL;
+    newenvp[newenvppos] = NULL;
 
     /* No hashbang in argv */
     if (hashbang[0] != '#' || hashbang[1] != '!')
Index: man/fakechroot.pod
===================================================================
--- man/fakechroot.pod	(revision 323)
+++ man/fakechroot.pod	(working copy)
@@ -139,6 +139,21 @@
 The list of directories which are excluded from being chrooted.  The elements
 of list are separated with colon.
 
+=item B<FAKECHROOT_CMD_SUBST>
+
+A list of command substitutions.  If a program tries to execute one of
+the commands given (path relative to the chroot) then the substitute
+command runs instead (path to substitute command is not chrooted).
+
+For example:
+
+ FAKECHROOT_CMD_SUBST=/sbin/ldconfig=/tmp/ldconfig-wrapper
+
+will substitute C</tmp/ldconfig-wrapper> for C</sbin/ldconfig>.
+
+Give as many substitute commands as you want, separated by C<:>
+(colon) characters.
+
 =item B<LD_LIBRARY_PATH>, B<LD_PRELOAD>
 
 Fakechroot is implemented by wrapping system calls.  This is accomplished by