1 /*
2 * Copyright (c) 1994 Christos Zoulas
3 * Copyright (c) 1995 Frank van der Linden
4 * Copyright (c) 1995 Scott Bartram
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. The name of the author may not be used to endorse or promote products
16 * derived from this software without specific prior written permission
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 *
29 * from: svr4_util.c,v 1.5 1995/01/22 23:44:50 christos Exp
30 * $FreeBSD: src/sys/compat/linux/linux_util.c,v 1.12.2.2 2001/11/05 19:08:23 marcel Exp $
31 * $DragonFly: src/sys/emulation/linux/linux_util.c,v 1.14 2006/10/27 04:56:28 dillon Exp $
32 */
33
34 #include <sys/param.h>
35 #include <sys/systm.h>
36 #include <sys/proc.h>
37 #include <sys/nlookup.h>
38 #include <sys/malloc.h>
39 #include <sys/vnode.h>
40
41 #include "linux_util.h"
42
43 const char linux_emul_path[] = "/compat/linux";
44
45 /*
46 * Search for an alternate path before passing pathname arguments on
47 * to system calls.
48 *
49 * Only signal an error if something really bad happens. In most cases
50 * we can just return the untranslated path, eg. name lookup failures.
51 */
52 int
53 linux_copyin_path(char *uname, char **kname, int flags)
54 {
55 struct nlookupdata nd, ndroot;
56 struct vattr vat, vatroot;
57 struct vnode *vp, *vproot;
58 char *buf, *cp;
59 int error, length, dummy, byte;
60
61 buf = (char *) kmalloc(MAXPATHLEN, M_TEMP, M_WAITOK);
62 *kname = buf;
63
64 /*
65 * Read a byte and see if uname is a valid address. if not, EFAULT.
66 */
67 byte = fubyte(uname);
68 if (byte == -1) {
69 error = EFAULT;
70 goto done;
71 }
72 /*
73 * Don't bother trying to translate if the path is relative.
74 */
75 if (byte != '/')
76 goto dont_translate;
77
78 /*
79 * The path is absolute. Prepend the buffer with the emulation
80 * path and copy in.
81 */
82 length = strlen(linux_emul_path);
83 bcopy(linux_emul_path, buf, length);
84 error = copyinstr(uname, buf + length, MAXPATHLEN - length, &dummy);
85 if (error)
86 goto done;
87
88 switch (flags) {
89 case LINUX_PATH_CREATE:
90 /*
91 * Check to see if the parent directory exists in the
92 * emulation tree. Walk the string backwards to find
93 * the last '/'.
94 */
95 cp = buf + strlen(buf);
96 while (--cp >= buf) {
97 if (*cp == '/')
98 break;
99 }
100 if (cp < buf)
101 goto dont_translate;
102 *cp = 0;
103
104 error = nlookup_init(&nd, buf, UIO_SYSSPACE, NLC_FOLLOW);
105 if (error == 0)
106 error = nlookup(&nd);
107 nlookup_done(&nd);
108 if (error)
109 goto dont_translate;
110 *cp = '/';
111 return (0);
112 case LINUX_PATH_EXISTS:
113 error = nlookup_init(&nd, buf, UIO_SYSSPACE, NLC_FOLLOW);
114 if (error == 0)
115 error = nlookup(&nd);
116 vp = NULL;
117 if (error == 0)
118 error = cache_vref(&nd.nl_nch, nd.nl_cred, &vp);
119 nlookup_done(&nd);
120 if (error)
121 goto dont_translate;
122
123 /*
124 * We now compare the vnode of the linux_root to the one
125 * vnode asked. If they resolve to be the same, then we
126 * ignore the match so that the real root gets used.
127 * This avoids the problem of traversing "../.." to find the
128 * root directory and never finding it, because "/" resolves
129 * to the emulation root directory. This is expensive :-(
130 *
131 * The next three function calls should not return errors.
132 * If they do something is seriously wrong, eg. the
133 * emulation subtree does not exist. Cross our fingers
134 * and return the untranslated path if something happens.
135 */
136 error = nlookup_init(&ndroot, linux_emul_path, UIO_SYSSPACE,
137 NLC_FOLLOW);
138 if (error == 0)
139 error = nlookup(&ndroot);
140 vproot = NULL;
141 if (error == 0) {
142 error = cache_vref(&ndroot.nl_nch, ndroot.nl_cred,
143 &vproot);
144 }
145 nlookup_done(&ndroot);
146 if (error) {
147 vrele(vp);
148 goto dont_translate;
149 }
150
151 error = VOP_GETATTR(vp, &vat);
152 if (error == 0) {
153 error = VOP_GETATTR(vproot, &vatroot);
154 if (error == 0) {
155 if (vat.va_fsid == vatroot.va_fsid &&
156 vat.va_fileid == vatroot.va_fileid)
157 error = ENOENT;
158 }
159 }
160 vrele(vp);
161 vrele(vproot);
162 if (error)
163 goto dont_translate;
164 return (0);
165 default:
166 error = EINVAL;
167 goto done;
168 }
169
170 dont_translate:
171 error = copyinstr(uname, buf, MAXPATHLEN, &dummy);
172 done:
173 if (error)
174 linux_free_path(kname);
175 return (error);
176 }
177
178 /*
179 * Smaller version of the above for translating in kernel buffers. Only
180 * used in exec_linux_imgact_try(). Only check is path exists.
181 */
182 int
183 linux_translate_path(char *path, int size)
184 {
185 struct nlookupdata nd;
186 char *buf;
187 int error, length, dummy;
188
189 buf = (char *) kmalloc(MAXPATHLEN, M_TEMP, M_WAITOK);
190 length = strlen(linux_emul_path);
191 bcopy(linux_emul_path, buf, length);
192 error = copystr(path, buf + length, MAXPATHLEN - length, &dummy);
193 if (error)
194 goto cleanup;
195
196 /*
197 * If this errors, then the path probably doesn't exist.
198 */
199 error = nlookup_init(&nd, buf, UIO_SYSSPACE, NLC_FOLLOW);
200 if (error == 0)
201 error = nlookup(&nd);
202 nlookup_done(&nd);
203 if (error) {
204 error = 0;
205 goto cleanup;
206 }
207
208 /*
209 * The alternate path does exist. Return it in the buffer if
210 * it fits.
211 */
212 if (strlen(buf) + 1 <= size)
213 error = copystr(buf, path, size, &dummy);
214
215 cleanup:
216
217 kfree(buf, M_TEMP);
218 return (error);
219 }
Cache object: 2d60cc262f12c58e0ff275953d61dd45
|