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