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 /* ONC_PLUS EXTRACT START */ 23 /* 24 * Copyright (c) 1994, 2010, Oracle and/or its affiliates. All rights reserved. 25 */ 26 27 /* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */ 28 /* All Rights Reserved */ 29 30 /* 31 * Portions of this source code were derived from Berkeley 4.3 BSD 32 * under license from the Regents of the University of California. 33 */ 34 35 /* ONC_PLUS EXTRACT END */ 36 37 #include <sys/param.h> 38 #include <sys/isa_defs.h> 39 #include <sys/types.h> 40 #include <sys/sysmacros.h> 41 #include <sys/systm.h> 42 #include <sys/errno.h> 43 #include <sys/fcntl.h> 44 /* ONC_PLUS EXTRACT START */ 45 #include <sys/flock.h> 46 /* ONC_PLUS EXTRACT END */ 47 #include <sys/vnode.h> 48 #include <sys/file.h> 49 #include <sys/mode.h> 50 #include <sys/proc.h> 51 #include <sys/filio.h> 52 #include <sys/share.h> 53 #include <sys/debug.h> 54 #include <sys/rctl.h> 55 #include <sys/nbmlock.h> 56 57 #include <sys/cmn_err.h> 58 59 /* ONC_PLUS EXTRACT START */ 60 static int flock_check(vnode_t *, flock64_t *, offset_t, offset_t); 61 static int flock_get_start(vnode_t *, flock64_t *, offset_t, u_offset_t *); 62 static void fd_too_big(proc_t *); 63 64 /* 65 * File control. 66 */ 67 int 68 fcntl(int fdes, int cmd, intptr_t arg) 69 { 70 int iarg; 71 int error = 0; 72 int retval; 73 proc_t *p; 74 file_t *fp; 75 vnode_t *vp; 76 u_offset_t offset; 77 u_offset_t start; 78 struct vattr vattr; 79 int in_crit; 80 int flag; 81 struct flock sbf; 82 struct flock64 bf; 83 struct o_flock obf; 84 struct flock64_32 bf64_32; 85 struct fshare fsh; 86 struct shrlock shr; 87 struct shr_locowner shr_own; 88 offset_t maxoffset; 89 model_t datamodel; 90 int fdres; 91 92 #if defined(_ILP32) && !defined(lint) && defined(_SYSCALL32) 93 ASSERT(sizeof (struct flock) == sizeof (struct flock32)); 94 ASSERT(sizeof (struct flock64) == sizeof (struct flock64_32)); 95 #endif 96 #if defined(_LP64) && !defined(lint) && defined(_SYSCALL32) 97 ASSERT(sizeof (struct flock) == sizeof (struct flock64_64)); 98 ASSERT(sizeof (struct flock64) == sizeof (struct flock64_64)); 99 #endif 100 101 /* 102 * First, for speed, deal with the subset of cases 103 * that do not require getf() / releasef(). 104 */ 105 switch (cmd) { 106 case F_GETFD: 107 if ((error = f_getfd_error(fdes, &flag)) == 0) 108 retval = flag; 109 goto out; 110 111 case F_SETFD: 112 error = f_setfd_error(fdes, (int)arg); 113 retval = 0; 114 goto out; 115 116 case F_GETFL: 117 if ((error = f_getfl(fdes, &flag)) == 0) 118 retval = (flag & (FMASK | FASYNC)) + FOPEN; 119 goto out; 120 121 case F_GETXFL: 122 if ((error = f_getfl(fdes, &flag)) == 0) 123 retval = flag + FOPEN; 124 goto out; 125 126 case F_BADFD: 127 if ((error = f_badfd(fdes, &fdres, (int)arg)) == 0) 128 retval = fdres; 129 goto out; 130 } 131 132 /* 133 * Second, for speed, deal with the subset of cases that 134 * require getf() / releasef() but do not require copyin. 135 */ 136 if ((fp = getf(fdes)) == NULL) { 137 error = EBADF; 138 goto out; 139 } 140 iarg = (int)arg; 141 142 switch (cmd) { 143 /* ONC_PLUS EXTRACT END */ 144 145 case F_DUPFD: 146 p = curproc; 147 if ((uint_t)iarg >= p->p_fno_ctl) { 148 if (iarg >= 0) 149 fd_too_big(p); 150 error = EINVAL; 151 goto done; 152 } 153 /* 154 * We need to increment the f_count reference counter 155 * before allocating a new file descriptor. 156 * Doing it other way round opens a window for race condition 157 * with closeandsetf() on the target file descriptor which can 158 * close the file still referenced by the original 159 * file descriptor. 160 */ 161 mutex_enter(&fp->f_tlock); 162 fp->f_count++; 163 mutex_exit(&fp->f_tlock); 164 if ((retval = ufalloc_file(iarg, fp)) == -1) { 165 /* 166 * New file descriptor can't be allocated. 167 * Revert the reference count. 168 */ 169 mutex_enter(&fp->f_tlock); 170 fp->f_count--; 171 mutex_exit(&fp->f_tlock); 172 error = EMFILE; 173 } 174 goto done; 175 176 case F_DUP2FD: 177 p = curproc; 178 if (fdes == iarg) { 179 retval = iarg; 180 } else if ((uint_t)iarg >= p->p_fno_ctl) { 181 if (iarg >= 0) 182 fd_too_big(p); 183 error = EBADF; 184 } else { 185 /* 186 * We can't hold our getf(fdes) across the call to 187 * closeandsetf() because it creates a window for 188 * deadlock: if one thread is doing dup2(a, b) while 189 * another is doing dup2(b, a), each one will block 190 * waiting for the other to call releasef(). The 191 * solution is to increment the file reference count 192 * (which we have to do anyway), then releasef(fdes), 193 * then closeandsetf(). Incrementing f_count ensures 194 * that fp won't disappear after we call releasef(). 195 * When closeandsetf() fails, we try avoid calling 196 * closef() because of all the side effects. 197 */ 198 mutex_enter(&fp->f_tlock); 199 fp->f_count++; 200 mutex_exit(&fp->f_tlock); 201 releasef(fdes); 202 if ((error = closeandsetf(iarg, fp)) == 0) { 203 retval = iarg; 204 } else { 205 mutex_enter(&fp->f_tlock); 206 if (fp->f_count > 1) { 207 fp->f_count--; 208 mutex_exit(&fp->f_tlock); 209 } else { 210 mutex_exit(&fp->f_tlock); 211 (void) closef(fp); 212 } 213 } 214 goto out; 215 } 216 goto done; 217 218 case F_SETFL: 219 vp = fp->f_vnode; 220 flag = fp->f_flag; 221 if ((iarg & (FNONBLOCK|FNDELAY)) == (FNONBLOCK|FNDELAY)) 222 iarg &= ~FNDELAY; 223 if ((error = VOP_SETFL(vp, flag, iarg, fp->f_cred, NULL)) == 224 0) { 225 iarg &= FMASK; 226 mutex_enter(&fp->f_tlock); 227 fp->f_flag &= ~FMASK | (FREAD|FWRITE); 228 fp->f_flag |= (iarg - FOPEN) & ~(FREAD|FWRITE); 229 mutex_exit(&fp->f_tlock); 230 } 231 retval = 0; 232 goto done; 233 } 234 235 /* 236 * Finally, deal with the expensive cases. 237 */ 238 retval = 0; 239 in_crit = 0; 240 maxoffset = MAXOFF_T; 241 datamodel = DATAMODEL_NATIVE; 242 #if defined(_SYSCALL32_IMPL) 243 if ((datamodel = get_udatamodel()) == DATAMODEL_ILP32) 244 maxoffset = MAXOFF32_T; 245 #endif 246 247 vp = fp->f_vnode; 248 flag = fp->f_flag; 249 offset = fp->f_offset; 250 251 switch (cmd) { 252 /* ONC_PLUS EXTRACT START */ 253 /* 254 * The file system and vnode layers understand and implement 255 * locking with flock64 structures. So here once we pass through 256 * the test for compatibility as defined by LFS API, (for F_SETLK, 257 * F_SETLKW, F_GETLK, F_GETLKW, F_FREESP) we transform 258 * the flock structure to a flock64 structure and send it to the 259 * lower layers. Similarly in case of GETLK the returned flock64 260 * structure is transformed to a flock structure if everything fits 261 * in nicely, otherwise we return EOVERFLOW. 262 */ 263 264 case F_GETLK: 265 case F_O_GETLK: 266 case F_SETLK: 267 case F_SETLKW: 268 case F_SETLK_NBMAND: 269 270 /* 271 * Copy in input fields only. 272 */ 273 274 if (cmd == F_O_GETLK) { 275 if (datamodel != DATAMODEL_ILP32) { 276 error = EINVAL; 277 break; 278 } 279 280 if (copyin((void *)arg, &obf, sizeof (obf))) { 281 error = EFAULT; 282 break; 283 } 284 bf.l_type = obf.l_type; 285 bf.l_whence = obf.l_whence; 286 bf.l_start = (off64_t)obf.l_start; 287 bf.l_len = (off64_t)obf.l_len; 288 bf.l_sysid = (int)obf.l_sysid; 289 bf.l_pid = obf.l_pid; 290 } else if (datamodel == DATAMODEL_NATIVE) { 291 if (copyin((void *)arg, &sbf, sizeof (sbf))) { 292 error = EFAULT; 293 break; 294 } 295 /* 296 * XXX In an LP64 kernel with an LP64 application 297 * there's no need to do a structure copy here 298 * struct flock == struct flock64. However, 299 * we did it this way to avoid more conditional 300 * compilation. 301 */ 302 bf.l_type = sbf.l_type; 303 bf.l_whence = sbf.l_whence; 304 bf.l_start = (off64_t)sbf.l_start; 305 bf.l_len = (off64_t)sbf.l_len; 306 bf.l_sysid = sbf.l_sysid; 307 bf.l_pid = sbf.l_pid; 308 } 309 #if defined(_SYSCALL32_IMPL) 310 else { 311 struct flock32 sbf32; 312 if (copyin((void *)arg, &sbf32, sizeof (sbf32))) { 313 error = EFAULT; 314 break; 315 } 316 bf.l_type = sbf32.l_type; 317 bf.l_whence = sbf32.l_whence; 318 bf.l_start = (off64_t)sbf32.l_start; 319 bf.l_len = (off64_t)sbf32.l_len; 320 bf.l_sysid = sbf32.l_sysid; 321 bf.l_pid = sbf32.l_pid; 322 } 323 #endif /* _SYSCALL32_IMPL */ 324 325 /* 326 * 64-bit support: check for overflow for 32-bit lock ops 327 */ 328 if ((error = flock_check(vp, &bf, offset, maxoffset)) != 0) 329 break; 330 331 /* 332 * Not all of the filesystems understand F_O_GETLK, and 333 * there's no need for them to know. Map it to F_GETLK. 334 */ 335 if ((error = VOP_FRLOCK(vp, (cmd == F_O_GETLK) ? F_GETLK : cmd, 336 &bf, flag, offset, NULL, fp->f_cred, NULL)) != 0) 337 break; 338 339 /* 340 * If command is GETLK and no lock is found, only 341 * the type field is changed. 342 */ 343 if ((cmd == F_O_GETLK || cmd == F_GETLK) && 344 bf.l_type == F_UNLCK) { 345 /* l_type always first entry, always a short */ 346 if (copyout(&bf.l_type, &((struct flock *)arg)->l_type, 347 sizeof (bf.l_type))) 348 error = EFAULT; 349 break; 350 } 351 352 if (cmd == F_O_GETLK) { 353 /* 354 * Return an SVR3 flock structure to the user. 355 */ 356 obf.l_type = (int16_t)bf.l_type; 357 obf.l_whence = (int16_t)bf.l_whence; 358 obf.l_start = (int32_t)bf.l_start; 359 obf.l_len = (int32_t)bf.l_len; 360 if (bf.l_sysid > SHRT_MAX || bf.l_pid > SHRT_MAX) { 361 /* 362 * One or both values for the above fields 363 * is too large to store in an SVR3 flock 364 * structure. 365 */ 366 error = EOVERFLOW; 367 break; 368 } 369 obf.l_sysid = (int16_t)bf.l_sysid; 370 obf.l_pid = (int16_t)bf.l_pid; 371 if (copyout(&obf, (void *)arg, sizeof (obf))) 372 error = EFAULT; 373 } else if (cmd == F_GETLK) { 374 /* 375 * Copy out SVR4 flock. 376 */ 377 int i; 378 379 if (bf.l_start > maxoffset || bf.l_len > maxoffset) { 380 error = EOVERFLOW; 381 break; 382 } 383 384 if (datamodel == DATAMODEL_NATIVE) { 385 for (i = 0; i < 4; i++) 386 sbf.l_pad[i] = 0; 387 /* 388 * XXX In an LP64 kernel with an LP64 389 * application there's no need to do a 390 * structure copy here as currently 391 * struct flock == struct flock64. 392 * We did it this way to avoid more 393 * conditional compilation. 394 */ 395 sbf.l_type = bf.l_type; 396 sbf.l_whence = bf.l_whence; 397 sbf.l_start = (off_t)bf.l_start; 398 sbf.l_len = (off_t)bf.l_len; 399 sbf.l_sysid = bf.l_sysid; 400 sbf.l_pid = bf.l_pid; 401 if (copyout(&sbf, (void *)arg, sizeof (sbf))) 402 error = EFAULT; 403 } 404 #if defined(_SYSCALL32_IMPL) 405 else { 406 struct flock32 sbf32; 407 if (bf.l_start > MAXOFF32_T || 408 bf.l_len > MAXOFF32_T) { 409 error = EOVERFLOW; 410 break; 411 } 412 for (i = 0; i < 4; i++) 413 sbf32.l_pad[i] = 0; 414 sbf32.l_type = (int16_t)bf.l_type; 415 sbf32.l_whence = (int16_t)bf.l_whence; 416 sbf32.l_start = (off32_t)bf.l_start; 417 sbf32.l_len = (off32_t)bf.l_len; 418 sbf32.l_sysid = (int32_t)bf.l_sysid; 419 sbf32.l_pid = (pid32_t)bf.l_pid; 420 if (copyout(&sbf32, 421 (void *)arg, sizeof (sbf32))) 422 error = EFAULT; 423 } 424 #endif 425 } 426 break; 427 /* ONC_PLUS EXTRACT END */ 428 429 case F_CHKFL: 430 /* 431 * This is for internal use only, to allow the vnode layer 432 * to validate a flags setting before applying it. User 433 * programs can't issue it. 434 */ 435 error = EINVAL; 436 break; 437 438 case F_ALLOCSP: 439 case F_FREESP: 440 case F_ALLOCSP64: 441 case F_FREESP64: 442 /* 443 * Test for not-a-regular-file (and returning EINVAL) 444 * before testing for open-for-writing (and returning EBADF). 445 * This is relied upon by posix_fallocate() in libc. 446 */ 447 if (vp->v_type != VREG) { 448 error = EINVAL; 449 break; 450 } 451 452 if ((flag & FWRITE) == 0) { 453 error = EBADF; 454 break; 455 } 456 457 if (datamodel != DATAMODEL_ILP32 && 458 (cmd == F_ALLOCSP64 || cmd == F_FREESP64)) { 459 error = EINVAL; 460 break; 461 } 462 463 #if defined(_ILP32) || defined(_SYSCALL32_IMPL) 464 if (datamodel == DATAMODEL_ILP32 && 465 (cmd == F_ALLOCSP || cmd == F_FREESP)) { 466 struct flock32 sbf32; 467 /* 468 * For compatibility we overlay an SVR3 flock on an SVR4 469 * flock. This works because the input field offsets 470 * in "struct flock" were preserved. 471 */ 472 if (copyin((void *)arg, &sbf32, sizeof (sbf32))) { 473 error = EFAULT; 474 break; 475 } else { 476 bf.l_type = sbf32.l_type; 477 bf.l_whence = sbf32.l_whence; 478 bf.l_start = (off64_t)sbf32.l_start; 479 bf.l_len = (off64_t)sbf32.l_len; 480 bf.l_sysid = sbf32.l_sysid; 481 bf.l_pid = sbf32.l_pid; 482 } 483 } 484 #endif /* _ILP32 || _SYSCALL32_IMPL */ 485 486 #if defined(_LP64) 487 if (datamodel == DATAMODEL_LP64 && 488 (cmd == F_ALLOCSP || cmd == F_FREESP)) { 489 if (copyin((void *)arg, &bf, sizeof (bf))) { 490 error = EFAULT; 491 break; 492 } 493 } 494 #endif /* defined(_LP64) */ 495 496 #if !defined(_LP64) || defined(_SYSCALL32_IMPL) 497 if (datamodel == DATAMODEL_ILP32 && 498 (cmd == F_ALLOCSP64 || cmd == F_FREESP64)) { 499 if (copyin((void *)arg, &bf64_32, sizeof (bf64_32))) { 500 error = EFAULT; 501 break; 502 } else { 503 /* 504 * Note that the size of flock64 is different in 505 * the ILP32 and LP64 models, due to the l_pad 506 * field. We do not want to assume that the 507 * flock64 structure is laid out the same in 508 * ILP32 and LP64 environments, so we will 509 * copy in the ILP32 version of flock64 510 * explicitly and copy it to the native 511 * flock64 structure. 512 */ 513 bf.l_type = (short)bf64_32.l_type; 514 bf.l_whence = (short)bf64_32.l_whence; 515 bf.l_start = bf64_32.l_start; 516 bf.l_len = bf64_32.l_len; 517 bf.l_sysid = (int)bf64_32.l_sysid; 518 bf.l_pid = (pid_t)bf64_32.l_pid; 519 } 520 } 521 #endif /* !defined(_LP64) || defined(_SYSCALL32_IMPL) */ 522 523 if (cmd == F_ALLOCSP || cmd == F_FREESP) 524 error = flock_check(vp, &bf, offset, maxoffset); 525 else if (cmd == F_ALLOCSP64 || cmd == F_FREESP64) 526 error = flock_check(vp, &bf, offset, MAXOFFSET_T); 527 if (error) 528 break; 529 530 if (vp->v_type == VREG && bf.l_len == 0 && 531 bf.l_start > OFFSET_MAX(fp)) { 532 error = EFBIG; 533 break; 534 } 535 536 /* 537 * Make sure that there are no conflicting non-blocking 538 * mandatory locks in the region being manipulated. If 539 * there are such locks then return EACCES. 540 */ 541 if ((error = flock_get_start(vp, &bf, offset, &start)) != 0) 542 break; 543 544 if (nbl_need_check(vp)) { 545 u_offset_t begin; 546 ssize_t length; 547 548 nbl_start_crit(vp, RW_READER); 549 in_crit = 1; 550 vattr.va_mask = AT_SIZE; 551 if ((error = VOP_GETATTR(vp, &vattr, 0, CRED(), NULL)) 552 != 0) 553 break; 554 begin = start > vattr.va_size ? vattr.va_size : start; 555 length = vattr.va_size > start ? vattr.va_size - start : 556 start - vattr.va_size; 557 if (nbl_conflict(vp, NBL_WRITE, begin, length, 0, 558 NULL)) { 559 error = EACCES; 560 break; 561 } 562 } 563 564 if (cmd == F_ALLOCSP64) 565 cmd = F_ALLOCSP; 566 else if (cmd == F_FREESP64) 567 cmd = F_FREESP; 568 569 error = VOP_SPACE(vp, cmd, &bf, flag, offset, fp->f_cred, NULL); 570 571 break; 572 573 #if !defined(_LP64) || defined(_SYSCALL32_IMPL) 574 /* ONC_PLUS EXTRACT START */ 575 case F_GETLK64: 576 case F_SETLK64: 577 case F_SETLKW64: 578 case F_SETLK64_NBMAND: 579 /* 580 * Large Files: Here we set cmd as *LK and send it to 581 * lower layers. *LK64 is only for the user land. 582 * Most of the comments described above for F_SETLK 583 * applies here too. 584 * Large File support is only needed for ILP32 apps! 585 */ 586 if (datamodel != DATAMODEL_ILP32) { 587 error = EINVAL; 588 break; 589 } 590 591 if (cmd == F_GETLK64) 592 cmd = F_GETLK; 593 else if (cmd == F_SETLK64) 594 cmd = F_SETLK; 595 else if (cmd == F_SETLKW64) 596 cmd = F_SETLKW; 597 else if (cmd == F_SETLK64_NBMAND) 598 cmd = F_SETLK_NBMAND; 599 600 /* 601 * Note that the size of flock64 is different in the ILP32 602 * and LP64 models, due to the sucking l_pad field. 603 * We do not want to assume that the flock64 structure is 604 * laid out in the same in ILP32 and LP64 environments, so 605 * we will copy in the ILP32 version of flock64 explicitly 606 * and copy it to the native flock64 structure. 607 */ 608 609 if (copyin((void *)arg, &bf64_32, sizeof (bf64_32))) { 610 error = EFAULT; 611 break; 612 } 613 614 bf.l_type = (short)bf64_32.l_type; 615 bf.l_whence = (short)bf64_32.l_whence; 616 bf.l_start = bf64_32.l_start; 617 bf.l_len = bf64_32.l_len; 618 bf.l_sysid = (int)bf64_32.l_sysid; 619 bf.l_pid = (pid_t)bf64_32.l_pid; 620 621 if ((error = flock_check(vp, &bf, offset, MAXOFFSET_T)) != 0) 622 break; 623 624 if ((error = VOP_FRLOCK(vp, cmd, &bf, flag, offset, 625 NULL, fp->f_cred, NULL)) != 0) 626 break; 627 628 if ((cmd == F_GETLK) && bf.l_type == F_UNLCK) { 629 if (copyout(&bf.l_type, &((struct flock *)arg)->l_type, 630 sizeof (bf.l_type))) 631 error = EFAULT; 632 break; 633 } 634 635 if (cmd == F_GETLK) { 636 int i; 637 638 /* 639 * We do not want to assume that the flock64 structure 640 * is laid out in the same in ILP32 and LP64 641 * environments, so we will copy out the ILP32 version 642 * of flock64 explicitly after copying the native 643 * flock64 structure to it. 644 */ 645 for (i = 0; i < 4; i++) 646 bf64_32.l_pad[i] = 0; 647 bf64_32.l_type = (int16_t)bf.l_type; 648 bf64_32.l_whence = (int16_t)bf.l_whence; 649 bf64_32.l_start = bf.l_start; 650 bf64_32.l_len = bf.l_len; 651 bf64_32.l_sysid = (int32_t)bf.l_sysid; 652 bf64_32.l_pid = (pid32_t)bf.l_pid; 653 if (copyout(&bf64_32, (void *)arg, sizeof (bf64_32))) 654 error = EFAULT; 655 } 656 break; 657 /* ONC_PLUS EXTRACT END */ 658 #endif /* !defined(_LP64) || defined(_SYSCALL32_IMPL) */ 659 660 /* ONC_PLUS EXTRACT START */ 661 case F_SHARE: 662 case F_SHARE_NBMAND: 663 case F_UNSHARE: 664 665 /* 666 * Copy in input fields only. 667 */ 668 if (copyin((void *)arg, &fsh, sizeof (fsh))) { 669 error = EFAULT; 670 break; 671 } 672 673 /* 674 * Local share reservations always have this simple form 675 */ 676 shr.s_access = fsh.f_access; 677 shr.s_deny = fsh.f_deny; 678 shr.s_sysid = 0; 679 shr.s_pid = ttoproc(curthread)->p_pid; 680 shr_own.sl_pid = shr.s_pid; 681 shr_own.sl_id = fsh.f_id; 682 shr.s_own_len = sizeof (shr_own); 683 shr.s_owner = (caddr_t)&shr_own; 684 error = VOP_SHRLOCK(vp, cmd, &shr, flag, fp->f_cred, NULL); 685 /* ONC_PLUS EXTRACT END */ 686 break; 687 688 default: 689 error = EINVAL; 690 break; 691 } 692 693 if (in_crit) 694 nbl_end_crit(vp); 695 696 done: 697 releasef(fdes); 698 out: 699 if (error) 700 return (set_errno(error)); 701 return (retval); 702 } 703 704 /* ONC_PLUS EXTRACT START */ 705 int 706 flock_check(vnode_t *vp, flock64_t *flp, offset_t offset, offset_t max) 707 { 708 struct vattr vattr; 709 int error; 710 u_offset_t start, end; 711 712 /* 713 * Determine the starting point of the request 714 */ 715 switch (flp->l_whence) { 716 case 0: /* SEEK_SET */ 717 start = (u_offset_t)flp->l_start; 718 if (start > max) 719 return (EINVAL); 720 break; 721 case 1: /* SEEK_CUR */ 722 if (flp->l_start > (max - offset)) 723 return (EOVERFLOW); 724 start = (u_offset_t)(flp->l_start + offset); 725 if (start > max) 726 return (EINVAL); 727 break; 728 case 2: /* SEEK_END */ 729 vattr.va_mask = AT_SIZE; 730 if (error = VOP_GETATTR(vp, &vattr, 0, CRED(), NULL)) 731 return (error); 732 if (flp->l_start > (max - (offset_t)vattr.va_size)) 733 return (EOVERFLOW); 734 start = (u_offset_t)(flp->l_start + (offset_t)vattr.va_size); 735 if (start > max) 736 return (EINVAL); 737 break; 738 default: 739 return (EINVAL); 740 } 741 742 /* 743 * Determine the range covered by the request. 744 */ 745 if (flp->l_len == 0) 746 end = MAXEND; 747 else if ((offset_t)flp->l_len > 0) { 748 if (flp->l_len > (max - start + 1)) 749 return (EOVERFLOW); 750 end = (u_offset_t)(start + (flp->l_len - 1)); 751 ASSERT(end <= max); 752 } else { 753 /* 754 * Negative length; why do we even allow this ? 755 * Because this allows easy specification of 756 * the last n bytes of the file. 757 */ 758 end = start; 759 start += (u_offset_t)flp->l_len; 760 (start)++; 761 if (start > max) 762 return (EINVAL); 763 ASSERT(end <= max); 764 } 765 ASSERT(start <= max); 766 if (flp->l_type == F_UNLCK && flp->l_len > 0 && 767 end == (offset_t)max) { 768 flp->l_len = 0; 769 } 770 if (start > end) 771 return (EINVAL); 772 return (0); 773 } 774 775 static int 776 flock_get_start(vnode_t *vp, flock64_t *flp, offset_t offset, u_offset_t *start) 777 { 778 struct vattr vattr; 779 int error; 780 781 /* 782 * Determine the starting point of the request. Assume that it is 783 * a valid starting point. 784 */ 785 switch (flp->l_whence) { 786 case 0: /* SEEK_SET */ 787 *start = (u_offset_t)flp->l_start; 788 break; 789 case 1: /* SEEK_CUR */ 790 *start = (u_offset_t)(flp->l_start + offset); 791 break; 792 case 2: /* SEEK_END */ 793 vattr.va_mask = AT_SIZE; 794 if (error = VOP_GETATTR(vp, &vattr, 0, CRED(), NULL)) 795 return (error); 796 *start = (u_offset_t)(flp->l_start + (offset_t)vattr.va_size); 797 break; 798 default: 799 return (EINVAL); 800 } 801 802 return (0); 803 } 804 805 /* 806 * Take rctl action when the requested file descriptor is too big. 807 */ 808 static void 809 fd_too_big(proc_t *p) 810 { 811 mutex_enter(&p->p_lock); 812 (void) rctl_action(rctlproc_legacy[RLIMIT_NOFILE], 813 p->p_rctls, p, RCA_SAFE); 814 mutex_exit(&p->p_lock); 815 } 816 /* ONC_PLUS EXTRACT END */ 817