提交 16ed05e8 编写于 作者: Z zhushengle

feat: 支持time容器

BREAKING CHANGE:
支持ipc容器及增强对外变更:
1.clone 支持CLONE_NEWTIME
2.增加”/proc/[pid]/container/time" 用于查询容器信息
3.增加”/proc/[pid]/container/time_for_children" 用于查询容器信息
4.增加”/proc/[pid]/container/pid_for_children" 用于查询容器信息
5.增加”/proc/[pid]/time_offsets" 用于查询和配置time容器信息

Close #I6B0A3
Signed-off-by: Nzhushengle <zhushengle@huawei.com>
Change-Id: I54d79937ca608a10a4384f61e11c88757f833edf
上级 7e0dfb79
......@@ -599,13 +599,22 @@ int clock_gettime(clockid_t clockID, struct timespec *tp)
switch (clockID) {
case CLOCK_MONOTONIC_RAW:
#ifdef LOSCFG_TIME_CONTAINER
tmp = OsTimeSpecAdd(hwTime, CLOCK_MONOTONIC_TIME_BASE);
tp->tv_sec = tmp.tv_sec;
tp->tv_nsec = tmp.tv_nsec;
#else
tp->tv_sec = hwTime.tv_sec;
tp->tv_nsec = hwTime.tv_nsec;
#endif
break;
case CLOCK_MONOTONIC:
LOS_SpinLockSave(&g_timeSpin, &intSave);
tmp = OsTimeSpecAdd(hwTime, g_accDeltaFromAdj);
LOS_SpinUnlockRestore(&g_timeSpin, intSave);
#ifdef LOSCFG_TIME_CONTAINER
tmp = OsTimeSpecAdd(tmp, CLOCK_MONOTONIC_TIME_BASE);
#endif
tp->tv_sec = tmp.tv_sec;
tp->tv_nsec = tmp.tv_nsec;
break;
......@@ -639,7 +648,7 @@ int clock_gettime(clockid_t clockID, struct timespec *tp)
return 0;
ERROUT:
ERROUT:
TIME_RETURN(EINVAL);
}
......
......@@ -34,6 +34,8 @@
#include "proc_fs.h"
#include "internal.h"
#include "los_process_pri.h"
#include "user_copy.h"
#include "los_memory.h"
#ifdef LOSCFG_PROC_PROCESS_DIR
#include "los_vm_dump.h"
......@@ -64,7 +66,7 @@ struct ProcessData {
static ssize_t ProcessContainerLink(unsigned int containerID, ContainerType type, char *buffer, size_t bufLen)
{
ssize_t count = -1;
if (type == PID_CONTAINER) {
if ((type == PID_CONTAINER) || (type == PID_CHILD_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);
......@@ -72,6 +74,8 @@ static ssize_t ProcessContainerLink(unsigned int containerID, ContainerType type
count = snprintf_s(buffer, bufLen, bufLen - 1, "'mnt:[%u]'", containerID);
} else if (type == IPC_CONTAINER) {
count = snprintf_s(buffer, bufLen, bufLen - 1, "'ipc:[%u]'", containerID);
} else if ((type == TIME_CONTAINER) || (type == TIME_CHILD_CONTAINER)) {
count = snprintf_s(buffer, bufLen, bufLen - 1, "'time:[%u]'", containerID);
}
if (count < 0) {
......@@ -174,6 +178,110 @@ static int ProcessCpupRead(struct SeqBuf *seqBuf, LosProcessCB *pcb)
}
#endif
#ifdef LOSCFG_TIME_CONTAINER
static const CHAR *g_monotonic = "monotonic";
#define DECIMAL_BASE 10
static int ProcTimeContainerRead(struct SeqBuf *m, void *v)
{
int ret;
unsigned int intSave;
struct timespec64 offsets = {0};
if ((m == NULL) || (v == NULL)) {
return -EINVAL;
}
struct ProcessData *data = (struct ProcessData *)v;
SCHEDULER_LOCK(intSave);
LosProcessCB *processCB = (LosProcessCB *)data->process;
ret = OsGetTimeContainerMonotonic(processCB, &offsets);
SCHEDULER_UNLOCK(intSave);
if (ret != LOS_OK) {
return -ret;
}
LosBufPrintf(m, "monotonic %lld %ld\n", offsets.tv_sec, offsets.tv_nsec);
return 0;
}
static int ProcSetTimensOffset(const char *buf, LosProcessCB *processCB)
{
unsigned int intSave;
struct timespec64 offsets;
char *endptr = NULL;
offsets.tv_sec = strtoll(buf, &endptr, DECIMAL_BASE);
offsets.tv_sec = strtoll(endptr, NULL, DECIMAL_BASE);
if (offsets.tv_nsec >= OS_SYS_NS_PER_SECOND) {
return -EACCES;
}
SCHEDULER_LOCK(intSave);
unsigned int ret = OsSetTimeContainerMonotonic(processCB, &offsets);
SCHEDULER_UNLOCK(intSave);
if (ret != LOS_OK) {
return -ret;
}
return 0;
}
static int ProcTimeContainerWrite(struct ProcFile *pf, const char *buf, size_t count, loff_t *ppos)
{
(void)ppos;
char *kbuf = NULL;
int ret;
if ((pf == NULL) || (count <= 0)) {
return -EINVAL;
}
struct ProcDirEntry *entry = pf->pPDE;
if (entry == NULL) {
return -EINVAL;
}
struct ProcessData *data = (struct ProcessData *)entry->data;
if (data == NULL) {
return -EINVAL;
}
if (LOS_IsUserAddressRange((VADDR_T)(UINTPTR)buf, count)) {
kbuf = LOS_MemAlloc(m_aucSysMem1, count + 1);
if (kbuf == NULL) {
return -ENOMEM;
}
if (LOS_ArchCopyFromUser(kbuf, buf, count) != 0) {
(VOID)LOS_MemFree(m_aucSysMem1, kbuf);
return -EFAULT;
}
kbuf[count] = '\0';
buf = kbuf;
}
ret = strncmp(buf, g_monotonic, strlen(g_monotonic));
if (ret != 0) {
(VOID)LOS_MemFree(m_aucSysMem1, kbuf);
return -EINVAL;
}
buf += strlen(g_monotonic);
ret = ProcSetTimensOffset(buf, (LosProcessCB *)data->process);
if (ret < 0) {
(VOID)LOS_MemFree(m_aucSysMem1, kbuf);
return ret;
}
(VOID)LOS_MemFree(m_aucSysMem1, kbuf);
return count;
}
static const struct ProcFileOperations TIME_CONTAINER_FOPS = {
.read = ProcTimeContainerRead,
.write = ProcTimeContainerWrite,
};
#endif
static int ProcProcessRead(struct SeqBuf *m, void *v)
{
if ((m == NULL) || (v == NULL)) {
......@@ -235,6 +343,12 @@ static struct ProcProcess g_procProcess[] = {
.type = PID_CONTAINER,
.fileOps = &PID_CONTAINER_FOPS
},
{
.name = "container/pid_for_children",
.mode = S_IFLNK,
.type = PID_CHILD_CONTAINER,
.fileOps = &PID_CONTAINER_FOPS
},
#endif
#ifdef LOSCFG_UTS_CONTAINER
{
......@@ -260,6 +374,26 @@ static struct ProcProcess g_procProcess[] = {
.fileOps = &PID_CONTAINER_FOPS
},
#endif
#ifdef LOSCFG_TIME_CONTAINER
{
.name = "container/time",
.mode = S_IFLNK,
.type = TIME_CONTAINER,
.fileOps = &PID_CONTAINER_FOPS
},
{
.name = "container/time_for_children",
.mode = S_IFLNK,
.type = TIME_CHILD_CONTAINER,
.fileOps = &PID_CONTAINER_FOPS
},
{
.name = "time_offsets",
.mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH,
.type = TIME_CONTAINER,
.fileOps = &TIME_CONTAINER_FOPS
},
#endif
#endif
};
......
......@@ -98,6 +98,11 @@ config IPC_CONTAINER
default n
depends on KERNEL_CONTAINER
config TIME_CONTAINER
bool "Enable time container"
default n
depends on KERNEL_CONTAINER
######################### config options of extended #####################
source "kernel/extended/Kconfig"
......
......@@ -36,6 +36,7 @@ kernel_module(module_name) {
"container/los_ipc_container.c",
"container/los_mnt_container.c",
"container/los_pid_container.c",
"container/los_time_container.c",
"container/los_uts_container.c",
"core/los_bitmap.c",
"core/los_info.c",
......
......@@ -53,6 +53,7 @@ VOID OsInitRootContainer(VOID)
{
#ifdef LOSCFG_PID_CONTAINER
(VOID)OsInitRootPidContainer(&g_rootContainer.pidContainer);
g_rootContainer.pidForChildContainer = g_rootContainer.pidContainer;
#endif
#ifdef LOSCFG_UTS_CONTAINER
(VOID)OsInitRootUtsContainer(&g_rootContainer.utsContainer);
......@@ -62,13 +63,17 @@ VOID OsInitRootContainer(VOID)
#endif
#ifdef LOSCFG_IPC_CONTAINER
(VOID)OsInitRootIpcContainer(&g_rootContainer.ipcContainer);
#endif
#ifdef LOSCFG_TIME_CONTAINER
(VOID)OsInitRootTimeContainer(&g_rootContainer.timeContainer);
g_rootContainer.timeForChildContainer = g_rootContainer.timeContainer;
#endif
return;
}
STATIC INLINE Container *CreateContainer(VOID)
{
Container *container = LOS_MemAlloc(m_aucSysMem1, sizeof(Container));
Container *container = (Container *)LOS_MemAlloc(m_aucSysMem1, sizeof(Container));
if (container == NULL) {
return NULL;
}
......@@ -88,7 +93,7 @@ UINT32 OsCopyContainers(UINTPTR flags, LosProcessCB *child, LosProcessCB *parent
UINT32 intSave;
UINT32 ret = LOS_OK;
if (!(flags & (CLONE_NEWNS | CLONE_NEWUTS | CLONE_NEWIPC | CLONE_NEWPID | CLONE_NEWNET))) {
if (!(flags & (CLONE_NEWNS | CLONE_NEWUTS | CLONE_NEWIPC | CLONE_NEWPID | CLONE_NEWNET | CLONE_NEWTIME))) {
SCHEDULER_LOCK(intSave);
child->container = parent->container;
LOS_AtomicInc(&child->container->rc);
......@@ -124,6 +129,12 @@ UINT32 OsCopyContainers(UINTPTR flags, LosProcessCB *child, LosProcessCB *parent
if (ret != LOS_OK) {
return ret;
}
#endif
#ifdef LOSCFG_TIME_CONTAINER
ret = OsCopyTimeContainer(flags, child, parent);
if (ret != LOS_OK) {
return ret;
}
#endif
return ret;
}
......@@ -149,9 +160,13 @@ VOID OsContainersDestroy(LosProcessCB *processCB)
OsIpcContainersDestroy(processCB);
#endif
#ifdef LOSCFG_TIME_CONTAINER
OsTimeContainersDestroy(processCB);
#endif
#ifndef LOSCFG_PID_CONTAINER
LOS_AtomicDec(&curr->container->rc);
if (LOS_AtomicRead(&processCB->container->rc) == 1) {
if (LOS_AtomicRead(&processCB->container->rc) == 0) {
(VOID)LOS_MemFree(m_aucSysMem1, processCB->container);
processCB->container = NULL;
}
......@@ -168,6 +183,8 @@ UINT32 OsGetContainerID(Container *container, ContainerType type)
#ifdef LOSCFG_PID_CONTAINER
case PID_CONTAINER:
return OsGetPidContainerID(container->pidContainer);
case PID_CHILD_CONTAINER:
return OsGetPidContainerID(container->pidForChildContainer);
#endif
#ifdef LOSCFG_UTS_CONTAINER
case UTS_CONTAINER:
......@@ -180,6 +197,12 @@ UINT32 OsGetContainerID(Container *container, ContainerType type)
#ifdef LOSCFG_IPC_CONTAINER
case IPC_CONTAINER:
return OsGetIpcContainerID(container->ipcContainer);
#endif
#ifdef LOSCFG_TIME_CONTAINER
case TIME_CONTAINER:
return OsGetTimeContainerID(container->timeContainer);
case TIME_CHILD_CONTAINER:
return OsGetTimeContainerID(container->timeForChildContainer);
#endif
default:
break;
......
......@@ -41,21 +41,20 @@
STATIC UINT32 g_currentIpcContainerNum = 0;
STATIC UINT32 CreateIpcContainer(IpcContainer **newIpcContainer)
STATIC IpcContainer *CreateNewIpcContainer(IpcContainer *parent)
{
pthread_mutexattr_t attr;
UINT32 intSave;
UINT32 size = sizeof(IpcContainer);
IpcContainer *ipcContainer = (IpcContainer *)LOS_MemAlloc(m_aucSysMem1, size);
if (ipcContainer == NULL) {
return ENOMEM;
return NULL;
}
(VOID)memset_s(ipcContainer, size, 0, size);
ipcContainer->allQueue = OsAllQueueCBInit(&ipcContainer->freeQueueList);
if (ipcContainer->allQueue == NULL) {
(VOID)LOS_MemFree(m_aucSysMem1, ipcContainer);
return ENOMEM;
return NULL;
}
pthread_mutexattr_init(&attr);
pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE_NP);
......@@ -66,22 +65,47 @@ STATIC UINT32 CreateIpcContainer(IpcContainer **newIpcContainer)
if (ipcContainer->shmSegs == NULL) {
(VOID)LOS_MemFree(m_aucSysMem1, ipcContainer->allQueue);
(VOID)LOS_MemFree(m_aucSysMem1, ipcContainer);
return ENOMEM;
return NULL;
}
LOS_AtomicSet(&ipcContainer->rc, 1);
ipcContainer->containerID = OsAllocContainerID();
if (parent != NULL) {
LOS_AtomicSet(&ipcContainer->rc, 1);
} else {
LOS_AtomicSet(&ipcContainer->rc, 3); /* 3: Three system processes */
}
return ipcContainer;
}
STATIC UINT32 CreateIpcContainer(LosProcessCB *child, LosProcessCB *parent)
{
UINT32 intSave;
IpcContainer *parentContainer = parent->container->ipcContainer;
IpcContainer *newIpcContainer = CreateNewIpcContainer(parentContainer);
if (newIpcContainer == NULL) {
return ENOMEM;
}
SCHEDULER_LOCK(intSave);
g_currentIpcContainerNum += 1;
*newIpcContainer = ipcContainer;
g_currentIpcContainerNum++;
child->container->ipcContainer = newIpcContainer;
SCHEDULER_UNLOCK(intSave);
return LOS_OK;
}
UINT32 OsInitRootIpcContainer(IpcContainer **ipcContainer)
{
return CreateIpcContainer(ipcContainer);
UINT32 intSave;
IpcContainer *newIpcContainer = CreateNewIpcContainer(NULL);
if (newIpcContainer == NULL) {
return ENOMEM;
}
SCHEDULER_LOCK(intSave);
g_currentIpcContainerNum++;
*ipcContainer = newIpcContainer;
SCHEDULER_UNLOCK(intSave);
return LOS_OK;
}
UINT32 OsCopyIpcContainer(UINTPTR flags, LosProcessCB *child, LosProcessCB *parent)
......@@ -97,7 +121,7 @@ UINT32 OsCopyIpcContainer(UINTPTR flags, LosProcessCB *child, LosProcessCB *pare
return LOS_OK;
}
return CreateIpcContainer(&child->container->ipcContainer);
return CreateIpcContainer(child, parent);
}
VOID OsIpcContainersDestroy(LosProcessCB *curr)
......
......@@ -44,20 +44,50 @@ LIST_HEAD *GetContainerMntList(VOID)
return &OsCurrProcessGet()->container->mntContainer->mountList;
}
STATIC UINT32 CreateMntContainer(MntContainer **newMntContainer)
STATIC MntContainer *CreateNewMntContainer(MntContainer *parent)
{
UINT32 intSave;
MntContainer *mntContainer = (MntContainer *)LOS_MemAlloc(m_aucSysMem1, sizeof(MntContainer));
if (mntContainer == NULL) {
return ENOMEM;
return NULL;
}
mntContainer->containerID = OsAllocContainerID();
LOS_AtomicSet(&mntContainer->rc, 1);
LOS_ListInit(&mntContainer->mountList);
if (parent != NULL) {
LOS_AtomicSet(&mntContainer->rc, 1);
} else {
LOS_AtomicSet(&mntContainer->rc, 3); /* 3: Three system processes */
}
return mntContainer;
}
STATIC UINT32 CreateMntContainer(LosProcessCB *child, LosProcessCB *parent)
{
UINT32 intSave;
MntContainer *parentContainer = parent->container->mntContainer;
MntContainer *newMntContainer = CreateNewMntContainer(parentContainer);
if (newMntContainer == NULL) {
return ENOMEM;
}
SCHEDULER_LOCK(intSave);
g_currentMntContainerNum++;
child->container->mntContainer = newMntContainer;
SCHEDULER_UNLOCK(intSave);
return LOS_OK;
}
UINT32 OsInitRootMntContainer(MntContainer **mntContainer)
{
UINT32 intSave;
MntContainer *newMntContainer = CreateNewMntContainer(NULL);
if (newMntContainer == NULL) {
return ENOMEM;
}
SCHEDULER_LOCK(intSave);
g_currentMntContainerNum++;
*newMntContainer = mntContainer;
*mntContainer = newMntContainer;
SCHEDULER_UNLOCK(intSave);
return LOS_OK;
}
......@@ -94,7 +124,7 @@ UINT32 OsCopyMntContainer(UINTPTR flags, LosProcessCB *child, LosProcessCB *pare
return LOS_OK;
}
ret = CreateMntContainer(&child->container->mntContainer);
ret = CreateMntContainer(child, parent);
if (ret != LOS_OK) {
return ret;
}
......@@ -158,9 +188,4 @@ UINT32 OsGetMntContainerID(MntContainer *mntContainer)
return mntContainer->containerID;
}
UINT32 OsInitRootMntContainer(MntContainer **mntContainer)
{
return CreateMntContainer(mntContainer);
}
#endif
......@@ -289,6 +289,7 @@ STATIC UINT32 CreatePidContainer(LosProcessCB *child, LosProcessCB *parent)
g_currentPidContainerNum++;
child->container->pidContainer = newPidContainer;
child->container->pidForChildContainer = newPidContainer;
ret = OsAllocSpecifiedVpidUnsafe(OS_USER_ROOT_PROCESS_ID, child, parent);
if (ret == OS_INVALID_VALUE) {
g_currentPidContainerNum--;
......@@ -313,8 +314,9 @@ VOID OsPidContainersDestroy(LosProcessCB *curr)
FreeVpid(curr);
if (LOS_AtomicRead(&pidContainer->rc) == 0) {
g_currentPidContainerNum--;
(VOID)LOS_MemFree(m_aucSysMem1, pidContainer);
curr->container->pidContainer = NULL;
curr->container->pidForChildContainer = NULL;
(VOID)LOS_MemFree(m_aucSysMem1, pidContainer);
}
}
......@@ -333,6 +335,7 @@ UINT32 OsCopyPidContainer(UINTPTR flags, LosProcessCB *child, LosProcessCB *pare
if (!(flags & CLONE_NEWPID)) {
SCHEDULER_LOCK(intSave);
child->container->pidContainer = parent->container->pidContainer;
child->container->pidForChildContainer = parent->container->pidContainer;
ret = OsAllocVpid(child);
SCHEDULER_UNLOCK(intSave);
if (ret == OS_INVALID_VALUE) {
......
/*
* Copyright (c) 2023-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 "los_time_container_pri.h"
#include "los_process_pri.h"
#ifdef LOSCFG_TIME_CONTAINER
STATIC UINT32 g_currentTimeContainerNum;
STATIC TimeContainer *CreateNewTimeContainer(TimeContainer *parent)
{
UINT32 size = sizeof(TimeContainer);
TimeContainer *timeContainer = (TimeContainer *)LOS_MemAlloc(m_aucSysMem1, size);
if (timeContainer == NULL) {
return NULL;
}
(VOID)memset_s(timeContainer, size, 0, size);
timeContainer->containerID = OsAllocContainerID();
if (parent != NULL) {
timeContainer->frozenOffsets = FALSE;
LOS_AtomicSet(&timeContainer->rc, 1);
} else {
timeContainer->frozenOffsets = TRUE;
LOS_AtomicSet(&timeContainer->rc, 3); /* 3: Three system processes */
}
return timeContainer;
}
STATIC UINT32 CreateTimeContainer(LosProcessCB *child, LosProcessCB *parent)
{
UINT32 intSave;
TimeContainer *parentContainer = parent->container->timeContainer;
TimeContainer *newTimeContainer = CreateNewTimeContainer(parentContainer);
if (newTimeContainer == NULL) {
return ENOMEM;
}
SCHEDULER_LOCK(intSave);
g_currentTimeContainerNum++;
(VOID)memcpy_s(&newTimeContainer->monotonic, sizeof(struct timespec64),
&parentContainer->monotonic, sizeof(struct timespec64));
child->container->timeContainer = newTimeContainer;
child->container->timeForChildContainer = newTimeContainer;
SCHEDULER_UNLOCK(intSave);
return LOS_OK;
}
UINT32 OsInitRootTimeContainer(TimeContainer **timeContainer)
{
UINT32 intSave;
TimeContainer *newTimeContainer = CreateNewTimeContainer(NULL);
if (newTimeContainer == NULL) {
return ENOMEM;
}
SCHEDULER_LOCK(intSave);
*timeContainer = newTimeContainer;
g_currentTimeContainerNum++;
SCHEDULER_UNLOCK(intSave);
return LOS_OK;
}
UINT32 OsCopyTimeContainer(UINTPTR flags, LosProcessCB *child, LosProcessCB *parent)
{
UINT32 intSave;
TimeContainer *currTimeContainer = parent->container->timeContainer;
if (!(flags & CLONE_NEWTIME)) {
SCHEDULER_LOCK(intSave);
if (!currTimeContainer->frozenOffsets) {
currTimeContainer->frozenOffsets = TRUE;
}
LOS_AtomicInc(&currTimeContainer->rc);
child->container->timeContainer = currTimeContainer;
child->container->timeForChildContainer = currTimeContainer;
SCHEDULER_UNLOCK(intSave);
return LOS_OK;
}
return CreateTimeContainer(child, parent);
}
VOID OsTimeContainersDestroy(LosProcessCB *curr)
{
UINT32 intSave;
if (curr->container == NULL) {
return;
}
SCHEDULER_LOCK(intSave);
TimeContainer *timeContainer = curr->container->timeContainer;
if (timeContainer != NULL) {
LOS_AtomicDec(&timeContainer->rc);
if (LOS_AtomicRead(&timeContainer->rc) == 0) {
g_currentTimeContainerNum--;
curr->container->timeContainer = NULL;
curr->container->timeForChildContainer = NULL;
SCHEDULER_UNLOCK(intSave);
(VOID)LOS_MemFree(m_aucSysMem1, timeContainer);
return;
}
}
SCHEDULER_UNLOCK(intSave);
return;
}
UINT32 OsGetTimeContainerID(TimeContainer *timeContainer)
{
if (timeContainer == NULL) {
return OS_INVALID_VALUE;
}
return timeContainer->containerID;
}
TimeContainer *OsGetCurrTimeContainer(VOID)
{
return OsCurrProcessGet()->container->timeContainer;
}
UINT32 OsGetTimeContainerMonotonic(LosProcessCB *processCB, struct timespec64 *offsets)
{
if ((processCB == NULL) || (offsets == NULL)) {
return EINVAL;
}
if (OsProcessIsInactive(processCB)) {
return ESRCH;
}
TimeContainer *timeContainer = processCB->container->timeForChildContainer;
(VOID)memcpy_s(offsets, sizeof(struct timespec64), &timeContainer->monotonic, sizeof(struct timespec64));
return LOS_OK;
}
UINT32 OsSetTimeContainerMonotonic(LosProcessCB *processCB, struct timespec64 *offsets)
{
if ((processCB == NULL) || (offsets == NULL)) {
return EINVAL;
}
if (OsProcessIsInactive(processCB)) {
return ESRCH;
}
TimeContainer *timeContainer = processCB->container->timeForChildContainer;
if (timeContainer->frozenOffsets) {
return EACCES;
}
timeContainer->monotonic.tv_sec = offsets->tv_sec;
timeContainer->monotonic.tv_nsec = offsets->tv_nsec;
return LOS_OK;
}
#endif
......@@ -36,22 +36,88 @@
STATIC UINT32 g_currentUtsContainerNum;
STATIC UINT32 CreateUtsContainer(UtsContainer **newUtsContainer)
STATIC UINT32 InitUtsContainer(struct utsname *name)
{
UINT32 intSave;
UINT32 ret = sprintf_s(name->sysname, sizeof(name->sysname), "%s", KERNEL_NAME);
if (ret < 0) {
return LOS_NOK;
}
ret = sprintf_s(name->nodename, sizeof(name->nodename), "%s", KERNEL_NODE_NAME);
if (ret < 0) {
return LOS_NOK;
}
ret = sprintf_s(name->version, sizeof(name->version), "%s %u.%u.%u.%u %s %s",
KERNEL_NAME, KERNEL_MAJOR, KERNEL_MINOR, KERNEL_PATCH, KERNEL_ITRE, __DATE__, __TIME__);
if (ret < 0) {
return LOS_NOK;
}
const char *cpuInfo = LOS_CpuInfo();
ret = sprintf_s(name->machine, sizeof(name->machine), "%s", cpuInfo);
if (ret < 0) {
return LOS_NOK;
}
ret = sprintf_s(name->release, sizeof(name->release), "%u.%u.%u.%u",
KERNEL_MAJOR, KERNEL_MINOR, KERNEL_PATCH, KERNEL_ITRE);
if (ret < 0) {
return LOS_NOK;
}
name->domainname[0] = '\0';
return LOS_OK;
}
STATIC UtsContainer *CreateNewUtsContainer(UtsContainer *parent)
{
UINT32 ret;
UINT32 size = sizeof(UtsContainer);
UtsContainer *utsContainer = LOS_MemAlloc(m_aucSysMem1, size);
UtsContainer *utsContainer = (UtsContainer *)LOS_MemAlloc(m_aucSysMem1, size);
if (utsContainer == NULL) {
return ENOMEM;
return NULL;
}
(VOID)memset_s(utsContainer, sizeof(UtsContainer), 0, sizeof(UtsContainer));
utsContainer->containerID = OsAllocContainerID();
LOS_AtomicSet(&utsContainer->rc, 1);
if (parent != NULL) {
LOS_AtomicSet(&utsContainer->rc, 1);
return utsContainer;
}
LOS_AtomicSet(&utsContainer->rc, 3); /* 3: Three system processes */
ret = InitUtsContainer(&utsContainer->utsName);
if (ret != LOS_OK) {
(VOID)LOS_MemFree(m_aucSysMem1, utsContainer);
return NULL;
}
return utsContainer;
}
STATIC UINT32 CreateUtsContainer(LosProcessCB *child, LosProcessCB *parent)
{
UINT32 intSave;
UtsContainer *parentContainer = parent->container->utsContainer;
UtsContainer *newUtsContainer = CreateNewUtsContainer(parentContainer);
if (newUtsContainer == NULL) {
return ENOMEM;
}
SCHEDULER_LOCK(intSave);
g_currentUtsContainerNum += 1;
*newUtsContainer = utsContainer;
g_currentUtsContainerNum++;
(VOID)memcpy_s(&newUtsContainer->utsName, sizeof(newUtsContainer->utsName),
&parentContainer->utsName, sizeof(parentContainer->utsName));
child->container->utsContainer = newUtsContainer;
SCHEDULER_UNLOCK(intSave);
return LOS_OK;
}
UINT32 OsInitRootUtsContainer(UtsContainer **utsContainer)
{
UINT32 intSave;
UtsContainer *newUtsContainer = CreateNewUtsContainer(NULL);
if (newUtsContainer == NULL) {
return ENOMEM;
}
SCHEDULER_LOCK(intSave);
g_currentUtsContainerNum++;
*utsContainer = newUtsContainer;
SCHEDULER_UNLOCK(intSave);
return LOS_OK;
}
......@@ -59,8 +125,6 @@ STATIC UINT32 CreateUtsContainer(UtsContainer **newUtsContainer)
UINT32 OsCopyUtsContainer(UINTPTR flags, LosProcessCB *child, LosProcessCB *parent)
{
UINT32 intSave;
UINT32 ret;
UtsContainer *newUtsContainer = NULL;
UtsContainer *currUtsContainer = parent->container->utsContainer;
if (!(flags & CLONE_NEWUTS)) {
......@@ -71,17 +135,7 @@ UINT32 OsCopyUtsContainer(UINTPTR flags, LosProcessCB *child, LosProcessCB *pare
return LOS_OK;
}
ret = CreateUtsContainer(&newUtsContainer);
if (ret != LOS_OK) {
return ret;
}
SCHEDULER_LOCK(intSave);
(VOID)memcpy_s(&newUtsContainer->utsName, sizeof(newUtsContainer->utsName),
&currUtsContainer->utsName, sizeof(currUtsContainer->utsName));
child->container->utsContainer = newUtsContainer;
SCHEDULER_UNLOCK(intSave);
return LOS_OK;
return CreateUtsContainer(child, parent);
}
VOID OsUtsContainersDestroy(LosProcessCB *curr)
......@@ -107,47 +161,6 @@ VOID OsUtsContainersDestroy(LosProcessCB *curr)
return;
}
STATIC UINT32 InitUtsContainer(struct utsname *name)
{
UINT32 ret;
ret = sprintf_s(name->sysname, sizeof(name->sysname), "%s", KERNEL_NAME);
if (ret < 0) {
return LOS_NOK;
}
ret = sprintf_s(name->nodename, sizeof(name->nodename), "%s", KERNEL_NODE_NAME);
if (ret < 0) {
return LOS_NOK;
}
ret = sprintf_s(name->version, sizeof(name->version), "%s %u.%u.%u.%u %s %s",
KERNEL_NAME, KERNEL_MAJOR, KERNEL_MINOR, KERNEL_PATCH, KERNEL_ITRE, __DATE__, __TIME__);
if (ret < 0) {
return LOS_NOK;
}
const char *cpuInfo = LOS_CpuInfo();
ret = sprintf_s(name->machine, sizeof(name->machine), "%s", cpuInfo);
if (ret < 0) {
return LOS_NOK;
}
ret = sprintf_s(name->release, sizeof(name->release), "%u.%u.%u.%u",
KERNEL_MAJOR, KERNEL_MINOR, KERNEL_PATCH, KERNEL_ITRE);
if (ret < 0) {
return LOS_NOK;
}
name->domainname[0] = '\0';
return LOS_OK;
}
UINT32 OsInitRootUtsContainer(UtsContainer **utsContainer)
{
UINT32 ret = CreateUtsContainer(utsContainer);
if (ret != LOS_OK) {
return ret;
}
return InitUtsContainer(&(*utsContainer)->utsName);
}
struct utsname *OsGetCurrUtsName(VOID)
{
Container *container = OsCurrProcessGet()->container;
......
......@@ -2075,6 +2075,9 @@ LITE_OS_SEC_TEXT INT32 OsClone(UINT32 flags, UINTPTR sp, UINT32 size)
return -LOS_EINVAL;
}
#endif
#ifdef LOSCFG_TIME_CONTAINER
cloneFlag |= CLONE_NEWTIME;
#endif
#endif
if (flags & (~cloneFlag)) {
......
......@@ -45,19 +45,26 @@
#ifdef LOSCFG_IPC_CONTAINER
#include "los_ipc_container_pri.h"
#endif
#ifdef LOSCFG_TIME_CONTAINER
#include "los_time_container_pri.h"
#endif
typedef enum {
CONTAINER = 0,
PID_CONTAINER,
PID_CHILD_CONTAINER,
UTS_CONTAINER,
MNT_CONTAINER,
IPC_CONTAINER,
TIME_CONTAINER,
TIME_CHILD_CONTAINER,
} ContainerType;
typedef struct Container {
Atomic rc;
#ifdef LOSCFG_PID_CONTAINER
struct PidContainer *pidContainer;
struct PidContainer *pidForChildContainer;
#endif
#ifdef LOSCFG_UTS_CONTAINER
struct UtsContainer *utsContainer;
......@@ -68,6 +75,10 @@ typedef struct Container {
#ifdef LOSCFG_IPC_CONTAINER
struct IpcContainer *ipcContainer;
#endif
#ifdef LOSCFG_IPC_CONTAINER
struct TimeContainer *timeContainer;
struct TimeContainer *timeForChildContainer;
#endif
} Container;
VOID OsContainerInitSystemProcess(LosProcessCB *processCB);
......
/*
* Copyright (c) 2022-2022 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.
*/
#ifndef _LOS_TIME_CONTAINER_PRI_H
#define _LOS_TIME_CONTAINER_PRI_H
#include "time.h"
#include "los_atomic.h"
#ifdef LOSCFG_TIME_CONTAINER
typedef struct ProcessCB LosProcessCB;
typedef struct TimeContainer {
Atomic rc;
BOOL frozenOffsets;
struct timespec64 monotonic;
UINT32 containerID;
} TimeContainer;
UINT32 OsInitRootTimeContainer(TimeContainer **timeContainer);
UINT32 OsCopyTimeContainer(UINTPTR flags, LosProcessCB *child, LosProcessCB *parent);
VOID OsTimeContainersDestroy(LosProcessCB *curr);
UINT32 OsGetTimeContainerID(TimeContainer *timeContainer);
TimeContainer *OsGetCurrTimeContainer(VOID);
UINT32 OsGetTimeContainerMonotonic(LosProcessCB *processCB, struct timespec64 *offsets);
UINT32 OsSetTimeContainerMonotonic(LosProcessCB *processCB, struct timespec64 *offsets);
#define CLOCK_MONOTONIC_TIME_BASE (OsGetCurrTimeContainer()->monotonic)
#endif
#endif /* _LOS_TIME_CONTAINER_PRI_H */
......@@ -137,6 +137,7 @@ LOSCFG_USER_TEST_PID_CONTAINER = false
LOSCFG_USER_TEST_UTS_CONTAINER = false
LOSCFG_USER_TEST_MNT_CONTAINER = false
LOSCFG_USER_TEST_IPC_CONTAINER = false
LOSCFG_USER_TEST_TIME_CONTAINER = false
if (defined(LOSCFG_KERNEL_CONTAINER)) {
LOSCFG_USER_TEST_CONTAINER = true
if (defined(LOSCFG_PID_CONTAINER)) {
......@@ -151,4 +152,7 @@ if (defined(LOSCFG_KERNEL_CONTAINER)) {
if (defined(LOSCFG_IPC_CONTAINER)) {
LOSCFG_USER_TEST_IPC_CONTAINER = true
}
if (defined(LOSCFG_TIME_CONTAINER)) {
LOSCFG_USER_TEST_TIME_CONTAINER = true
}
}
......@@ -44,6 +44,9 @@ config("container_config") {
if (defined(LOSCFG_USER_TEST_IPC_CONTAINER)) {
cflags += [ "-DLOSCFG_USER_TEST_IPC_CONTAINER" ]
}
if (defined(LOSCFG_USER_TEST_TIME_CONTAINER)) {
cflags += [ "-DLOSCFG_USER_TEST_TIME_CONTAINER" ]
}
cflags_cc = cflags
}
......
......@@ -126,6 +126,30 @@ HWTEST_F(ContainerTest, ItPidContainer023, TestSize.Level0)
{
ItPidContainer023();
}
/**
* @tc.name: Container_Pid_Test_025
* @tc.desc: pid container function test case
* @tc.type: FUNC
* @tc.require: issueI68LVW
* @tc.author:
*/
HWTEST_F(ContainerTest, ItPidContainer025, TestSize.Level0)
{
ItPidContainer025();
}
/**
* @tc.name: Container_Pid_Test_026
* @tc.desc: pid container function test case
* @tc.type: FUNC
* @tc.require: issueI68LVW
* @tc.author:
*/
HWTEST_F(ContainerTest, ItPidContainer026, TestSize.Level0)
{
ItPidContainer026();
}
#endif
#if defined(LOSCFG_USER_TEST_UTS_CONTAINER)
/**
......@@ -242,6 +266,56 @@ HWTEST_F(ContainerTest, ItIpcContainer004, TestSize.Level0)
ItIpcContainer004();
}
#endif
#if defined(LOSCFG_USER_TEST_TIME_CONTAINER)
/**
* @tc.name: Container_TIME_Test_001
* @tc.desc: time container function test case
* @tc.type: FUNC
* @tc.require: issueI6B0A3
* @tc.author:
*/
HWTEST_F(ContainerTest, ItTimeContainer001, TestSize.Level0)
{
ItTimeContainer001();
}
/*
* @tc.name: Container_TIME_Test_007
* @tc.desc: time container function test case
* @tc.type: FUNC
* @tc.require: issueI6B0A3
* @tc.author:
*/
HWTEST_F(ContainerTest, ItTimeContainer007, TestSize.Level0)
{
ItTimeContainer007();
}
/**
* @tc.name: Container_TIME_Test_009
* @tc.desc: time container function test case
* @tc.type: FUNC
* @tc.require: issueI6B0A3
* @tc.author:
*/
HWTEST_F(ContainerTest, ItTimeContainer009, TestSize.Level0)
{
ItTimeContainer009();
}
/**
* @tc.name: Container_TIME_Test_010
* @tc.desc: time container function test case
* @tc.type: FUNC
* @tc.require: issueI6B0A3
* @tc.author:
*/
HWTEST_F(ContainerTest, ItTimeContainer010, TestSize.Level0)
{
ItTimeContainer010();
}
#endif
#endif /* LOSCFG_USER_TEST_SMOKE */
#if defined(LOSCFG_USER_TEST_FULL)
......
......@@ -38,6 +38,7 @@
#include <csignal>
#include <sys/syscall.h>
#include <sys/capability.h>
#include <cstring>
#include "osTest.h"
#include "mqueue.h"
#include "sys/time.h"
......@@ -86,6 +87,10 @@ extern const int CHILD_FUNC_ARG;
const int MQUEUE_STANDARD_NAME_LENGTH = 255;
extern "C" {
#define CLONE_NEWTIME 0x00000080
}
int ChildFunction(void *args);
pid_t CloneWrapper(int (*func)(void *), int flag, void *args);
......@@ -135,6 +140,8 @@ void ItContainer001(void);
void ItContainerChroot001(void);
#if defined(LOSCFG_USER_TEST_PID_CONTAINER)
void ItPidContainer023(void);
void ItPidContainer025(void);
void ItPidContainer026(void);
#endif
#if defined(LOSCFG_USER_TEST_UTS_CONTAINER)
void ItUtsContainer001(void);
......@@ -158,6 +165,18 @@ void ItIpcContainer004(void);
void ItIpcContainer005(void);
void ItIpcContainer006(void);
#endif
#if defined(LOSCFG_USER_TEST_TIME_CONTAINER)
void ItTimeContainer001(void);
void ItTimeContainer002(void);
void ItTimeContainer003(void);
void ItTimeContainer004(void);
void ItTimeContainer005(void);
void ItTimeContainer006(void);
void ItTimeContainer007(void);
void ItTimeContainer008(void);
void ItTimeContainer009(void);
void ItTimeContainer010(void);
#endif
#endif
#if defined(LOSCFG_USER_TEST_FULL)
......
......@@ -44,8 +44,11 @@ sources_smoke = [
sources_full = []
if (defined(LOSCFG_USER_TEST_PID_CONTAINER)) {
sources_smoke +=
[ "$TEST_UNITTEST_DIR/container/smoke/It_pid_container_023.cpp" ]
sources_smoke += [
"$TEST_UNITTEST_DIR/container/smoke/It_pid_container_023.cpp",
"$TEST_UNITTEST_DIR/container/smoke/It_pid_container_025.cpp",
"$TEST_UNITTEST_DIR/container/smoke/It_pid_container_026.cpp",
]
sources_full += [
"$TEST_UNITTEST_DIR/container/full/It_pid_container_001.cpp",
"$TEST_UNITTEST_DIR/container/full/It_pid_container_002.cpp",
......@@ -102,3 +105,18 @@ if (defined(LOSCFG_USER_TEST_IPC_CONTAINER)) {
"$TEST_UNITTEST_DIR/container/smoke/It_ipc_container_006.cpp",
]
}
if (defined(LOSCFG_USER_TEST_TIME_CONTAINER)) {
sources_smoke += [
"$TEST_UNITTEST_DIR/container/smoke/It_time_container_001.cpp",
"$TEST_UNITTEST_DIR/container/smoke/It_time_container_002.cpp",
"$TEST_UNITTEST_DIR/container/smoke/It_time_container_003.cpp",
"$TEST_UNITTEST_DIR/container/smoke/It_time_container_004.cpp",
"$TEST_UNITTEST_DIR/container/smoke/It_time_container_005.cpp",
"$TEST_UNITTEST_DIR/container/smoke/It_time_container_006.cpp",
"$TEST_UNITTEST_DIR/container/smoke/It_time_container_007.cpp",
"$TEST_UNITTEST_DIR/container/smoke/It_time_container_008.cpp",
"$TEST_UNITTEST_DIR/container/smoke/It_time_container_009.cpp",
"$TEST_UNITTEST_DIR/container/smoke/It_time_container_010.cpp",
]
}
/*
* Copyright (c) 2023-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 "It_container_test.h"
static int childFunc(void *arg)
{
(void)arg;
return 0;
}
void ItPidContainer025(void)
{
int ret;
int status;
char *containerType = "pid";
char *containerType1 = "pid_for_children";
char *stack = (char *)mmap(NULL, STACK_SIZE, PROT_READ | PROT_WRITE, CLONE_STACK_MMAP_FLAG, -1, 0);
ASSERT_NE(stack, nullptr);
char *stackTop = stack + STACK_SIZE;
std::cout << getpid() << std::endl;
auto linkBuffer = ReadlinkContainer(getpid(), containerType);
auto linkBuffer1 = ReadlinkContainer(getpid(), containerType1);
ret = linkBuffer.compare(linkBuffer1);
ASSERT_EQ(ret, 0);
auto pid = clone(childFunc, stackTop, CLONE_NEWPID | SIGCHLD, NULL);
ASSERT_TRUE(pid != -1);
ret = waitpid(pid, &status, 0);
ASSERT_EQ(ret, pid);
ret = WIFEXITED(status);
ASSERT_NE(ret, 0);
int exitCode = WEXITSTATUS(status);
ASSERT_EQ(exitCode, 0);
auto linkBuffer2 = ReadlinkContainer(getpid(), containerType);
ret = linkBuffer.compare(linkBuffer2);
ASSERT_EQ(ret, 0);
}
/*
* Copyright (c) 2023-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 "It_container_test.h"
static int childFunc(void *arg)
{
(void)arg;
sleep(1);
return 0;
}
void ItPidContainer026(void)
{
int ret;
int status;
char *containerType = "pid";
char *containerType1 = "pid_for_children";
char *stack = (char *)mmap(NULL, STACK_SIZE, PROT_READ | PROT_WRITE, CLONE_STACK_MMAP_FLAG, -1, 0);
ASSERT_NE(stack, nullptr);
char *stackTop = stack + STACK_SIZE;
std::cout << getpid() << std::endl;
auto linkBuffer = ReadlinkContainer(getpid(), containerType);
auto linkBuffer1 = ReadlinkContainer(getpid(), containerType1);
ret = linkBuffer.compare(linkBuffer1);
ASSERT_EQ(ret, 0);
auto pid = clone(childFunc, stackTop, CLONE_NEWPID | SIGCHLD, NULL);
ASSERT_TRUE(pid != -1);
auto linkBuffer2 = ReadlinkContainer(pid, containerType);
ret = linkBuffer.compare(linkBuffer2);
ASSERT_NE(ret, 0);
ret = waitpid(pid, &status, 0);
ASSERT_EQ(ret, pid);
ret = WIFEXITED(status);
ASSERT_NE(ret, 0);
int exitCode = WEXITSTATUS(status);
ASSERT_EQ(exitCode, 0);
}
/*
* Copyright (c) 2023-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 "It_container_test.h"
static int childFunc(void *arg)
{
int value = *((int*)arg);
if (value != CHILD_FUNC_ARG) {
return EXIT_CODE_ERRNO_1;
}
sleep(1);
return 0;
}
void ItTimeContainer001(void)
{
int ret;
int status;
char *containerType = "time";
char *containerType1 = "time_for_children";
char *stack = (char *)mmap(NULL, STACK_SIZE, PROT_READ | PROT_WRITE, CLONE_STACK_MMAP_FLAG, -1, 0);
ASSERT_NE(stack, nullptr);
char *stackTop = stack + STACK_SIZE;
std::cout << getpid() << std::endl;
auto linkBuffer = ReadlinkContainer(getpid(), containerType);
auto linkBuffer1 = ReadlinkContainer(getpid(), containerType1);
ret = linkBuffer.compare(linkBuffer1);
ASSERT_EQ(ret, 0);
int arg = CHILD_FUNC_ARG;
auto pid = clone(childFunc, stackTop, CLONE_NEWTIME | SIGCHLD, &arg);
ASSERT_TRUE(pid != -1);
auto linkBuffer2 = ReadlinkContainer(pid, containerType);
ret = linkBuffer.compare(linkBuffer2);
ASSERT_NE(ret, 0);
ret = waitpid(pid, &status, 0);
ASSERT_EQ(ret, pid);
ret = WIFEXITED(status);
ASSERT_NE(ret, 0);
int exitCode = WEXITSTATUS(status);
ASSERT_EQ(exitCode, 0);
}
/*
* Copyright (c) 2023-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 "It_container_test.h"
const int STR_LEN = 50;
const int SEC = 600;
const int NSEC = 800000000;
static int childFunc(void *arg)
{
char path[STR_LEN];
char timeOff[STR_LEN];
char readBuf[STR_LEN];
int ret;
ret = sprintf_s(timeOff, STR_LEN, "monotonic %d %d", SEC, NSEC);
if (ret <= 0) {
return EXIT_CODE_ERRNO_4;
}
ret = sprintf_s(path, STR_LEN, "/proc/%d/time_offsets", getpid());
if (ret <= 0) {
return EXIT_CODE_ERRNO_5;
}
int fd = open(path, O_RDWR);
if (fd == -1) {
return EXIT_CODE_ERRNO_1;
}
ret = read(fd, readBuf, STR_LEN);
if (ret == -1) {
close(fd);
return EXIT_CODE_ERRNO_2;
}
close(fd);
ret = strncmp(timeOff, readBuf, strlen(timeOff));
if (ret != 0) {
return EXIT_CODE_ERRNO_3;
}
return 0;
}
static int WriteProcTime(int pid)
{
int ret = 0;
char path[STR_LEN];
char timeOff[STR_LEN];
ret = sprintf_s(timeOff, STR_LEN, "monotonic %d %d", SEC, NSEC);
if (ret <= 0) {
return EXIT_CODE_ERRNO_6;
}
ret = sprintf_s(path, STR_LEN, "/proc/%d/time_offsets", pid);
if (ret <= 0) {
return EXIT_CODE_ERRNO_7;
}
int strLen = strlen(timeOff);
int fd = open(path, O_WRONLY);
if (ret == -1) {
return EXIT_CODE_ERRNO_8;
}
ret = write(fd, timeOff, strLen);
if (ret != strLen) {
close(fd);
return EXIT_CODE_ERRNO_9;
}
close(fd);
return 0;
}
void ItTimeContainer002(void)
{
int ret;
int status;
char *containerType = "time";
char *containerType1 = "time_for_children";
char *stack = (char *)mmap(NULL, STACK_SIZE, PROT_READ | PROT_WRITE, CLONE_STACK_MMAP_FLAG, -1, 0);
ASSERT_NE(stack, nullptr);
char *stackTop = stack + STACK_SIZE;
ret = unshare(CLONE_NEWTIME);
ASSERT_EQ(ret, 0);
ret = WriteProcTime(getpid());
ASSERT_EQ(ret, 0);
auto linkBuffer = ReadlinkContainer(getpid(), containerType);
auto linkBuffer1 = ReadlinkContainer(getpid(), containerType1);
ret = linkBuffer.compare(linkBuffer1);
ASSERT_TRUE(ret != 0);
int arg = CHILD_FUNC_ARG;
auto pid = clone(childFunc, stackTop, CLONE_NEWTIME | SIGCHLD, &arg);
ASSERT_TRUE(pid != -1);
auto linkBuffer2 = ReadlinkContainer(pid, containerType);
ret = linkBuffer1.compare(linkBuffer2);
ASSERT_EQ(ret, 0);
ret = waitpid(pid, &status, 0);
ASSERT_EQ(ret, pid);
ret = WIFEXITED(status);
ASSERT_TRUE(ret != 0);
int exitCode = WEXITSTATUS(status);
ASSERT_EQ(exitCode, 0);
}
/*
* Copyright (c) 2023-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 "It_container_test.h"
static int childFunc(void *arg)
{
int ret;
char *containerType = "time";
char *containerType1 = "time_for_children";
char pid_link[100]; /* 100: test len */
char targetpath[100]; /* 100: test len */
auto linkBuffer = ReadlinkContainer(getppid(), containerType);
int fd;
ret = sprintf_s(pid_link, 100, "%s", linkBuffer.c_str()); /* 100: test len */
if (ret <= 0) {
return EXIT_CODE_ERRNO_4;
}
ret = sprintf_s(targetpath, 100, "/proc/%d/container/time", getppid()); /* 100: test len */
if (ret <= 0) {
return EXIT_CODE_ERRNO_5;
}
fd = open(targetpath, O_RDONLY | O_CLOEXEC);
if (fd == -1) {
return EXIT_CODE_ERRNO_1;
}
ret = setns(fd, CLONE_NEWTIME);
if (ret != 0) {
close(fd);
return EXIT_CODE_ERRNO_2;
}
close(fd);
auto linkBuffer1 = ReadlinkContainer(getpid(), containerType);
auto linkBuffer2 = ReadlinkContainer(getpid(), containerType1);
ret = linkBuffer1.compare(linkBuffer2);
EXPECT_EQ(ret, 0);
if (ret != 0) {
return EXIT_CODE_ERRNO_3;
}
return 0;
}
void ItTimeContainer003(void)
{
int ret;
int status;
char *containerType = "time";
char *containerType1 = "time_for_children";
char *stack = (char *)mmap(NULL, STACK_SIZE, PROT_READ | PROT_WRITE, CLONE_STACK_MMAP_FLAG, -1, 0);
ASSERT_NE(stack, nullptr);
char *stackTop = stack + STACK_SIZE;
ret = unshare(CLONE_NEWTIME);
ASSERT_EQ(ret, 0);
auto linkBuffer = ReadlinkContainer(getpid(), containerType1);
int arg = CHILD_FUNC_ARG;
auto pid = clone(childFunc, stackTop, CLONE_NEWTIME | SIGCHLD, &arg);
ASSERT_TRUE(pid != -1);
ret = waitpid(pid, &status, 0);
ASSERT_EQ(ret, pid);
ret = WIFEXITED(status);
ASSERT_TRUE(ret != 0);
int exitCode = WEXITSTATUS(status);
ASSERT_EQ(exitCode, 0);
}
/*
* Copyright (c) 2023-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 "It_container_test.h"
const int STR_LEN = 50;
const int SEC = 172800;
const int NSEC = 800000000;
static int childFunc(void *arg)
{
int ret;
struct timespec tp = *((struct timespec *)arg);
struct timespec tp1;
ret = clock_gettime(CLOCK_MONOTONIC_RAW, &tp1);
if (ret != 0) {
return EXIT_CODE_ERRNO_1;
}
ret = ((tp1.tv_sec >= tp.tv_sec + SEC));
if (ret != 1) {
return EXIT_CODE_ERRNO_2;
}
return 0;
}
static int WriteProcTime(int pid)
{
int ret;
char path[STR_LEN];
char timeOff[STR_LEN];
ret = sprintf_s(timeOff, STR_LEN, "monotonic %d %d", SEC, NSEC);
if (ret <= 0) {
return EXIT_CODE_ERRNO_5;
}
ret = sprintf_s(path, STR_LEN, "/proc/%d/time_offsets", pid);
if (ret <= 0) {
return EXIT_CODE_ERRNO_6;
}
int strLen = strlen(timeOff);
int fd = open(path, O_WRONLY);
if (fd == -1) {
return EXIT_CODE_ERRNO_3;
}
ret = write(fd, timeOff, strLen);
if (ret != strLen) {
close(fd);
return EXIT_CODE_ERRNO_4;
}
close(fd);
return 0;
}
void ItTimeContainer004(void)
{
int ret;
int status;
struct timespec tp;
char *stack = (char *)mmap(NULL, STACK_SIZE, PROT_READ | PROT_WRITE, CLONE_STACK_MMAP_FLAG, -1, 0);
ASSERT_NE(stack, nullptr);
char *stackTop = stack + STACK_SIZE;
ret = unshare(CLONE_NEWTIME);
ASSERT_EQ(ret, 0);
ret = WriteProcTime(getpid());
ASSERT_EQ(ret, 0);
ret = clock_gettime(CLOCK_MONOTONIC_RAW, &tp);
ASSERT_EQ(ret, 0);
auto pid = clone(childFunc, stackTop, CLONE_NEWTIME | SIGCHLD, &tp);
ASSERT_TRUE(pid != -1);
ret = waitpid(pid, &status, 0);
ASSERT_EQ(ret, pid);
ret = WIFEXITED(status);
ASSERT_NE(ret, 0);
int exitCode = WEXITSTATUS(status);
ASSERT_EQ(exitCode, 0);
}
/*
* Copyright (c) 2023-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 "It_container_test.h"
const int STR_LEN = 50;
const int SEC = 172800;
const int NSEC = 800000000;
static int childFunc(void *arg)
{
int ret;
struct timespec tp = *((struct timespec *)arg);
struct timespec tp1 = {0};
ret = clock_gettime(CLOCK_MONOTONIC, &tp1);
if (ret != 0) {
return EXIT_CODE_ERRNO_1;
}
ret = ((tp1.tv_sec >= tp.tv_sec + SEC));
if (ret != 1) {
return EXIT_CODE_ERRNO_2;
}
return 0;
}
static int WriteProcTime(int pid)
{
int ret;
char path[STR_LEN];
char timeOff[STR_LEN];
ret = sprintf_s(timeOff, STR_LEN, "monotonic %d %d", SEC, NSEC);
if (ret <= 0) {
return EXIT_CODE_ERRNO_5;
}
ret = sprintf_s(path, STR_LEN, "/proc/%d/time_offsets", pid);
if (ret <= 0) {
return EXIT_CODE_ERRNO_5;
}
int strLen = strlen(timeOff);
int fd = open(path, O_WRONLY);
if (fd == -1) {
return EXIT_CODE_ERRNO_3;
}
ret = write(fd, timeOff, strLen);
if (ret != strLen) {
close(fd);
return EXIT_CODE_ERRNO_4;
}
close(fd);
return 0;
}
void ItTimeContainer005(void)
{
int ret;
int status;
struct timespec tp = {0};
char *stack = (char *)mmap(NULL, STACK_SIZE, PROT_READ | PROT_WRITE, CLONE_STACK_MMAP_FLAG, -1, 0);
ASSERT_NE(stack, nullptr);
char *stackTop = stack + STACK_SIZE;
ret = unshare(CLONE_NEWTIME);
ASSERT_EQ(ret, 0);
ret = WriteProcTime(getpid());
ASSERT_EQ(ret, 0);
ret = clock_gettime(CLOCK_MONOTONIC, &tp);
ASSERT_EQ(ret, 0);
auto pid = clone(childFunc, stackTop, CLONE_NEWTIME | SIGCHLD, &tp);
ASSERT_TRUE(pid != -1);
ret = waitpid(pid, &status, 0);
ASSERT_EQ(ret, pid);
ret = WIFEXITED(status);
ASSERT_TRUE(ret != 0);
int exitCode = WEXITSTATUS(status);
ASSERT_EQ(exitCode, 0);
}
/*
* Copyright (c) 2023-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 "It_container_test.h"
const int MAX_TIME_CONTAINER = 64;
const int STR_LEN = 100;
void ItTimeContainer006(void)
{
int ret;
char *fileName = "/proc/sys/user/max_time_container";
FILE *fp = nullptr;
char strBuf[STR_LEN] = {0};
fp = fopen(fileName, "rb");
ASSERT_TRUE(fp != 0);
ret = fread(strBuf, 1, STR_LEN, fp);
ASSERT_TRUE(ret != -1);
ret = atoi(strBuf);
ASSERT_EQ(ret, MAX_TIME_CONTAINER);
(void)fclose(fp);
}
/*
* Copyright (c) 2023-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 "It_container_test.h"
const int STR_LEN = 50;
const int SEC = 172800;
const int NSEC = 80000000;
static int WriteProcTime(int pid)
{
int ret;
char path[STR_LEN] = {0};
char timeOff[STR_LEN] = {0};
ret = sprintf_s(timeOff, STR_LEN, "monotonic %d %d", SEC, NSEC);
if (ret < 0) {
return EXIT_CODE_ERRNO_3;
}
ret = sprintf_s(path, STR_LEN, "/proc/%d/time_offsets", pid);
if (ret < 0) {
return EXIT_CODE_ERRNO_4;
}
int strLen = strlen(timeOff);
int fd = open(path, O_WRONLY);
if (fd == -1) {
return EXIT_CODE_ERRNO_1;
}
ret = write(fd, timeOff, strLen);
if (ret != -1) {
close(fd);
return EXIT_CODE_ERRNO_2;
}
close(fd);
return 0;
}
void ItTimeContainer007(void)
{
int ret;
ret = WriteProcTime(getpid());
ASSERT_EQ(ret, 0);
}
/*
* Copyright (c) 2023-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 "It_container_test.h"
const int STR_LEN = 50;
const int SEC = 172800;
const long long NSEC = 800000000000;
static int WriteProcTime(int pid)
{
int ret;
char path[STR_LEN] = {0};
char timeOff[STR_LEN] = {0};
ret = sprintf_s(timeOff, STR_LEN, "monotonic %d %lld", SEC, NSEC);
if (ret < 0) {
return EXIT_CODE_ERRNO_3;
}
ret = sprintf_s(path, STR_LEN, "/proc/%d/time_offsets", pid);
if (ret < 0) {
return EXIT_CODE_ERRNO_3;
}
int strLen = strlen(timeOff);
int fd = open(path, O_WRONLY);
if (fd == -1) {
return EXIT_CODE_ERRNO_1;
}
ret = write(fd, timeOff, strLen);
if (ret != -1) {
close(fd);
return EXIT_CODE_ERRNO_2;
}
close(fd);
return 0;
}
void ItTimeContainer008(void)
{
int ret = unshare(CLONE_NEWTIME);
ASSERT_EQ(ret, 0);
ret = WriteProcTime(getpid());
ASSERT_EQ(ret, 0);
}
/*
* Copyright (c) 2023-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 <iostream>
#include "It_container_test.h"
static std::string GenTimeLinkPath(int pid)
{
std::ostringstream buf;
buf << "/proc/" << pid << "/container/time";
return buf.str();
}
static std::string ReadlinkTime(int pid)
{
auto path = GenTimeLinkPath(pid);
struct stat sb;
int ret = lstat(path.data(), &sb);
if (ret == -1) {
perror("lstat");
return std::string();
}
auto bufsiz = sb.st_size + 1;
if (sb.st_size == 0) {
bufsiz = PATH_MAX;
}
std::vector<char> buf(bufsiz);
auto nbytes = readlink(path.c_str(), buf.data(), bufsiz);
if (nbytes == -1) {
perror("readlink");
return std::string();
}
return buf.data();
}
void ItTimeContainer009(void)
{
auto timelink = ReadlinkTime(getpid());
std::cout << "Contents of the time link is: " << timelink << std::endl;
std::regex reg("'time:\\[[0-9]+\\]'");
bool ret = std::regex_match(timelink, reg);
ASSERT_TRUE(ret);
}
/*
* Copyright (c) 2023-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 "It_container_test.h"
static int childFunc(void *arg)
{
int value = *((int*)arg);
if (value != CHILD_FUNC_ARG) {
return EXIT_CODE_ERRNO_1;
}
return 0;
}
void ItTimeContainer010(void)
{
int ret;
int status;
char *containerType = "time";
char *containerType1 = "time_for_children";
char *stack = (char *)mmap(NULL, STACK_SIZE, PROT_READ | PROT_WRITE, CLONE_STACK_MMAP_FLAG, -1, 0);
ASSERT_NE(stack, nullptr);
char *stackTop = stack + STACK_SIZE;
std::cout << getpid() << std::endl;
auto linkBuffer = ReadlinkContainer(getpid(), containerType);
auto linkBuffer1 = ReadlinkContainer(getpid(), containerType1);
ret = linkBuffer.compare(linkBuffer1);
ASSERT_EQ(ret, 0);
int arg = CHILD_FUNC_ARG;
auto pid = clone(childFunc, stackTop, CLONE_NEWTIME | SIGCHLD, &arg);
ASSERT_TRUE(pid != -1);
ret = waitpid(pid, &status, 0);
ASSERT_EQ(ret, pid);
ret = WIFEXITED(status);
ASSERT_NE(ret, 0);
int exitCode = WEXITSTATUS(status);
ASSERT_EQ(exitCode, 0);
auto linkBuffer2 = ReadlinkContainer(getpid(), containerType);
ret = linkBuffer.compare(linkBuffer2);
ASSERT_EQ(ret, 0);
}
......@@ -54,5 +54,12 @@ extern void ItProcessFs012(void);
extern void ItProcessFs013(void);
extern void ItProcessFs014(void);
extern void ItProcessFs015(void);
extern void ItProcessFs015(void);
extern void ItProcessFs016(void);
extern void ItProcessFs017(void);
extern void ItProcessFs018(void);
extern void ItProcessFs019(void);
extern void ItProcessFs020(void);
extern void ItProcessFs021(void);
extern void ItProcessFs022(void);
#endif
......@@ -61,7 +61,13 @@ process_fs_sources_smoke = [
"$TEST_UNITTEST_DIR/process/fs/smoke/It_process_fs_013.cpp",
"$TEST_UNITTEST_DIR/process/fs/smoke/It_process_fs_014.cpp",
"$TEST_UNITTEST_DIR/process/fs/smoke/It_process_fs_015.cpp",
"$TEST_UNITTEST_DIR/process/fs/smoke/It_process_fs_016.cpp",
"$TEST_UNITTEST_DIR/process/fs/smoke/It_process_fs_017.cpp",
"$TEST_UNITTEST_DIR/process/fs/smoke/It_process_fs_018.cpp",
"$TEST_UNITTEST_DIR/process/fs/smoke/It_process_fs_019.cpp",
"$TEST_UNITTEST_DIR/process/fs/smoke/It_process_fs_020.cpp",
"$TEST_UNITTEST_DIR/process/fs/smoke/It_process_fs_021.cpp",
"$TEST_UNITTEST_DIR/process/fs/smoke/It_process_fs_022.cpp",
]
process_fs_sources_full = []
......
......@@ -36,7 +36,7 @@ VOID PrintTest(const CHAR *fmt, ...)
{
#ifdef PRINT_TEST
va_list ap;
if (g_osLkHook != NULL) {
if (g_osLkHook != nullptr) {
va_start(ap, fmt);
printf(fmt, ap);
va_end(ap);
......@@ -224,5 +224,17 @@ HWTEST_F(ProcessFsTest, ItProcessFs021, TestSize.Level0)
{
ItProcessFs021();
}
/**
* @tc.name: Process_fs_Test_022
* @tc.desc: Process mount directory test
* @tc.type: FUNC
* @tc.require: issueI6B0A3
* @tc.author:
*/
HWTEST_F(ProcessFsTest, ItProcessFs022, TestSize.Level0)
{
ItProcessFs022();
}
#endif
}
......@@ -46,8 +46,6 @@ static int childFunc(void *arg)
void ItProcessFs016(void)
{
const int CONFIG_FILE_LEN = 1024;
char szFile[CONFIG_FILE_LEN] = {0};
std::string path = "/proc/sys/user/max_uts_container";
int fd = open(path.c_str(), O_WRONLY);
ASSERT_NE(fd, -1);
......@@ -59,9 +57,9 @@ void ItProcessFs016(void)
int arg = CHILD_FUNC_ARG;
char *stack = (char *)mmap(NULL, STACK_SIZE, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS | MAP_STACK,
char *stack = (char *)mmap(nullptr, STACK_SIZE, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS | MAP_STACK,
-1, 0);
ASSERT_NE(stack, NULL);
ASSERT_NE(stack, nullptr);
char *stackTop = stack + STACK_SIZE;
auto pid = clone(childFunc, stackTop, CLONE_NEWUTS, &arg);
......
......@@ -46,8 +46,6 @@ static int childFunc(void *arg)
void ItProcessFs017(void)
{
const int CONFIG_FILE_LEN = 1024;
char szFile[CONFIG_FILE_LEN] = {0};
std::string path = "/proc/sys/user/max_user_container";
int fd = open(path.c_str(), O_WRONLY);
ASSERT_NE(fd, -1);
......@@ -60,9 +58,9 @@ void ItProcessFs017(void)
int arg = CHILD_FUNC_ARG;
char *stack = (char *)mmap(NULL, STACK_SIZE, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS | MAP_STACK,
char *stack = (char *)mmap(nullptr, STACK_SIZE, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS | MAP_STACK,
-1, 0);
ASSERT_NE(stack, NULL);
ASSERT_NE(stack, nullptr);
char *stackTop = stack + STACK_SIZE;
auto pid = clone(childFunc, stackTop, CLONE_NEWUSER, &arg);
......
......@@ -46,8 +46,6 @@ static int childFunc(void *arg)
void ItProcessFs018(void)
{
const int CONFIG_FILE_LEN = 1024;
char szFile[CONFIG_FILE_LEN] = {0};
std::string path = "/proc/sys/user/max_mnt_container";
int fd = open(path.c_str(), O_WRONLY);
ASSERT_NE(fd, -1);
......@@ -60,9 +58,9 @@ void ItProcessFs018(void)
int arg = CHILD_FUNC_ARG;
char *stack = (char *)mmap(NULL, STACK_SIZE, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS | MAP_STACK,
char *stack = (char *)mmap(nullptr, STACK_SIZE, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS | MAP_STACK,
-1, 0);
ASSERT_NE(stack, NULL);
ASSERT_NE(stack, nullptr);
char *stackTop = stack + STACK_SIZE;
auto pid = clone(childFunc, stackTop, CLONE_NEWNS, &arg);
......
......@@ -46,8 +46,6 @@ static int childFunc(void *arg)
void ItProcessFs019(void)
{
const int CONFIG_FILE_LEN = 1024;
char szFile[CONFIG_FILE_LEN] = {0};
std::string path = "/proc/sys/user/max_pid_container";
int fd = open(path.c_str(), O_WRONLY);
ASSERT_NE(fd, -1);
......@@ -60,9 +58,9 @@ void ItProcessFs019(void)
int arg = CHILD_FUNC_ARG;
char *stack = (char *)mmap(NULL, STACK_SIZE, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS | MAP_STACK,
char *stack = (char *)mmap(nullptr, STACK_SIZE, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS | MAP_STACK,
-1, 0);
ASSERT_NE(stack, NULL);
ASSERT_NE(stack, nullptr);
char *stackTop = stack + STACK_SIZE;
auto pid = clone(childFunc, stackTop, CLONE_NEWPID, &arg);
......
......@@ -46,23 +46,21 @@ static int childFunc(void *arg)
void ItProcessFs020(void)
{
const int CONFIG_FILE_LEN = 1024;
char szFile[CONFIG_FILE_LEN] = {0};
std::string path = "/proc/sys/user/max_net_container";
int fd = open(path.c_str(), O_WRONLY);
ASSERT_NE(fd, -1);
char buf[configLen];
size_t ret = sprintf(buf, configLen, "%d", invalidNum);
size_t ret = sprintf_s(buf, configLen, "%d", invalidNum);
ASSERT_GT(ret, 0);
ret = write(fd, buf, (strlen(buf) + 1));
ASSERT_NE(ret, -1);
int arg = CHILD_FUNC_ARG;
char *stack = (char *)mmap(NULL, STACK_SIZE, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS | MAP_STACK,
char *stack = (char *)mmap(nullptr, STACK_SIZE, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS | MAP_STACK,
-1, 0);
ASSERT_NE(stack, NULL);
ASSERT_NE(stack, nullptr);
char *stackTop = stack + STACK_SIZE;
auto pid = clone(childFunc, stackTop, CLONE_NEWNET, &arg);
......
/*
* Copyright (c) 2023-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 <sched.h>
#include <unistd.h>
#include <sys/stat.h>
#include <climits>
#include <string>
#include <iostream>
#include <regex>
#include "It_process_fs_test.h"
void ItProcessFs022(void)
{
auto path = GenProcPidContainerPath(getpid(), "time");
std::vector<char> buf(PATH_MAX);
auto nbytes = readlink(path.c_str(), buf.data(), PATH_MAX);
ASSERT_NE(nbytes, -1);
std::regex reg("'time:\\[[0-9]+\\]'");
bool ret = std::regex_match(buf.data(), reg);
ASSERT_EQ(ret, true);
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册