openGauss-server/src/gausskernel/cbb/bbox/bbox_lib.cpp

537 lines
15 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*
* 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.
noteThe two pointers shouldn't be null. The last argument shouldn't less than zero.
date: 2022/8/2
contact tel: 18720816902
*/
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.
noteThe 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
*/
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;
}
/*
* make a directory
*/
/*
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;
}
/*
* search free pipe id
*/
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;
}
/*
* Release the occupied pipeid
*/
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");
}
/*
* find available pipe id by file handle
*/
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;
}
/*
* run popen
*/
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;
}
/*
* close file handle
*/
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);
}
/*
* list file in directory
*/
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;
}