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