initial commit
[freebsd-arm:freebsd-arm.git] / compat / svr4 / svr4_fcntl.c
1 /*-
2  * Copyright (c) 1998 Mark Newton
3  * Copyright (c) 1994, 1997 Christos Zoulas.  
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  * 3. All advertising materials mentioning features or use of this software
15  *    must display the following acknowledgement:
16  *      This product includes software developed by Christos Zoulas.
17  * 4. The name of the author may not be used to endorse or promote products
18  *    derived from this software without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
21  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
22  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
23  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
24  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
25  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
29  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30  */
31
32 #include <sys/cdefs.h>
33 __FBSDID("$FreeBSD$");
34
35 #include <sys/param.h>
36 #include <sys/systm.h>
37 #include <sys/file.h>
38 #include <sys/filedesc.h>
39 /*#include <sys/ioctl.h>*/
40 #include <sys/lock.h>
41 #include <sys/malloc.h>
42 #include <sys/mount.h>
43 #include <sys/mutex.h>
44 #include <sys/namei.h>
45 #include <sys/priv.h>
46 #include <sys/proc.h>
47 #include <sys/stat.h>
48 #include <sys/syscallsubr.h>
49 #include <sys/unistd.h>
50 #include <sys/vnode.h>
51
52 #include <sys/sysproto.h>
53
54 #include <compat/svr4/svr4.h>
55 #include <compat/svr4/svr4_types.h>
56 #include <compat/svr4/svr4_signal.h>
57 #include <compat/svr4/svr4_proto.h>
58 #include <compat/svr4/svr4_util.h>
59 #include <compat/svr4/svr4_fcntl.h>
60
61 #include <security/mac/mac_framework.h>
62
63 static int svr4_to_bsd_flags(int);
64 static u_long svr4_to_bsd_cmd(u_long);
65 static int fd_revoke(struct thread *, int);
66 static int fd_truncate(struct thread *, int, struct flock *);
67 static int bsd_to_svr4_flags(int);
68 static void bsd_to_svr4_flock(struct flock *, struct svr4_flock *);
69 static void svr4_to_bsd_flock(struct svr4_flock *, struct flock *);
70 static void bsd_to_svr4_flock64(struct flock *, struct svr4_flock64 *);
71 static void svr4_to_bsd_flock64(struct svr4_flock64 *, struct flock *);
72
73 static u_long
74 svr4_to_bsd_cmd(cmd)
75         u_long  cmd;
76 {
77         switch (cmd) {
78         case SVR4_F_DUPFD:
79                 return F_DUPFD;
80         case SVR4_F_DUP2FD:
81                 return F_DUP2FD;
82         case SVR4_F_GETFD:
83                 return F_GETFD;
84         case SVR4_F_SETFD:
85                 return F_SETFD;
86         case SVR4_F_GETFL:
87                 return F_GETFL;
88         case SVR4_F_SETFL:
89                 return F_SETFL;
90         case SVR4_F_GETLK:
91                 return F_GETLK;
92         case SVR4_F_SETLK:
93                 return F_SETLK;
94         case SVR4_F_SETLKW:
95                 return F_SETLKW;
96         default:
97                 return -1;
98         }
99 }
100
101 static int
102 svr4_to_bsd_flags(l)
103         int     l;
104 {
105         int     r = 0;
106         r |= (l & SVR4_O_RDONLY) ? O_RDONLY : 0;
107         r |= (l & SVR4_O_WRONLY) ? O_WRONLY : 0;
108         r |= (l & SVR4_O_RDWR) ? O_RDWR : 0;
109         r |= (l & SVR4_O_NDELAY) ? O_NONBLOCK : 0;
110         r |= (l & SVR4_O_APPEND) ? O_APPEND : 0;
111         r |= (l & SVR4_O_SYNC) ? O_FSYNC : 0;
112         r |= (l & SVR4_O_NONBLOCK) ? O_NONBLOCK : 0;
113         r |= (l & SVR4_O_PRIV) ? O_EXLOCK : 0;
114         r |= (l & SVR4_O_CREAT) ? O_CREAT : 0;
115         r |= (l & SVR4_O_TRUNC) ? O_TRUNC : 0;
116         r |= (l & SVR4_O_EXCL) ? O_EXCL : 0;
117         r |= (l & SVR4_O_NOCTTY) ? O_NOCTTY : 0;
118         return r;
119 }
120
121 static int
122 bsd_to_svr4_flags(l)
123         int     l;
124 {
125         int     r = 0;
126         r |= (l & O_RDONLY) ? SVR4_O_RDONLY : 0;
127         r |= (l & O_WRONLY) ? SVR4_O_WRONLY : 0;
128         r |= (l & O_RDWR) ? SVR4_O_RDWR : 0;
129         r |= (l & O_NDELAY) ? SVR4_O_NONBLOCK : 0;
130         r |= (l & O_APPEND) ? SVR4_O_APPEND : 0;
131         r |= (l & O_FSYNC) ? SVR4_O_SYNC : 0;
132         r |= (l & O_NONBLOCK) ? SVR4_O_NONBLOCK : 0;
133         r |= (l & O_EXLOCK) ? SVR4_O_PRIV : 0;
134         r |= (l & O_CREAT) ? SVR4_O_CREAT : 0;
135         r |= (l & O_TRUNC) ? SVR4_O_TRUNC : 0;
136         r |= (l & O_EXCL) ? SVR4_O_EXCL : 0;
137         r |= (l & O_NOCTTY) ? SVR4_O_NOCTTY : 0;
138         return r;
139 }
140
141
142 static void
143 bsd_to_svr4_flock(iflp, oflp)
144         struct flock            *iflp;
145         struct svr4_flock       *oflp;
146 {
147         switch (iflp->l_type) {
148         case F_RDLCK:
149                 oflp->l_type = SVR4_F_RDLCK;
150                 break;
151         case F_WRLCK:
152                 oflp->l_type = SVR4_F_WRLCK;
153                 break;
154         case F_UNLCK:
155                 oflp->l_type = SVR4_F_UNLCK;
156                 break;
157         default:
158                 oflp->l_type = -1;
159                 break;
160         }
161
162         oflp->l_whence = (short) iflp->l_whence;
163         oflp->l_start = (svr4_off_t) iflp->l_start;
164         oflp->l_len = (svr4_off_t) iflp->l_len;
165         oflp->l_sysid = 0;
166         oflp->l_pid = (svr4_pid_t) iflp->l_pid;
167 }
168
169
170 static void
171 svr4_to_bsd_flock(iflp, oflp)
172         struct svr4_flock       *iflp;
173         struct flock            *oflp;
174 {
175         switch (iflp->l_type) {
176         case SVR4_F_RDLCK:
177                 oflp->l_type = F_RDLCK;
178                 break;
179         case SVR4_F_WRLCK:
180                 oflp->l_type = F_WRLCK;
181                 break;
182         case SVR4_F_UNLCK:
183                 oflp->l_type = F_UNLCK;
184                 break;
185         default:
186                 oflp->l_type = -1;
187                 break;
188         }
189
190         oflp->l_whence = iflp->l_whence;
191         oflp->l_start = (off_t) iflp->l_start;
192         oflp->l_len = (off_t) iflp->l_len;
193         oflp->l_pid = (pid_t) iflp->l_pid;
194         oflp->l_sysid = iflp->l_sysid;
195 }
196
197 static void
198 bsd_to_svr4_flock64(iflp, oflp)
199         struct flock            *iflp;
200         struct svr4_flock64     *oflp;
201 {
202         switch (iflp->l_type) {
203         case F_RDLCK:
204                 oflp->l_type = SVR4_F_RDLCK;
205                 break;
206         case F_WRLCK:
207                 oflp->l_type = SVR4_F_WRLCK;
208                 break;
209         case F_UNLCK:
210                 oflp->l_type = SVR4_F_UNLCK;
211                 break;
212         default:
213                 oflp->l_type = -1;
214                 break;
215         }
216
217         oflp->l_whence = (short) iflp->l_whence;
218         oflp->l_start = (svr4_off64_t) iflp->l_start;
219         oflp->l_len = (svr4_off64_t) iflp->l_len;
220         oflp->l_sysid = iflp->l_sysid;
221         oflp->l_pid = (svr4_pid_t) iflp->l_pid;
222 }
223
224
225 static void
226 svr4_to_bsd_flock64(iflp, oflp)
227         struct svr4_flock64     *iflp;
228         struct flock            *oflp;
229 {
230         switch (iflp->l_type) {
231         case SVR4_F_RDLCK:
232                 oflp->l_type = F_RDLCK;
233                 break;
234         case SVR4_F_WRLCK:
235                 oflp->l_type = F_WRLCK;
236                 break;
237         case SVR4_F_UNLCK:
238                 oflp->l_type = F_UNLCK;
239                 break;
240         default:
241                 oflp->l_type = -1;
242                 break;
243         }
244
245         oflp->l_whence = iflp->l_whence;
246         oflp->l_start = (off_t) iflp->l_start;
247         oflp->l_len = (off_t) iflp->l_len;
248         oflp->l_pid = (pid_t) iflp->l_pid;
249
250 }
251
252
253 static int
254 fd_revoke(td, fd)
255         struct thread *td;
256         int fd;
257 {
258         struct vnode *vp;
259         struct mount *mp;
260         struct vattr vattr;
261         int error, *retval;
262
263         retval = td->td_retval;
264         if ((error = fgetvp(td, fd, &vp)) != 0)
265                 return (error);
266
267         if (vp->v_type != VCHR && vp->v_type != VBLK) {
268                 error = EINVAL;
269                 goto out;
270         }
271
272 #ifdef MAC
273         vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
274         error = mac_vnode_check_revoke(td->td_ucred, vp);
275         VOP_UNLOCK(vp, 0);
276         if (error)
277                 goto out;
278 #endif
279
280         if ((error = VOP_GETATTR(vp, &vattr, td->td_ucred)) != 0)
281                 goto out;
282
283         if (td->td_ucred->cr_uid != vattr.va_uid &&
284             (error = priv_check(td, PRIV_VFS_ADMIN)) != 0)
285                 goto out;
286
287         if ((error = vn_start_write(vp, &mp, V_WAIT | PCATCH)) != 0)
288                 goto out;
289         if (vcount(vp) > 1)
290                 VOP_REVOKE(vp, REVOKEALL);
291         vn_finished_write(mp);
292 out:
293         vrele(vp);
294         return error;
295 }
296
297
298 static int
299 fd_truncate(td, fd, flp)
300         struct thread *td;
301         int fd;
302         struct flock *flp;
303 {
304         off_t start, length;
305         struct file *fp;
306         struct vnode *vp;
307         struct vattr vattr;
308         int error, *retval;
309         struct ftruncate_args ft;
310
311         retval = td->td_retval;
312
313         /*
314          * We only support truncating the file.
315          */
316         if ((error = fget(td, fd, &fp)) != 0)
317                 return (error);
318
319         vp = fp->f_vnode;
320
321         if (fp->f_type != DTYPE_VNODE || vp->v_type == VFIFO) {
322                 fdrop(fp, td);
323                 return ESPIPE;
324         }
325
326         if ((error = VOP_GETATTR(vp, &vattr, td->td_ucred)) != 0) {
327                 fdrop(fp, td);
328                 return error;
329         }
330
331         length = vattr.va_size;
332
333         switch (flp->l_whence) {
334         case SEEK_CUR:
335                 start = fp->f_offset + flp->l_start;
336                 break;
337
338         case SEEK_END:
339                 start = flp->l_start + length;
340                 break;
341
342         case SEEK_SET:
343                 start = flp->l_start;
344                 break;
345
346         default:
347                 fdrop(fp, td);
348                 return EINVAL;
349         }
350
351         if (start + flp->l_len < length) {
352                 /* We don't support free'ing in the middle of the file */
353                 fdrop(fp, td);
354                 return EINVAL;
355         }
356
357         ft.fd = fd;
358         ft.length = start;
359
360         error = ftruncate(td, &ft);
361
362         fdrop(fp, td);
363         return (error);
364 }
365
366 int
367 svr4_sys_open(td, uap)
368         struct thread *td;
369         struct svr4_sys_open_args *uap;
370 {
371         struct proc *p = td->td_proc;
372         char *newpath;
373         int bsd_flags, error, retval;
374
375         CHECKALTEXIST(td, uap->path, &newpath);
376
377         bsd_flags = svr4_to_bsd_flags(uap->flags);
378         error = kern_open(td, newpath, UIO_SYSSPACE, bsd_flags, uap->mode);
379         free(newpath, M_TEMP);
380
381         if (error) {
382           /*            uprintf("svr4_open(%s, 0x%0x, 0%o): %d\n", uap->path,
383                         uap->flags, uap->mode, error);*/
384                 return error;
385         }
386
387         retval = td->td_retval[0];
388
389         PROC_LOCK(p);
390         if (!(bsd_flags & O_NOCTTY) && SESS_LEADER(p) &&
391             !(p->p_flag & P_CONTROLT)) {
392 #if defined(NOTYET)
393                 struct file     *fp;
394
395                 error = fget(td, retval, &fp);
396                 PROC_UNLOCK(p);
397                 /*
398                  * we may have lost a race the above open() and
399                  * another thread issuing a close()
400                  */
401                 if (error) 
402                         return (EBADF); /* XXX: correct errno? */
403                 /* ignore any error, just give it a try */
404                 if (fp->f_type == DTYPE_VNODE)
405                         fo_ioctl(fp, TIOCSCTTY, (caddr_t) 0, td->td_ucred,
406                             td);
407                 fdrop(fp, td);
408         } else {
409                 PROC_UNLOCK(p);
410         }
411 #else
412         }
413         PROC_UNLOCK(p);
414 #endif
415         return error;
416 }
417
418 int
419 svr4_sys_open64(td, uap)
420         struct thread *td;
421         struct svr4_sys_open64_args *uap;
422 {
423         return svr4_sys_open(td, (struct svr4_sys_open_args *)uap);
424 }
425
426 int
427 svr4_sys_creat(td, uap)
428         struct thread *td;
429         struct svr4_sys_creat_args *uap;
430 {
431         char *newpath;
432         int error;
433
434         CHECKALTEXIST(td, uap->path, &newpath);
435
436         error = kern_open(td, newpath, UIO_SYSSPACE, O_WRONLY | O_CREAT |
437             O_TRUNC, uap->mode);
438         free(newpath, M_TEMP);
439         return (error);
440 }
441
442 int
443 svr4_sys_creat64(td, uap)
444         struct thread *td;
445         struct svr4_sys_creat64_args *uap;
446 {
447         return svr4_sys_creat(td, (struct svr4_sys_creat_args *)uap);
448 }
449
450 int
451 svr4_sys_llseek(td, uap)
452         struct thread *td;
453         struct svr4_sys_llseek_args *uap;
454 {
455         struct lseek_args ap;
456
457         ap.fd = uap->fd;
458
459 #if BYTE_ORDER == BIG_ENDIAN
460         ap.offset = (((u_int64_t) uap->offset1) << 32) | 
461                 uap->offset2;
462 #else
463         ap.offset = (((u_int64_t) uap->offset2) << 32) | 
464                 uap->offset1;
465 #endif
466         ap.whence = uap->whence;
467
468         return lseek(td, &ap);
469 }
470
471 int
472 svr4_sys_access(td, uap)
473         struct thread *td;
474         struct svr4_sys_access_args *uap;
475 {
476         char *newpath;
477         int error;
478
479         CHECKALTEXIST(td, uap->path, &newpath);
480         error = kern_access(td, newpath, UIO_SYSSPACE, uap->flags);
481         free(newpath, M_TEMP);
482         return (error);
483 }
484
485 #if defined(NOTYET)
486 int
487 svr4_sys_pread(td, uap)
488         struct thread *td;
489         struct svr4_sys_pread_args *uap;
490 {
491         struct pread_args pra;
492
493         /*
494          * Just translate the args structure and call the NetBSD
495          * pread(2) system call (offset type is 64-bit in NetBSD).
496          */
497         pra.fd = uap->fd;
498         pra.buf = uap->buf;
499         pra.nbyte = uap->nbyte;
500         pra.offset = uap->off;
501
502         return pread(td, &pra);
503 }
504 #endif
505
506 #if defined(NOTYET)
507 int
508 svr4_sys_pread64(td, v, retval)
509         struct thread *td;
510         void *v; 
511         register_t *retval;
512 {
513
514         struct svr4_sys_pread64_args *uap = v;
515         struct sys_pread_args pra;
516
517         /*
518          * Just translate the args structure and call the NetBSD
519          * pread(2) system call (offset type is 64-bit in NetBSD).
520          */
521         pra.fd = uap->fd;
522         pra.buf = uap->buf;
523         pra.nbyte = uap->nbyte;
524         pra.offset = uap->off;
525
526         return (sys_pread(td, &pra, retval));
527 }
528 #endif /* NOTYET */
529
530 #if defined(NOTYET)
531 int
532 svr4_sys_pwrite(td, uap)
533         struct thread *td;
534         struct svr4_sys_pwrite_args *uap;
535 {
536         struct pwrite_args pwa;
537
538         /*
539          * Just translate the args structure and call the NetBSD
540          * pwrite(2) system call (offset type is 64-bit in NetBSD).
541          */
542         pwa.fd = uap->fd;
543         pwa.buf = uap->buf;
544         pwa.nbyte = uap->nbyte;
545         pwa.offset = uap->off;
546
547         return pwrite(td, &pwa);
548 }
549 #endif
550
551 #if defined(NOTYET)
552 int
553 svr4_sys_pwrite64(td, v, retval)
554         struct thread *td;
555         void *v; 
556         register_t *retval;
557 {
558         struct svr4_sys_pwrite64_args *uap = v;
559         struct sys_pwrite_args pwa;
560
561         /*
562          * Just translate the args structure and call the NetBSD
563          * pwrite(2) system call (offset type is 64-bit in NetBSD).
564          */
565         pwa.fd = uap->fd;
566         pwa.buf = uap->buf;
567         pwa.nbyte = uap->nbyte;
568         pwa.offset = uap->off;
569
570         return (sys_pwrite(td, &pwa, retval));
571 }
572 #endif /* NOTYET */
573
574 int
575 svr4_sys_fcntl(td, uap)
576         struct thread *td;
577         struct svr4_sys_fcntl_args *uap;
578 {
579         int cmd, error, *retval;
580
581         retval = td->td_retval;
582
583         cmd = svr4_to_bsd_cmd(uap->cmd);
584
585         switch (cmd) {
586         case F_DUPFD:
587         case F_DUP2FD:
588         case F_GETFD:
589         case F_SETFD:
590                 return (kern_fcntl(td, uap->fd, cmd, (intptr_t)uap->arg));
591
592         case F_GETFL:
593                 error = kern_fcntl(td, uap->fd, cmd, (intptr_t)uap->arg);
594                 if (error)
595                         return (error);
596                 *retval = bsd_to_svr4_flags(*retval);
597                 return (error);
598
599         case F_SETFL:
600                 {
601                         /*
602                          * we must save the O_ASYNC flag, as that is
603                          * handled by ioctl(_, I_SETSIG, _) emulation.
604                          */
605                         int flags;
606
607                         DPRINTF(("Setting flags %p\n", uap->arg));
608
609                         error = kern_fcntl(td, uap->fd, F_GETFL, 0);
610                         if (error)
611                                 return (error);
612                         flags = *retval;
613                         flags &= O_ASYNC;
614                         flags |= svr4_to_bsd_flags((u_long) uap->arg);
615                         return (kern_fcntl(td, uap->fd, F_SETFL, flags));
616                 }
617
618         case F_GETLK:
619         case F_SETLK:
620         case F_SETLKW:
621                 {
622                         struct svr4_flock       ifl;
623                         struct flock            fl;
624
625                         error = copyin(uap->arg, &ifl, sizeof (ifl));
626                         if (error)
627                                 return (error);
628
629                         svr4_to_bsd_flock(&ifl, &fl);
630
631                         error = kern_fcntl(td, uap->fd, cmd, (intptr_t)&fl);
632                         if (error || cmd != F_GETLK)
633                                 return (error);
634
635                         bsd_to_svr4_flock(&fl, &ifl);
636
637                         return (copyout(&ifl, uap->arg, sizeof (ifl)));
638                 }
639         case -1:
640                 switch (uap->cmd) {
641                 case SVR4_F_FREESP:
642                         {
643                                 struct svr4_flock        ifl;
644                                 struct flock             fl;
645
646                                 error = copyin(uap->arg, &ifl,
647                                     sizeof ifl);
648                                 if (error)
649                                         return error;
650                                 svr4_to_bsd_flock(&ifl, &fl);
651                                 return fd_truncate(td, uap->fd, &fl);
652                         }
653
654                 case SVR4_F_GETLK64:
655                 case SVR4_F_SETLK64:
656                 case SVR4_F_SETLKW64:
657                         {
658                                 struct svr4_flock64     ifl;
659                                 struct flock            fl;
660
661                                 switch (uap->cmd) {
662                                 case SVR4_F_GETLK64:
663                                         cmd = F_GETLK;
664                                         break;
665                                 case SVR4_F_SETLK64:
666                                         cmd = F_SETLK;
667                                         break;                                  
668                                 case SVR4_F_SETLKW64:
669                                         cmd = F_SETLKW;
670                                         break;
671                                 }
672                                 error = copyin(uap->arg, &ifl,
673                                     sizeof (ifl));
674                                 if (error)
675                                         return (error);
676
677                                 svr4_to_bsd_flock64(&ifl, &fl);
678
679                                 error = kern_fcntl(td, uap->fd, cmd,
680                                     (intptr_t)&fl);
681                                 if (error || cmd != F_GETLK)
682                                         return (error);
683
684                                 bsd_to_svr4_flock64(&fl, &ifl);
685
686                                 return (copyout(&ifl, uap->arg,
687                                     sizeof (ifl)));
688                         }
689
690                 case SVR4_F_FREESP64:
691                         {
692                                 struct svr4_flock64      ifl;
693                                 struct flock             fl;
694
695                                 error = copyin(uap->arg, &ifl,
696                                     sizeof ifl);
697                                 if (error)
698                                         return error;
699                                 svr4_to_bsd_flock64(&ifl, &fl);
700                                 return fd_truncate(td, uap->fd, &fl);
701                         }
702
703                 case SVR4_F_REVOKE:
704                         return fd_revoke(td, uap->fd);
705
706                 default:
707                         return ENOSYS;
708                 }
709
710         default:
711                 return ENOSYS;
712         }
713 }