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