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