1 | /* Linux fcntl syscall implementation. |
2 | Copyright (C) 2000-2021 Free Software Foundation, Inc. |
3 | This file is part of the GNU C Library. |
4 | |
5 | The GNU C Library is free software; you can redistribute it and/or |
6 | modify it under the terms of the GNU Lesser General Public |
7 | License as published by the Free Software Foundation; either |
8 | version 2.1 of the License, or (at your option) any later version. |
9 | |
10 | The GNU C Library is distributed in the hope that it will be useful, |
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
13 | Lesser General Public License for more details. |
14 | |
15 | You should have received a copy of the GNU Lesser General Public |
16 | License along with the GNU C Library; if not, see |
17 | <https://www.gnu.org/licenses/>. */ |
18 | |
19 | #include <fcntl.h> |
20 | #include <stdarg.h> |
21 | #include <errno.h> |
22 | #include <sysdep-cancel.h> |
23 | |
24 | #ifndef __OFF_T_MATCHES_OFF64_T |
25 | |
26 | # ifndef FCNTL_ADJUST_CMD |
27 | # define FCNTL_ADJUST_CMD(__cmd) __cmd |
28 | # endif |
29 | |
30 | int |
31 | __libc_fcntl (int fd, int cmd, ...) |
32 | { |
33 | va_list ap; |
34 | void *arg; |
35 | |
36 | va_start (ap, cmd); |
37 | arg = va_arg (ap, void *); |
38 | va_end (ap); |
39 | |
40 | cmd = FCNTL_ADJUST_CMD (cmd); |
41 | |
42 | switch (cmd) |
43 | { |
44 | case F_SETLKW: |
45 | case F_SETLKW64: |
46 | return SYSCALL_CANCEL (fcntl64, fd, cmd, arg); |
47 | case F_OFD_SETLKW: |
48 | { |
49 | struct flock *flk = (struct flock *) arg; |
50 | struct flock64 flk64 = |
51 | { |
52 | .l_type = flk->l_type, |
53 | .l_whence = flk->l_whence, |
54 | .l_start = flk->l_start, |
55 | .l_len = flk->l_len, |
56 | .l_pid = flk->l_pid |
57 | }; |
58 | return SYSCALL_CANCEL (fcntl64, fd, cmd, &flk64); |
59 | } |
60 | case F_OFD_GETLK: |
61 | case F_OFD_SETLK: |
62 | { |
63 | struct flock *flk = (struct flock *) arg; |
64 | struct flock64 flk64 = |
65 | { |
66 | .l_type = flk->l_type, |
67 | .l_whence = flk->l_whence, |
68 | .l_start = flk->l_start, |
69 | .l_len = flk->l_len, |
70 | .l_pid = flk->l_pid |
71 | }; |
72 | int ret = INLINE_SYSCALL_CALL (fcntl64, fd, cmd, &flk64); |
73 | if (ret == -1) |
74 | return -1; |
75 | if ((off_t) flk64.l_start != flk64.l_start |
76 | || (off_t) flk64.l_len != flk64.l_len) |
77 | { |
78 | __set_errno (EOVERFLOW); |
79 | return -1; |
80 | } |
81 | flk->l_type = flk64.l_type; |
82 | flk->l_whence = flk64.l_whence; |
83 | flk->l_start = flk64.l_start; |
84 | flk->l_len = flk64.l_len; |
85 | flk->l_pid = flk64.l_pid; |
86 | return ret; |
87 | } |
88 | /* Since only F_SETLKW{64}/F_OLD_SETLK are cancellation entrypoints and |
89 | only OFD locks require LFS handling, all others flags are handled |
90 | unmodified by calling __NR_fcntl64. */ |
91 | default: |
92 | return __fcntl64_nocancel_adjusted (fd, cmd, arg); |
93 | } |
94 | } |
95 | libc_hidden_def (__libc_fcntl) |
96 | |
97 | weak_alias (__libc_fcntl, __fcntl) |
98 | libc_hidden_weak (__fcntl) |
99 | |
100 | # include <shlib-compat.h> |
101 | # if SHLIB_COMPAT(libc, GLIBC_2_0, GLIBC_2_28) |
102 | int |
103 | __old_libc_fcntl64 (int fd, int cmd, ...) |
104 | { |
105 | va_list ap; |
106 | void *arg; |
107 | |
108 | va_start (ap, cmd); |
109 | arg = va_arg (ap, void *); |
110 | va_end (ap); |
111 | |
112 | /* Previous versions called __NR_fcntl64 for fcntl (which did not handle |
113 | OFD locks in LFS mode). */ |
114 | return __libc_fcntl64 (fd, cmd, arg); |
115 | } |
116 | compat_symbol (libc, __old_libc_fcntl64, fcntl, GLIBC_2_0); |
117 | versioned_symbol (libc, __libc_fcntl, fcntl, GLIBC_2_28); |
118 | # else |
119 | weak_alias (__libc_fcntl, fcntl) |
120 | # endif |
121 | |
122 | #endif /* __OFF_T_MATCHES_OFF64_T */ |
123 | |