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