1 /* Copyright (C) 1992-2024 Free Software Foundation, Inc.
2 This file is part of the GNU C Library.
4 The GNU C Library is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Lesser General Public
6 License as published by the Free Software Foundation; either
7 version 2.1 of the License, or (at your option) any later version.
9 The GNU C Library is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 Lesser General Public License for more details.
14 You should have received a copy of the GNU Lesser General Public
15 License along with the GNU C Library; if not, see
16 <https://www.gnu.org/licenses/>. */
23 #include <sys/file.h> /* XXX for LOCK_* */
25 #include <not-cancel.h>
27 #include <sysdep-cancel.h>
31 /* Perform file control operations on FD. */
33 __libc_fcntl (int fd
, int cmd
, ...)
39 d
= _hurd_fd_get (fd
);
42 return __hurd_fail (EBADF
);
50 default: /* Bad command. */
51 result
= __hurd_fail (EINVAL
);
54 /* First the descriptor-based commands, which do no RPCs. */
56 case F_DUPFD
: /* Duplicate the file descriptor. */
61 struct hurd_userlink ulink
, ctty_ulink
;
66 /* Extract the ports and flags from the file descriptor. */
67 __spin_lock (&d
->port
.lock
);
69 ctty
= _hurd_port_get (&d
->ctty
, &ctty_ulink
);
70 port
= _hurd_port_locked_get (&d
->port
, &ulink
); /* Unlocks D. */
72 if (cmd
== F_DUPFD_CLOEXEC
)
75 /* Duplication clears the FD_CLOEXEC flag. */
78 /* Get a new file descriptor. The third argument to __fcntl is the
79 minimum file descriptor number for it. */
80 new = _hurd_alloc_fd (&result
, va_arg (ap
, int));
82 /* _hurd_alloc_fd has set errno. */
86 /* Give the ports each a user ref for the new descriptor. */
87 __mach_port_mod_refs (__mach_task_self (), port
,
88 MACH_PORT_RIGHT_SEND
, 1);
89 if (ctty
!= MACH_PORT_NULL
)
90 __mach_port_mod_refs (__mach_task_self (), ctty
,
91 MACH_PORT_RIGHT_SEND
, 1);
93 /* Install the ports and flags in the new descriptor. */
94 if (ctty
!= MACH_PORT_NULL
)
95 _hurd_port_set (&new->ctty
, ctty
);
97 _hurd_port_locked_set (&new->port
, port
); /* Unlocks NEW. */
102 _hurd_port_free (&d
->port
, &ulink
, port
);
103 if (ctty
!= MACH_PORT_NULL
)
104 _hurd_port_free (&d
->ctty
, &ctty_ulink
, port
);
109 /* Set RESULT by evaluating EXPR with the descriptor locked.
110 Check for an empty descriptor and return EBADF. */
111 #define LOCKED(expr) do { \
112 HURD_CRITICAL_BEGIN; \
113 __spin_lock (&d->port.lock); \
114 if (d->port.port == MACH_PORT_NULL) \
115 result = __hurd_fail (EBADF); \
118 __spin_unlock (&d->port.lock); \
122 case F_GETFD
: /* Get descriptor flags. */
126 case F_SETFD
: /* Set descriptor flags. */
127 LOCKED ((d
->flags
= va_arg (ap
, int), 0));
131 /* Now the real io operations, done by RPCs to io servers. */
137 struct flock
*fl
= va_arg (ap
, struct flock
*);
151 return __hurd_fail (EINVAL
);
154 struct flock64 fl64
= {
155 .l_type
= fl
->l_type
,
156 .l_whence
= fl
->l_whence
,
157 .l_start
= fl
->l_start
,
163 if (cmd
== F_SETLKW64
)
165 int cancel_oldtype
= LIBC_CANCEL_ASYNC();
166 err
= HURD_FD_PORT_USE_CANCEL (d
, __file_record_lock (port
, cmd
,
167 &fl64
, MACH_PORT_NULL
,
168 MACH_MSG_TYPE_MAKE_SEND
));
169 LIBC_CANCEL_RESET (cancel_oldtype
);
173 err
= HURD_FD_PORT_USE (d
, __file_record_lock (port
, cmd
, &fl64
,
174 MACH_PORT_NULL
, MACH_MSG_TYPE_MAKE_SEND
));
176 /* XXX: To remove once file_record_lock RPC is settled. */
177 if (err
== EMIG_BAD_ID
|| err
== EOPNOTSUPP
)
184 return __hurd_fail (ENOSYS
);
189 return __f_setlk (fd
, fl
->l_type
, fl
->l_whence
,
190 fl
->l_start
, fl
->l_len
, wait
);
192 return __hurd_fail (EINVAL
);
195 else if (cmd
== F_GETLK64
)
197 fl
->l_type
= fl64
.l_type
;
198 fl
->l_whence
= fl64
.l_whence
;
199 fl
->l_start
= fl64
.l_start
;
200 fl
->l_len
= fl64
.l_len
;
201 fl
->l_pid
= fl64
.l_pid
;
203 if ((sizeof fl
->l_start
!= sizeof fl64
.l_start
204 && fl
->l_start
!= fl64
.l_start
)
205 || (sizeof fl
->l_len
!= sizeof fl64
.l_len
206 && fl
->l_len
!= fl64
.l_len
))
207 return __hurd_fail (EOVERFLOW
);
210 result
= err
? __hurd_dfail (fd
, err
) : 0;
218 struct flock64
*fl
= va_arg (ap
, struct flock64
*);
221 if (cmd
== F_SETLKW64
)
223 int cancel_oldtype
= LIBC_CANCEL_ASYNC();
224 err
= HURD_FD_PORT_USE_CANCEL (d
, __file_record_lock (port
, cmd
,
226 MACH_MSG_TYPE_MAKE_SEND
));
227 LIBC_CANCEL_RESET (cancel_oldtype
);
231 err
= HURD_FD_PORT_USE (d
, __file_record_lock (port
, cmd
, fl
,
232 MACH_PORT_NULL
, MACH_MSG_TYPE_MAKE_SEND
));
234 /* XXX: To remove once file_record_lock RPC is settled. */
235 if (err
== EMIG_BAD_ID
|| err
== EOPNOTSUPP
)
242 return __hurd_fail (ENOSYS
);
247 return __f_setlk (fd
, fl
->l_type
, fl
->l_whence
,
248 fl
->l_start
, fl
->l_len
, wait
);
250 return __hurd_fail (EINVAL
);
254 result
= err
? __hurd_dfail (fd
, err
) : 0;
258 case F_GETFL
: /* Get per-open flags. */
259 if (err
= HURD_FD_PORT_USE (d
, __io_get_openmodes (port
, &result
)))
260 result
= __hurd_dfail (fd
, err
);
263 case F_SETFL
: /* Set per-open flags. */
264 err
= HURD_FD_PORT_USE (d
, __io_set_all_openmodes (port
,
266 result
= err
? __hurd_dfail (fd
, err
) : 0;
269 case F_GETOWN
: /* Get owner. */
270 if (err
= HURD_FD_PORT_USE (d
, __io_get_owner (port
, &result
)))
271 result
= __hurd_dfail (fd
, err
);
274 case F_SETOWN
: /* Set owner. */
275 err
= HURD_FD_PORT_USE (d
, __io_mod_owner (port
, va_arg (ap
, pid_t
)));
276 result
= err
? __hurd_dfail (fd
, err
) : 0;
284 libc_hidden_def (__libc_fcntl
)
287 weak_alias (__libc_fcntl
, __fcntl
)
288 libc_hidden_weak (__fcntl
)
289 weak_alias (__libc_fcntl
, fcntl
)
291 strong_alias (__libc_fcntl
, __libc_fcntl64
)
292 libc_hidden_def (__libc_fcntl64
)
293 weak_alias (__libc_fcntl64
, __fcntl64
)
294 libc_hidden_weak (__fcntl64
)
295 weak_alias (__fcntl64
, fcntl64
)