1/* 2 * Copyright (c) 2021-2023 Huawei Device Co., Ltd. All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without modification, 5 * are permitted provided that the following conditions are met: 6 * 7 * 1. Redistributions of source code must retain the above copyright notice, this list of 8 * conditions and the following disclaimer. 9 * 10 * 2. Redistributions in binary form must reproduce the above copyright notice, this list 11 * of conditions and the following disclaimer in the documentation and/or other materials 12 * provided with the distribution. 13 * 14 * 3. Neither the name of the copyright holder nor the names of its contributors may be used 15 * to endorse or promote products derived from this software without specific prior written 16 * permission. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 20 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 21 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR 22 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 23 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 24 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 25 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 26 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 27 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 28 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 */ 30 31#include "proc_file.h" 32 33#include <sys/statfs.h> 34#include <stdlib.h> 35#include <fcntl.h> 36#include <unistd.h> 37 38#include "fs/dirent_fs.h" 39#include "fs/mount.h" 40#include "fs/fs.h" 41#include "los_tables.h" 42#include "internal.h" 43 44#ifdef LOSCFG_FS_PROC 45static struct VnodeOps g_procfsVops; 46static struct file_operations_vfs g_procfsFops; 47 48struct ProcDirEntry *VnodeToEntry(struct Vnode *node) 49{ 50 return (struct ProcDirEntry *)(node->data); 51} 52 53static struct Vnode *EntryToVnode(struct ProcDirEntry *entry) 54{ 55 struct Vnode *node = NULL; 56 57 (void)VnodeAlloc(&g_procfsVops, &node); 58 node->fop = &g_procfsFops; 59 node->data = entry; 60 node->type = entry->type; 61 node->uid = entry->uid; 62 node->gid = entry->gid; 63 node->mode = entry->mode; 64 return node; 65} 66 67static int EntryMatch(const char *name, int len, const struct ProcDirEntry *pn) 68{ 69 if (len != pn->nameLen) { 70 return 0; 71 } 72 return !strncmp(name, pn->name, len); 73} 74 75int VfsProcfsTruncate(struct Vnode *pVnode, off_t len) 76{ 77 return 0; 78} 79 80int VfsProcfsCreate(struct Vnode* parent, const char *name, int mode, struct Vnode **vnode) 81{ 82 int ret; 83 struct Vnode *vp = NULL; 84 struct ProcDirEntry *curEntry = NULL; 85 86 struct ProcDirEntry *parentEntry = VnodeToEntry(parent); 87 if (parentEntry == NULL) { 88 return -ENODATA; 89 } 90 91 ret = VnodeAlloc(&g_procfsVops, &vp); 92 if (ret != 0) { 93 return -ENOMEM; 94 } 95 96 curEntry = ProcCreate(name, mode, parentEntry, NULL); 97 if (curEntry == NULL) { 98 VnodeFree(vp); 99 return -ENODATA; 100 } 101 102 vp->data = curEntry; 103 vp->type = curEntry->type; 104 if (vp->type == VNODE_TYPE_DIR) { 105 vp->mode = S_IFDIR | PROCFS_DEFAULT_MODE; 106 } else { 107 vp->mode = S_IFREG | PROCFS_DEFAULT_MODE; 108 } 109 110 vp->vop = parent->vop; 111 vp->fop = parent->fop; 112 vp->parent = parent; 113 vp->originMount = parent->originMount; 114 115 *vnode = vp; 116 117 return LOS_OK; 118} 119 120int VfsProcfsRead(struct file *filep, char *buffer, size_t buflen) 121{ 122 ssize_t size; 123 struct ProcDirEntry *entry = NULL; 124 if ((filep == NULL) || (filep->f_vnode == NULL) || (buffer == NULL)) { 125 return -EINVAL; 126 } 127 128 VnodeHold(); 129 entry = VnodeToEntry(filep->f_vnode); 130 if (entry == NULL) { 131 VnodeDrop(); 132 return -EPERM; 133 } 134 135 size = (ssize_t)ReadProcFile(entry, (void *)buffer, buflen); 136 filep->f_pos = entry->pf->fPos; 137 VnodeDrop(); 138 return size; 139} 140 141int VfsProcfsWrite(struct file *filep, const char *buffer, size_t buflen) 142{ 143 ssize_t size; 144 struct ProcDirEntry *entry = NULL; 145 if ((filep == NULL) || (filep->f_vnode == NULL) || (buffer == NULL)) { 146 return -EINVAL; 147 } 148 149 VnodeHold(); 150 entry = VnodeToEntry(filep->f_vnode); 151 if (entry == NULL) { 152 VnodeDrop(); 153 return -EPERM; 154 } 155 156 size = (ssize_t)WriteProcFile(entry, (void *)buffer, buflen); 157 filep->f_pos = entry->pf->fPos; 158 VnodeDrop(); 159 return size; 160} 161 162int VfsProcfsLookup(struct Vnode *parent, const char *name, int len, struct Vnode **vpp) 163{ 164 if (parent == NULL || name == NULL || len <= 0 || vpp == NULL) { 165 return -EINVAL; 166 } 167 struct ProcDirEntry *entry = VnodeToEntry(parent); 168 if (entry == NULL) { 169 return -ENODATA; 170 } 171 172 entry = entry->subdir; 173 while (1) { 174 if (entry == NULL) { 175 return -ENOENT; 176 } 177 if (EntryMatch(name, len, entry)) { 178 break; 179 } 180 entry = entry->next; 181 } 182 183 *vpp = EntryToVnode(entry); 184 if ((*vpp) == NULL) { 185 return -ENOMEM; 186 } 187 (*vpp)->originMount = parent->originMount; 188 (*vpp)->parent = parent; 189 return LOS_OK; 190} 191 192int VfsProcfsMount(struct Mount *mnt, struct Vnode *device, const void *data) 193{ 194 struct Vnode *vp = NULL; 195 int ret; 196 197 spin_lock_init(&procfsLock); 198 procfsInit = true; 199 200 ret = VnodeAlloc(&g_procfsVops, &vp); 201 if (ret != 0) { 202 return -ENOMEM; 203 } 204 205 struct ProcDirEntry *root = GetProcRootEntry(); 206 vp->data = root; 207 vp->originMount = mnt; 208 vp->fop = &g_procfsFops; 209 mnt->data = NULL; 210 mnt->vnodeCovered = vp; 211 vp->type = root->type; 212 if (vp->type == VNODE_TYPE_DIR) { 213 vp->mode = S_IFDIR | PROCFS_DEFAULT_MODE; 214 } else { 215 vp->mode = S_IFREG | PROCFS_DEFAULT_MODE; 216 } 217 218 return LOS_OK; 219} 220 221int VfsProcfsUnmount(void *handle, struct Vnode **blkdriver) 222{ 223 (void)handle; 224 (void)blkdriver; 225 return -EPERM; 226} 227 228int VfsProcfsStat(struct Vnode *node, struct stat *buf) 229{ 230 VnodeHold(); 231 struct ProcDirEntry *entry = VnodeToEntry(node); 232 if (entry == NULL) { 233 VnodeDrop(); 234 return -EPERM; 235 } 236 (void)memset_s(buf, sizeof(struct stat), 0, sizeof(struct stat)); 237 buf->st_mode = entry->mode; 238 VnodeDrop(); 239 return LOS_OK; 240} 241 242#ifdef LOSCFG_KERNEL_PLIMITS 243int VfsProcfsMkdir(struct Vnode *parent, const char *dirName, mode_t mode, struct Vnode **vnode) 244{ 245 struct ProcDirEntry *parentEntry = VnodeToEntry(parent); 246 struct ProcDirEntry *pde = NULL; 247 if ((parentEntry->procDirOps == NULL) || (parentEntry->procDirOps->mkdir == NULL)) { 248 return -ENOSYS; 249 } 250 251 int ret = parentEntry->procDirOps->mkdir(parentEntry, dirName, mode, &pde); 252 if ((ret < 0) || (pde == NULL)) { 253 return ret; 254 } 255 256 *vnode = EntryToVnode(pde); 257 (*vnode)->vop = parent->vop; 258 (*vnode)->parent = parent; 259 (*vnode)->originMount = parent->originMount; 260 if ((*vnode)->type == VNODE_TYPE_DIR) { 261 (*vnode)->mode = S_IFDIR | PROCFS_DEFAULT_MODE; 262 } else { 263 (*vnode)->mode = S_IFREG | PROCFS_DEFAULT_MODE; 264 } 265 return ret; 266} 267 268int VfsProcfsRmdir(struct Vnode *parent, struct Vnode *vnode, const char *dirName) 269{ 270 if (parent == NULL) { 271 return -EINVAL; 272 } 273 274 struct ProcDirEntry *parentEntry = VnodeToEntry(parent); 275 if ((parentEntry->procDirOps == NULL) || (parentEntry->procDirOps->rmdir == NULL)) { 276 return -ENOSYS; 277 } 278 279 struct ProcDirEntry *dirEntry = VnodeToEntry(vnode); 280 int ret = parentEntry->procDirOps->rmdir(parentEntry, dirEntry, dirName); 281 if (ret < 0) { 282 return ret; 283 } 284 vnode->data = NULL; 285 return 0; 286} 287#endif 288 289int VfsProcfsReaddir(struct Vnode *node, struct fs_dirent_s *dir) 290{ 291 int result; 292 char *buffer = NULL; 293 unsigned int minSize, dstNameSize; 294 struct ProcDirEntry *pde = NULL; 295 int i = 0; 296 297 if (dir == NULL) { 298 return -EINVAL; 299 } 300 if (node->type != VNODE_TYPE_DIR) { 301 return -ENOTDIR; 302 } 303 VnodeHold(); 304 pde = VnodeToEntry(node); 305 if (pde == NULL) { 306 VnodeDrop(); 307 return -EPERM; 308 } 309 310 while (i < dir->read_cnt) { 311 buffer = (char *)zalloc(sizeof(char) * NAME_MAX); 312 if (buffer == NULL) { 313 VnodeDrop(); 314 PRINT_ERR("malloc failed\n"); 315 return -ENOMEM; 316 } 317 318 result = ReadProcFile(pde, (void *)buffer, NAME_MAX); 319 if (result != ENOERR) { 320 free(buffer); 321 break; 322 } 323 dstNameSize = sizeof(dir->fd_dir[i].d_name); 324 minSize = (dstNameSize < NAME_MAX) ? dstNameSize : NAME_MAX; 325 result = strncpy_s(dir->fd_dir[i].d_name, dstNameSize, buffer, minSize); 326 if (result != EOK) { 327 VnodeDrop(); 328 free(buffer); 329 return -ENAMETOOLONG; 330 } 331 dir->fd_dir[i].d_name[dstNameSize - 1] = '\0'; 332 dir->fd_position++; 333 dir->fd_dir[i].d_off = dir->fd_position; 334 dir->fd_dir[i].d_reclen = (uint16_t)sizeof(struct dirent); 335 336 i++; 337 free(buffer); 338 } 339 VnodeDrop(); 340 return i; 341} 342 343int VfsProcfsOpendir(struct Vnode *node, struct fs_dirent_s *dir) 344{ 345 VnodeHold(); 346 struct ProcDirEntry *pde = VnodeToEntry(node); 347 if (pde == NULL) { 348 VnodeDrop(); 349 return -EINVAL; 350 } 351 352 pde->pdirCurrent = pde->subdir; 353 if (pde->pf == NULL) { 354 VnodeDrop(); 355 return -EINVAL; 356 } 357 pde->pf->fPos = 0; 358 VnodeDrop(); 359 return LOS_OK; 360} 361 362int VfsProcfsOpen(struct file *filep) 363{ 364 if (filep == NULL) { 365 return -EINVAL; 366 } 367 VnodeHold(); 368 struct Vnode *node = filep->f_vnode; 369 struct ProcDirEntry *pde = VnodeToEntry(node); 370 if (pde == NULL) { 371 VnodeDrop(); 372 return -EPERM; 373 } 374 375 if (ProcOpen(pde->pf) != OK) { 376 return -ENOMEM; 377 } 378 if (S_ISREG(pde->mode) && (pde->procFileOps != NULL) && (pde->procFileOps->open != NULL)) { 379 (void)pde->procFileOps->open((struct Vnode *)pde, pde->pf); 380 } 381 if (S_ISDIR(pde->mode)) { 382 pde->pdirCurrent = pde->subdir; 383 pde->pf->fPos = 0; 384 } 385 filep->f_priv = (void *)pde; 386 VnodeDrop(); 387 return LOS_OK; 388} 389 390int VfsProcfsClose(struct file *filep) 391{ 392 int result = 0; 393 if (filep == NULL) { 394 return -EINVAL; 395 } 396 397 VnodeHold(); 398 struct Vnode *node = filep->f_vnode; 399 struct ProcDirEntry *pde = VnodeToEntry(node); 400 if ((pde == NULL) || (pde->pf == NULL)) { 401 VnodeDrop(); 402 return -EPERM; 403 } 404 405 pde->pf->fPos = 0; 406 if ((pde->procFileOps != NULL) && (pde->procFileOps->release != NULL)) { 407 result = pde->procFileOps->release((struct Vnode *)pde, pde->pf); 408 } 409 LosBufRelease(pde->pf->sbuf); 410 pde->pf->sbuf = NULL; 411 VnodeDrop(); 412 return result; 413} 414 415int VfsProcfsStatfs(struct Mount *mnt, struct statfs *buf) 416{ 417 (void)memset_s(buf, sizeof(struct statfs), 0, sizeof(struct statfs)); 418 buf->f_type = PROCFS_MAGIC; 419 420 return LOS_OK; 421} 422 423int VfsProcfsClosedir(struct Vnode *vp, struct fs_dirent_s *dir) 424{ 425 return LOS_OK; 426} 427 428ssize_t VfsProcfsReadlink(struct Vnode *vnode, char *buffer, size_t bufLen) 429{ 430 int result = -EINVAL; 431 if (vnode == NULL) { 432 return result; 433 } 434 435 struct ProcDirEntry *pde = VnodeToEntry(vnode); 436 if (pde == NULL) { 437 return -EPERM; 438 } 439 440 if ((pde->procFileOps != NULL) && (pde->procFileOps->readLink != NULL)) { 441 result = pde->procFileOps->readLink(pde, buffer, bufLen); 442 } 443 return result; 444} 445 446const struct MountOps procfs_operations = { 447 .Mount = VfsProcfsMount, 448 .Unmount = NULL, 449 .Statfs = VfsProcfsStatfs, 450}; 451 452static struct VnodeOps g_procfsVops = { 453 .Lookup = VfsProcfsLookup, 454 .Getattr = VfsProcfsStat, 455 .Readdir = VfsProcfsReaddir, 456 .Opendir = VfsProcfsOpendir, 457 .Closedir = VfsProcfsClosedir, 458 .Truncate = VfsProcfsTruncate, 459 .Readlink = VfsProcfsReadlink, 460#ifdef LOSCFG_KERNEL_PLIMITS 461 .Mkdir = VfsProcfsMkdir, 462 .Rmdir = VfsProcfsRmdir, 463#endif 464}; 465 466static struct file_operations_vfs g_procfsFops = { 467 .read = VfsProcfsRead, 468 .write = VfsProcfsWrite, 469 .open = VfsProcfsOpen, 470 .close = VfsProcfsClose 471}; 472 473FSMAP_ENTRY(procfs_fsmap, "procfs", procfs_operations, FALSE, FALSE); 474#endif 475