• 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 (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 
GetFdTable(void)77 struct 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 
IsValidProcessFd(struct fd_table_s * fdt,int procFd)94 static 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 
AssociateSystemFd(int procFd,int sysFd)105 void 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 
CheckProcessFd(int procFd)122 int 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 
GetAssociatedSystemFd(int procFd)133 int 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  */
AllocSpecifiedProcessFd(int procFd)157 int 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 
FreeProcessFd(int procFd)186 void 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 
DisassociateProcessFd(int procFd)201 int 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 
AllocProcessFd(void)223 int AllocProcessFd(void)
224 {
225     return AllocLowestProcessFd(MIN_START_FD);
226 }
227 
AllocLowestProcessFd(int minFd)228 int 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 
AllocAndAssocProcessFd(int sysFd,int minFd)256 int 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 
AllocAndAssocSystemFd(int procFd,int minFd)285 int 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 
FdRefer(int sysFd)305 static 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 
FdClose(int sysFd,unsigned int targetPid)322 static 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 
GetProcessFTable(unsigned int pid,sem_t * semId)349 static 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 
CopyFdToProc(int fd,unsigned int targetPid)373 int 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 
CloseProcFd(int procFd,unsigned int targetPid)426 int 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