1 /****************************************************************************
2 * fs/vfs/fs_fcntl.c
3 *
4 * Copyright (C) 2009, 2012-2014, 2016-2017 Gregory Nutt. All rights
5 * reserved.
6 * Author: Gregory Nutt <gnutt@nuttx.org>
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 *
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in
16 * the documentation and/or other materials provided with the
17 * distribution.
18 * 3. Neither the name NuttX nor the names of its contributors may be
19 * used to endorse or promote products derived from this software
20 * without specific prior written permission.
21 *
22 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
23 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
24 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
25 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
26 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
27 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
28 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
29 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
30 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
32 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
33 * POSSIBILITY OF SUCH DAMAGE.
34 *
35 ****************************************************************************/
36
37 /****************************************************************************
38 * Included Files
39 ****************************************************************************/
40
41 #include "vfs_config.h"
42
43 #include "stdarg.h"
44 #include "fcntl.h"
45 #include "errno.h"
46 #include "assert.h"
47 #include "vnode.h"
48
49 #if defined(LOSCFG_NET_LWIP_SACK)
50 #include "lwip/sockets.h"
51 #endif
52
53 #define FAPPEND O_APPEND
54 #define FFSYNC O_SYNC
55 #define FNONBLOCK O_NONBLOCK
56 #define FNDELAY O_NDELAY
57 #define FFCNTL (FNONBLOCK | FNDELAY | FAPPEND | FFSYNC | FASYNC)
58
59 /****************************************************************************
60 * Public Functions
61 ****************************************************************************/
62
63 /****************************************************************************
64 * Name: file_vfcntl
65 *
66 * Description:
67 * Similar to the standard vfcntl function except that is accepts a struct
68 * struct file instance instead of a file descriptor.
69 *
70 * Input Parameters:
71 * filep - Instance for struct file for the opened file.
72 * cmd - Indentifies the operation to be performed.
73 * ap - Variable argument following the command.
74 *
75 * Returned Value:
76 * The nature of the return value depends on the command. Non-negative
77 * values indicate success. Failures are reported as negated errno
78 * values.
79 *
80 ****************************************************************************/
81
82 #if CONFIG_NFILE_DESCRIPTORS > 0
file_vfcntl(struct file * filep,int cmd,va_list ap)83 int file_vfcntl(struct file *filep, int cmd, va_list ap)
84 {
85 int err = 0;
86 int ret = OK;
87
88 /* Was this file opened ? */
89
90 if (!filep || !filep->f_vnode)
91 {
92 err = EBADF;
93 goto errout;
94 }
95
96 switch (cmd)
97 {
98 case F_DUPFD:
99 /* Return a new file descriptor which shall be the lowest numbered
100 * available (that is, not already open) file descriptor greater than
101 * or equal to the third argument, arg, taken as an integer of type
102 * int. The new file descriptor shall refer to the same open file
103 * description as the original file descriptor, and shall share any
104 * locks. The FD_CLOEXEC flag associated with the new file descriptor
105 * shall be cleared to keep the file open across calls to one of the
106 * exec functions.
107 */
108
109 {
110 /* Does not set the errno variable in the event of a failure */
111
112 ret = file_dup(filep, va_arg(ap, int));
113 }
114 break;
115
116 case F_GETFD:
117 /* Get the file descriptor flags defined in <fcntl.h> that are associated
118 * with the file descriptor fd. File descriptor flags are associated
119 * with a single file descriptor and do not affect other file descriptors
120 * that refer to the same file.
121 */
122
123 {
124 ret = (filep->f_oflags & O_CLOEXEC) ? FD_CLOEXEC : 0;
125 }
126 break;
127
128 case F_SETFD:
129 /* Set the file descriptor flags defined in <fcntl.h>, that are associated
130 * with fd, to the third argument, arg, taken as type int. If the
131 * FD_CLOEXEC flag in the third argument is 0, the file shall remain open
132 * across the exec functions; otherwise, the file shall be closed upon
133 * successful execution of one of the exec functions.
134 */
135
136 {
137 int oflags = va_arg(ap, int);
138
139 if (oflags & FD_CLOEXEC)
140 {
141 filep->f_oflags |= O_CLOEXEC;
142 }
143 else
144 {
145 err = EPERM; /* Not support */
146 }
147 }
148 break;
149
150 case F_GETFL:
151 /* Get the file status flags and file access modes, defined in
152 * <fcntl.h>, for the file description associated with fd. The file
153 * access modes can be extracted from the return value using the
154 * mask O_ACCMODE, which is defined in <fcntl.h>. File status flags
155 * and file access modes are associated with the file description
156 * and do not affect other file descriptors that refer to the same
157 * file with different open file descriptions.
158 */
159
160 {
161 ret = filep->f_oflags;
162 }
163 break;
164
165 case F_SETFL:
166 /* Set the file status flags, defined in <fcntl.h>, for the file
167 * description associated with fd from the corresponding bits in
168 * the third argument, arg, taken as type int. Bits corresponding
169 * to the file access mode and the file creation flags, as defined
170 * in <fcntl.h>, that are set in arg shall be ignored. If any bits
171 * in arg other than those mentioned here are changed by the
172 * application, the result is unspecified.
173 */
174
175 {
176 int oflags = va_arg(ap, int);
177
178 oflags &= FFCNTL;
179 filep->f_oflags &= ~FFCNTL;
180 filep->f_oflags |= oflags;
181 }
182 break;
183
184 case F_GETOWN:
185 /* If fd refers to a socket, get the process or process group ID
186 * specified to receive SIGURG signals when out-of-band data is
187 * available. Positive values indicate a process ID; negative
188 * values, other than -1, indicate a process group ID. If fd does
189 * not refer to a socket, the results are unspecified.
190 */
191
192 case F_SETOWN:
193 /* If fd refers to a socket, set the process or process group ID
194 * specified to receive SIGURG signals when out-of-band data is
195 * available, using the value of the third argument, arg, taken as
196 * type int. Positive values indicate a process ID; negative values,
197 * other than -1, indicate a process group ID. If fd does not refer
198 * to a socket, the results are unspecified.
199 */
200
201 err = EBADF; /* Only valid on socket descriptors */
202 break;
203
204 case F_GETLK:
205 /* Get the first lock which blocks the lock description pointed to
206 * by the third argument, arg, taken as a pointer to type struct
207 * flock, defined in <fcntl.h>. The information retrieved shall
208 * overwrite the information passed to fcntl() in the structure
209 * flock. If no lock is found that would prevent this lock from
210 * being created, then the structure shall be left unchanged except
211 * for the lock type which shall be set to F_UNLCK.
212 */
213
214 case F_SETLK:
215 /* Set or clear a file segment lock according to the lock
216 * description pointed to by the third argument, arg, taken as a
217 * pointer to type struct flock, defined in <fcntl.h>. F_SETLK can
218 * establish shared (or read) locks (F_RDLCK) or exclusive (or
219 * write) locks (F_WRLCK), as well as to remove either type of lock
220 * (F_UNLCK). F_RDLCK, F_WRLCK, and F_UNLCK are defined in
221 * <fcntl.h>. If a shared or exclusive lock cannot be set, fcntl()
222 * shall return immediately with a return value of -1.
223 */
224
225 case F_SETLKW:
226 /* This command shall be equivalent to F_SETLK except that if a
227 * shared or exclusive lock is blocked by other locks, the thread
228 * shall wait until the request can be satisfied. If a signal that
229 * is to be caught is received while fcntl() is waiting for a
230 * region, fcntl() shall be interrupted. Upon return from the signal
231 * handler, fcntl() shall return -1 with errno set to [EINTR], and
232 * the lock operation shall not be done.
233 */
234
235 err = ENOSYS; /* Not implemented */
236 break;
237
238 default:
239 err = EINVAL;
240 break;
241 }
242
243 errout:
244 if (err != 0)
245 {
246 set_errno(err);
247 return VFS_ERROR;
248 }
249
250 return ret;
251 }
252 #endif /* CONFIG_NFILE_DESCRIPTORS > 0 */
253
254 /****************************************************************************
255 * Name: fcntl
256 *
257 * Description:
258 * fcntl() will perform the operation specified by 'cmd' on an open file.
259 *
260 * Input Parameters:
261 * fd - File descriptor of the open file
262 * cmd - Identifies the operation to be performed. Command specific
263 * arguments may follow.
264 *
265 * Returned Value:
266 * The returned value depends on the nature of the command but for all
267 * commands the return value of -1 (ERROR) indicates that an error has
268 * occurred and, in this case, the errno variable will be set
269 * appropriately
270 *
271 ****************************************************************************/
272
fcntl(int fd,int cmd,...)273 int fcntl(int fd, int cmd, ...)
274 {
275 struct file *filep = NULL;
276 va_list ap;
277 int ret;
278 int val = 0;
279
280 /* Setup to access the variable argument list */
281
282 va_start(ap, cmd);
283
284 /* Did we get a valid file descriptor? */
285
286 #if CONFIG_NFILE_DESCRIPTORS > 0
287 if ((unsigned int)fd < CONFIG_NFILE_DESCRIPTORS)
288 {
289 /* Get the file structure corresponding to the file descriptor. */
290
291 ret = fs_getfilep(fd, &filep);
292 if (ret < 0)
293 {
294 /* The errno value has already been set */
295 va_end(ap);
296 return VFS_ERROR;
297 }
298
299 /* Let file_vfcntl() do the real work. The errno is not set on
300 * failures.
301 */
302
303 ret = file_vfcntl(filep, cmd, ap);
304 }
305 else
306 #endif
307 {
308 /* No... check for operations on a socket descriptor */
309
310 #if defined(LOSCFG_NET_LWIP_SACK)
311 if ((unsigned int)fd < (unsigned int)(CONFIG_NFILE_DESCRIPTORS+CONFIG_NSOCKET_DESCRIPTORS))
312 {
313 /* Yes.. defer socket descriptor operations to net_vfcntl() */
314
315 val = va_arg(ap, int);
316 ret = lwip_fcntl(fd, cmd, val);
317 }
318 else
319 #endif
320 {
321 /* No.. this descriptor number is out of range */
322
323 (void)val;
324 ret = EBADF;
325 set_errno(ret);
326 va_end(ap);
327 return VFS_ERROR;
328 }
329 }
330
331 va_end(ap);
332 return ret;
333 }
334
fcntl64(int fd,int cmd,...)335 int fcntl64(int fd, int cmd, ...)
336 {
337 struct file *filep = NULL;
338 va_list va_ap;
339 int reval;
340 int va_val = 0;
341
342 /* Setup to access the variable argument list */
343
344 va_start(va_ap, cmd);
345
346 /* Did we get a valid file descriptor? */
347
348 #if CONFIG_NFILE_DESCRIPTORS > 0
349 if ((unsigned int)fd < CONFIG_NFILE_DESCRIPTORS)
350 {
351 /* Get the file structure corresponding to the file descriptor. */
352
353 int ret = fs_getfilep(fd, &filep);
354 if (ret < 0)
355 {
356 /* The errno value has already been set */
357 va_end(va_ap);
358 return VFS_ERROR;
359 }
360
361 /* Let file_vfcntl() do the real work */
362
363 reval = file_vfcntl(filep, cmd, va_ap);
364 }
365 else
366 #endif
367 {
368 /* No... check for operations on a socket descriptor */
369
370 #if defined(LOSCFG_NET_LWIP_SACK)
371 if ((unsigned int)fd < (unsigned int)(CONFIG_NFILE_DESCRIPTORS+CONFIG_NSOCKET_DESCRIPTORS))
372 {
373 /* Yes.. defer socket descriptor operations to net_vfcntl() */
374
375 va_val = va_arg(va_ap, int);
376 reval = lwip_fcntl(fd, cmd, va_val);
377 }
378 else
379 #endif
380 {
381 /* No.. this descriptor number is out of range */
382
383 (void)va_val;
384 reval = EBADF;
385 set_errno(reval);
386 va_end(va_ap);
387 return VFS_ERROR;
388 }
389 }
390
391 va_end(va_ap);
392 return reval;
393 }
394