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 2007 Sun Microsystems, Inc.  All rights reserved.
  24  * Use is subject to license terms.
  25  */
  26 
  27 
  28 #pragma ident   "%Z%%M% %I%     %E% SMI"
  29 
  30 #include <sys/types.h>
  31 #include <sys/filio.h>
  32 #include <unistd.h>
  33 #include <fcntl.h>
  34 #include <stropts.h>
  35 #include <libintl.h>
  36 #include <errno.h>
  37 #include <string.h>
  38 
  39 #include <sys/lx_fcntl.h>
  40 #include <sys/lx_debug.h>
  41 #include <sys/lx_misc.h>
  42 
  43 static int lx_fcntl_com(int fd, int cmd, ulong_t arg);
  44 static void ltos_flock(struct lx_flock *l, struct flock *s);
  45 static void stol_flock(struct flock *s, struct lx_flock *l);
  46 static void ltos_flock64(struct lx_flock64 *l, struct flock64 *s);
  47 static void stol_flock64(struct flock64 *s, struct lx_flock64 *l);
  48 static short ltos_type(short l_type);
  49 static short stol_type(short l_type);
  50 static int lx_fcntl_getfl(int fd);
  51 static int lx_fcntl_setfl(int fd, ulong_t arg);
  52 
  53 int
  54 lx_dup2(uintptr_t p1, uintptr_t p2)
  55 {
  56         int oldfd = (int)p1;
  57         int newfd = (int)p2;
  58         int rc;
  59 
  60         rc = fcntl(oldfd, F_DUP2FD, newfd);
  61         return ((rc == -1) ? -errno : rc);
  62 }
  63 
  64 int
  65 lx_fcntl(uintptr_t p1, uintptr_t p2, uintptr_t p3)
  66 {
  67         int             fd = (int)p1;
  68         int             cmd = (int)p2;
  69         ulong_t         arg = (ulong_t)p3;
  70         struct lx_flock lxflk;
  71         struct flock    fl;
  72         int             lk = 0;
  73         int             rc;
  74 
  75         /*
  76          * The 64-bit fcntl commands must go through fcntl64().
  77          */
  78         if (cmd == LX_F_GETLK64 || cmd == LX_F_SETLK64 ||
  79             cmd == LX_F_SETLKW64)
  80                 return (-EINVAL);
  81 
  82         if (cmd == LX_F_SETSIG || cmd == LX_F_GETSIG || cmd == LX_F_SETLEASE ||
  83             cmd == LX_F_GETLEASE) {
  84                 lx_unsupported(gettext("%s(): unsupported command: %d"),
  85                     "fcntl", cmd);
  86                 return (-ENOTSUP);
  87         }
  88 
  89         if (cmd == LX_F_GETLK || cmd == LX_F_SETLK ||
  90             cmd == LX_F_SETLKW) {
  91                 if (uucopy((void *)p3, (void *)&lxflk,
  92                     sizeof (struct lx_flock)) != 0)
  93                         return (-errno);
  94                 lk = 1;
  95                 ltos_flock(&lxflk, &fl);
  96                 arg = (ulong_t)&fl;
  97         }
  98 
  99         rc = lx_fcntl_com(fd, cmd, arg);
 100 
 101         if (lk)
 102                 stol_flock(&fl, (struct lx_flock *)p3);
 103 
 104         return (rc);
 105 }
 106 
 107 int
 108 lx_fcntl64(uintptr_t p1, uintptr_t p2, uintptr_t p3)
 109 {
 110         int             fd = (int)p1;
 111         int             cmd = (int)p2;
 112         struct lx_flock lxflk;
 113         struct lx_flock64 lxflk64;
 114         struct flock    fl;
 115         struct flock64  fl64;
 116         int             rc;
 117 
 118         if (cmd == LX_F_SETSIG || cmd == LX_F_GETSIG || cmd == LX_F_SETLEASE ||
 119             cmd == LX_F_GETLEASE) {
 120                 lx_unsupported(gettext("%s(): unsupported command: %d"),
 121                     "fcntl64", cmd);
 122                 return (-ENOTSUP);
 123         }
 124 
 125         if (cmd == LX_F_GETLK || cmd == LX_F_SETLK || cmd == LX_F_SETLKW) {
 126                 if (uucopy((void *)p3, (void *)&lxflk,
 127                     sizeof (struct lx_flock)) != 0)
 128                         return (-errno);
 129                 ltos_flock(&lxflk, &fl);
 130                 rc = lx_fcntl_com(fd, cmd, (ulong_t)&fl);
 131                 stol_flock(&fl, (struct lx_flock *)p3);
 132         } else if (cmd == LX_F_GETLK64 || cmd == LX_F_SETLKW64 || \
 133             cmd == LX_F_SETLK64) {
 134                 if (uucopy((void *)p3, (void *)&lxflk64,
 135                     sizeof (struct lx_flock64)) != 0)
 136                         return (-errno);
 137                 ltos_flock64(&lxflk64, &fl64);
 138                 rc = lx_fcntl_com(fd, cmd, (ulong_t)&fl64);
 139                 stol_flock64(&fl64, (struct lx_flock64 *)p3);
 140         } else {
 141                 rc = lx_fcntl_com(fd, cmd, (ulong_t)p3);
 142         }
 143 
 144         return (rc);
 145 }
 146 
 147 static int
 148 lx_fcntl_com(int fd, int cmd, ulong_t arg)
 149 {
 150         int             rc = 0;
 151 
 152         switch (cmd) {
 153         case LX_F_DUPFD:
 154                 rc = fcntl(fd, F_DUPFD, arg);
 155                 break;
 156 
 157         case LX_F_GETFD:
 158                 rc = fcntl(fd, F_GETFD, 0);
 159                 break;
 160 
 161         case LX_F_SETFD:
 162                 rc = fcntl(fd, F_SETFD, arg);
 163                 break;
 164 
 165         case LX_F_GETFL:
 166                 rc = lx_fcntl_getfl(fd);
 167                 break;
 168 
 169         case LX_F_SETFL:
 170                 rc = lx_fcntl_setfl(fd, arg);
 171                 break;
 172 
 173         case LX_F_GETLK:
 174                 rc = fcntl(fd, F_GETLK, arg);
 175                 break;
 176 
 177         case LX_F_SETLK:
 178                 rc = fcntl(fd, F_SETLK, arg);
 179                 break;
 180 
 181         case LX_F_SETLKW:
 182                 rc = fcntl(fd, F_SETLKW, arg);
 183                 break;
 184 
 185         case LX_F_GETLK64:
 186                 rc = fcntl(fd, F_GETLK64, arg);
 187                 break;
 188 
 189         case LX_F_SETLK64:
 190                 rc = fcntl(fd, F_SETLK64, arg);
 191                 break;
 192 
 193         case LX_F_SETLKW64:
 194                 rc = fcntl(fd, F_SETLKW64, arg);
 195                 break;
 196 
 197         case LX_F_SETOWN:
 198                 rc = fcntl(fd, F_SETOWN, arg);
 199                 break;
 200 
 201         case LX_F_GETOWN:
 202                 rc = fcntl(fd, F_GETOWN, arg);
 203                 break;
 204 
 205         default:
 206                 return (-EINVAL);
 207         }
 208 
 209         return ((rc == -1) ? -errno : rc);
 210 }
 211 
 212 
 213 #define LTOS_FLOCK(l, s)                                                \
 214 {                                                                       \
 215         s->l_type = ltos_type(l->l_type);                         \
 216         s->l_whence = l->l_whence;                                        \
 217         s->l_start = l->l_start;                                  \
 218         s->l_len = l->l_len;                                              \
 219         s->l_sysid = 0;                      /* not defined in linux */      \
 220         s->l_pid = (pid_t)l->l_pid;                                       \
 221 }
 222 
 223 #define STOL_FLOCK(s, l)                                                \
 224 {                                                                       \
 225         l->l_type = stol_type(s->l_type);                         \
 226         l->l_whence = s->l_whence;                                        \
 227         l->l_start = s->l_start;                                  \
 228         l->l_len = s->l_len;                                              \
 229         l->l_pid = (int)s->l_pid;                                 \
 230 }
 231 
 232 static void
 233 ltos_flock(struct lx_flock *l, struct flock *s)
 234 {
 235         LTOS_FLOCK(l, s)
 236 }
 237 
 238 static void
 239 stol_flock(struct flock *s, struct lx_flock *l)
 240 {
 241         STOL_FLOCK(s, l)
 242 }
 243 
 244 static void
 245 ltos_flock64(struct lx_flock64 *l, struct flock64 *s)
 246 {
 247         LTOS_FLOCK(l, s)
 248 }
 249 
 250 static void
 251 stol_flock64(struct flock64 *s, struct lx_flock64 *l)
 252 {
 253         STOL_FLOCK(s, l)
 254 }
 255 
 256 static short
 257 ltos_type(short l_type)
 258 {
 259         switch (l_type) {
 260         case LX_F_RDLCK:
 261                 return (F_RDLCK);
 262         case LX_F_WRLCK:
 263                 return (F_WRLCK);
 264         case LX_F_UNLCK:
 265                 return (F_UNLCK);
 266         default:
 267                 return (-1);
 268         }
 269 }
 270 
 271 static short
 272 stol_type(short l_type)
 273 {
 274         switch (l_type) {
 275         case F_RDLCK:
 276                 return (LX_F_RDLCK);
 277         case F_WRLCK:
 278                 return (LX_F_WRLCK);
 279         case F_UNLCK:
 280                 return (LX_F_UNLCK);
 281         default:
 282                 /* can't ever happen */
 283                 return (0);
 284         }
 285 }
 286 
 287 int
 288 lx_fcntl_getfl(int fd)
 289 {
 290         int retval;
 291         int rc;
 292 
 293         retval = fcntl(fd, F_GETFL, 0);
 294 
 295         if ((retval & O_ACCMODE) == O_RDONLY)
 296                 rc = LX_O_RDONLY;
 297         else if ((retval & O_ACCMODE) == O_WRONLY)
 298                 rc = LX_O_WRONLY;
 299         else
 300                 rc = LX_O_RDWR;
 301         /* O_NDELAY != O_NONBLOCK, so we need to check for both */
 302         if (retval & O_NDELAY)
 303                 rc |= LX_O_NDELAY;
 304         if (retval & O_NONBLOCK)
 305                 rc |= LX_O_NONBLOCK;
 306         if (retval & O_APPEND)
 307                 rc |= LX_O_APPEND;
 308         if (retval & O_SYNC)
 309                 rc |= LX_O_SYNC;
 310         if (retval & O_LARGEFILE)
 311                 rc |= LX_O_LARGEFILE;
 312         if (retval & FASYNC)
 313                 rc |= LX_O_ASYNC;
 314 
 315         return (rc);
 316 }
 317 
 318 int
 319 lx_fcntl_setfl(int fd, ulong_t arg)
 320 {
 321         int new_arg;
 322 
 323         new_arg = 0;
 324         /* LX_O_NDELAY == LX_O_NONBLOCK, so we only check for one */
 325         if (arg & LX_O_NDELAY)
 326                 new_arg |= O_NONBLOCK;
 327         if (arg & LX_O_APPEND)
 328                 new_arg |= O_APPEND;
 329         if (arg & LX_O_SYNC)
 330                 new_arg |= O_SYNC;
 331         if (arg & LX_O_LARGEFILE)
 332                 new_arg |= O_LARGEFILE;
 333         if (arg & LX_O_ASYNC)
 334                 new_arg |= FASYNC;
 335 
 336         return ((fcntl(fd, F_SETFL, new_arg) == 0) ? 0 : -errno);
 337 }
 338 
 339 /*
 340  * flock() applies or removes an advisory lock on the file
 341  * associated with the file descriptor fd.
 342  *
 343  * Stolen verbatim from usr/src/ucblib/libucb/port/sys/flock.c
 344  *
 345  * operation is: LX_LOCK_SH, LX_LOCK_EX, LX_LOCK_UN, LX_LOCK_NB
 346  */
 347 int
 348 lx_flock(uintptr_t p1, uintptr_t p2)
 349 {
 350         int                     fd = (int)p1;
 351         int                     operation = (int)p2;
 352         struct flock            fl;
 353         int                     cmd;
 354         int                     ret;
 355 
 356         /* In non-blocking lock, use F_SETLK for cmd, F_SETLKW otherwise */
 357         if (operation & LX_LOCK_NB) {
 358                 cmd = F_SETLK;
 359                 operation &= ~LX_LOCK_NB; /* turn off this bit */
 360         } else
 361                 cmd = F_SETLKW;
 362 
 363         switch (operation) {
 364                 case LX_LOCK_UN:
 365                         fl.l_type = F_UNLCK;
 366                         break;
 367                 case LX_LOCK_SH:
 368                         fl.l_type = F_RDLCK;
 369                         break;
 370                 case LX_LOCK_EX:
 371                         fl.l_type = F_WRLCK;
 372                         break;
 373                 default:
 374                         return (-EINVAL);
 375         }
 376 
 377         fl.l_whence = 0;
 378         fl.l_start = 0;
 379         fl.l_len = 0;
 380 
 381         ret = fcntl(fd, cmd, &fl);
 382 
 383         if (ret == -1 && errno == EACCES)
 384                 return (-EWOULDBLOCK);
 385 
 386         return ((ret == -1) ? -errno : ret);
 387 }