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