/* * Copyright (c) 2013-2019 Huawei Technologies Co., Ltd. All rights reserved. * Copyright (c) 2020-2023 Huawei Device Co., Ltd. All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, this list of * conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, this list * of conditions and the following disclaimer in the documentation and/or other materials * provided with the distribution. * * 3. Neither the name of the copyright holder nor the names of its contributors may be used * to endorse or promote products derived from this software without specific prior written * permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include #include #include "proc_fs.h" #include "internal.h" #include "los_process_pri.h" #ifdef LOSCFG_PROC_PROCESS_DIR #include "los_vm_dump.h" typedef enum { PROC_PID, PROC_PID_MEM, #ifdef LOSCFG_KERNEL_CPUP PROC_PID_CPUP, #endif } ProcessDataType; struct ProcProcess { char *name; mode_t mode; int type; const struct ProcFileOperations *fileOps; }; struct ProcessData { uintptr_t process; unsigned int type; }; #define PROC_PID_PRIVILEGE 7 #define PROC_PID_DIR_LEN 100 #ifdef LOSCFG_KERNEL_CONTAINER static ssize_t ProcessContainerLink(unsigned int containerID, ContainerType type, char *buffer, size_t bufLen) { ssize_t count = -1; if (type == PID_CONTAINER) { count = snprintf_s(buffer, bufLen, bufLen - 1, "'pid:[%u]'", containerID); } else if (type == UTS_CONTAINER) { count = snprintf_s(buffer, bufLen, bufLen - 1, "'uts:[%u]'", containerID); } else if (type == MNT_CONTAINER) { count = snprintf_s(buffer, bufLen, bufLen - 1, "'mnt:[%u]'", containerID); } if (count < 0) { return -EBADF; } return count; } static ssize_t ProcessContainerReadLink(struct ProcDirEntry *entry, char *buffer, size_t bufLen) { ssize_t count; unsigned int intSave; if (entry == NULL) { return -EINVAL; } struct ProcessData *data = (struct ProcessData *)entry->data; if (data == NULL) { return -EINVAL; } LosProcessCB *processCB = (LosProcessCB *)data->process; SCHEDULER_LOCK(intSave); UINT32 containerID = OsGetContainerID(processCB->container, (ContainerType)data->type); SCHEDULER_UNLOCK(intSave); if (containerID != OS_INVALID_VALUE) { return ProcessContainerLink(containerID, (ContainerType)data->type, buffer, bufLen); } count = strlen("(unknown)"); if (memcpy_s(buffer, bufLen, "(unknown)", count + 1) != EOK) { return -EBADF; } return count; } static const struct ProcFileOperations PID_CONTAINER_FOPS = { .readLink = ProcessContainerReadLink, }; #endif /* LOSCFG_KERNEL_CONTAINER */ static int ProcessMemInfoRead(struct SeqBuf *seqBuf, LosProcessCB *pcb) { unsigned int intSave; unsigned int size = sizeof(LosVmSpace) + sizeof(LosVmMapRegion); LosVmSpace *vmSpace = (LosVmSpace *)LOS_MemAlloc(m_aucSysMem1, size); if (vmSpace == NULL) { return -ENOMEM; } (void)memset_s(vmSpace, size, 0, size); LosVmMapRegion *heap = (LosVmMapRegion *)((char *)vmSpace + sizeof(LosVmSpace)); SCHEDULER_LOCK(intSave); if (OsProcessIsInactive(pcb)) { SCHEDULER_UNLOCK(intSave); (void)LOS_MemFree(m_aucSysMem1, vmSpace); return -EINVAL; } (void)memcpy_s(vmSpace, sizeof(LosVmSpace), pcb->vmSpace, sizeof(LosVmSpace)); (void)memcpy_s(heap, sizeof(LosVmMapRegion), pcb->vmSpace->heap, sizeof(LosVmMapRegion)); SCHEDULER_UNLOCK(intSave); (void)LosBufPrintf(seqBuf, "\nVMSpaceSize: %u KB\n", vmSpace->size); (void)LosBufPrintf(seqBuf, "VMRegionSize: %u KB\n", heap->range.size); (void)LosBufPrintf(seqBuf, "RegionFlags: %s\n", OsGetRegionNameOrFilePath(heap)); (void)LosBufPrintf(seqBuf, "ShmidAboutSharedRegion: %u\n", heap->shmid); (void)LosBufPrintf(seqBuf, "VMSpaceRorkFlags: 0x%x\n", heap->forkFlags); (void)LosBufPrintf(seqBuf, "VMRegionRype: 0x%x\n", heap->regionType); (void)LosBufPrintf(seqBuf, "VMSpaceMappingAreaSize: %u KB\n", vmSpace->mapSize); (void)LosBufPrintf(seqBuf, "TLB Asid: %u\n", vmSpace->archMmu.asid); (void)LOS_MemFree(m_aucSysMem1, vmSpace); return 0; } #ifdef LOSCFG_KERNEL_CPUP static int ProcessCpupRead(struct SeqBuf *seqBuf, LosProcessCB *pcb) { unsigned int intSave; OsCpupBase *processCpup = (OsCpupBase *)LOS_MemAlloc(m_aucSysMem1, sizeof(OsCpupBase)); if (processCpup == NULL) { return -ENOMEM; } (void)memset_s(processCpup, sizeof(OsCpupBase), 0, sizeof(OsCpupBase)); SCHEDULER_LOCK(intSave); if (OsProcessIsInactive(pcb)) { SCHEDULER_UNLOCK(intSave); (VOID)LOS_MemFree(m_aucSysMem1, processCpup); return -EINVAL; } (void)memcpy_s(processCpup, sizeof(OsCpupBase), pcb->processCpup, sizeof(OsCpupBase)); SCHEDULER_UNLOCK(intSave); (void)LosBufPrintf(seqBuf, "\nTotalRunningTime: %lu\n", processCpup->allTime); (void)LosBufPrintf(seqBuf, "StartTime: %lu\n", processCpup->startTime); (void)LosBufPrintf(seqBuf, "HistoricalRunningTime: "); for (UINT32 i = 0; i < OS_CPUP_HISTORY_RECORD_NUM + 1; i++) { (void)LosBufPrintf(seqBuf, "%lu ", processCpup->historyTime[i]); } (void)LosBufPrintf(seqBuf, "\n"); (void)LOS_MemFree(m_aucSysMem1, processCpup); return 0; } #endif static int ProcProcessRead(struct SeqBuf *m, void *v) { if ((m == NULL) || (v == NULL)) { return -EINVAL; } struct ProcessData *data = (struct ProcessData *)v; switch (data->type) { case PROC_PID_MEM: return ProcessMemInfoRead(m, (LosProcessCB *)data->process); #ifdef LOSCFG_KERNEL_CPUP case PROC_PID_CPUP: return ProcessCpupRead(m, (LosProcessCB *)data->process); #endif default: break; } return -EINVAL; } static const struct ProcFileOperations PID_FOPS = { .read = ProcProcessRead, }; static struct ProcProcess g_procProcess[] = { { .name = NULL, .mode = S_IFDIR | S_IRUSR | S_IXUSR | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH, .type = PROC_PID, .fileOps = &PID_FOPS }, { .name = "meminfo", .mode = 0, .type = PROC_PID_MEM, .fileOps = &PID_FOPS }, #ifdef LOSCFG_KERNEL_CPUP { .name = "cpup", .mode = 0, .type = PROC_PID_CPUP, .fileOps = &PID_FOPS }, #endif #ifdef LOSCFG_KERNEL_CONTAINER { .name = "container", .mode = S_IFDIR | S_IRUSR | S_IXUSR | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH, .type = CONTAINER, .fileOps = &PID_CONTAINER_FOPS }, #ifdef LOSCFG_PID_CONTAINER { .name = "container/pid", .mode = S_IFLNK, .type = PID_CONTAINER, .fileOps = &PID_CONTAINER_FOPS }, #endif #ifdef LOSCFG_UTS_CONTAINER { .name = "container/uts", .mode = S_IFLNK, .type = UTS_CONTAINER, .fileOps = &PID_CONTAINER_FOPS }, #endif #ifdef LOSCFG_MNT_CONTAINER { .name = "container/mnt", .mode = S_IFLNK, .type = MNT_CONTAINER, .fileOps = &PID_CONTAINER_FOPS }, #endif #endif }; void ProcFreeProcessDir(struct ProcDirEntry *processDir) { if (processDir == NULL) { return; } RemoveProcEntry(processDir->name, NULL); } static struct ProcDirEntry *ProcCreatePorcess(UINT32 pid, struct ProcProcess *porcess, uintptr_t processCB) { int ret; char pidName[PROC_PID_DIR_LEN] = {0}; struct ProcessData *data = (struct ProcessData *)malloc(sizeof(struct ProcessData)); if (data == NULL) { return NULL; } if (porcess->name != NULL) { ret = snprintf_s(pidName, PROC_PID_DIR_LEN, PROC_PID_DIR_LEN - 1, "%u/%s", pid, porcess->name); } else { ret = snprintf_s(pidName, PROC_PID_DIR_LEN, PROC_PID_DIR_LEN - 1, "%u", pid); } if (ret < 0) { free(data); return NULL; } data->process = processCB; data->type = porcess->type; struct ProcDirEntry *container = ProcCreateData(pidName, porcess->mode, NULL, porcess->fileOps, (void *)data); if (container == NULL) { free(data); PRINT_ERR("create /proc/%s error!\n", pidName); return NULL; } return container; } int ProcCreateProcessDir(UINT32 pid, uintptr_t process) { unsigned int intSave; struct ProcDirEntry *pidDir = NULL; for (int index = 0; index < (sizeof(g_procProcess) / sizeof(struct ProcProcess)); index++) { struct ProcProcess *procProcess = &g_procProcess[index]; struct ProcDirEntry *dir = ProcCreatePorcess(pid, procProcess, process); if (dir == NULL) { PRINT_ERR("create /proc/%s error!\n", procProcess->name); goto CREATE_ERROR; } if (index == 0) { pidDir = dir; } } SCHEDULER_LOCK(intSave); ((LosProcessCB *)process)->procDir = pidDir; SCHEDULER_UNLOCK(intSave); return 0; CREATE_ERROR: if (pidDir != NULL) { RemoveProcEntry(pidDir->name, NULL); } return -1; } #endif /* LOSCFG_PROC_PROCESS_DIR */ static int ProcessProcFill(struct SeqBuf *m, void *v) { (void)v; (void)OsShellCmdTskInfoGet(OS_ALL_TASK_MASK, m, OS_PROCESS_INFO_ALL); return 0; } static const struct ProcFileOperations PROCESS_PROC_FOPS = { .read = ProcessProcFill, }; void ProcProcessInit(void) { struct ProcDirEntry *pde = CreateProcEntry("process", 0, NULL); if (pde == NULL) { PRINT_ERR("create /proc/process error!\n"); return; } pde->procFileOps = &PROCESS_PROC_FOPS; #ifdef LOSCFG_PROC_PROCESS_DIR int ret = ProcCreateProcessDir(OS_USER_ROOT_PROCESS_ID, (uintptr_t)OsGetUserInitProcess()); if (ret < 0) { PRINT_ERR("Create proc process %d dir failed!\n", OS_USER_ROOT_PROCESS_ID); } #endif return; }