linux_file.c revision 1.4 1 /* $NetBSD: linux_file.c,v 1.4 1995/06/22 21:34:33 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 #include <sys/exec.h>
46
47 #include <sys/syscallargs.h>
48
49 #include <compat/linux/linux_types.h>
50 #include <compat/linux/linux_syscallargs.h>
51 #include <compat/linux/linux_fcntl.h>
52 #include <compat/linux/linux_util.h>
53
54 /*
55 * Some file-related calls are handled here. The usual flag conversion
56 * an structure conversion is done, and alternate emul path searching.
57 */
58
59 /*
60 * The next two functions convert between the Linux and NetBSD values
61 * of the flags used in open(2) and fcntl(2).
62 */
63 static int
64 linux_to_bsd_ioflags(int lflags)
65 {
66 int res = 0;
67
68 res |= cvtto_bsd_mask(lflags, LINUX_O_WRONLY, O_WRONLY);
69 res |= cvtto_bsd_mask(lflags, LINUX_O_RDONLY, O_RDONLY);
70 res |= cvtto_bsd_mask(lflags, LINUX_O_RDWR, O_RDWR);
71 res |= cvtto_bsd_mask(lflags, LINUX_O_CREAT, O_CREAT);
72 res |= cvtto_bsd_mask(lflags, LINUX_O_EXCL, O_EXCL);
73 res |= cvtto_bsd_mask(lflags, LINUX_O_NOCTTY, O_NOCTTY);
74 res |= cvtto_bsd_mask(lflags, LINUX_O_TRUNC, O_TRUNC);
75 res |= cvtto_bsd_mask(lflags, LINUX_O_NDELAY, O_NDELAY);
76 res |= cvtto_bsd_mask(lflags, LINUX_O_SYNC, O_FSYNC);
77 res |= cvtto_bsd_mask(lflags, LINUX_FASYNC, O_ASYNC);
78 res |= cvtto_bsd_mask(lflags, LINUX_O_APPEND, O_APPEND);
79
80 return res;
81 }
82
83 static int
84 bsd_to_linux_ioflags(int bflags)
85 {
86 int res = 0;
87
88 res |= cvtto_linux_mask(bflags, O_WRONLY, LINUX_O_WRONLY);
89 res |= cvtto_linux_mask(bflags, O_RDONLY, LINUX_O_RDONLY);
90 res |= cvtto_linux_mask(bflags, O_RDWR, LINUX_O_RDWR);
91 res |= cvtto_linux_mask(bflags, O_CREAT, LINUX_O_CREAT);
92 res |= cvtto_linux_mask(bflags, O_EXCL, LINUX_O_EXCL);
93 res |= cvtto_linux_mask(bflags, O_NOCTTY, LINUX_O_NOCTTY);
94 res |= cvtto_linux_mask(bflags, O_TRUNC, LINUX_O_TRUNC);
95 res |= cvtto_linux_mask(bflags, O_NDELAY, LINUX_O_NDELAY);
96 res |= cvtto_linux_mask(bflags, O_FSYNC, LINUX_O_SYNC);
97 res |= cvtto_linux_mask(bflags, O_ASYNC, LINUX_FASYNC);
98 res |= cvtto_linux_mask(bflags, O_APPEND, LINUX_O_APPEND);
99
100 return res;
101 }
102
103 /*
104 * creat(2) is an obsolete function, but it's present as a Linux
105 * system call, so let's deal with it.
106 *
107 * Just call open(2) with the TRUNC, CREAT and WRONLY flags.
108 */
109 int
110 linux_creat(p, uap, retval)
111 struct proc *p;
112 struct linux_creat_args /* {
113 syscallarg(char *) path;
114 syscallarg(int) mode;
115 } */ *uap;
116 register_t *retval;
117 {
118 struct open_args oa;
119 caddr_t sg;
120
121 sg = stackgap_init();
122 CHECK_ALT_CREAT(p, &sg, SCARG(uap, path));
123
124 SCARG(&oa, path) = SCARG(uap, path);
125 SCARG(&oa, flags) = O_CREAT | O_TRUNC | O_WRONLY;
126 SCARG(&oa, mode) = SCARG(uap, mode);
127 return open(p, &oa, retval);
128 }
129
130 /*
131 * open(2). Take care of the different flag values, and let the
132 * NetBSD syscall do the real work. See if this operation
133 * gives the current process a controlling terminal.
134 * (XXX is this necessary?)
135 */
136 int
137 linux_open(p, uap, retval)
138 struct proc *p;
139 struct linux_open_args /* {
140 syscallarg(char *) path;
141 syscallarg(int) flags;
142 syscallarg(int) mode;
143 } */ *uap;
144 register_t *retval;
145 {
146 int error, fl;
147 struct open_args boa;
148 caddr_t sg;
149
150 sg = stackgap_init();
151
152 fl = linux_to_bsd_ioflags(SCARG(uap, flags));
153
154 if (fl & O_CREAT)
155 CHECK_ALT_CREAT(p, &sg, SCARG(uap, path));
156 else
157 CHECK_ALT_EXIST(p, &sg, SCARG(uap, path));
158
159 SCARG(&boa, path) = SCARG(uap, path);
160 SCARG(&boa, flags) = fl;
161 SCARG(&boa, mode) = SCARG(uap, mode);
162
163 if ((error = open(p, &boa, retval)))
164 return error;
165
166 /*
167 * this bit from sunos_misc.c (and svr4_fcntl.c).
168 * If we are a session leader, and we don't have a controlling
169 * terminal yet, and the O_NOCTTY flag is not set, try to make
170 * this the controlling terminal.
171 */
172 if (!(fl & O_NOCTTY) && SESS_LEADER(p) && !(p->p_flag & P_CONTROLT)) {
173 struct filedesc *fdp = p->p_fd;
174 struct file *fp = fdp->fd_ofiles[*retval];
175
176 /* ignore any error, just give it a try */
177 if (fp->f_type == DTYPE_VNODE)
178 (fp->f_ops->fo_ioctl) (fp, TIOCSCTTY, (caddr_t) 0, p);
179 }
180 return 0;
181 }
182
183 /*
184 * This appears to be part of a Linux attempt to switch to 64 bits file sizes.
185 */
186 int
187 linux_llseek(p, uap, retval)
188 struct proc *p;
189 struct linux_llseek_args /* {
190 syscallarg(int) fd;
191 syscallarg(uint32_t) ohigh;
192 syscallarg(uint32_t) olow;
193 syscallarg(caddr_t) res;
194 syscallarg(int) whence;
195 } */ *uap;
196 register_t *retval;
197 {
198 struct lseek_args bla;
199 int error;
200 off_t off;
201
202 off = SCARG(uap, olow) | (((off_t) SCARG(uap, ohigh)) << 32);
203
204 SCARG(&bla, fd) = SCARG(uap, fd);
205 SCARG(&bla, offset) = off;
206 SCARG(&bla, whence) = SCARG(uap, whence);
207
208 if ((error = lseek(p, &bla, retval)))
209 return error;
210
211 if ((error = copyout(retval, SCARG(uap, res), sizeof (off_t))))
212 return error;
213
214 retval[0] = 0;
215 return 0;
216 }
217
218 /*
219 * The next two functions take care of converting the flock
220 * structure back and forth between Linux and NetBSD format.
221 * The only difference in the structures is the order of
222 * the fields, and the 'whence' value.
223 */
224 static void
225 bsd_to_linux_flock(bfp, lfp)
226 struct flock *bfp;
227 struct linux_flock *lfp;
228 {
229 lfp->l_start = bfp->l_start;
230 lfp->l_len = bfp->l_len;
231 lfp->l_pid = bfp->l_pid;
232 lfp->l_whence = bfp->l_whence;
233 switch (bfp->l_type) {
234 case F_RDLCK:
235 lfp->l_type = LINUX_F_RDLCK;
236 break;
237 case F_UNLCK:
238 lfp->l_type = LINUX_F_UNLCK;
239 break;
240 case F_WRLCK:
241 lfp->l_type = LINUX_F_WRLCK;
242 break;
243 }
244 }
245
246 static void
247 linux_to_bsd_flock(lfp, bfp)
248 struct linux_flock *lfp;
249 struct flock *bfp;
250 {
251 bfp->l_start = lfp->l_start;
252 bfp->l_len = lfp->l_len;
253 bfp->l_pid = lfp->l_pid;
254 bfp->l_whence = lfp->l_whence;
255 switch (lfp->l_type) {
256 case LINUX_F_RDLCK:
257 bfp->l_type = F_RDLCK;
258 break;
259 case LINUX_F_UNLCK:
260 bfp->l_type = F_UNLCK;
261 break;
262 case LINUX_F_WRLCK:
263 bfp->l_type = F_WRLCK;
264 break;
265 }
266 }
267
268 /*
269 * Most actions in the fcntl() call are straightforward; simply
270 * pass control to the NetBSD system call. A few commands need
271 * conversions after the actual system call has done its work,
272 * because the flag values and lock structure are different.
273 */
274 int
275 linux_fcntl(p, uap, retval)
276 struct proc *p;
277 struct linux_fcntl_args /* {
278 syscallarg(int) fd;
279 syscallarg(int) cmd;
280 syscallarg(void *) arg;
281 } */ *uap;
282 register_t *retval;
283 {
284 int fd, cmd, error, *tval,val;
285 caddr_t arg, sg;
286 struct linux_flock lfl;
287 struct flock *bfp, bfl;
288 struct fcntl_args fca;
289
290 fd = SCARG(uap, fd);
291 cmd = SCARG(uap, cmd);
292 arg = (caddr_t) SCARG(uap, arg);
293
294 switch (cmd) {
295 case LINUX_F_DUPFD:
296 cmd = F_DUPFD;
297 break;
298 case LINUX_F_GETFD:
299 cmd = F_GETFD;
300 break;
301 case LINUX_F_SETFD:
302 cmd = F_SETFD;
303 break;
304 case LINUX_F_GETFL:
305 SCARG(&fca, fd) = fd;
306 SCARG(&fca, cmd) = F_GETFL;
307 SCARG(&fca, arg) = arg;
308 if ((error = fcntl(p, &fca, retval)))
309 return error;
310 retval[0] = bsd_to_linux_ioflags(retval[0]);
311 return 0;
312 case LINUX_F_SETFL:
313 if ((error = copyin(SCARG(uap, arg), &val, sizeof (int))))
314 return error;
315 val = linux_to_bsd_ioflags(val);
316 sg = stackgap_init();
317 tval = (int *) stackgap_alloc(&sg, sizeof (int));
318 if ((error = copyout(&val, tval, sizeof (int))))
319 return error;
320 SCARG(&fca, fd) = fd;
321 SCARG(&fca, cmd) = F_SETFL;
322 SCARG(&fca, arg) = tval;
323 return fcntl(p, &fca, retval);
324 case LINUX_F_GETLK:
325 sg = stackgap_init();
326 bfp = (struct flock *) stackgap_alloc(&sg, sizeof *bfp);
327 SCARG(&fca, fd) = fd;
328 SCARG(&fca, cmd) = F_GETLK;
329 SCARG(&fca, arg) = bfp;
330 if ((error = fcntl(p, &fca, retval)))
331 return error;
332 if ((error = copyin(bfp, &bfl, sizeof bfl)))
333 return error;
334 bsd_to_linux_flock(&bfl, &lfl);
335 return copyout(&lfl, arg, sizeof lfl);
336 break;
337 case LINUX_F_SETLK:
338 case LINUX_F_SETLKW:
339 cmd = (cmd == LINUX_F_SETLK ? F_SETLK : F_SETLKW);
340 if ((error = copyin(arg, &lfl, sizeof lfl)))
341 return error;
342 linux_to_bsd_flock(&lfl, &bfl);
343 sg = stackgap_init();
344 bfp = (struct flock *) stackgap_alloc(&sg, sizeof *bfp);
345 if ((error = copyout(&bfl, bfp, sizeof bfl)))
346 return error;
347 SCARG(&fca, fd) = fd;
348 SCARG(&fca, cmd) = cmd;
349 SCARG(&fca, arg) = bfp;
350 return fcntl(p, &fca, retval);
351 break;
352 case LINUX_F_SETOWN:
353 cmd = F_SETOWN;
354 break;
355 case LINUX_F_GETOWN:
356 cmd = F_GETOWN;
357 break;
358 default:
359 return EOPNOTSUPP;
360 }
361
362 SCARG(&fca, fd) = fd;
363 SCARG(&fca, cmd) = cmd;
364 SCARG(&fca, arg) = arg;
365 return fcntl(p, uap, retval);
366 }
367
368 /*
369 * Convert a NetBSD stat structure to a Linux stat structure.
370 * Only the order of the fields and the padding in the structure
371 * is different.
372 */
373 static void
374 bsd_to_linux_stat(bsp, lsp)
375 struct stat *bsp;
376 struct linux_stat *lsp;
377 {
378 lsp->lst_dev = bsp->st_dev;
379 lsp->lst_ino = bsp->st_ino;
380 lsp->lst_mode = bsp->st_mode;
381 lsp->lst_nlink = bsp->st_nlink;
382 lsp->lst_uid = bsp->st_uid;
383 lsp->lst_gid = bsp->st_gid;
384 lsp->lst_rdev = bsp->st_rdev;
385 lsp->lst_size = bsp->st_size;
386 lsp->lst_blksize = bsp->st_blksize;
387 lsp->lst_blocks = bsp->st_blocks;
388 lsp->lst_atime = bsp->st_atime;
389 lsp->lst_mtime = bsp->st_mtime;
390 lsp->lst_ctime = bsp->st_ctime;
391 }
392
393 /*
394 * The stat functions below are plain sailing. stat and lstat are handled
395 * by one function to avoid code duplication.
396 */
397 int
398 linux_fstat(p, uap, retval)
399 struct proc *p;
400 struct linux_fstat_args /* {
401 syscallarg(int) fd;
402 syscallarg(linux_stat *) sp;
403 } */ *uap;
404 register_t *retval;
405 {
406 struct fstat_args fsa;
407 struct linux_stat tmplst;
408 struct stat *st,tmpst;
409 caddr_t sg;
410 int error;
411
412 sg = stackgap_init();
413
414 st = stackgap_alloc(&sg, sizeof (struct stat));
415
416 SCARG(&fsa, fd) = SCARG(uap, fd);
417 SCARG(&fsa, sb) = st;
418
419 if ((error = fstat(p, &fsa, retval)))
420 return error;
421
422 if ((error = copyin(st, &tmpst, sizeof tmpst)))
423 return error;
424
425 bsd_to_linux_stat(&tmpst, &tmplst);
426
427 if ((error = copyout(&tmplst, SCARG(uap, sp), sizeof tmplst)))
428 return error;
429
430 return 0;
431 }
432
433 static int
434 linux_stat1(p, uap, retval, dolstat)
435 struct proc *p;
436 struct linux_stat_args *uap;
437 register_t *retval;
438 int dolstat;
439 {
440 struct stat_args sa;
441 struct linux_stat tmplst;
442 struct stat *st, tmpst;
443 caddr_t sg;
444 int error;
445
446 sg = stackgap_init();
447
448 CHECK_ALT_EXIST(p, &sg, SCARG(uap, path));
449
450 st = stackgap_alloc(&sg, sizeof (struct stat));
451 SCARG(&sa, ub) = st;
452 SCARG(&sa, path) = SCARG(uap, path);
453
454 if ((error = (dolstat ? lstat(p, &sa, retval) : stat(p, &sa, retval))))
455 return error;
456
457 if ((error = copyin(st, &tmpst, sizeof tmpst)))
458 return error;
459
460 bsd_to_linux_stat(&tmpst, &tmplst);
461
462 if ((error = copyout(&tmplst, SCARG(uap, sp), sizeof tmplst)))
463 return error;
464
465 return 0;
466 }
467
468 int
469 linux_stat(p, uap, retval)
470 struct proc *p;
471 struct linux_stat_args /* {
472 syscallarg(char *) path;
473 syscallarg(struct linux_stat *) sp;
474 } */ *uap;
475 register_t *retval;
476 {
477 return linux_stat1(p, uap, retval, 0);
478 }
479
480 int
481 linux_lstat(p, uap, retval)
482 struct proc *p;
483 struct linux_lstat_args /* {
484 syscallarg(char *) path;
485 syscallarg(struct linux_stat *) sp;
486 } */ *uap;
487 register_t *retval;
488 {
489 return linux_stat1(p, uap, retval, 1);
490 }
491
492 /*
493 * The following syscalls are only here because of the alternate path check.
494 */
495 int
496 linux_access(p, uap, retval)
497 struct proc *p;
498 struct linux_access_args /* {
499 syscallarg(char *) path;
500 syscallarg(int) flags;
501 } */ *uap;
502 register_t *retval;
503 {
504 caddr_t sg = stackgap_init();
505
506 CHECK_ALT_EXIST(p, &sg, SCARG(uap, path));
507
508 return access(p, uap, retval);
509 }
510
511 int
512 linux_unlink(p, uap, retval)
513 struct proc *p;
514 struct linux_unlink_args /* {
515 syscallarg(char *) path;
516 } */ *uap;
517 register_t *retval;
518
519 {
520 caddr_t sg = stackgap_init();
521
522 CHECK_ALT_EXIST(p, &sg, SCARG(uap, path));
523
524 return unlink(p, uap, retval);
525 }
526
527 int linux_chdir(p, uap, retval)
528 struct proc *p;
529 struct linux_chdir_args /* {
530 syscallarg(char *) path;
531 } */ *uap;
532 register_t *retval;
533 {
534 caddr_t sg = stackgap_init();
535
536 CHECK_ALT_EXIST(p, &sg, SCARG(uap, path));
537
538 return chdir(p, uap, retval);
539 }
540
541 int
542 linux_mknod(p, uap, retval)
543 struct proc *p;
544 struct linux_mknod_args /* {
545 syscallarg(char *) path;
546 syscallarg(int) mode;
547 syscallarg(int) dev;
548 } */ *uap;
549 register_t *retval;
550 {
551 caddr_t sg = stackgap_init();
552
553 CHECK_ALT_CREAT(p, &sg, SCARG(uap, path));
554
555 return mknod(p, uap, retval);
556 }
557
558 int
559 linux_chmod(p, uap, retval)
560 struct proc *p;
561 struct linux_chmod_args /* {
562 syscallarg(char *) path;
563 syscallarg(int) mode;
564 } */ *uap;
565 register_t *retval;
566 {
567 caddr_t sg = stackgap_init();
568
569 CHECK_ALT_EXIST(p, &sg, SCARG(uap, path));
570
571 return chmod(p, uap, retval);
572 }
573
574 int
575 linux_chown(p, uap, retval)
576 struct proc *p;
577 struct linux_chown_args /* {
578 syscallarg(char *) path;
579 syscallarg(int) uid;
580 syscallarg(int) gid;
581 } */ *uap;
582 register_t *retval;
583 {
584 caddr_t sg = stackgap_init();
585
586 CHECK_ALT_EXIST(p, &sg, SCARG(uap, path));
587
588 return chmod(p, uap, retval);
589 }
590
591 int
592 linux_rename(p, uap, retval)
593 struct proc *p;
594 struct linux_rename_args /* {
595 syscallarg(char *) from;
596 syscallarg(char *) to;
597 } */ *uap;
598 register_t *retval;
599 {
600 caddr_t sg = stackgap_init();
601
602 CHECK_ALT_EXIST(p, &sg, SCARG(uap, from));
603 CHECK_ALT_CREAT(p, &sg, SCARG(uap, to));
604
605 return rename(p, uap, retval);
606 }
607
608 int
609 linux_mkdir(p, uap, retval)
610 struct proc *p;
611 struct linux_mkdir_args /* {
612 syscallarg(char *) path;
613 } */ *uap;
614 register_t *retval;
615 {
616 caddr_t sg = stackgap_init();
617
618 CHECK_ALT_CREAT(p, &sg, SCARG(uap, path));
619 return mkdir(p, uap, retval);
620 }
621
622 int
623 linux_rmdir(p, uap, retval)
624 struct proc *p;
625 struct linux_rmdir_args /* {
626 syscallarg(char *) path;
627 } */ *uap;
628 register_t *retval;
629 {
630 caddr_t sg = stackgap_init();
631
632 CHECK_ALT_EXIST(p, &sg, SCARG(uap, path));
633 return rmdir(p, uap, retval);
634 }
635
636 int
637 linux_symlink(p, uap, retval)
638 struct proc *p;
639 struct linux_symlink_args /* {
640 syscallarg(char *) path;
641 syscallarg(char *) to;
642 } */ *uap;
643 register_t *retval;
644 {
645 caddr_t sg = stackgap_init();
646
647 CHECK_ALT_EXIST(p, &sg, SCARG(uap, path));
648 CHECK_ALT_CREAT(p, &sg, SCARG(uap, to));
649
650 return symlink(p, uap, retval);
651 }
652
653 int
654 linux_readlink(p, uap, retval)
655 struct proc *p;
656 struct linux_readlink_args /* {
657 syscallarg(char *) name;
658 syscallarg(char *) buf;
659 syscallarg(int) count;
660 } */ *uap;
661 {
662 caddr_t sg = stackgap_init();
663
664 CHECK_ALT_EXIST(p, &sg, SCARG(uap, name));
665 return readlink(p, uap, retval);
666 }
667
668 int
669 linux_truncate(p, uap, retval)
670 struct proc *p;
671 struct linux_truncate_args /* {
672 syscallarg(char *) path;
673 syscallarg(long) length;
674 } */ *uap;
675 {
676 caddr_t sg = stackgap_init();
677
678 CHECK_ALT_EXIST(p, &sg, SCARG(uap, path));
679 return compat_43_truncate(p, uap, retval);
680 }
681