xref: /netbsd-src/sys/compat/linux/common/linux_file.c (revision 4c34be6b52a699cc7287e3b937a69ca90fd2ced9)
1 /*	$NetBSD: linux_file.c,v 1.1 1995/02/28 23:24:53 fvdl Exp $	*/
2 
3 /*
4  * Copyright (c) 1995 Frank van der Linden
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. All advertising materials mentioning features or use of this software
16  *    must display the following acknowledgement:
17  *      This product includes software developed for the NetBSD Project
18  *      by Frank van der Linden
19  * 4. The name of the author may not be used to endorse or promote products
20  *    derived from this software without specific prior written permission
21  *
22  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
23  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
24  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
25  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
26  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
27  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
31  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32  */
33 
34 #include <sys/param.h>
35 #include <sys/systm.h>
36 #include <sys/namei.h>
37 #include <sys/proc.h>
38 #include <sys/file.h>
39 #include <sys/stat.h>
40 #include <sys/filedesc.h>
41 #include <sys/ioctl.h>
42 #include <sys/kernel.h>
43 #include <sys/mount.h>
44 #include <sys/malloc.h>
45 
46 #include <sys/syscallargs.h>
47 
48 #include <compat/linux/linux_types.h>
49 #include <compat/linux/linux_syscallargs.h>
50 #include <compat/linux/linux_fcntl.h>
51 #include <compat/linux/linux_util.h>
52 
53 /*
54  * Some file-related calls are handled here. The usual flag conversion
55  * an structure conversion is done, and alternate emul path searching.
56  */
57 
58 /*
59  * The next two functions convert between the Linux and NetBSD values
60  * of the flags used in open(2) and fcntl(2).
61  */
62 static int
63 linux_to_bsd_ioflags(int lflags)
64 {
65 	int res = 0;
66 
67 	res |= cvtto_bsd_mask(lflags, LINUX_O_WRONLY, O_WRONLY);
68 	res |= cvtto_bsd_mask(lflags, LINUX_O_RDONLY, O_RDONLY);
69 	res |= cvtto_bsd_mask(lflags, LINUX_O_RDWR, O_RDWR);
70 	res |= cvtto_bsd_mask(lflags, LINUX_O_CREAT, O_CREAT);
71 	res |= cvtto_bsd_mask(lflags, LINUX_O_EXCL, O_EXCL);
72 	res |= cvtto_bsd_mask(lflags, LINUX_O_NOCTTY, O_NOCTTY);
73 	res |= cvtto_bsd_mask(lflags, LINUX_O_TRUNC, O_TRUNC);
74 	res |= cvtto_bsd_mask(lflags, LINUX_O_NDELAY, O_NDELAY);
75 	res |= cvtto_bsd_mask(lflags, LINUX_O_SYNC, O_FSYNC);
76 	res |= cvtto_bsd_mask(lflags, LINUX_FASYNC, O_ASYNC);
77 	res |= cvtto_bsd_mask(lflags, LINUX_O_APPEND, O_APPEND);
78 
79 	return res;
80 }
81 
82 static int
83 bsd_to_linux_ioflags(int bflags)
84 {
85 	int res = 0;
86 
87 	res |= cvtto_linux_mask(bflags, O_WRONLY, LINUX_O_WRONLY);
88 	res |= cvtto_linux_mask(bflags, O_RDONLY, LINUX_O_RDONLY);
89 	res |= cvtto_linux_mask(bflags, O_RDWR, LINUX_O_RDWR);
90 	res |= cvtto_linux_mask(bflags, O_CREAT, LINUX_O_CREAT);
91 	res |= cvtto_linux_mask(bflags, O_EXCL, LINUX_O_EXCL);
92 	res |= cvtto_linux_mask(bflags, O_NOCTTY, LINUX_O_NOCTTY);
93 	res |= cvtto_linux_mask(bflags, O_TRUNC, LINUX_O_TRUNC);
94 	res |= cvtto_linux_mask(bflags, O_NDELAY, LINUX_O_NDELAY);
95 	res |= cvtto_linux_mask(bflags, O_FSYNC, LINUX_O_SYNC);
96 	res |= cvtto_linux_mask(bflags, O_ASYNC, LINUX_FASYNC);
97 	res |= cvtto_linux_mask(bflags, O_APPEND, LINUX_O_APPEND);
98 
99 	return res;
100 }
101 
102 /*
103  * creat(2) is an obsolete function, but it's present as a Linux
104  * system call, so let's deal with it.
105  *
106  * Just call open(2) with the TRUNC, CREAT and WRONLY flags.
107  */
108 int
109 linux_creat(p, uap, retval)
110 	struct proc *p;
111 	struct linux_creat_args /* {
112 		syscallarg(char *) path;
113 		syscallarg(int) mode;
114 	} */ *uap;
115 	register_t *retval;
116 {
117 	struct open_args oa;
118 	caddr_t sg;
119 
120 	sg = stackgap_init();
121 	CHECK_ALT(p, &sg, SCARG(uap, path));
122 
123 	SCARG(&oa, path) = SCARG(uap, path);
124 	SCARG(&oa, flags) = O_CREAT | O_TRUNC | O_WRONLY;
125 	SCARG(&oa, mode) = SCARG(uap, mode);
126 	return open(p, &oa, retval);
127 }
128 
129 /*
130  * open(2). Take care of the different flag values, and let the
131  * NetBSD syscall do the real work. See if this operation
132  * gives the current process a controlling terminal.
133  * (XXX is this necessary?)
134  */
135 int
136 linux_open(p, uap, retval)
137 	struct proc *p;
138 	struct linux_open_args /* {
139 		syscallarg(char *) path;
140 		syscallarg(int) flags;
141 		syscallarg(int) mode;
142 	} */ *uap;
143 	register_t *retval;
144 {
145 	int error, fl;
146 	struct open_args boa;
147 	caddr_t sg;
148 
149 	sg = stackgap_init();
150 
151 	CHECK_ALT(p, &sg, SCARG(uap, path));
152 
153 	fl = linux_to_bsd_ioflags(SCARG(uap, flags));
154 
155 	SCARG(&boa, path) = SCARG(uap, path);
156 	SCARG(&boa, flags) = fl;
157 	SCARG(&boa, mode) = SCARG(uap, mode);
158 	if ((error = open(p, &boa, retval)))
159 		return error;
160 
161 	/*
162 	 * this bit from sunos_misc.c (and svr4_fcntl.c).
163 	 * If we are a session leader, and we don't have a controlling
164 	 * terminal yet, and the O_NOCTTY flag is not set, try to make
165 	 * this the controlling terminal.
166 	 */
167         if (!(fl & O_NOCTTY) && SESS_LEADER(p) && !(p->p_flag & P_CONTROLT)) {
168                 struct filedesc *fdp = p->p_fd;
169                 struct file     *fp = fdp->fd_ofiles[*retval];
170 
171                 /* ignore any error, just give it a try */
172                 if (fp->f_type == DTYPE_VNODE)
173                         (fp->f_ops->fo_ioctl) (fp, TIOCSCTTY, (caddr_t) 0, p);
174         }
175 	return 0;
176 }
177 
178 /*
179  * The next two functions take care of converting the flock
180  * structure back and forth between Linux and NetBSD format.
181  * The only difference in the structures is the order of
182  * the fields, and the 'whence' value.
183  */
184 static void
185 bsd_to_linux_flock(bfp, lfp)
186 	struct flock *bfp;
187 	struct linux_flock *lfp;
188 {
189 	lfp->l_start = bfp->l_start;
190 	lfp->l_len = bfp->l_len;
191 	lfp->l_pid = bfp->l_pid;
192 	lfp->l_type = bfp->l_type;
193 	switch (bfp->l_whence) {
194 	case F_RDLCK:
195 		lfp->l_whence = LINUX_F_RDLCK;
196 		break;
197 	case F_UNLCK:
198 		lfp->l_whence = LINUX_F_UNLCK;
199 		break;
200 	case F_WRLCK:
201 		lfp->l_whence = LINUX_F_WRLCK;
202 		break;
203 	}
204 }
205 
206 static void
207 linux_to_bsd_flock(lfp, bfp)
208 	struct linux_flock *lfp;
209 	struct flock *bfp;
210 {
211 	bfp->l_start = lfp->l_start;
212 	bfp->l_len = lfp->l_len;
213 	bfp->l_pid = lfp->l_pid;
214 	bfp->l_type = lfp->l_type;
215 	switch (lfp->l_whence) {
216 	case LINUX_F_RDLCK:
217 		bfp->l_whence = F_RDLCK;
218 		break;
219 	case LINUX_F_UNLCK:
220 		bfp->l_whence = F_UNLCK;
221 		break;
222 	case LINUX_F_WRLCK:
223 		bfp->l_whence = F_WRLCK;
224 		break;
225 	}
226 }
227 
228 /*
229  * Most actions in the fcntl() call are straightforward; simply
230  * pass control to the NetBSD system call. A few commands need
231  * conversions after the actual system call has done its work,
232  * because the flag values and lock structure are different.
233  */
234 int
235 linux_fcntl(p, uap, retval)
236 	struct proc *p;
237 	struct linux_fcntl_args /* {
238 		syscallarg(int) fd;
239 		syscallarg(int) cmd;
240 		syscallarg(void *) arg;
241 	} */ *uap;
242 	register_t *retval;
243 {
244 	int fd, cmd, error, *tval,val;
245 	caddr_t arg, sg;
246 	struct linux_flock lfl;
247 	struct flock *bfp, bfl;
248 	struct fcntl_args fca;
249 
250 	fd = SCARG(uap, fd);
251 	cmd = SCARG(uap, cmd);
252 	arg = (caddr_t) SCARG(uap, arg);
253 
254 	switch (cmd) {
255 	case LINUX_F_DUPFD:
256 		cmd = F_DUPFD;
257 		break;
258 	case LINUX_F_GETFD:
259 		cmd = F_GETFD;
260 		break;
261 	case LINUX_F_SETFD:
262 		cmd = F_SETFD;
263 		break;
264 	case LINUX_F_GETFL:
265 		SCARG(&fca, fd) = fd;
266 		SCARG(&fca, cmd) = F_GETFL;
267 		SCARG(&fca, arg) = arg;
268 		if ((error = fcntl(p, &fca, retval)))
269 			return error;
270 		retval[0] = bsd_to_linux_ioflags(retval[0]);
271 		return 0;
272 	case LINUX_F_SETFL:
273 		if ((error = copyin(SCARG(uap, arg), &val, sizeof (int))))
274 			return error;
275 		val = linux_to_bsd_ioflags(val);
276 		sg = stackgap_init();
277 		tval = (int *) stackgap_alloc(&sg, sizeof (int));
278 		if ((error = copyout(&val, tval, sizeof (int))))
279 			return error;
280 		SCARG(&fca, fd) = fd;
281 		SCARG(&fca, cmd) = F_SETFL;
282 		SCARG(&fca, arg) = tval;
283 		return fcntl(p, &fca, retval);
284 	case LINUX_F_GETLK:
285 		sg = stackgap_init();
286 		bfp = (struct flock *) stackgap_alloc(&sg, sizeof *bfp);
287 		SCARG(&fca, fd) = fd;
288 		SCARG(&fca, cmd) = F_GETLK;
289 		SCARG(&fca, arg) = bfp;
290 		if ((error = fcntl(p, &fca, retval)))
291 			return error;
292 		if ((error = copyin(bfp, &bfl, sizeof bfl)))
293 			return error;
294 		bsd_to_linux_flock(&bfl, &lfl);
295 		return copyout(&lfl, arg, sizeof lfl);
296 		break;
297 	case LINUX_F_SETLK:
298 	case LINUX_F_SETLKW:
299 		cmd = (cmd == LINUX_F_SETLK ? F_SETLK : F_SETLKW);
300 		if ((error = copyin(arg, &lfl, sizeof lfl)))
301 			return error;
302 		linux_to_bsd_flock(&lfl, &bfl);
303 		sg = stackgap_init();
304 		bfp = (struct flock *) stackgap_alloc(&sg, sizeof *bfp);
305 		if ((error = copyout(&bfl, bfp, sizeof bfl)))
306 			return error;
307 		SCARG(&fca, fd) = fd;
308 		SCARG(&fca, cmd) = cmd;
309 		SCARG(&fca, arg) = bfp;
310 		return fcntl(p, &fca, retval);
311 		break;
312 	case LINUX_F_SETOWN:
313 		cmd = F_SETOWN;
314 		break;
315 	case LINUX_F_GETOWN:
316 		cmd = F_GETOWN;
317 		break;
318 	default:
319 		return EOPNOTSUPP;
320 	}
321 
322 	SCARG(&fca, fd) = fd;
323 	SCARG(&fca, cmd) = cmd;
324 	SCARG(&fca, arg) = arg;
325 	return fcntl(p, uap, retval);
326 }
327 
328 /*
329  * Convert a NetBSD stat structure to a Linux stat structure.
330  * Only the order of the fields and the padding in the structure
331  * is different.
332  */
333 static void
334 bsd_to_linux_stat(bsp, lsp)
335 	struct stat *bsp;
336 	struct linux_stat *lsp;
337 {
338 	lsp->lst_dev     = bsp->st_dev;
339 	lsp->lst_ino     = bsp->st_ino;
340 	lsp->lst_mode    = bsp->st_mode;
341 	lsp->lst_nlink   = bsp->st_nlink;
342 	lsp->lst_uid     = bsp->st_uid;
343 	lsp->lst_gid     = bsp->st_gid;
344 	lsp->lst_rdev    = bsp->st_rdev;
345 	lsp->lst_size    = bsp->st_size;
346 	lsp->lst_blksize = bsp->st_blksize;
347 	lsp->lst_blocks  = bsp->st_blocks;
348 	lsp->lst_atime   = bsp->st_atime;
349 	lsp->lst_mtime   = bsp->st_mtime;
350 	lsp->lst_ctime   = bsp->st_ctime;
351 }
352 
353 /*
354  * The stat functions below are plain sailing. stat and lstat are handled
355  * by one function to avoid code duplication.
356  */
357 int
358 linux_fstat(p, uap, retval)
359 	struct proc *p;
360 	struct linux_fstat_args /* {
361 		syscallarg(int) fd;
362 		syscallarg(linux_stat *) sp;
363 	} */ *uap;
364 	register_t *retval;
365 {
366 	struct fstat_args fsa;
367 	struct linux_stat tmplst;
368 	struct stat *st,tmpst;
369 	caddr_t sg;
370 	int error;
371 
372 	sg = stackgap_init();
373 
374 	st = stackgap_alloc(&sg, sizeof (struct stat));
375 
376 	SCARG(&fsa, fd) = SCARG(uap, fd);
377 	SCARG(&fsa, sb) = st;
378 
379 	if ((error = fstat(p, &fsa, retval)))
380 		return error;
381 
382 	if ((error = copyin(st, &tmpst, sizeof tmpst)))
383 		return error;
384 
385 	bsd_to_linux_stat(&tmpst, &tmplst);
386 
387 	if ((error = copyout(&tmplst, SCARG(uap, sp), sizeof tmplst)))
388 		return error;
389 
390 	return 0;
391 }
392 
393 static int
394 linux_stat1(p, uap, retval, dolstat)
395 	struct proc *p;
396 	struct linux_stat_args *uap;
397 	register_t *retval;
398 	int dolstat;
399 {
400 	struct stat_args sa;
401 	struct linux_stat tmplst;
402 	struct stat *st, tmpst;
403 	caddr_t sg;
404 	int error;
405 
406 	sg = stackgap_init();
407 
408 	CHECK_ALT(p, &sg, SCARG(uap, path));
409 
410 	st = stackgap_alloc(&sg, sizeof (struct stat));
411 	SCARG(&sa, ub) = st;
412 	SCARG(&sa, path) = SCARG(uap, path);
413 
414 	if ((error = (dolstat ? lstat(p, &sa, retval) : stat(p, &sa, retval))))
415 		return error;
416 
417 	if ((error = copyin(st, &tmpst, sizeof tmpst)))
418 		return error;
419 
420 	bsd_to_linux_stat(&tmpst, &tmplst);
421 
422 	if ((error = copyout(&tmplst, SCARG(uap, sp), sizeof tmplst)))
423 		return error;
424 
425 	return 0;
426 }
427 
428 int
429 linux_stat(p, uap, retval)
430 	struct proc *p;
431 	struct linux_stat_args /* {
432 		syscallarg(char *) path;
433 		syscallarg(struct linux_stat *) sp;
434 	} */ *uap;
435 	register_t *retval;
436 {
437 	return linux_stat1(p, uap, retval, 0);
438 }
439 
440 int
441 linux_lstat(p, uap, retval)
442 	struct proc *p;
443 	struct linux_lstat_args /* {
444 		syscallarg(char *) path;
445 		syscallarg(struct linux_stat *) sp;
446 	} */ *uap;
447 	register_t *retval;
448 {
449 	return linux_stat1(p, uap, retval, 1);
450 }
451 
452 /*
453  * This one is only here because of the alternate path check.
454  */
455 int
456 linux_access(p, uap, retval)
457 	struct proc *p;
458 	struct linux_access_args /* {
459 		syscallarg(char *) path;
460 		syscallarg(int) flags;
461 	} */ *uap;
462 	register_t *retval;
463 {
464 	caddr_t sg = stackgap_init();
465 
466 	CHECK_ALT(p, &sg, SCARG(uap, path));
467 
468 	return access(p, uap, retval);
469 }
470