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