1 /*
   2  * CDDL HEADER START
   3  *
   4  * The contents of this file are subject to the terms of the
   5  * Common Development and Distribution License (the "License").
   6  * You may not use this file except in compliance with the License.
   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 
  22 /*
  23  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  24  * Use is subject to license terms.
  25  */
  26 
  27 #include <sys/types.h>
  28 #include <sys/stat.h>
  29 #include <sys/inttypes.h>
  30 #include <unistd.h>
  31 #include <fcntl.h>
  32 #include <errno.h>
  33 #include <libintl.h>
  34 #include <stdio.h>
  35 
  36 #include <sys/lx_types.h>
  37 #include <sys/lx_debug.h>
  38 #include <sys/lx_syscall.h>
  39 #include <sys/lx_fcntl.h>
  40 #include <sys/lx_misc.h>
  41 
  42 static int
  43 ltos_open_flags(uintptr_t p2)
  44 {
  45         int flags;
  46 
  47         if ((p2 & O_ACCMODE) == LX_O_RDONLY)
  48                 flags = O_RDONLY;
  49         else if ((p2 & O_ACCMODE) == LX_O_WRONLY)
  50                 flags = O_WRONLY;
  51         else
  52                 flags = O_RDWR;
  53 
  54         if (p2 & LX_O_CREAT) {
  55                 flags |= O_CREAT;
  56         }
  57 
  58         if (p2 & LX_O_EXCL)
  59                 flags |= O_EXCL;
  60         if (p2 & LX_O_NOCTTY)
  61                 flags |= O_NOCTTY;
  62         if (p2 & LX_O_TRUNC)
  63                 flags |= O_TRUNC;
  64         if (p2 & LX_O_APPEND)
  65                 flags |= O_APPEND;
  66         if (p2 & LX_O_NONBLOCK)
  67                 flags |= O_NONBLOCK;
  68         if (p2 & LX_O_SYNC)
  69                 flags |= O_SYNC;
  70         if (p2 & LX_O_LARGEFILE)
  71                 flags |= O_LARGEFILE;
  72         if (p2 & LX_O_NOFOLLOW)
  73                 flags |= O_NOFOLLOW;
  74 
  75         /*
  76          * Linux uses the LX_O_DIRECT flag to do raw, synchronous I/O to the
  77          * device backing the fd in question.  Solaris doesn't have similar
  78          * functionality, but we can attempt to simulate it using the flags
  79          * (O_RSYNC|O_SYNC) and directio(3C).
  80          *
  81          * The LX_O_DIRECT flag also requires that the transfer size and
  82          * alignment of I/O buffers be a multiple of the logical block size for
  83          * the underlying file system, but frankly there isn't an easy way to
  84          * support that functionality without doing something like adding an
  85          * fcntl(2) flag to denote LX_O_DIRECT mode.
  86          *
  87          * Since LX_O_DIRECT is merely a performance advisory, we'll just
  88          * emulate what we can and trust that the only applications expecting
  89          * an error when performing I/O from a misaligned buffer or when
  90          * passing a transfer size is not a multiple of the underlying file
  91          * system block size will be test suites.
  92          */
  93         if (p2 & LX_O_DIRECT)
  94                 flags |= (O_RSYNC|O_SYNC);
  95 
  96         return (flags);
  97 }
  98 
  99 static int
 100 lx_open_postprocess(int fd, uintptr_t p2)
 101 {
 102         struct stat64 statbuf;
 103 
 104         /*
 105          * Check the file type AFTER opening the file to avoid a race condition
 106          * where the file we want to open could change types between a stat64()
 107          * and an open().
 108          */
 109         if (p2 & LX_O_DIRECTORY) {
 110                 if (fstat64(fd, &statbuf) < 0) {
 111                         int ret = -errno;
 112 
 113                         (void) close(fd);
 114                         return (ret);
 115                 } else if (!S_ISDIR(statbuf.st_mode)) {
 116                         (void) close(fd);
 117                         return (-ENOTDIR);
 118                 }
 119         }
 120 
 121         if (p2 & LX_O_DIRECT)
 122                 (void) directio(fd, DIRECTIO_ON);
 123 
 124         /*
 125          * Set the ASYNC flag if passsed.
 126          */
 127         if (p2 & LX_O_ASYNC) {
 128                 if (fcntl(fd, F_SETFL, FASYNC) < 0) {
 129                         int ret = -errno;
 130 
 131                         (void) close(fd);
 132                         return (ret);
 133                 }
 134         }
 135 
 136         return (fd);
 137 }
 138 
 139 int
 140 lx_openat(uintptr_t ext1, uintptr_t p1, uintptr_t p2, uintptr_t p3)
 141 {
 142         int atfd = (int)ext1;
 143         int flags, fd;
 144         mode_t mode = 0;
 145         char *path = (char *)p1;
 146 
 147         if (atfd == LX_AT_FDCWD)
 148                 atfd = AT_FDCWD;
 149 
 150         flags = ltos_open_flags(p2);
 151 
 152         if (flags & O_CREAT) {
 153                 mode = (mode_t)p3;
 154         }
 155 
 156         lx_debug("\topenat(%d, %s, 0%o, 0%o)", atfd, path, flags, mode);
 157 
 158         if ((fd = openat(atfd, path, flags, mode)) < 0)
 159                 return (-errno);
 160 
 161         return (lx_open_postprocess(fd, p2));
 162 }
 163 
 164 int
 165 lx_open(uintptr_t p1, uintptr_t p2, uintptr_t p3)
 166 {
 167         int flags, fd;
 168         mode_t mode = 0;
 169         char *path = (char *)p1;
 170 
 171         flags = ltos_open_flags(p2);
 172 
 173         if (flags & O_CREAT) {
 174                 mode = (mode_t)p3;
 175         }
 176 
 177         lx_debug("\topen(%s, 0%o, 0%o)", path, flags, mode);
 178 
 179         if ((fd = open(path, flags, mode)) < 0)
 180                 return (-errno);
 181 
 182         return (lx_open_postprocess(fd, p2));
 183 }