xref: /kernel/liteos_a/fs/vfs/operation/vfs_procfd.c (revision 0d163575)
1/*
2 * Copyright (c) 2013-2019 Huawei Technologies Co., Ltd. All rights reserved.
3 * Copyright (c) 2020-2021 Huawei Device Co., Ltd. All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without modification,
6 * are permitted provided that the following conditions are met:
7 *
8 * 1. Redistributions of source code must retain the above copyright notice, this list of
9 *    conditions and the following disclaimer.
10 *
11 * 2. Redistributions in binary form must reproduce the above copyright notice, this list
12 *    of conditions and the following disclaimer in the documentation and/or other materials
13 *    provided with the distribution.
14 *
15 * 3. Neither the name of the copyright holder nor the names of its contributors may be used
16 *    to endorse or promote products derived from this software without specific prior written
17 *    permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
21 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
23 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
24 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
25 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
26 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
27 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
28 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
29 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 */
31
32#include "fs/file.h"
33#include "los_process_pri.h"
34#include "fs/fd_table.h"
35#include "mqueue.h"
36#ifdef LOSCFG_NET_LWIP_SACK
37#include "lwip/sockets.h"
38#endif
39
40void FileTableLock(struct fd_table_s *fdt)
41{
42    /* Take the semaphore (perhaps waiting) */
43    while (sem_wait(&fdt->ft_sem) != 0) {
44        /*
45        * The only case that an error should occur here is if the wait was
46        * awakened by a signal.
47        */
48        LOS_ASSERT(errno == EINTR);
49    }
50}
51
52void FileTableUnLock(struct fd_table_s *fdt)
53{
54    int ret = sem_post(&fdt->ft_sem);
55    if (ret == -1) {
56        PRINTK("sem_post error, errno %d \n", get_errno());
57    }
58}
59
60static int AssignProcessFd(const struct fd_table_s *fdt, int minFd)
61{
62    if (minFd >= fdt->max_fds) {
63        set_errno(EINVAL);
64        return VFS_ERROR;
65    }
66
67    /* search unused fd from table */
68    for (int i = minFd; i < fdt->max_fds; i++) {
69        if (!FD_ISSET(i, fdt->proc_fds)) {
70            return i;
71        }
72    }
73    set_errno(EMFILE);
74    return VFS_ERROR;
75}
76
77struct fd_table_s *GetFdTable(void)
78{
79    struct fd_table_s *fdt = NULL;
80    struct files_struct *procFiles = OsCurrProcessGet()->files;
81
82    if (procFiles == NULL) {
83        return NULL;
84    }
85
86    fdt = procFiles->fdt;
87    if ((fdt == NULL) || (fdt->ft_fds == NULL)) {
88        return NULL;
89    }
90
91    return fdt;
92}
93
94static bool IsValidProcessFd(struct fd_table_s *fdt, int procFd)
95{
96    if (fdt == NULL) {
97        return false;
98    }
99    if ((procFd < 0) || (procFd >= fdt->max_fds)) {
100        return false;
101    }
102    return true;
103}
104
105void AssociateSystemFd(int procFd, int sysFd)
106{
107    struct fd_table_s *fdt = GetFdTable();
108
109    if (!IsValidProcessFd(fdt, procFd)) {
110        return;
111    }
112
113    if (sysFd < 0) {
114        return;
115    }
116
117    FileTableLock(fdt);
118    fdt->ft_fds[procFd].sysFd = sysFd;
119    FileTableUnLock(fdt);
120}
121
122int CheckProcessFd(int procFd)
123{
124    struct fd_table_s *fdt = GetFdTable();
125
126    if (!IsValidProcessFd(fdt, procFd)) {
127        return VFS_ERROR;
128    }
129
130    return OK;
131}
132
133int GetAssociatedSystemFd(int procFd)
134{
135    struct fd_table_s *fdt = GetFdTable();
136
137    if (!IsValidProcessFd(fdt, procFd)) {
138        return VFS_ERROR;
139    }
140
141    FileTableLock(fdt);
142    if (fdt->ft_fds[procFd].sysFd < 0) {
143        FileTableUnLock(fdt);
144        return VFS_ERROR;
145    }
146    int sysFd = fdt->ft_fds[procFd].sysFd;
147    FileTableUnLock(fdt);
148
149    return sysFd;
150}
151
152/* Occupy the procFd, there are three circumstances:
153 * 1.procFd is already associated, we need disassociate procFd with relevant sysfd.
154 * 2.procFd is not allocated, we occupy it immediately.
155 * 3.procFd is in open(), close(), dup() process, we return EBUSY immediately.
156 */
157int AllocSpecifiedProcessFd(int procFd)
158{
159    struct fd_table_s *fdt = GetFdTable();
160
161    if (!IsValidProcessFd(fdt, procFd)) {
162        return -EBADF;
163    }
164
165    FileTableLock(fdt);
166    if (fdt->ft_fds[procFd].sysFd >= 0) {
167        /* Disassociate procFd */
168        fdt->ft_fds[procFd].sysFd = -1;
169        FileTableUnLock(fdt);
170        return OK;
171    }
172
173    if (FD_ISSET(procFd, fdt->proc_fds)) {
174        /* procFd in race condition */
175        FileTableUnLock(fdt);
176        return -EBUSY;
177    } else {
178        /* Unused procFd */
179        FD_SET(procFd, fdt->proc_fds);
180    }
181
182    FileTableUnLock(fdt);
183    return OK;
184}
185
186void FreeProcessFd(int procFd)
187{
188    struct fd_table_s *fdt = GetFdTable();
189
190    if (!IsValidProcessFd(fdt, procFd)) {
191        return;
192    }
193
194    FileTableLock(fdt);
195    FD_CLR(procFd, fdt->proc_fds);
196    FD_CLR(procFd, fdt->cloexec_fds);
197    fdt->ft_fds[procFd].sysFd = -1;
198    FileTableUnLock(fdt);
199}
200
201int DisassociateProcessFd(int procFd)
202{
203    struct fd_table_s *fdt = GetFdTable();
204
205    if (!IsValidProcessFd(fdt, procFd)) {
206        return VFS_ERROR;
207    }
208
209    FileTableLock(fdt);
210    if (fdt->ft_fds[procFd].sysFd < 0) {
211        FileTableUnLock(fdt);
212        return VFS_ERROR;
213    }
214    int sysFd = fdt->ft_fds[procFd].sysFd;
215    if (procFd >= MIN_START_FD) {
216        fdt->ft_fds[procFd].sysFd = -1;
217    }
218    FileTableUnLock(fdt);
219
220    return sysFd;
221}
222
223int AllocProcessFd(void)
224{
225    return AllocLowestProcessFd(MIN_START_FD);
226}
227
228int AllocLowestProcessFd(int minFd)
229{
230    struct fd_table_s *fdt = GetFdTable();
231
232    if (fdt == NULL) {
233        return VFS_ERROR;
234    }
235
236    /* minFd should be a positive number,and 0,1,2 had be distributed to stdin,stdout,stderr */
237    if (minFd < MIN_START_FD) {
238        minFd = MIN_START_FD;
239    }
240
241    FileTableLock(fdt);
242
243    int procFd = AssignProcessFd(fdt, minFd);
244    if (procFd == VFS_ERROR) {
245        FileTableUnLock(fdt);
246        return VFS_ERROR;
247    }
248
249    /* occupy the fd set */
250    FD_SET(procFd, fdt->proc_fds);
251    FileTableUnLock(fdt);
252
253    return procFd;
254}
255
256int AllocAndAssocProcessFd(int sysFd, int minFd)
257{
258    struct fd_table_s *fdt = GetFdTable();
259
260    if (fdt == NULL) {
261        return VFS_ERROR;
262    }
263
264    /* minFd should be a positive number,and 0,1,2 had be distributed to stdin,stdout,stderr */
265    if (minFd < MIN_START_FD) {
266        minFd = MIN_START_FD;
267    }
268
269    FileTableLock(fdt);
270
271    int procFd = AssignProcessFd(fdt, minFd);
272    if (procFd == VFS_ERROR) {
273        FileTableUnLock(fdt);
274        return VFS_ERROR;
275    }
276
277    /* occupy the fd set */
278    FD_SET(procFd, fdt->proc_fds);
279    fdt->ft_fds[procFd].sysFd = sysFd;
280    FileTableUnLock(fdt);
281
282    return procFd;
283}
284
285int AllocAndAssocSystemFd(int procFd, int minFd)
286{
287    struct fd_table_s *fdt = GetFdTable();
288
289    if (!IsValidProcessFd(fdt, procFd)) {
290        return VFS_ERROR;
291    }
292
293    int sysFd = alloc_fd(minFd);
294    if (sysFd < 0) {
295        return VFS_ERROR;
296    }
297
298    FileTableLock(fdt);
299    fdt->ft_fds[procFd].sysFd = sysFd;
300    FileTableUnLock(fdt);
301
302    return sysFd;
303}
304
305static void FdRefer(int sysFd)
306{
307    if ((sysFd > STDERR_FILENO) && (sysFd < CONFIG_NFILE_DESCRIPTORS)) {
308        files_refer(sysFd);
309    }
310#if defined(LOSCFG_NET_LWIP_SACK)
311    if ((sysFd >= CONFIG_NFILE_DESCRIPTORS) && (sysFd < (CONFIG_NFILE_DESCRIPTORS + CONFIG_NSOCKET_DESCRIPTORS))) {
312        socks_refer(sysFd);
313    }
314#endif
315#if defined(LOSCFG_COMPAT_POSIX)
316    if ((sysFd >= MQUEUE_FD_OFFSET) && (sysFd < (MQUEUE_FD_OFFSET + CONFIG_NQUEUE_DESCRIPTORS))) {
317        MqueueRefer(sysFd);
318    }
319#endif
320}
321
322static void FdClose(int sysFd, unsigned int targetPid)
323{
324    UINT32 intSave;
325
326    if ((sysFd > STDERR_FILENO) && (sysFd < CONFIG_NFILE_DESCRIPTORS)) {
327        LosProcessCB *processCB = OS_PCB_FROM_PID(targetPid);
328        SCHEDULER_LOCK(intSave);
329        if (OsProcessIsInactive(processCB)) {
330            SCHEDULER_UNLOCK(intSave);
331            return;
332        }
333        SCHEDULER_UNLOCK(intSave);
334
335        files_close_internal(sysFd, processCB);
336    }
337#if defined(LOSCFG_NET_LWIP_SACK)
338    if ((sysFd >= CONFIG_NFILE_DESCRIPTORS) && (sysFd < (CONFIG_NFILE_DESCRIPTORS + CONFIG_NSOCKET_DESCRIPTORS))) {
339        socks_close(sysFd);
340    }
341#endif
342#if defined(LOSCFG_COMPAT_POSIX)
343    if ((sysFd >= MQUEUE_FD_OFFSET) && (sysFd < (MQUEUE_FD_OFFSET + CONFIG_NQUEUE_DESCRIPTORS))) {
344        mq_close((mqd_t)sysFd);
345    }
346#endif
347}
348
349static struct fd_table_s *GetProcessFTable(unsigned int pid, sem_t *semId)
350{
351    UINT32 intSave;
352    struct files_struct *procFiles = NULL;
353    LosProcessCB *processCB = OS_PCB_FROM_PID(pid);
354
355    SCHEDULER_LOCK(intSave);
356    if (OsProcessIsInactive(processCB)) {
357        SCHEDULER_UNLOCK(intSave);
358        return NULL;
359    }
360
361    procFiles = processCB->files;
362    if (procFiles == NULL || procFiles->fdt == NULL) {
363        SCHEDULER_UNLOCK(intSave);
364        return NULL;
365    }
366
367    *semId = procFiles->fdt->ft_sem;
368    SCHEDULER_UNLOCK(intSave);
369
370    return procFiles->fdt;
371}
372
373int CopyFdToProc(int fd, unsigned int targetPid)
374{
375#if !defined(LOSCFG_NET_LWIP_SACK) && !defined(LOSCFG_COMPAT_POSIX) && !defined(LOSCFG_FS_VFS)
376    return -ENOSYS;
377#else
378    int sysFd;
379    struct fd_table_s *fdt = NULL;
380    int procFd;
381    sem_t semId;
382
383    if (OS_PID_CHECK_INVALID(targetPid)) {
384        return -EINVAL;
385    }
386
387    sysFd = GetAssociatedSystemFd(fd);
388    if (sysFd < 0) {
389        return -EBADF;
390    }
391
392    FdRefer(sysFd);
393    fdt = GetProcessFTable(targetPid, &semId);
394    if (fdt == NULL || fdt->ft_fds == NULL) {
395        FdClose(sysFd, targetPid);
396        return -EPERM;
397    }
398
399    /* Take the semaphore (perhaps waiting) */
400    if (sem_wait(&semId) != 0) {
401        /* Target process changed */
402        FdClose(sysFd, targetPid);
403        return -ESRCH;
404    }
405
406    procFd = AssignProcessFd(fdt, 3); // minfd is 3
407    if (procFd < 0) {
408        if (sem_post(&semId) == -1) {
409            PRINT_ERR("sem_post error, errno %d \n", get_errno());
410        }
411        FdClose(sysFd, targetPid);
412        return -EPERM;
413    }
414
415    /* occupy the fd set */
416    FD_SET(procFd, fdt->proc_fds);
417    fdt->ft_fds[procFd].sysFd = sysFd;
418    if (sem_post(&semId) == -1) {
419        PRINTK("sem_post error, errno %d \n", get_errno());
420    }
421
422    return procFd;
423#endif
424}
425
426int CloseProcFd(int procFd, unsigned int targetPid)
427{
428#if !defined(LOSCFG_NET_LWIP_SACK) && !defined(LOSCFG_COMPAT_POSIX) && !defined(LOSCFG_FS_VFS)
429    return -ENOSYS;
430#else
431    int sysFd;
432    struct fd_table_s *fdt = NULL;
433    sem_t semId;
434
435    if (OS_PID_CHECK_INVALID(targetPid)) {
436        return -EINVAL;
437    }
438
439    fdt = GetProcessFTable(targetPid, &semId);
440    if (fdt == NULL || fdt->ft_fds == NULL) {
441        return -EPERM;
442    }
443
444    /* Take the semaphore (perhaps waiting) */
445    if (sem_wait(&semId) != 0) {
446        /* Target process changed */
447        return -ESRCH;
448    }
449
450    if (!IsValidProcessFd(fdt, procFd)) {
451        if (sem_post(&semId) == -1) {
452            PRINTK("sem_post error, errno %d \n", get_errno());
453        }
454        return -EPERM;
455    }
456
457    sysFd = fdt->ft_fds[procFd].sysFd;
458    if (sysFd < 0) {
459        if (sem_post(&semId) == -1) {
460            PRINTK("sem_post error, errno %d \n", get_errno());
461        }
462        return -EPERM;
463    }
464
465    /* clean the fd set */
466    FD_CLR(procFd, fdt->proc_fds);
467    FD_CLR(procFd, fdt->cloexec_fds);
468    fdt->ft_fds[procFd].sysFd = -1;
469    if (sem_post(&semId) == -1) {
470        PRINTK("sem_post error, errno %d \n", get_errno());
471    }
472    FdClose(sysFd, targetPid);
473
474    return 0;
475#endif
476}
477