• 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 "proc_file.h"
33 #include <stdio.h>
34 #include <linux/errno.h>
35 #include <linux/module.h>
36 #include "internal.h"
37 #include "user_copy.h"
38 
39 #define MIN(a, b) ((a) < (b) ? (a) : (b))
40 #define PROC_ROOTDIR_NAMELEN   5
41 #define PROC_INUSE             2
42 
43 DEFINE_SPINLOCK(procfsLock);
44 bool procfsInit = false;
45 
46 static struct ProcFile g_procPf = {
47     .fPos       = 0,
48 };
49 
50 static struct ProcDirEntry g_procRootDirEntry = {
51     .nameLen     = 5,
52     .mode        = S_IFDIR | PROCFS_DEFAULT_MODE,
53     .count       = ATOMIC_INIT(1),
54     .procFileOps = NULL,
55     .parent      = &g_procRootDirEntry,
56     .name        = "/proc",
57     .subdir      = NULL,
58     .next        = NULL,
59     .pf          = &g_procPf,
60     .type        = VNODE_TYPE_DIR,
61 };
62 
ProcMatch(unsigned int len,const char * name,struct ProcDirEntry * pn)63 int ProcMatch(unsigned int len, const char *name, struct ProcDirEntry *pn)
64 {
65     if (len != pn->nameLen)
66         return 0;
67     return !strncmp(name, pn->name, len);
68 }
69 
ProcFindNode(struct ProcDirEntry * parent,const char * name)70 static struct ProcDirEntry *ProcFindNode(struct ProcDirEntry *parent, const char *name)
71 {
72     struct ProcDirEntry *pn = NULL;
73     int length;
74 
75     if ((parent == NULL) || (name == NULL)) {
76         return pn;
77     }
78     length = strlen(name);
79 
80     for (pn = parent->subdir; pn != NULL; pn = pn->next) {
81         if ((length == pn->nameLen) && strcmp(pn->name, name) == 0) {
82             break;
83         }
84     }
85 
86     return pn;
87 }
88 
89 /*
90  * descrition: find the file's handle
91  * path: the file of fullpath
92  * return: the file of handle
93  * add by ll
94  */
ProcFindEntry(const char * path)95 struct ProcDirEntry *ProcFindEntry(const char *path)
96 {
97     struct ProcDirEntry *pn = NULL;
98     int isfoundsub;
99     const char *next = NULL;
100     unsigned int len;
101     int leveltotal = 0;
102     int levelcount = 0;
103     const char *p = NULL;
104     const char *name = path;
105 
106     while ((p = strchr(name, '/')) != NULL) {
107         leveltotal++;
108         name = p;
109         name++;
110     }
111     if (leveltotal < 1) {
112         return pn;
113     }
114 
115     spin_lock(&procfsLock);
116 
117     pn = &g_procRootDirEntry;
118 
119     while ((pn != NULL) && (levelcount < leveltotal)) {
120         levelcount++;
121         isfoundsub = 0;
122         while (pn != NULL) {
123             next = strchr(path, '/');
124             if (next == NULL) {
125                 while (pn != NULL) {
126                     if (strcmp(path, pn->name) == 0) {
127                         spin_unlock(&procfsLock);
128                         return pn;
129                     }
130                     pn = pn->next;
131                 }
132                 pn = NULL;
133                 spin_unlock(&procfsLock);
134                 return pn;
135             }
136 
137             len = next - path;
138             if (pn == &g_procRootDirEntry) {
139                 if (levelcount == leveltotal) {
140                     spin_unlock(&procfsLock);
141                     return pn;
142                 }
143                 len = g_procRootDirEntry.nameLen;
144             }
145             if (ProcMatch(len, path, pn)) {
146                 isfoundsub = 1;
147                 path += len + 1;
148                 break;
149             }
150 
151             pn = pn->next;
152         }
153 
154         if ((isfoundsub == 1) && (pn != NULL)) {
155             pn = pn->subdir;
156         } else {
157             pn = NULL;
158             spin_unlock(&procfsLock);
159             return pn;
160         }
161     }
162     spin_unlock(&procfsLock);
163     return NULL;
164 }
165 
CheckProcName(const char * name,struct ProcDirEntry ** parent,const char ** lastName)166 static int CheckProcName(const char *name, struct ProcDirEntry **parent, const char **lastName)
167 {
168     struct ProcDirEntry *pn = *parent;
169     const char *segment = name;
170     const char *restName = NULL;
171     int length;
172 
173     if (pn == NULL) {
174         pn = &g_procRootDirEntry;
175     }
176 
177     spin_lock(&procfsLock);
178 
179     restName = strchr(segment, '/');
180     for (; restName != NULL; restName = strchr(segment, '/')) {
181         length = restName - segment;
182         for (pn = pn->subdir; pn != NULL; pn = pn->next) {
183             if (ProcMatch(length, segment, pn)) {
184                 break;
185             }
186         }
187         if (pn == NULL) {
188             PRINT_ERR(" Error!No such name '%s'\n", name);
189             spin_unlock(&procfsLock);
190             return -ENOENT;
191         }
192         segment = restName;
193         segment++;
194     }
195     *lastName = segment;
196     *parent = pn;
197     spin_unlock(&procfsLock);
198 
199     return 0;
200 }
201 
ProcAllocNode(struct ProcDirEntry ** parent,const char * name,mode_t mode)202 static struct ProcDirEntry *ProcAllocNode(struct ProcDirEntry **parent, const char *name, mode_t mode)
203 {
204     struct ProcDirEntry *pn = NULL;
205     const char *lastName = NULL;
206     int ret;
207 
208     if ((name == NULL) || (strlen(name) == 0) || (procfsInit == false)) {
209         return pn;
210     }
211 
212     if (CheckProcName(name, parent, &lastName) != 0) {
213         return pn;
214     }
215 
216     if (strlen(lastName) > NAME_MAX) {
217         return pn;
218     }
219 
220     if ((S_ISDIR((*parent)->mode) == 0) || (strchr(lastName, '/'))) {
221         return pn;
222     }
223 
224     pn = (struct ProcDirEntry *)malloc(sizeof(struct ProcDirEntry));
225     if (pn == NULL) {
226         return NULL;
227     }
228 
229     if ((mode & S_IALLUGO) == 0) {
230         mode |= S_IRUSR | S_IRGRP | S_IROTH;
231     }
232 
233     (void)memset_s(pn, sizeof(struct ProcDirEntry), 0, sizeof(struct ProcDirEntry));
234     pn->nameLen = strlen(lastName);
235     pn->mode = mode;
236     ret = memcpy_s(pn->name, sizeof(pn->name), lastName, strlen(lastName) + 1);
237     if (ret != EOK) {
238         free(pn);
239         return NULL;
240     }
241 
242     pn->pf = (struct ProcFile *)malloc(sizeof(struct ProcFile));
243     if (pn->pf == NULL) {
244         free(pn);
245         return NULL;
246     }
247     (void)memset_s(pn->pf, sizeof(struct ProcFile), 0, sizeof(struct ProcFile));
248     pn->pf->pPDE = pn;
249     ret = memcpy_s(pn->pf->name, sizeof(pn->pf->name), pn->name, pn->nameLen + 1);
250     if (ret != EOK) {
251         free(pn->pf);
252         free(pn);
253         return NULL;
254     }
255 
256     atomic_set(&pn->count, 1);
257     spin_lock_init(&pn->pdeUnloadLock);
258     return pn;
259 }
260 
ProcAddNode(struct ProcDirEntry * parent,struct ProcDirEntry * pn)261 static int ProcAddNode(struct ProcDirEntry *parent, struct ProcDirEntry *pn)
262 {
263     struct ProcDirEntry *temp = NULL;
264 
265     if (parent == NULL) {
266         PRINT_ERR("%s(): parent is NULL", __FUNCTION__);
267         return -EINVAL;
268     }
269 
270     if (pn->parent != NULL) {
271         PRINT_ERR("%s(): node already has a parent", __FUNCTION__);
272         return -EINVAL;
273     }
274 
275     if (S_ISDIR(parent->mode) == 0) {
276         PRINT_ERR("%s(): parent is not a directory", __FUNCTION__);
277         return -EINVAL;
278     }
279 
280     spin_lock(&procfsLock);
281 
282     temp = ProcFindNode(parent, pn->name);
283     if (temp != NULL) {
284         PRINT_ERR("Error!ProcDirEntry '%s/%s' already registered\n", parent->name, pn->name);
285         spin_unlock(&procfsLock);
286         return -EEXIST;
287     }
288 
289     pn->parent = parent;
290     pn->next = parent->subdir;
291     parent->subdir = pn;
292 
293     spin_unlock(&procfsLock);
294 
295     return 0;
296 }
297 
ProcDetachNode(struct ProcDirEntry * pn)298 static void ProcDetachNode(struct ProcDirEntry *pn)
299 {
300     struct ProcDirEntry *parent = pn->parent;
301     struct ProcDirEntry **iter = NULL;
302 
303     if (parent == NULL) {
304         PRINT_ERR("%s(): node has no parent", __FUNCTION__);
305         return;
306     }
307 
308     iter = &parent->subdir;
309     while (*iter != NULL) {
310         if (*iter == pn) {
311             *iter = pn->next;
312             break;
313         }
314         iter = &(*iter)->next;
315     }
316     pn->parent = NULL;
317 }
318 
ProcCreateDir(struct ProcDirEntry * parent,const char * name,const struct ProcFileOperations * procFileOps,mode_t mode)319 static struct ProcDirEntry *ProcCreateDir(struct ProcDirEntry *parent, const char *name,
320                                           const struct ProcFileOperations *procFileOps, mode_t mode)
321 {
322     struct ProcDirEntry *pn = NULL;
323     int ret;
324 
325     pn = ProcAllocNode(&parent, name, S_IFDIR | mode);
326     if (pn == NULL) {
327         return pn;
328     }
329     pn->procFileOps = procFileOps;
330     pn->type = VNODE_TYPE_DIR;
331     ret = ProcAddNode(parent, pn);
332     if (ret != 0) {
333         free(pn->pf);
334         free(pn);
335         return NULL;
336     }
337 
338     return pn;
339 }
340 
ProcCreateFile(struct ProcDirEntry * parent,const char * name,const struct ProcFileOperations * procFileOps,mode_t mode)341 static struct ProcDirEntry *ProcCreateFile(struct ProcDirEntry *parent, const char *name,
342                                            const struct ProcFileOperations *procFileOps, mode_t mode)
343 {
344     struct ProcDirEntry *pn = NULL;
345     int ret;
346 
347     pn = ProcAllocNode(&parent, name, S_IFREG | mode);
348     if (pn == NULL) {
349         return pn;
350     }
351 
352     pn->procFileOps = procFileOps;
353     pn->type = VNODE_TYPE_REG;
354     ret = ProcAddNode(parent, pn);
355     if (ret != 0) {
356         free(pn->pf);
357         free(pn);
358         return NULL;
359     }
360 
361     return pn;
362 }
363 
CreateProcEntry(const char * name,mode_t mode,struct ProcDirEntry * parent)364 struct ProcDirEntry *CreateProcEntry(const char *name, mode_t mode, struct ProcDirEntry *parent)
365 {
366     struct ProcDirEntry *pde = NULL;
367 
368     if (S_ISDIR(mode)) {
369         pde = ProcCreateDir(parent, name, NULL, mode);
370     } else {
371         pde = ProcCreateFile(parent, name, NULL, mode);
372     }
373     return pde;
374 }
375 
FreeProcEntry(struct ProcDirEntry * entry)376 static void FreeProcEntry(struct ProcDirEntry *entry)
377 {
378     if (entry == NULL) {
379         return;
380     }
381     if (entry->pf != NULL) {
382         free(entry->pf);
383         entry->pf = NULL;
384     }
385     free(entry);
386 }
387 
ProcFreeEntry(struct ProcDirEntry * pn)388 void ProcFreeEntry(struct ProcDirEntry *pn)
389 {
390     if (atomic_dec_and_test(&pn->count))
391         FreeProcEntry(pn);
392 }
393 
RemoveProcEntryTravalsal(struct ProcDirEntry * pn)394 static void RemoveProcEntryTravalsal(struct ProcDirEntry *pn)
395 {
396     if (pn == NULL) {
397         return;
398     }
399     RemoveProcEntryTravalsal(pn->next);
400     RemoveProcEntryTravalsal(pn->subdir);
401 
402     ProcFreeEntry(pn);
403 }
404 
RemoveProcEntry(const char * name,struct ProcDirEntry * parent)405 void RemoveProcEntry(const char *name, struct ProcDirEntry *parent)
406 {
407     struct ProcDirEntry *pn = NULL;
408     const char *lastName = name;
409 
410     if ((name == NULL) || (strlen(name) == 0) || (procfsInit == false)) {
411         return;
412     }
413 
414     if (CheckProcName(name, &parent, &lastName) != 0) {
415         return;
416     }
417 
418     spin_lock(&procfsLock);
419 
420     pn = ProcFindNode(parent, lastName);
421     if (pn == NULL) {
422         PRINT_ERR("Error:name '%s' not found!\n", name);
423         spin_unlock(&procfsLock);
424         return;
425     }
426     ProcDetachNode(pn);
427 
428     spin_unlock(&procfsLock);
429 
430     RemoveProcEntryTravalsal(pn->subdir);
431     ProcFreeEntry(pn);
432 }
433 
ProcMkdirMode(const char * name,mode_t mode,struct ProcDirEntry * parent)434 struct ProcDirEntry *ProcMkdirMode(const char *name, mode_t mode, struct ProcDirEntry *parent)
435 {
436     return ProcCreateDir(parent, name, NULL, mode);
437 }
438 
ProcMkdir(const char * name,struct ProcDirEntry * parent)439 struct ProcDirEntry *ProcMkdir(const char *name, struct ProcDirEntry *parent)
440 {
441     return ProcCreateDir(parent, name, NULL, 0);
442 }
443 
ProcCreateData(const char * name,mode_t mode,struct ProcDirEntry * parent,const struct ProcFileOperations * procFileOps,void * data)444 struct ProcDirEntry *ProcCreateData(const char *name, mode_t mode, struct ProcDirEntry *parent,
445                                     const struct ProcFileOperations *procFileOps, void *data)
446 {
447     struct ProcDirEntry *pde = CreateProcEntry(name, mode, parent);
448     if (pde != NULL) {
449         if (procFileOps != NULL) {
450             pde->procFileOps = procFileOps;
451         }
452         pde->data = data;
453     }
454     return pde;
455 }
456 
ProcCreate(const char * name,mode_t mode,struct ProcDirEntry * parent,const struct ProcFileOperations * procFileOps)457 struct ProcDirEntry *ProcCreate(const char *name, mode_t mode, struct ProcDirEntry *parent,
458                                 const struct ProcFileOperations *procFileOps)
459 {
460     return ProcCreateData(name, mode, parent, procFileOps, NULL);
461 }
462 
ProcStat(const char * file,struct ProcStat * buf)463 int ProcStat(const char *file, struct ProcStat *buf)
464 {
465     struct ProcDirEntry *pn = NULL;
466     int len = sizeof(buf->name);
467     int ret;
468 
469     pn = ProcFindEntry(file);
470     if (pn == NULL) {
471         return ENOENT;
472     }
473     ret = strncpy_s(buf->name, len, pn->name, len - 1);
474     if (ret != EOK) {
475         return ENAMETOOLONG;
476     }
477     buf->name[len - 1] = '\0';
478     buf->stMode = pn->mode;
479     buf->pPDE = pn;
480 
481     return 0;
482 }
483 
GetNextDir(struct ProcDirEntry * pn,void * buf,size_t len)484 static int GetNextDir(struct ProcDirEntry *pn, void *buf, size_t len)
485 {
486     char *buff = (char *)buf;
487 
488     if (pn->pdirCurrent == NULL) {
489         *buff = '\0';
490         return -ENOENT;
491     }
492     int namelen = pn->pdirCurrent->nameLen;
493     int ret = memcpy_s(buff, len, pn->pdirCurrent->name, namelen);
494     if (ret != EOK) {
495         return -ENAMETOOLONG;
496     }
497 
498     pn->pdirCurrent = pn->pdirCurrent->next;
499     pn->pf->fPos++;
500     return ENOERR;
501 }
502 
ProcOpen(struct ProcFile * procFile)503 int ProcOpen(struct ProcFile *procFile)
504 {
505     if (procFile == NULL) {
506         return PROC_ERROR;
507     }
508     if (procFile->sbuf != NULL) {
509         return OK;
510     }
511 
512     struct SeqBuf *buf = LosBufCreat();
513     if (buf == NULL) {
514         return PROC_ERROR;
515     }
516     procFile->sbuf = buf;
517     return OK;
518 }
519 
ProcRead(struct ProcDirEntry * pde,char * buf,size_t len)520 static int ProcRead(struct ProcDirEntry *pde, char *buf, size_t len)
521 {
522     if (pde == NULL || pde == NULL || pde->pf == NULL) {
523         return PROC_ERROR;
524     }
525     struct ProcFile *procFile = pde->pf;
526     struct SeqBuf *sb = procFile->sbuf;
527 
528     if (sb->buf == NULL) {
529         // only read once to build the storage buffer
530         if (pde->procFileOps->read(sb, NULL) != 0) {
531             return PROC_ERROR;
532         }
533     }
534 
535     size_t realLen;
536     loff_t pos = procFile->fPos;
537 
538     if ((pos >= sb->count) || (len == 0)) {
539         /* there's no data or at the file tail. */
540         realLen = 0;
541     } else {
542         realLen = MIN((sb->count - pos), MIN(len, INT_MAX));
543         if (LOS_CopyFromKernel(buf, len, sb->buf + pos, realLen) != 0) {
544             return PROC_ERROR;
545         }
546 
547         procFile->fPos = pos + realLen;
548     }
549 
550     return (ssize_t)realLen;
551 }
552 
OpenProcFile(const char * fileName,int flags,...)553 struct ProcDirEntry *OpenProcFile(const char *fileName, int flags, ...)
554 {
555     unsigned int intSave;
556     struct ProcDirEntry *pn = ProcFindEntry(fileName);
557     if (pn == NULL) {
558         return NULL;
559     }
560 
561     SCHEDULER_LOCK(intSave);
562     if (S_ISREG(pn->mode) && (pn->count != 1)) {
563         SCHEDULER_UNLOCK(intSave);
564         return NULL;
565     }
566 
567     pn->flags = (unsigned int)(pn->flags) | (unsigned int)flags;
568     atomic_set(&pn->count, PROC_INUSE);
569     SCHEDULER_UNLOCK(intSave);
570     if (ProcOpen(pn->pf) != OK) {
571         return NULL;
572     }
573     if (S_ISREG(pn->mode) && (pn->procFileOps != NULL) && (pn->procFileOps->open != NULL)) {
574         (void)pn->procFileOps->open((struct Vnode *)pn, pn->pf);
575     }
576     if (S_ISDIR(pn->mode)) {
577         pn->pdirCurrent = pn->subdir;
578         pn->pf->fPos = 0;
579     }
580 
581     return pn;
582 }
583 
ReadProcFile(struct ProcDirEntry * pde,void * buf,size_t len)584 int ReadProcFile(struct ProcDirEntry *pde, void *buf, size_t len)
585 {
586     int result = -EPERM;
587 
588     if (pde == NULL) {
589         return result;
590     }
591     if (S_ISREG(pde->mode)) {
592         if ((pde->procFileOps != NULL) && (pde->procFileOps->read != NULL)) {
593             result = ProcRead(pde, (char *)buf, len);
594         }
595     } else if (S_ISDIR(pde->mode)) {
596         result = GetNextDir(pde, buf, len);
597     }
598     return result;
599 }
600 
WriteProcFile(struct ProcDirEntry * pde,const void * buf,size_t len)601 int WriteProcFile(struct ProcDirEntry *pde, const void *buf, size_t len)
602 {
603     int result = -EPERM;
604 
605     if (pde == NULL) {
606         return result;
607     }
608 
609     if (S_ISDIR(pde->mode)) {
610         return -EISDIR;
611     }
612 
613     spin_lock(&procfsLock);
614     if ((pde->procFileOps != NULL) && (pde->procFileOps->write != NULL)) {
615         result = pde->procFileOps->write(pde->pf, (const char *)buf, len, &(pde->pf->fPos));
616     }
617     spin_unlock(&procfsLock);
618 
619     return result;
620 }
621 
LseekProcFile(struct ProcDirEntry * pde,loff_t offset,int whence)622 loff_t LseekProcFile(struct ProcDirEntry *pde, loff_t offset, int whence)
623 {
624     if (pde == NULL || pde->pf == NULL) {
625         return PROC_ERROR;
626     }
627 
628     struct ProcFile *procFile = pde->pf;
629 
630     loff_t result = -EINVAL;
631 
632     switch (whence) {
633         case SEEK_CUR:
634             result = procFile->fPos + offset;
635             break;
636 
637         case SEEK_SET:
638             result = offset;
639             break;
640 
641         default:
642             break;
643     }
644 
645     if (result >= 0) {
646         procFile->fPos = result;
647     }
648 
649     return result;
650 }
651 
LseekDirProcFile(struct ProcDirEntry * pde,off_t * pos,int whence)652 int LseekDirProcFile(struct ProcDirEntry *pde, off_t *pos, int whence)
653 {
654     /* Only allow SEEK_SET to zero */
655     if ((whence != SEEK_SET) || (*pos != 0)) {
656         return EINVAL;
657     }
658     pde->pdirCurrent = pde->subdir;
659     pde->pf->fPos = 0;
660     return ENOERR;
661 }
662 
CloseProcFile(struct ProcDirEntry * pde)663 int CloseProcFile(struct ProcDirEntry *pde)
664 {
665     int result = 0;
666 
667     if (pde == NULL) {
668         return -EPERM;
669     }
670     pde->pf->fPos = 0;
671     atomic_set(&pde->count, 1);
672     if (S_ISDIR(pde->mode)) {
673         pde->pdirCurrent = pde->subdir;
674     }
675 
676     if ((pde->procFileOps != NULL) && (pde->procFileOps->release != NULL)) {
677         result = pde->procFileOps->release((struct Vnode *)pde, pde->pf);
678     }
679     LosBufRelease(pde->pf->sbuf);
680     pde->pf->sbuf = NULL;
681 
682     if (pde->parent == NULL) {
683         FreeProcEntry(pde);
684     }
685     return result;
686 }
687 
GetProcRootEntry(void)688 struct ProcDirEntry *GetProcRootEntry(void)
689 {
690     return &g_procRootDirEntry;
691 }
692