• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
FileTableLock(struct fd_table_s * fdt)40 void 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 
FileTableUnLock(struct fd_table_s * fdt)52 void 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 
AssignProcessFd(const struct fd_table_s * fdt,int minFd)60 static int AssignProcessFd(const struct fd_table_s *fdt, int minFd)
61 {
62     if (fdt == NULL) {
63         return VFS_ERROR;
64     }
65 
66     if (minFd >= fdt->max_fds) {
67         set_errno(EINVAL);
68         return VFS_ERROR;
69     }
70 
71     /* search unused fd from table */
72     for (int i = minFd; i < fdt->max_fds; i++) {
73         if (!FD_ISSET(i, fdt->proc_fds)) {
74             return i;
75         }
76     }
77     set_errno(EMFILE);
78     return VFS_ERROR;
79 }
80 
GetFdTable(void)81 struct fd_table_s *GetFdTable(void)
82 {
83     struct fd_table_s *fdt = NULL;
84     struct files_struct *procFiles = OsCurrProcessGet()->files;
85 
86     if (procFiles == NULL) {
87         return NULL;
88     }
89 
90     fdt = procFiles->fdt;
91     if ((fdt == NULL) || (fdt->ft_fds == NULL)) {
92         return NULL;
93     }
94 
95     return fdt;
96 }
97 
IsValidProcessFd(struct fd_table_s * fdt,int procFd)98 static bool IsValidProcessFd(struct fd_table_s *fdt, int procFd)
99 {
100     if (fdt == NULL) {
101         return false;
102     }
103     if ((procFd < 0) || (procFd >= fdt->max_fds)) {
104         return false;
105     }
106     return true;
107 }
108 
AssociateSystemFd(int procFd,int sysFd)109 void AssociateSystemFd(int procFd, int sysFd)
110 {
111     struct fd_table_s *fdt = GetFdTable();
112 
113     if (!IsValidProcessFd(fdt, procFd)) {
114         return;
115     }
116 
117     if (sysFd < 0) {
118         return;
119     }
120 
121     FileTableLock(fdt);
122     fdt->ft_fds[procFd].sysFd = sysFd;
123     FileTableUnLock(fdt);
124 }
125 
CheckProcessFd(int procFd)126 int CheckProcessFd(int procFd)
127 {
128     struct fd_table_s *fdt = GetFdTable();
129 
130     if (!IsValidProcessFd(fdt, procFd)) {
131         return VFS_ERROR;
132     }
133 
134     return OK;
135 }
136 
GetAssociatedSystemFd(int procFd)137 int GetAssociatedSystemFd(int procFd)
138 {
139     struct fd_table_s *fdt = GetFdTable();
140 
141     if (!IsValidProcessFd(fdt, procFd)) {
142         return VFS_ERROR;
143     }
144 
145     FileTableLock(fdt);
146     if (fdt->ft_fds[procFd].sysFd < 0) {
147         FileTableUnLock(fdt);
148         return VFS_ERROR;
149     }
150     int sysFd = fdt->ft_fds[procFd].sysFd;
151     FileTableUnLock(fdt);
152 
153     return sysFd;
154 }
155 
156 /* Occupy the procFd, there are three circumstances:
157  * 1.procFd is already associated, we need disassociate procFd with relevant sysfd.
158  * 2.procFd is not allocated, we occupy it immediately.
159  * 3.procFd is in open(), close(), dup() process, we return EBUSY immediately.
160  */
AllocSpecifiedProcessFd(int procFd)161 int AllocSpecifiedProcessFd(int procFd)
162 {
163     struct fd_table_s *fdt = GetFdTable();
164 
165     if (!IsValidProcessFd(fdt, procFd)) {
166         return -EBADF;
167     }
168 
169     FileTableLock(fdt);
170     if (fdt->ft_fds[procFd].sysFd >= 0) {
171         /* Disassociate procFd */
172         fdt->ft_fds[procFd].sysFd = -1;
173         FileTableUnLock(fdt);
174         return OK;
175     }
176 
177     if (FD_ISSET(procFd, fdt->proc_fds)) {
178         /* procFd in race condition */
179         FileTableUnLock(fdt);
180         return -EBUSY;
181     } else {
182         /* Unused procFd */
183         FD_SET(procFd, fdt->proc_fds);
184     }
185 
186     FileTableUnLock(fdt);
187     return OK;
188 }
189 
FreeProcessFd(int procFd)190 void FreeProcessFd(int procFd)
191 {
192     struct fd_table_s *fdt = GetFdTable();
193 
194     if (!IsValidProcessFd(fdt, procFd)) {
195         return;
196     }
197 
198     FileTableLock(fdt);
199     FD_CLR(procFd, fdt->proc_fds);
200     FD_CLR(procFd, fdt->cloexec_fds);
201     fdt->ft_fds[procFd].sysFd = -1;
202     FileTableUnLock(fdt);
203 }
204 
DisassociateProcessFd(int procFd)205 int DisassociateProcessFd(int procFd)
206 {
207     struct fd_table_s *fdt = GetFdTable();
208 
209     if (!IsValidProcessFd(fdt, procFd)) {
210         return VFS_ERROR;
211     }
212 
213     FileTableLock(fdt);
214     if (fdt->ft_fds[procFd].sysFd < 0) {
215         FileTableUnLock(fdt);
216         return VFS_ERROR;
217     }
218     int sysFd = fdt->ft_fds[procFd].sysFd;
219     if (procFd >= MIN_START_FD) {
220         fdt->ft_fds[procFd].sysFd = -1;
221     }
222     FileTableUnLock(fdt);
223 
224     return sysFd;
225 }
226 
AllocProcessFd(void)227 int AllocProcessFd(void)
228 {
229     return AllocLowestProcessFd(MIN_START_FD);
230 }
231 
AllocLowestProcessFd(int minFd)232 int AllocLowestProcessFd(int minFd)
233 {
234     struct fd_table_s *fdt = GetFdTable();
235 
236     if (fdt == NULL) {
237         return VFS_ERROR;
238     }
239 
240     /* minFd should be a positive number,and 0,1,2 had be distributed to stdin,stdout,stderr */
241     if (minFd < MIN_START_FD) {
242         minFd = MIN_START_FD;
243     }
244 
245     FileTableLock(fdt);
246 
247     int procFd = AssignProcessFd(fdt, minFd);
248     if (procFd == VFS_ERROR) {
249         FileTableUnLock(fdt);
250         return VFS_ERROR;
251     }
252 
253     /* occupy the fd set */
254     FD_SET(procFd, fdt->proc_fds);
255     FileTableUnLock(fdt);
256 
257     return procFd;
258 }
259 
AllocAndAssocProcessFd(int sysFd,int minFd)260 int AllocAndAssocProcessFd(int sysFd, int minFd)
261 {
262     struct fd_table_s *fdt = GetFdTable();
263 
264     if (fdt == NULL) {
265         return VFS_ERROR;
266     }
267 
268     /* minFd should be a positive number,and 0,1,2 had be distributed to stdin,stdout,stderr */
269     if (minFd < MIN_START_FD) {
270         minFd = MIN_START_FD;
271     }
272 
273     FileTableLock(fdt);
274 
275     int procFd = AssignProcessFd(fdt, minFd);
276     if (procFd == VFS_ERROR) {
277         FileTableUnLock(fdt);
278         return VFS_ERROR;
279     }
280 
281     /* occupy the fd set */
282     FD_SET(procFd, fdt->proc_fds);
283     fdt->ft_fds[procFd].sysFd = sysFd;
284     FileTableUnLock(fdt);
285 
286     return procFd;
287 }
288 
AllocAndAssocSystemFd(int procFd,int minFd)289 int AllocAndAssocSystemFd(int procFd, int minFd)
290 {
291     struct fd_table_s *fdt = GetFdTable();
292 
293     if (!IsValidProcessFd(fdt, procFd)) {
294         return VFS_ERROR;
295     }
296 
297     int sysFd = alloc_fd(minFd);
298     if (sysFd < 0) {
299         return VFS_ERROR;
300     }
301 
302     FileTableLock(fdt);
303     fdt->ft_fds[procFd].sysFd = sysFd;
304     FileTableUnLock(fdt);
305 
306     return sysFd;
307 }
308 
FdRefer(int sysFd)309 static void FdRefer(int sysFd)
310 {
311     if ((sysFd > STDERR_FILENO) && (sysFd < CONFIG_NFILE_DESCRIPTORS)) {
312         files_refer(sysFd);
313     }
314 #if defined(LOSCFG_NET_LWIP_SACK)
315     if ((sysFd >= CONFIG_NFILE_DESCRIPTORS) && (sysFd < (CONFIG_NFILE_DESCRIPTORS + CONFIG_NSOCKET_DESCRIPTORS))) {
316         socks_refer(sysFd);
317     }
318 #endif
319 #if defined(LOSCFG_COMPAT_POSIX)
320     if ((sysFd >= MQUEUE_FD_OFFSET) && (sysFd < (MQUEUE_FD_OFFSET + CONFIG_NQUEUE_DESCRIPTORS))) {
321         MqueueRefer(sysFd);
322     }
323 #endif
324 }
325 
FdClose(int sysFd,unsigned int targetPid)326 static void FdClose(int sysFd, unsigned int targetPid)
327 {
328     UINT32 intSave;
329 
330     if ((sysFd > STDERR_FILENO) && (sysFd < CONFIG_NFILE_DESCRIPTORS)) {
331         LosProcessCB *processCB = OS_PCB_FROM_PID(targetPid);
332         SCHEDULER_LOCK(intSave);
333         if (OsProcessIsInactive(processCB)) {
334             SCHEDULER_UNLOCK(intSave);
335             return;
336         }
337         SCHEDULER_UNLOCK(intSave);
338 
339         files_close_internal(sysFd, processCB);
340     }
341 #if defined(LOSCFG_NET_LWIP_SACK)
342     if ((sysFd >= CONFIG_NFILE_DESCRIPTORS) && (sysFd < (CONFIG_NFILE_DESCRIPTORS + CONFIG_NSOCKET_DESCRIPTORS))) {
343         socks_close(sysFd);
344     }
345 #endif
346 #if defined(LOSCFG_COMPAT_POSIX)
347     if ((sysFd >= MQUEUE_FD_OFFSET) && (sysFd < (MQUEUE_FD_OFFSET + CONFIG_NQUEUE_DESCRIPTORS))) {
348         mq_close((mqd_t)sysFd);
349     }
350 #endif
351 }
352 
GetProcessFTable(unsigned int pid,sem_t * semId)353 static struct fd_table_s *GetProcessFTable(unsigned int pid, sem_t *semId)
354 {
355     UINT32 intSave;
356     struct files_struct *procFiles = NULL;
357     LosProcessCB *processCB = OS_PCB_FROM_PID(pid);
358 
359     SCHEDULER_LOCK(intSave);
360     if (OsProcessIsInactive(processCB)) {
361         SCHEDULER_UNLOCK(intSave);
362         return NULL;
363     }
364 
365     procFiles = processCB->files;
366     if (procFiles == NULL || procFiles->fdt == NULL) {
367         SCHEDULER_UNLOCK(intSave);
368         return NULL;
369     }
370 
371     *semId = procFiles->fdt->ft_sem;
372     SCHEDULER_UNLOCK(intSave);
373 
374     return procFiles->fdt;
375 }
376 
CopyFdToProc(int fd,unsigned int targetPid)377 int CopyFdToProc(int fd, unsigned int targetPid)
378 {
379 #if !defined(LOSCFG_NET_LWIP_SACK) && !defined(LOSCFG_COMPAT_POSIX) && !defined(LOSCFG_FS_VFS)
380     return -ENOSYS;
381 #else
382     int sysFd;
383     struct fd_table_s *fdt = NULL;
384     int procFd;
385     sem_t semId;
386 
387     if (OS_PID_CHECK_INVALID(targetPid)) {
388         return -EINVAL;
389     }
390 
391     sysFd = GetAssociatedSystemFd(fd);
392     if (sysFd < 0) {
393         return -EBADF;
394     }
395 
396     FdRefer(sysFd);
397     fdt = GetProcessFTable(targetPid, &semId);
398     if (fdt == NULL || fdt->ft_fds == NULL) {
399         FdClose(sysFd, targetPid);
400         return -EPERM;
401     }
402 
403     /* Take the semaphore (perhaps waiting) */
404     if (sem_wait(&semId) != 0) {
405         /* Target process changed */
406         FdClose(sysFd, targetPid);
407         return -ESRCH;
408     }
409 
410     procFd = AssignProcessFd(fdt, 3); // minfd is 3
411     if (procFd < 0) {
412         if (sem_post(&semId) == -1) {
413             PRINT_ERR("sem_post error, errno %d \n", get_errno());
414         }
415         FdClose(sysFd, targetPid);
416         return -EPERM;
417     }
418 
419     /* occupy the fd set */
420     FD_SET(procFd, fdt->proc_fds);
421     fdt->ft_fds[procFd].sysFd = sysFd;
422     if (sem_post(&semId) == -1) {
423         PRINTK("sem_post error, errno %d \n", get_errno());
424     }
425 
426     return procFd;
427 #endif
428 }
429 
CloseProcFd(int procFd,unsigned int targetPid)430 int CloseProcFd(int procFd, unsigned int targetPid)
431 {
432 #if !defined(LOSCFG_NET_LWIP_SACK) && !defined(LOSCFG_COMPAT_POSIX) && !defined(LOSCFG_FS_VFS)
433     return -ENOSYS;
434 #else
435     int sysFd;
436     struct fd_table_s *fdt = NULL;
437     sem_t semId;
438 
439     if (OS_PID_CHECK_INVALID(targetPid)) {
440         return -EINVAL;
441     }
442 
443     fdt = GetProcessFTable(targetPid, &semId);
444     if (fdt == NULL || fdt->ft_fds == NULL) {
445         return -EPERM;
446     }
447 
448     /* Take the semaphore (perhaps waiting) */
449     if (sem_wait(&semId) != 0) {
450         /* Target process changed */
451         return -ESRCH;
452     }
453 
454     if (!IsValidProcessFd(fdt, procFd)) {
455         if (sem_post(&semId) == -1) {
456             PRINTK("sem_post error, errno %d \n", get_errno());
457         }
458         return -EPERM;
459     }
460 
461     sysFd = fdt->ft_fds[procFd].sysFd;
462     if (sysFd < 0) {
463         if (sem_post(&semId) == -1) {
464             PRINTK("sem_post error, errno %d \n", get_errno());
465         }
466         return -EPERM;
467     }
468 
469     /* clean the fd set */
470     FD_CLR(procFd, fdt->proc_fds);
471     FD_CLR(procFd, fdt->cloexec_fds);
472     fdt->ft_fds[procFd].sysFd = -1;
473     if (sem_post(&semId) == -1) {
474         PRINTK("sem_post error, errno %d \n", get_errno());
475     }
476     FdClose(sysFd, targetPid);
477 
478     return 0;
479 #endif
480 }
481