static int proc_open(FAR struct file *filep, FAR const char *relpath, int oflags, mode_t mode) { FAR struct proc_file_s *procfile; FAR const struct proc_node_s *node; FAR struct tcb_s *tcb; FAR char *ptr; irqstate_t flags; unsigned long tmp; pid_t pid; fvdbg("Open '%s'\n", relpath); /* PROCFS is read-only. Any attempt to open with any kind of write * access is not permitted. * * REVISIT: Write-able proc files could be quite useful. */ if ((oflags & O_WRONLY) != 0 || (oflags & O_RDONLY) == 0) { fdbg("ERROR: Only O_RDONLY supported\n"); return -EACCES; } /* The first segment of the relative path should be a task/thread ID */ ptr = NULL; tmp = strtoul(relpath, &ptr, 10); if (!ptr || *ptr != '/') { fdbg("ERROR: Invalid path \"%s\"\n", relpath); return -ENOENT; } /* Skip over the slash */ ptr++; /* A valid PID would be in the range of 0-32767 (0 is reserved for the * IDLE thread). */ if (tmp >= 32768) { fdbg("ERROR: Invalid PID %ld\n", tmp); return -ENOENT; } /* Now verify that a task with this task/thread ID exists */ pid = (pid_t)tmp; flags = irqsave(); tcb = sched_gettcb(pid); irqrestore(flags); if (!tcb) { fdbg("ERROR: PID %d is no longer valid\n", (int)pid); return -ENOENT; } /* The remaining segments of the relpath should be a well known node in * the task/thread tree. */ node = proc_findnode(ptr); if (!node) { fdbg("ERROR: Invalid path \"%s\"\n", relpath); return -ENOENT; } /* The node must be a file, not a directory */ if (node->dtype != DTYPE_FILE) { fdbg("ERROR: Path \"%s\" is a directory\n", relpath); return -EISDIR; } /* Allocate a container to hold the task and node selection */ procfile = (FAR struct proc_file_s *)kzalloc(sizeof(struct proc_file_s)); if (!procfile) { fdbg("ERROR: Failed to allocate file container\n"); return -ENOMEM; } /* Initialize the file container */ procfile->pid = pid; procfile->node = node; /* Save the index as the open-specific state in filep->f_priv */ filep->f_priv = (FAR void *)procfile; return OK; }
static int proc_opendir(FAR const char *relpath, FAR struct fs_dirent_s *dir) { FAR struct proc_dir_s *procdir; FAR const struct proc_node_s *node; FAR struct tcb_s *tcb; irqstate_t flags; unsigned long tmp; FAR char *ptr; pid_t pid; fvdbg("relpath: \"%s\"\n", relpath ? relpath : "NULL"); DEBUGASSERT(relpath && dir && !dir->u.procfs); /* The relative must be either: * * (1) "<pid>" - The sub-directory of task/thread attributes, or * (2) The name of a directory node under <pid> */ /* Otherwise, the relative path should be a valid task/thread ID */ ptr = NULL; tmp = strtoul(relpath, &ptr, 10); if (!ptr || (*ptr != '\0' && *ptr != '/')) { /* strtoul failed or there is something in the path after the pid */ fdbg("ERROR: Invalid path \"%s\"\n", relpath); return -ENOENT; } /* A valid PID would be in the range of 0-32767 (0 is reserved for the * IDLE thread). */ if (tmp >= 32768) { fdbg("ERROR: Invalid PID %ld\n", tmp); return -ENOENT; } /* Now verify that a task with this task/thread ID exists */ pid = (pid_t)tmp; flags = irqsave(); tcb = sched_gettcb(pid); irqrestore(flags); if (!tcb) { fdbg("ERROR: PID %d is not valid\n", (int)pid); return -ENOENT; } /* Allocate the directory structure. Note that the index and procentry * pointer are implicitly nullified by kzalloc(). Only the remaining, * non-zero entries will need be initialized. */ procdir = (FAR struct proc_dir_s *)kzalloc(sizeof(struct proc_dir_s)); if (!procdir) { fdbg("ERROR: Failed to allocate the directory structure\n"); return -ENOMEM; } /* Was the <pid> the final element of the path? */ if (*ptr != '\0' && strcmp(ptr, "/") != 0) { /* There is something in the path after the pid. Skip over the path * segment delimiter and see if we can identify the node of interest. */ ptr++; node = proc_findnode(ptr); if (!node) { fdbg("ERROR: Invalid path \"%s\"\n", relpath); kfree(procdir); return -ENOENT; } /* The node must be a directory, not a file */ if (node->dtype != DTYPE_DIRECTORY) { fdbg("ERROR: Path \"%s\" is not a directory\n", relpath); kfree(procdir); return -ENOTDIR; } /* This is a second level directory */ procdir->base.level = 2; procdir->base.nentries = PROC_NGROUPNODES; procdir->node = node; } else { /* Use the special level0 node */ procdir->base.level = 1; procdir->base.nentries = PROC_NLEVEL0NODES; procdir->node = &g_level0node; } procdir->pid = pid; dir->u.procfs = (FAR void *)procdir; return OK; }
static int proc_stat(const char *relpath, struct stat *buf) { FAR const struct proc_node_s *node; FAR struct tcb_s *tcb; unsigned long tmp; FAR char *ptr; irqstate_t flags; pid_t pid; /* Two path forms are accepted: * * "<pid>" - If <pid> refers to a currently active task/thread, then it * is a directory * "<pid>/<node>" - If <node> is a recognized node then, then it * is a file or directory. */ ptr = NULL; tmp = strtoul(relpath, &ptr, 10); if (!ptr) { fdbg("ERROR: Invalid path \"%s\"\n", relpath); return -ENOENT; } /* A valid PID would be in the range of 0-32767 (0 is reserved for the * IDLE thread). */ if (tmp >= 32768) { fdbg("ERROR: Invalid PID %ld\n", tmp); return -ENOENT; } /* Now verify that a task with this task/thread ID exists */ pid = (pid_t)tmp; flags = irqsave(); tcb = sched_gettcb(pid); irqrestore(flags); if (!tcb) { fdbg("ERROR: PID %d is no longer valid\n", (int)pid); return -ENOENT; } /* Was the <pid> the final element of the path? */ if (*ptr == '\0' || strcmp(ptr, "/") == 0) { /* Yes ... It's a read-only directory */ buf->st_mode = S_IFDIR|S_IROTH|S_IRGRP|S_IRUSR; } /* Verify that the process ID is followed by valid path segment delimiter */ else if (*ptr != '/') { /* We are required to return -ENOENT all all invalid paths */ fdbg("ERROR: Bad delimiter '%c' in relpath '%s'\n", *ptr, relpath); return -ENOENT; } else { /* Otherwise, the second segment of the relpath should be a well * known node of the task/thread directory structure. */ /* Skip over the path segment delimiter */ ptr++; /* Lookup the well-known node associated with the relative path. */ node = proc_findnode(ptr); if (!node) { fdbg("ERROR: Invalid path \"%s\"\n", relpath); return -ENOENT; } /* If the node exists, it is the name for a read-only file or * directory. */ if (node->dtype == DTYPE_FILE) { buf->st_mode = S_IFREG|S_IROTH|S_IRGRP|S_IRUSR; } else { buf->st_mode = S_IFDIR|S_IROTH|S_IRGRP|S_IRUSR; } } /* File/directory size, access block size */ buf->st_size = 0; buf->st_blksize = 0; buf->st_blocks = 0; return OK; }
static int proc_open(FAR struct file *filep, FAR const char *relpath, int oflags, mode_t mode) { FAR struct proc_file_s *procfile; FAR const struct proc_node_s *node; FAR struct tcb_s *tcb; FAR char *ptr; irqstate_t flags; unsigned long tmp; pid_t pid; finfo("Open '%s'\n", relpath); /* PROCFS is read-only. Any attempt to open with any kind of write * access is not permitted. * * REVISIT: Write-able proc files could be quite useful. */ if ((oflags & O_WRONLY) != 0 || (oflags & O_RDONLY) == 0) { ferr("ERROR: Only O_RDONLY supported\n"); return -EACCES; } /* The first segment of the relative path should be a task/thread ID or * the string "self". */ ptr = NULL; if (strncmp(relpath, "self", 4) == 0) { tmp = (unsigned long)getpid(); /* Get the PID of the calling task */ ptr = (FAR char *)relpath + 4; /* Discard const */ } else { tmp = strtoul(relpath, &ptr, 10); /* Extract the PID from path */ } if (ptr == NULL || *ptr != '/') { ferr("ERROR: Invalid path \"%s\"\n", relpath); return -ENOENT; } /* Skip over the slash */ ptr++; /* A valid PID would be in the range of 0-32767 (0 is reserved for the * IDLE thread). */ if (tmp >= 32768) { ferr("ERROR: Invalid PID %ld\n", tmp); return -ENOENT; } /* Now verify that a task with this task/thread ID exists */ pid = (pid_t)tmp; flags = enter_critical_section(); tcb = sched_gettcb(pid); leave_critical_section(flags); if (tcb == NULL) { ferr("ERROR: PID %d is no longer valid\n", (int)pid); return -ENOENT; } /* The remaining segments of the relpath should be a well known node in * the task/thread tree. */ node = proc_findnode(ptr); if (node == NULL) { ferr("ERROR: Invalid path \"%s\"\n", relpath); return -ENOENT; } /* The node must be a file, not a directory */ if (!DIRENT_ISFILE(node->dtype)) { ferr("ERROR: Path \"%s\" is not a regular file\n", relpath); return -EISDIR; } /* Allocate a container to hold the task and node selection */ procfile = (FAR struct proc_file_s *)kmm_zalloc(sizeof(struct proc_file_s)); if (procfile == NULL) { ferr("ERROR: Failed to allocate file container\n"); return -ENOMEM; } /* Initialize the file container */ procfile->pid = pid; procfile->node = node; /* Save the index as the open-specific state in filep->f_priv */ filep->f_priv = (FAR void *)procfile; return OK; }