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