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 }