]>
Commit | Line | Data |
---|---|---|
28f540f4 | 1 | /* File descriptors. |
dff8da6b | 2 | Copyright (C) 1993-2024 Free Software Foundation, Inc. |
c84142e8 UD |
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 | |
41bdb6e2 AJ |
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. | |
c84142e8 UD |
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 | |
41bdb6e2 | 13 | Lesser General Public License for more details. |
c84142e8 | 14 | |
41bdb6e2 | 15 | You should have received a copy of the GNU Lesser General Public |
59ba27a6 | 16 | License along with the GNU C Library; if not, see |
5a82c748 | 17 | <https://www.gnu.org/licenses/>. */ |
28f540f4 RM |
18 | |
19 | #ifndef _HURD_FD_H | |
20 | ||
21 | #define _HURD_FD_H 1 | |
22 | #include <features.h> | |
23 | ||
24 | #include <hurd/hurd_types.h> | |
25 | #include <hurd/port.h> | |
e66ecb22 | 26 | #include <sys/socket.h> |
ba89615d | 27 | #include <sys/select.h> |
09085ede | 28 | #include <fcntl.h> |
ba89615d | 29 | #include <bits/types/sigset_t.h> |
28f540f4 RM |
30 | |
31 | ||
32 | /* Structure representing a file descriptor. */ | |
33 | ||
34 | struct hurd_fd | |
35 | { | |
36 | struct hurd_port port; /* io server port. */ | |
37 | int flags; /* fcntl flags; locked by port.lock. */ | |
38 | ||
39 | /* Normal port to the ctty. When `port' is our ctty, this is a port to | |
40 | the same io object but which never returns EBACKGROUND; when not, | |
41 | this is nil. */ | |
42 | struct hurd_port ctty; | |
43 | }; | |
44 | ||
45 | ||
46 | /* Current file descriptor table. */ | |
47 | ||
9446e02b ST |
48 | #if defined __USE_EXTERN_INLINES && defined _LIBC |
49 | #include <lock-intern.h> | |
28f540f4 RM |
50 | extern int _hurd_dtablesize; |
51 | extern struct hurd_fd **_hurd_dtable; | |
52 | extern struct mutex _hurd_dtable_lock; /* Locks those two variables. */ | |
9446e02b | 53 | #endif |
28f540f4 RM |
54 | \f |
55 | #include <hurd/signal.h> | |
28f540f4 | 56 | |
6f9dc08b | 57 | #ifndef _HURD_FD_H_EXTERN_INLINE |
b037a293 | 58 | #define _HURD_FD_H_EXTERN_INLINE __extern_inline |
28f540f4 RM |
59 | #endif |
60 | ||
61 | /* Returns the descriptor cell for FD. If FD is invalid or unused, return | |
62 | NULL. The cell is unlocked; when ready to use it, lock it and check for | |
63 | it being unused. */ | |
64 | ||
28f6186f ST |
65 | extern struct hurd_fd *_hurd_fd_get (int fd); |
66 | ||
67 | #if defined __USE_EXTERN_INLINES && defined _LIBC | |
2f8902cc | 68 | # if IS_IN (libc) |
6f9dc08b | 69 | _HURD_FD_H_EXTERN_INLINE struct hurd_fd * |
28f540f4 RM |
70 | _hurd_fd_get (int fd) |
71 | { | |
72 | struct hurd_fd *descriptor; | |
73 | ||
802ca5a5 | 74 | HURD_CRITICAL_BEGIN; |
28f540f4 | 75 | __mutex_lock (&_hurd_dtable_lock); |
a9fb5710 | 76 | if (__glibc_unlikely (fd < 0 || fd >= _hurd_dtablesize)) |
28f540f4 RM |
77 | descriptor = NULL; |
78 | else | |
79 | { | |
80 | struct hurd_fd *cell = _hurd_dtable[fd]; | |
a9fb5710 | 81 | if (__glibc_unlikely (cell == NULL)) |
28f540f4 RM |
82 | /* No descriptor allocated at this index. */ |
83 | descriptor = NULL; | |
84 | else | |
85 | { | |
86 | __spin_lock (&cell->port.lock); | |
a9fb5710 | 87 | if (__glibc_unlikely (cell->port.port == MACH_PORT_NULL)) |
28f540f4 RM |
88 | /* The descriptor at this index has no port in it. |
89 | This happens if it existed before but was closed. */ | |
90 | descriptor = NULL; | |
91 | else | |
92 | descriptor = cell; | |
93 | __spin_unlock (&cell->port.lock); | |
94 | } | |
95 | } | |
96 | __mutex_unlock (&_hurd_dtable_lock); | |
802ca5a5 | 97 | HURD_CRITICAL_END; |
28f540f4 RM |
98 | |
99 | return descriptor; | |
100 | } | |
2f8902cc | 101 | # endif |
28f6186f | 102 | #endif |
28f540f4 RM |
103 | |
104 | ||
105 | /* Evaluate EXPR with the variable `descriptor' bound to a pointer to the | |
106 | file descriptor structure for FD. */ | |
107 | ||
108 | #define HURD_FD_USE(fd, expr) \ | |
109 | ({ struct hurd_fd *descriptor = _hurd_fd_get (fd); \ | |
a9fb5710 | 110 | __glibc_unlikely (descriptor == NULL) ? EBADF : (expr); }) |
28f540f4 RM |
111 | |
112 | /* Evaluate EXPR with the variable `port' bound to the port to FD, and | |
113 | `ctty' bound to the ctty port. */ | |
114 | ||
115 | #define HURD_DPORT_USE(fd, expr) \ | |
116 | HURD_FD_USE ((fd), HURD_FD_PORT_USE (descriptor, (expr))) | |
117 | ||
118 | /* Likewise, but FD is a pointer to the file descriptor structure. */ | |
67a78072 | 119 | /* Also see HURD_FD_PORT_USE_CANCEL. */ |
28f540f4 RM |
120 | |
121 | #define HURD_FD_PORT_USE(fd, expr) \ | |
122 | ({ error_t __result; \ | |
123 | struct hurd_fd *const __d = (fd); \ | |
124 | struct hurd_userlink __ulink, __ctty_ulink; \ | |
125 | io_t port, ctty; \ | |
126 | void *crit = _hurd_critical_section_lock (); \ | |
127 | __spin_lock (&__d->port.lock); \ | |
a9fb5710 | 128 | if (__glibc_unlikely (__d->port.port == MACH_PORT_NULL)) \ |
28f540f4 RM |
129 | { \ |
130 | __spin_unlock (&__d->port.lock); \ | |
131 | _hurd_critical_section_unlock (crit); \ | |
132 | __result = EBADF; \ | |
133 | } \ | |
134 | else \ | |
135 | { \ | |
136 | ctty = _hurd_port_get (&__d->ctty, &__ctty_ulink); \ | |
137 | port = _hurd_port_locked_get (&__d->port, &__ulink); \ | |
138 | _hurd_critical_section_unlock (crit); \ | |
139 | __result = (expr); \ | |
140 | _hurd_port_free (&__d->port, &__ulink, port); \ | |
141 | if (ctty != MACH_PORT_NULL) \ | |
142 | _hurd_port_free (&__d->ctty, &__ctty_ulink, ctty); \ | |
143 | } \ | |
144 | __result; }) | |
145 | \f | |
146 | #include <errno.h> | |
974393ea | 147 | #include <bits/types/error_t.h> |
28f540f4 RM |
148 | |
149 | /* Check if ERR should generate a signal. | |
150 | Returns the signal to take, or zero if none. */ | |
151 | ||
6639cc10 | 152 | extern int _hurd_fd_error_signal (error_t err) __COLD; |
28f6186f ST |
153 | |
154 | #ifdef __USE_EXTERN_INLINES | |
7d409f11 | 155 | _HURD_FD_H_EXTERN_INLINE int |
28f540f4 RM |
156 | _hurd_fd_error_signal (error_t err) |
157 | { | |
158 | switch (err) | |
159 | { | |
160 | case EMACH_SEND_INVALID_DEST: | |
161 | case EMIG_SERVER_DIED: | |
162 | /* The server has disappeared! */ | |
163 | return SIGLOST; | |
164 | case EPIPE: | |
165 | return SIGPIPE; | |
166 | default: | |
167 | /* Having a default case avoids -Wenum-switch warnings. */ | |
168 | return 0; | |
169 | } | |
170 | } | |
28f6186f | 171 | #endif |
28f540f4 RM |
172 | |
173 | /* Handle an error from an RPC on a file descriptor's port. You should | |
174 | always use this function to handle errors from RPCs made on file | |
93a470c7 | 175 | descriptor ports. Some errors are translated into signals. */ |
28f540f4 | 176 | |
6639cc10 | 177 | extern error_t _hurd_fd_error (int fd, error_t err) __COLD; |
28f6186f ST |
178 | |
179 | #ifdef __USE_EXTERN_INLINES | |
6f9dc08b | 180 | _HURD_FD_H_EXTERN_INLINE error_t |
28f540f4 RM |
181 | _hurd_fd_error (int fd, error_t err) |
182 | { | |
183 | int signo = _hurd_fd_error_signal (err); | |
184 | if (signo) | |
93a470c7 RM |
185 | { |
186 | const struct hurd_signal_detail detail | |
48d34cbc | 187 | = { exc: 0, exc_code: 0, exc_subcode: 0, code: fd, error: err }; |
93a470c7 RM |
188 | _hurd_raise_signal (NULL, signo, &detail); |
189 | } | |
28f540f4 RM |
190 | return err; |
191 | } | |
28f6186f | 192 | #endif |
28f540f4 RM |
193 | |
194 | /* Handle error code ERR from an RPC on file descriptor FD's port. | |
195 | Set `errno' to the appropriate error code, and always return -1. */ | |
196 | ||
6639cc10 | 197 | extern int __hurd_dfail (int fd, error_t err) __COLD; |
28f6186f ST |
198 | |
199 | #ifdef __USE_EXTERN_INLINES | |
6f9dc08b | 200 | _HURD_FD_H_EXTERN_INLINE int |
28f540f4 RM |
201 | __hurd_dfail (int fd, error_t err) |
202 | { | |
203 | errno = _hurd_fd_error (fd, err); | |
204 | return -1; | |
205 | } | |
28f6186f | 206 | #endif |
e66ecb22 RM |
207 | |
208 | /* Likewise, but do not raise SIGPIPE on EPIPE if flags contain | |
209 | MSG_NOSIGNAL. */ | |
210 | ||
6639cc10 | 211 | extern int __hurd_sockfail (int fd, int flags, error_t err) __COLD; |
28f6186f ST |
212 | |
213 | #ifdef __USE_EXTERN_INLINES | |
e66ecb22 RM |
214 | _HURD_FD_H_EXTERN_INLINE int |
215 | __hurd_sockfail (int fd, int flags, error_t err) | |
216 | { | |
217 | if (!(flags & MSG_NOSIGNAL) || err != EPIPE) | |
218 | err = _hurd_fd_error (fd, err); | |
219 | errno = err; | |
220 | return -1; | |
221 | } | |
28f6186f | 222 | #endif |
28f540f4 RM |
223 | \f |
224 | /* Set up *FD to have PORT its server port, doing appropriate ctty magic. | |
225 | Does no locking or unlocking. */ | |
226 | ||
227 | extern void _hurd_port2fd (struct hurd_fd *fd, io_t port, int flags); | |
228 | ||
229 | /* Allocate a new file descriptor and install PORT in it (doing any | |
230 | appropriate ctty magic); consumes a user reference on PORT. FLAGS are | |
6f080c2f TS |
231 | as for `open'; only O_IGNORE_CTTY and O_CLOEXEC are meaningful, but all are |
232 | saved. | |
28f540f4 RM |
233 | |
234 | If the descriptor table is full, set errno, and return -1. | |
235 | If DEALLOC is nonzero, deallocate PORT first. */ | |
236 | ||
237 | extern int _hurd_intern_fd (io_t port, int flags, int dealloc); | |
238 | ||
239 | /* Allocate a new file descriptor in the table and return it, locked. The | |
240 | new descriptor number will be no less than FIRST_FD. If the table is | |
241 | full, set errno to EMFILE and return NULL. If FIRST_FD is negative or | |
242 | bigger than the size of the table, set errno to EINVAL and return NULL. */ | |
243 | ||
244 | extern struct hurd_fd *_hurd_alloc_fd (int *fd_ptr, int first_fd); | |
245 | ||
246 | /* Allocate a new file descriptor structure and initialize its port cells | |
247 | with PORT and CTTY. (This does not affect the descriptor table.) */ | |
248 | ||
249 | extern struct hurd_fd *_hurd_new_fd (io_t port, io_t ctty); | |
250 | ||
251 | /* Close a file descriptor, making it available for future reallocation. */ | |
252 | ||
253 | extern error_t _hurd_fd_close (struct hurd_fd *fd); | |
254 | ||
8b2134db RM |
255 | /* Read and write data from a file descriptor; just like `read' and `write' |
256 | if OFFSET is -1, or like `pread' and `pwrite' if OFFSET is not -1. | |
28f540f4 RM |
257 | If successful, stores the amount actually read or written in *NBYTES. */ |
258 | ||
8b2134db | 259 | extern error_t _hurd_fd_read (struct hurd_fd *fd, |
ba89615d | 260 | void *buf, size_t *nbytes, __loff_t offset); |
28f540f4 | 261 | extern error_t _hurd_fd_write (struct hurd_fd *fd, |
ba89615d | 262 | const void *buf, size_t *nbytes, __loff_t offset); |
28f540f4 RM |
263 | |
264 | ||
265 | /* Call *RPC on PORT and/or CTTY; if a call on CTTY returns EBACKGROUND, | |
266 | generate SIGTTIN/SIGTTOU or EIO as appropriate. */ | |
267 | ||
268 | extern error_t _hurd_ctty_input (io_t port, io_t ctty, error_t (*rpc) (io_t)); | |
269 | extern error_t _hurd_ctty_output (io_t port, io_t ctty, error_t (*rpc) (io_t)); | |
270 | ||
271 | ||
0d3eb016 RM |
272 | /* The guts of `select' and `poll'. Check the first NFDS descriptors |
273 | either in POLLFDS (if nonnull) or in each of READFDS, WRITEFDS, | |
274 | EXCEPTFDS that is nonnull. If TIMEOUT is not NULL, time out after | |
275 | waiting the interval specified therein. If SIGMASK is nonnull, | |
276 | the set of blocked signals is temporarily set to that during this call. | |
277 | Returns the number of ready descriptors, or -1 for errors. */ | |
278 | struct pollfd; | |
279 | struct timespec; | |
280 | extern int _hurd_select (int nfds, struct pollfd *pollfds, | |
281 | fd_set *readfds, fd_set *writefds, fd_set *exceptfds, | |
282 | const struct timespec *timeout, | |
283 | const sigset_t *sigmask); | |
284 | ||
09085ede ST |
285 | /* Apply AT_FLAGS on FLAGS, in preparation for calling |
286 | __hurd_file_name_lookup. */ | |
287 | ||
28f6186f | 288 | #if defined __USE_EXTERN_INLINES && defined _LIBC |
2f8902cc | 289 | # if IS_IN (libc) |
09085ede ST |
290 | _HURD_FD_H_EXTERN_INLINE error_t |
291 | __hurd_at_flags (int *at_flags, int *flags) | |
292 | { | |
293 | if ((*at_flags & AT_SYMLINK_FOLLOW) && (*at_flags & AT_SYMLINK_NOFOLLOW)) | |
294 | return EINVAL; | |
295 | ||
296 | *flags |= (*at_flags & AT_SYMLINK_NOFOLLOW) ? O_NOLINK : 0; | |
297 | *at_flags &= ~AT_SYMLINK_NOFOLLOW; | |
13710e7e | 298 | |
09085ede ST |
299 | if (*at_flags & AT_SYMLINK_FOLLOW) |
300 | *flags &= ~O_NOLINK; | |
301 | *at_flags &= ~AT_SYMLINK_FOLLOW; | |
13710e7e | 302 | |
13710e7e ST |
303 | *at_flags &= ~AT_NO_AUTOMOUNT; |
304 | ||
09085ede ST |
305 | if (*at_flags != 0) |
306 | return EINVAL; | |
307 | ||
308 | return 0; | |
309 | } | |
2f8902cc | 310 | # endif |
28f6186f | 311 | #endif |
09085ede | 312 | |
16a10468 | 313 | /* Variant of file_name_lookup used in *at function implementations. |
2a50c078 EPM |
314 | AT_FLAGS may only contain AT_SYMLINK_FOLLOW or AT_SYMLINK_NOFOLLOW, |
315 | which will remove and add O_NOLINK from FLAGS respectively. | |
316 | Other bits cause EINVAL. */ | |
16a10468 RM |
317 | extern file_t __file_name_lookup_at (int fd, int at_flags, |
318 | const char *file_name, | |
319 | int flags, mode_t mode); | |
320 | ||
321 | /* Variant of file_name_split used in *at function implementations. */ | |
322 | extern file_t __file_name_split_at (int fd, const char *file_name, | |
323 | char **name); | |
324 | ||
325 | /* Variant of directory_name_split used in *at function implementations. */ | |
326 | extern file_t __directory_name_split_at (int fd, const char *directory_name, | |
327 | char **name); | |
328 | ||
329 | ||
0d3eb016 | 330 | |
28f540f4 | 331 | #endif /* hurd/fd.h */ |