1 /*
2  * Copyright (c) 2018 Linaro Limited
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 #ifndef ZEPHYR_INCLUDE_SYS_FDTABLE_H_
7 #define ZEPHYR_INCLUDE_SYS_FDTABLE_H_
8 
9 #include <stdarg.h>
10 #include <time.h>
11 
12 /* FIXME: For native_posix ssize_t, off_t. */
13 #include <sys/types.h>
14 #include <zephyr/kernel.h>
15 #include <zephyr/sys/util.h>
16 
17 /* File mode bits */
18 #define ZVFS_MODE_IFMT   0170000
19 #define ZVFS_MODE_UNSPEC 0000000
20 #define ZVFS_MODE_IFIFO  0010000
21 #define ZVFS_MODE_IFCHR  0020000
22 #define ZVFS_MODE_IMSGQ  0030000
23 #define ZVFS_MODE_IFDIR  0040000
24 #define ZVFS_MODE_IFSEM  0050000
25 #define ZVFS_MODE_IFBLK  0060000
26 #define ZVFS_MODE_IFSHM  0070000
27 #define ZVFS_MODE_IFREG  0100000
28 #define ZVFS_MODE_IFLNK  0120000
29 #define ZVFS_MODE_IFSOCK 0140000
30 
31 #define ZVFS_POLLIN   BIT(0)
32 #define ZVFS_POLLPRI  BIT(1)
33 #define ZVFS_POLLOUT  BIT(2)
34 #define ZVFS_POLLERR  BIT(3)
35 #define ZVFS_POLLHUP  BIT(4)
36 #define ZVFS_POLLNVAL BIT(5)
37 
38 #ifdef __cplusplus
39 extern "C" {
40 #endif
41 
42 /* FIXME: use k_off_t and k_ssize_t to avoid the POSIX->Zephyr->POSIX dependency cycle */
43 #ifdef CONFIG_NEWLIB_LIBC
44 #ifndef _OFF_T_DECLARED
45 typedef __off_t off_t;
46 #define _OFF_T_DECLARED
47 #endif
48 #ifndef _SSIZE_T_DECLARED
49 typedef _ssize_t ssize_t;
50 #define _SSIZE_T_DECLARED
51 #endif
52 #endif
53 
54 /**
55  * File descriptor virtual method table.
56  * Currently all operations beyond read/write/close go thru ioctl method.
57  */
58 struct fd_op_vtable {
59 	union {
60 		ssize_t (*read)(void *obj, void *buf, size_t sz);
61 		ssize_t (*read_offs)(void *obj, void *buf, size_t sz, size_t offset);
62 	};
63 	union {
64 		ssize_t (*write)(void *obj, const void *buf, size_t sz);
65 		ssize_t (*write_offs)(void *obj, const void *buf, size_t sz, size_t offset);
66 	};
67 	union {
68 		int (*close)(void *obj);
69 		int (*close2)(void *obj, int fd);
70 	};
71 	int (*ioctl)(void *obj, unsigned int request, va_list args);
72 };
73 
74 /**
75  * @brief Reserve file descriptor.
76  *
77  * This function allows to reserve a space for file descriptor entry in
78  * the underlying table, and thus allows caller to fail fast if no free
79  * descriptor is available. If this function succeeds, zvfs_finalize_fd()
80  * or zvfs_free_fd() must be called mandatorily.
81  *
82  * @return Allocated file descriptor, or -1 in case of error (errno is set)
83  */
84 int zvfs_reserve_fd(void);
85 
86 /**
87  * @brief Finalize creation of file descriptor, with type.
88  *
89  * This function should be called exactly once after zvfs_reserve_fd(), and
90  * should not be called in any other case.
91  *
92  * The difference between this function and @ref zvfs_finalize_fd is that the
93  * latter does not relay type information of the created file descriptor.
94  *
95  * Values permitted for @a mode are one of `ZVFS_MODE_..`.
96  *
97  * @param fd File descriptor previously returned by zvfs_reserve_fd()
98  * @param obj pointer to I/O object structure
99  * @param vtable pointer to I/O operation implementations for the object
100  * @param mode File type as specified above.
101  */
102 void zvfs_finalize_typed_fd(int fd, void *obj, const struct fd_op_vtable *vtable, uint32_t mode);
103 
104 /**
105  * @brief Finalize creation of file descriptor.
106  *
107  * This function should be called exactly once after zvfs_reserve_fd(), and
108  * should not be called in any other case.
109  *
110  * @param fd File descriptor previously returned by zvfs_reserve_fd()
111  * @param obj pointer to I/O object structure
112  * @param vtable pointer to I/O operation implementations for the object
113  */
zvfs_finalize_fd(int fd,void * obj,const struct fd_op_vtable * vtable)114 static inline void zvfs_finalize_fd(int fd, void *obj, const struct fd_op_vtable *vtable)
115 {
116 	zvfs_finalize_typed_fd(fd, obj, vtable, ZVFS_MODE_UNSPEC);
117 }
118 
119 /**
120  * @brief Allocate file descriptor for underlying I/O object.
121  *
122  * This function combines operations of zvfs_reserve_fd() and zvfs_finalize_fd()
123  * in one step, and provided for convenience.
124  *
125  * @param obj pointer to I/O object structure
126  * @param vtable pointer to I/O operation implementations for the object
127  *
128  * @return Allocated file descriptor, or -1 in case of error (errno is set)
129  */
130 int zvfs_alloc_fd(void *obj, const struct fd_op_vtable *vtable);
131 
132 /**
133  * @brief Release reserved file descriptor.
134  *
135  * This function may be called once after zvfs_reserve_fd(), and should
136  * not be called in any other case.
137  *
138  * @param fd File descriptor previously returned by zvfs_reserve_fd()
139  */
140 void zvfs_free_fd(int fd);
141 
142 /**
143  * @brief Get underlying object pointer from file descriptor.
144  *
145  * This function is useful for functions other than read/write/ioctl
146  * to look up underlying I/O object by fd, optionally checking its
147  * type (using vtable reference). If fd refers to invalid entry,
148  * NULL will be returned with errno set to EBADF. If fd is valid,
149  * but vtable param is not NULL and doesn't match object's vtable,
150  * NULL is returned and errno set to err param.
151  *
152  * @param fd File descriptor previously returned by zvfs_reserve_fd()
153  * @param vtable Expected object vtable or NULL
154  * @param err errno value to set if object vtable doesn't match
155  *
156  * @return Object pointer or NULL, with errno set
157  */
158 void *zvfs_get_fd_obj(int fd, const struct fd_op_vtable *vtable, int err);
159 
160 /**
161  * @brief Get underlying object pointer and vtable pointer from file descriptor.
162  *
163  * @param fd File descriptor previously returned by zvfs_reserve_fd()
164  * @param vtable A pointer to a pointer variable to store the vtable
165  * @param lock An optional pointer to a pointer variable to store the mutex
166  *        preventing concurrent descriptor access. The lock is not taken,
167  *        it is just returned for the caller to use if necessary. Pass NULL
168  *        if the lock is not needed by the caller.
169  *
170  * @return Object pointer or NULL, with errno set
171  */
172 void *zvfs_get_fd_obj_and_vtable(int fd, const struct fd_op_vtable **vtable,
173 			      struct k_mutex **lock);
174 
175 /**
176  * @brief Get the mutex and condition variable associated with the given object and vtable.
177  *
178  * @param obj Object previously returned by a call to e.g. @ref zvfs_get_fd_obj.
179  * @param vtable A pointer the vtable associated with @p obj.
180  * @param lock An optional pointer to a pointer variable to store the mutex
181  *        preventing concurrent descriptor access. The lock is not taken,
182  *        it is just returned for the caller to use if necessary. Pass NULL
183  *        if the lock is not needed by the caller.
184  * @param cond An optional pointer to a pointer variable to store the condition variable
185  *        to notify waiting threads in the case of concurrent descriptor access. Pass NULL
186  *        if the condition variable is not needed by the caller.
187  *
188  * @return `true` on success, `false` otherwise.
189  */
190 bool zvfs_get_obj_lock_and_cond(void *obj, const struct fd_op_vtable *vtable, struct k_mutex **lock,
191 			     struct k_condvar **cond);
192 
193 /**
194  * @brief Call ioctl vmethod on an object using varargs.
195  *
196  * We need this helper function because ioctl vmethod is declared to
197  * take va_list and the only portable way to construct va_list is from
198  * function's ... parameters.
199  *
200  * @param vtable vtable containing ioctl function pointer
201  * @param obj Object to call ioctl on
202  * @param request ioctl request number
203  * @param ... Variadic arguments to ioctl
204  */
zvfs_fdtable_call_ioctl(const struct fd_op_vtable * vtable,void * obj,unsigned long request,...)205 static inline int zvfs_fdtable_call_ioctl(const struct fd_op_vtable *vtable, void *obj,
206 				       unsigned long request, ...)
207 {
208 	va_list args;
209 	int res;
210 
211 	va_start(args, request);
212 	res = vtable->ioctl(obj, request, args);
213 	va_end(args);
214 
215 	return res;
216 }
217 
218 struct zvfs_pollfd {
219 	int fd;
220 	short events;
221 	short revents;
222 };
223 
224 __syscall int zvfs_poll(struct zvfs_pollfd *fds, int nfds, int poll_timeout);
225 
226 struct zvfs_fd_set {
227 	uint32_t bitset[(CONFIG_ZVFS_OPEN_MAX + 31) / 32];
228 };
229 
230 /** @brief Number of file descriptors which can be added @ref zvfs_fd_set */
231 #define ZVFS_FD_SETSIZE (sizeof(((struct zvfs_fd_set *)0)->bitset) * 8)
232 
233 void ZVFS_FD_CLR(int fd, struct zvfs_fd_set *fdset);
234 int ZVFS_FD_ISSET(int fd, struct zvfs_fd_set *fdset);
235 void ZVFS_FD_SET(int fd, struct zvfs_fd_set *fdset);
236 void ZVFS_FD_ZERO(struct zvfs_fd_set *fdset);
237 
238 __syscall int zvfs_select(int nfds, struct zvfs_fd_set *ZRESTRICT readfds,
239 			  struct zvfs_fd_set *ZRESTRICT writefds,
240 			  struct zvfs_fd_set *ZRESTRICT errorfds,
241 			  const struct timespec *ZRESTRICT timeout, const void *ZRESTRICT sigmask);
242 
243 /**
244  * Request codes for fd_op_vtable.ioctl().
245  *
246  * Note that these codes are internal Zephyr numbers, for internal
247  * Zephyr operations (and subject to change without notice, not part
248  * of "stable ABI"). These are however expected to co-exist with
249  * "well-known" POSIX/Linux ioctl numbers, and not clash with them.
250  */
251 enum {
252 	/* Codes below 0x100 are reserved for fcntl() codes. */
253 	ZFD_IOCTL_FSYNC = 0x100,
254 	ZFD_IOCTL_LSEEK,
255 	ZFD_IOCTL_POLL_PREPARE,
256 	ZFD_IOCTL_POLL_UPDATE,
257 	ZFD_IOCTL_POLL_OFFLOAD,
258 	ZFD_IOCTL_SET_LOCK,
259 	ZFD_IOCTL_STAT,
260 	ZFD_IOCTL_TRUNCATE,
261 	ZFD_IOCTL_MMAP,
262 
263 	/* Codes above 0x5400 and below 0x5500 are reserved for termios, FIO, etc */
264 	ZFD_IOCTL_FIONREAD = 0x541B,
265 	ZFD_IOCTL_FIONBIO = 0x5421,
266 };
267 
268 #ifdef __cplusplus
269 }
270 #endif
271 
272 #include <zephyr/syscalls/fdtable.h>
273 
274 #endif /* ZEPHYR_INCLUDE_SYS_FDTABLE_H_ */
275