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