diff --git a/src/gausskernel/cbb/bbox/bbox_lib.cpp b/src/gausskernel/cbb/bbox/bbox_lib.cpp new file mode 100644 index 000000000..908105d23 --- /dev/null +++ b/src/gausskernel/cbb/bbox/bbox_lib.cpp @@ -0,0 +1,619 @@ +/* + * Copyright (c) 2020 Huawei Technologies Co.,Ltd. + * + * openGauss is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + * ------------------------------------------------------------------------- + * + * bbox_lib.cpp + * + * IDENTIFICATION + * src/gausskernel/cbb/bbox/bbox_lib.cpp + * + * ------------------------------------------------------------------------- + */ +#include "bbox_syscall_support.h" +#include "bbox_lib.h" +#include "bbox_print.h" +#include "../../src/include/securec.h" +#include "../../src/include/securec_check.h" + +#define PAGE_SIZE 4096 +#define BBOX_MAX_PIDS 32 +#define BBOX_TMP_LEN_32 32 + +#define container_of(ptr, type, member) \ + ({ \ + const typeof(((type*)0)->member)* __mptr = (ptr); \ + (type*)((char*)__mptr - offsetof(type, member)); \ + }) + +#define typeof decltype + +struct PIPE_ID { + s32 iFd; + pid_t pid; +}; + +struct PIPE_IDS { + struct PIPE_ID stPid; + s32 isUsed; +}; + +static struct PIPE_IDS astPipeIds[BBOX_MAX_PIDS]; + +/* +function name: bbox_strncmp +description: To compare two substrings, the pointers pszSrc and pszTarget store their host strings'addresses. +arguments: Two pointers of type const char*, pointing to two strings needed to be compared. + An integer indicates the number of characters at the former of two strings that + will be compared. +return value: Type s32, an interger. + If it's zero, then the former substrings of string pszSrc and pszTarget are same, + else it indicates the difference between the first two characters that these two + strings can't match. +note锛歍he two pointers shouldn't be null. The last argument shouldn't less than zero. +date: 2022/8/2 +contact tel: 18720816902 +*/ +/* +这段代码是一个用于比较字符串的函数bbox_strncmp。它接受三个参数:常量字符指针pszSrc,用于表示源字符串;常量字符指针pszTarget,用于表示目标字符串;整数count,表示要比较的字符数。 +首先,定义一个有符号字符变量cRes并初始化为0。 +然后,使用while循环进行字符串比较,条件为count大于0。每次循环执行以下操作: +首先,将源字符串指针的值与目标字符串指针的值相减,并将结果赋给cRes。如果结果不等于0,或者源字符串指针的值为0(即字符串结束),则跳出循环。 +然后,将目标字符串指针递增1,源字符串指针也递增1。 +最后,将count减1。 +循环结束后,返回变量cRes,它表示最后一次比较的结果。如果cRes为0,则表示两个字符串相等;如果cRes小于0,则表示源字符串小于目标字符串;如果cRes大于0,则表示源字符串大于目标字符串。 +*/ +s32 bbox_strncmp(const char* pszSrc, const char* pszTarget, s32 count) +{ + signed char cRes = 0; + + while (count) { + if ((cRes = *pszSrc - *pszTarget++) != 0 || !*pszSrc++) { + break; + } + count--; + } + + return cRes; +} + +/* +function name: bbox_strcmp +description: compare two strings, the pointer pszSrc and pszTarget store their addresses. +arguments: Two pointers of type const char*, pointing to two strings needed to be compared. + An integer indicates the number of characters at the former of two strings that + will be compared. +return value: Type s32, an interger. + If it's zero, then the former substrings of string pszSrc and pszTarget are same, + else if it's 1, then it indicates between first two characters that these two + strings can't match, the character of first string that pszSrc points is greater, + else if it's -1, the character of second string that pszTarget points is greater. +note锛歍he two pointers shouldn't be null. The last argument shouldn't less than zero. +date: 2022/8/2 +contact tel:same +*/ +s32 bbox_strcmp(const char* pszSrc, const char* pszTarget) +{ + unsigned char c1, c2; + + while (1) { + c1 = *pszSrc++; + c2 = *pszTarget++; + + if (c1 != c2) { + return c1 < c2 ? -1 : 1; + } + + if (c1 == 0) { + break; + } + } + return 0; +} + +/* +function name: bbox_strlen +description: Calculate the length of string. +arguments: An pointer that indicates the address of a string. +return value: Type s32, an integer indicating the length of string. +note: the length of string=(address of the last character not '\0'-address of the first character)/sizeof(char), and sizeof(char) + equals to 1, so the length of string=(address of the last character not '\0'-address of the first character). +date: 2022/8/2 +contact tel:same +*/ +s32 bbox_strlen(const char* pszString) +{ + const char* pszTemp = NULL; + + for (pszTemp = pszString; *pszTemp != '\0'; ++pszTemp) { + /* nothing */; + continue; + } + + return pszTemp - pszString; +} + +/* +function name: bbox_strnlen +description: Calculate the length of string, but having some restrictive conditions. +arguments: An pointer that indicates the address of a string. + And an integer that indicates the maxlenth. +return value: Type s32, an integer indicating the length of string. +note: If the length of string exceed the argument count, then return the length of string, + else return the argument count. +date: 2022/8/2 +contact tel:same +*/ +s32 bbox_strnlen(const char* pszString, s32 count) +{ + const char* pszTemp = NULL; + + for (pszTemp = pszString; count-- && *pszTemp != '\0'; ++pszTemp) { + /* nothing */; + } + + return pszTemp - pszString; +} + +/* +function name: bbox_atoi +description: Convert a string that includes continuous digital characters to an integer, + if the first character of the string is '-', then we will return a negative result. +arguments: An pointer that indicates the address of a string. +return value: Type s32, an integer indicating the result of string converted. +note: I think the function isn't perfect, though it's not a core function. For example, what about + the condition that the first character of the string is '+'? +date: 2022/8/2 +contact tel:same +*/ +/* +这段代码是一个将字符串转换为整数的函数bbox_atoi。它接受一个常量字符指针pszString,表示要转换的字符串,并返回一个整数值。 +首先,定义两个整数变量n和iNeg,并初始化为0。其中,n用于存储转换后的整数值,iNeg用于表示是否为负数。 +然后,判断字符串的第一个字符是否为'-'。如果是,则将iNeg设置为1,表示转换结果为负数。 +如果iNeg为1,将字符串指针向后移动一位,跳过负号。 +接下来,使用while循环,判断当前字符是否为数字字符,即是否在字符范围'0'到'9'之间。 +在循环内部,首先将n乘以10,然后将当前字符减去'0',并累加到n中。 +循环结束后,返回n的值。如果iNeg为1,则表示结果为负数,返回负数的n;如果iNeg为0,则表示结果为正数,返回正数的n。 +*/ +s32 bbox_atoi(const char* pszString) +{ + s32 n = 0; + s32 iNeg = 0; + + if (*pszString == '-') { + iNeg = 1; + } + + if (iNeg) { + pszString++; + } + + while (*pszString >= '0' && *pszString <= '9') { + n = 10 * n + (*pszString++ - '0'); + } + + return iNeg ? -n : n; +} +/* +function name: bbox_memcmp +description: Compare former count bytes in ASCII of data stored in two areas that pointers cs and ct direct. +arguments: Two pointers to areas of memory, and an integer indicating the max counts compared. +return value: Type s32, an integer. + If the value returned is 0, then the data stored in two areas destined are same, + else if is 1, then between two first data in ASCII of byte different, cs's is greater, + else if is -1, then ct's is greater. +note: The two pointers should not be null, it's dangerous. +date: 2022/8/2 +contact tel: same +*/ +s32 bbox_memcmp(const void* cs, const void* ct, s32 count) +{ + const unsigned char *su1 = NULL; + const unsigned char *su2 = NULL; + + for (su1 = (const unsigned char*)cs, su2 = (const unsigned char*)ct; count > 0; ++su1, ++su2, count--) { + if (*su1 != *su2) { + return *su1 < *su2 ? -1 : +1; + } + } + + return 0; +} + +/* +function name: bbox_strstr +description: Judge if the string s2 directs is substring of string s1 directs. +arguments: Two pointers of type const char*, pointing to two strings. +return value: Type char*, a pointer. Actually it's a address, if s2 directs a + null string, then return the address of the first character of s1, + if the string s2 directs isn't substring of string s1 directs, return + null, if the string s2 directs is substring of string s1 directs, then return + the address of first character matched. +note: The two pointers should not be null, it's dangerous. +date: 2022/8/2 +contact tel: same +*/ +char* bbox_strstr(const char* s1, const char* s2) +{ + int l1, l2; + + l2 = bbox_strlen(s2); + if (!l2) { + return (char*)s1; + } + + l1 = bbox_strlen(s1); + while (l1 >= l2) { + l1--; + if (!bbox_memcmp(s1, s2, l2)) { + return (char*)s1; + } + s1++; + } + return NULL; +} + +/* +function name: bbox_mkdir +description: We distinguish parent directory and child directory through character '/', + normally through a for loop, we can make sure all directories above the directory + we want to creat exist, finally we will creat the flag directory after its parent. +arguments: A pointers of type const char*, pointing to one strings, which indicates the filename and its full path. +return value: An integer of type s32, if it's RET_ERR, then we fail to make a directory, else if it's RET_OK then we succeed. +note: Take care the last non-null character of the string needed to be '/', and once if flag directory's + ancestors aren't exist, the function return RET_ERR. +date: 2022/8/2 +contact tel: same +*/ +s32 bbox_mkdir(const char* pszDir) +{ + char szDirName[BBOX_TMP_LEN_32 * 16]; + char* p = NULL; + s32 len; + + if (bbox_snprintf(szDirName, sizeof(szDirName), "%s", pszDir) <= 0) { + return RET_ERR; + } + + len = bbox_strnlen(szDirName, sizeof(szDirName)); + if (szDirName[len - 1] == '/') { + if (len == 1) { + return RET_OK; + } + + szDirName[len - 1] = 0; + } + + for (p = szDirName + 1; *p; p++) { + if (*p != '/') { + continue; + } + + *p = 0; + if (sys_mkdir(szDirName, S_IRWXU) < 0) { + if (errno != EEXIST) { + return RET_ERR; + } + } + + *p = '/'; + } + + if (sys_mkdir(szDirName, S_IRWXU) < 0) { + if (errno != EEXIST) { + return RET_ERR; + } + } + + return RET_OK; +} + +/* +function name: bbox_GetFreePid +description: Through a for loop, we search a free pipe in a structure array, to an array element if its + member variable isUsed's value is 0, we return the array element's another member variable + stPid's address. +arguments: void +return value: An pointer of type struct PIPE_ID* or NULL. +note: none +date: 2022/8/2 +contact tel: same +*/ +struct PIPE_ID* bbox_GetFreePid(void) +{ + u32 i; + + for (i = 0; i < BBOX_MAX_PIDS; i++) { + if (astPipeIds[i].isUsed == 0) { + astPipeIds[i].isUsed = 1; + return &(astPipeIds[i].stPid); + } + } + + return NULL; +} + +/* +function name: bbox_PutPid +description: Release the occupied pipe. +arguments: A pointer of type struct PIPE_ID*. +return value: void +note: If the argument pointer is null, then there is no need to free the storage, the function ends. +date: 2022/8/2 +contact tel: same +*/ +void bbox_PutPid(struct PIPE_ID* pstPid) +{ + struct PIPE_IDS* pstPids = NULL; + if (pstPid == NULL) { + return; + } + + pstPids = container_of(pstPid, struct PIPE_IDS, stPid); + + errno_t rc = memset_s(pstPids, sizeof(struct PIPE_IDS), 0, sizeof(struct PIPE_IDS)); + securec_check_c(rc, "\0", "\0"); +} + +/* +function name: bbox_FindPid +description: In all occupied pipes, the function search the flag pipe through compare all structure + array elements's member variable stPid's member variable iFd with the function + argument iFd, if they are equal, then return the addres of this array elements. +arguments: An integer that indicates a file's file handle. +return value: A pointer of type struct PIPE_ID* or NULL. +note: none +date: 2022/8/2 +contact tel: same +*/ +struct PIPE_ID* bbox_FindPid(int iFd) +{ + u32 i; + + for (i = 0; i < BBOX_MAX_PIDS; i++) { + if (astPipeIds[i].isUsed == 0) { + continue; + } + + if (astPipeIds[i].stPid.iFd == iFd) { + return &(astPipeIds[i].stPid); + } + } + + return NULL; +} + +/* +function name: sys_popen +description: The function gets a free pipe by function bbox_GetFreePid, if normally, then creat a pipe + through sys_pipe, andcreat a child process through function sys_fork, execute a shell command + to run a process. +arguments: One pointer to a string that represents command line, another pointer of type const char* + indicates that the file file handle directs is used in the this mode. +return value: A pointer of type struct PIPE_ID* or NULL. +note: The string that indicates pszMode should only be "r" or "w", +date: 2022/8/2 +contact tel: same +*/ +/* +函数sys_popen的作用是打开一个管道,用于执行指定的命令。 +它接受两个参数:一个字符指针pszCmd,用于存储要执行的命令;一个常量字符指针pszMode,表示管道的读写模式。函数返回一个整数值,表示管道文件描述符。 +首先,函数检查pszCmd和pszMode指针是否为空,如果为空,则设置errno为EINVAL,并返回-1。 +然后,函数检查读写模式是否正确,即pszMode只能为'r'或'w',并且只能有一个字符。如果模式不正确,则设置errno为EINVAL,并返回-1。 +接下来,函数使用bbox_GetFreePid函数获取一个空闲的管道ID。如果获取失败,则返回-1。 +然后,函数使用sys_pipe函数创建一个管道,如果创建失败,则返回-1。 +接着,函数使用sys_fork函数创建子进程。如果创建子进程失败,则关闭管道的文件描述符,释放管道ID,并返回-1。如果创建成功,则在子进程中执行以下操作: + +- 获取待执行的命令和参数数组pArgv。 +- 恢复信号函数。 +- 关闭其他文件描述符,除了管道的读写文件描述符。 +- 根据读写模式设置标准输入输出文件描述符。 +- 使用sys_execve函数执行命令。如果执行失败,则打印错误信息,并使用sys_exit函数退出进程。 +最后,如果当前进程是父进程,则根据读写模式选择要返回的文件描述符,并将管道ID和子进程ID保存起来。 +函数sys_pclose的作用是关闭由sys_popen打开的管道。它接受一个整数值iFd,表示要关闭的文件描述符。函数返回一个整数值,表示进程的最终状态。 +首先,函数使用bbox_FindPid函数根据文件描述符查找对应的管道ID。如果查找失败,则返回-1。 +然后,函数使用sys_close函数关闭文件描述符。 +接着,函数使用sys_waitpid函数等待子进程的退出,并获取进程的状态。如果等待失败,则继续等待,直到成功或出现其他错误。 +最后,函数释放管道ID,并根据等待的结果返回相应的值。 +*/ +s32 sys_popen(char* pszCmd, const char* pszMode) +{ + struct PIPE_ID* volatile stCurPid = NULL; + s32 iFd; + s32 saIpedes[2] = {0}; + pid_t pid; + + if (NULL == pszCmd || NULL == pszMode) { + errno = EINVAL; + return -1; + } + + /* determine whether the read-write mode is correct */ + if ((*pszMode != 'r' && *pszMode != 'w') || pszMode[1] != '\0') { + errno = EINVAL; + return -1; + } + + /* get free pipe id */ + stCurPid = bbox_GetFreePid(); + if (NULL == stCurPid) { + return -1; + } + + /* create pipe */ + if (sys_pipe(saIpedes) < 0) { + return -1; + } + + /* create child prosess */ + pid = sys_fork(); + if (pid < 0) { + /* close fd if error */ + sys_close(saIpedes[0]); + sys_close(saIpedes[1]); + bbox_PutPid(stCurPid); + return -1; + } else if (pid == 0) { /* Child. */ + /* child prosess */ + s32 i = 0; + char* pArgv[4]; + pArgv[0] = "sh"; + pArgv[1] = "-c"; + pArgv[2] = pszCmd; + pArgv[3] = 0; + + /* Restore signal function */ + sys_signal(SIGQUIT, SIG_DFL); + sys_signal(SIGTSTP, SIG_IGN); + sys_signal(SIGTERM, SIG_DFL); + sys_signal(SIGINT, SIG_DFL); + + for (i = STDERR_FILENO + 1; i < 1024; i++) { + /* do not close pipe. */ + if (i == saIpedes[0] || i == saIpedes[1]) { + continue; + } + + sys_close((int)i); + } + + if (*pszMode == 'r') { + int tpipedes1 = saIpedes[1]; + + sys_close(saIpedes[0]); + /* + * We must NOT modify saIpedes, due to the + * semantics of vfork. + */ + if (tpipedes1 != STDOUT_FILENO) { + sys_dup2(tpipedes1, STDOUT_FILENO); + sys_close(tpipedes1); + tpipedes1 = STDOUT_FILENO; + } + } else { + sys_close(saIpedes[1]); + if (saIpedes[0] != STDIN_FILENO) { + sys_dup2(saIpedes[0], STDIN_FILENO); + sys_close(saIpedes[0]); + } + } + + sys_execve("/bin/sh", pArgv, environ); + bbox_print(PRINT_ERR, "exec '%s' failed, errno = %d, pid = %d\n", pszCmd, errno, pid); + sys_exit(127); + /* NOTREACHED */ + } + + /* Parent; assume fdopen can't fail. */ + if (*pszMode == 'r') { + iFd = saIpedes[0]; + sys_close(saIpedes[1]); + } else { + iFd = saIpedes[1]; + sys_close(saIpedes[0]); + } + + /* Link into list of file descriptors. */ + stCurPid->iFd = iFd; + stCurPid->pid = pid; + return iFd; +} + +/* +function name: sys_pclose +description: The function has an contrary action to function sys_popen, it close the pipe + that sys_popen open. +arguments: iFd, an integer that indicates a file handle. +return value: An integer that indicates the final status of the process working before. +note: none +date: 2022/8/2 +contact tel: same +*/ +int sys_pclose(s32 iFd) +{ + struct PIPE_ID* pstCur = NULL; + s32 iStat = -1; + pid_t pid; + + pstCur = bbox_FindPid(iFd); + if (pstCur == NULL) { + return -1; + } + + sys_close(iFd); + + do { + pid = sys_waitpid(pstCur->pid, &iStat, 0); + } while (pid == -1 && errno == EINTR); + + bbox_PutPid(pstCur); + return (pid == -1 ? -1 : iStat); +} + +/* +function name: bbox_listdir +description: The function list all files below this path in directory. +arguments: The first argument is a pointer to a string representing a file path, all files below + this path will be listed in directory. The second argument is a pointer to a callback + function. The last is a pointer of type void*, it indicates a command line. +return value: An integer that indicates the result of function, if normal, it's RET_OK, else + it's RET_ERR. +note: The path that the first argument represents should be absolute path, take care. +date: 2022/8/2 +contact tel: same +*/ +s32 bbox_listdir(const char* pstPath, BBOX_LIST_DIR_CALLBACK callback, void* pArgs) +{ + struct linux_dirent* pstEntry = NULL; + s32 iDir; + char szBuff[PAGE_SIZE]; + ssize_t nBytes; + s32 iRet = RET_OK; + + if (callback == NULL || pstPath == NULL) { + return RET_ERR; + } + + iDir = sys_open(pstPath, O_RDONLY | O_DIRECTORY, 0); + if (iDir < 0) { + bbox_print(PRINT_ERR, "open directory failed, errno = %d\n", errno); + return RET_ERR; + } + + /* get the file in directory */ + do { + nBytes = sys_getdents(iDir, (struct linux_dirent*)szBuff, sizeof(szBuff)); + if (nBytes < 0) { + bbox_print(PRINT_ERR, "get directory ents failed, errno = %d\n", errno); + sys_close(iDir); + return RET_ERR; + } else if (nBytes == 0) { + /* break when there is no file not read */ + break; + } + + for (pstEntry = (struct linux_dirent*)szBuff; + (pstEntry < (struct linux_dirent*)&szBuff[nBytes]) && iRet == RET_OK; + pstEntry = (struct linux_dirent*)((char*)pstEntry + pstEntry->d_reclen)) { + if (pstEntry->d_ino == 0) { + continue; + } + + iRet = callback(pstPath, pstEntry->d_name, pArgs); + } + } while (nBytes > 0 && iRet == RET_OK); + + sys_close(iDir); + + return iRet; +}