2016-01-21 00:55:40 +08:00
|
|
|
/*
|
|
|
|
|
|
|
|
nsjail - useful procedures
|
|
|
|
-----------------------------------------
|
|
|
|
|
|
|
|
Copyright 2016 Google Inc. All Rights Reserved.
|
|
|
|
|
|
|
|
Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
you may not use this file except in compliance with the License.
|
|
|
|
You may obtain a copy of the License at
|
|
|
|
|
|
|
|
http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
|
|
|
|
Unless required by applicable law or agreed to in writing, software
|
|
|
|
distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
See the License for the specific language governing permissions and
|
|
|
|
limitations under the License.
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "util.h"
|
|
|
|
|
2017-05-27 05:07:47 +08:00
|
|
|
#include <ctype.h>
|
2016-02-28 09:34:43 +08:00
|
|
|
#include <errno.h>
|
|
|
|
#include <fcntl.h>
|
2017-10-18 20:27:34 +08:00
|
|
|
#include <limits.h>
|
2017-06-19 23:01:50 +08:00
|
|
|
#include <pthread.h>
|
2017-06-20 06:16:38 +08:00
|
|
|
#include <signal.h>
|
2017-02-08 07:36:32 +08:00
|
|
|
#include <stdarg.h>
|
2017-10-18 20:46:17 +08:00
|
|
|
#include <stdbool.h>
|
|
|
|
#include <stdint.h>
|
2016-08-19 00:59:06 +08:00
|
|
|
#include <stdio.h>
|
2016-01-21 00:55:40 +08:00
|
|
|
#include <stdlib.h>
|
2016-08-19 00:59:06 +08:00
|
|
|
#include <string.h>
|
2016-02-28 09:34:43 +08:00
|
|
|
#include <sys/stat.h>
|
2017-06-22 01:21:18 +08:00
|
|
|
#include <sys/syscall.h>
|
2017-06-22 01:18:02 +08:00
|
|
|
#include <sys/time.h>
|
2016-02-28 09:34:43 +08:00
|
|
|
#include <sys/types.h>
|
2017-06-22 00:46:19 +08:00
|
|
|
#include <time.h>
|
2017-06-22 01:21:18 +08:00
|
|
|
#include <unistd.h>
|
2016-01-21 00:55:40 +08:00
|
|
|
|
2022-08-09 18:05:33 +08:00
|
|
|
#include <iomanip>
|
2018-02-11 21:56:30 +08:00
|
|
|
#include <sstream>
|
2018-02-11 04:19:47 +08:00
|
|
|
#include <string>
|
2018-02-11 21:56:30 +08:00
|
|
|
#include <vector>
|
2018-02-11 04:19:47 +08:00
|
|
|
|
2018-02-11 00:49:15 +08:00
|
|
|
#include "logs.h"
|
2018-02-10 12:25:55 +08:00
|
|
|
#include "macros.h"
|
2016-01-21 00:55:40 +08:00
|
|
|
|
2018-02-10 01:45:50 +08:00
|
|
|
namespace util {
|
|
|
|
|
|
|
|
ssize_t readFromFd(int fd, void* buf, size_t len) {
|
2017-10-09 05:00:45 +08:00
|
|
|
uint8_t* charbuf = (uint8_t*)buf;
|
2016-02-28 09:34:43 +08:00
|
|
|
|
|
|
|
size_t readSz = 0;
|
|
|
|
while (readSz < len) {
|
2018-02-11 06:54:36 +08:00
|
|
|
ssize_t sz = TEMP_FAILURE_RETRY(read(fd, &charbuf[readSz], len - readSz));
|
|
|
|
if (sz <= 0) {
|
|
|
|
break;
|
|
|
|
}
|
2016-02-28 09:34:43 +08:00
|
|
|
readSz += sz;
|
|
|
|
}
|
|
|
|
return readSz;
|
|
|
|
}
|
|
|
|
|
2018-02-10 01:45:50 +08:00
|
|
|
ssize_t readFromFile(const char* fname, void* buf, size_t len) {
|
2019-04-18 05:10:18 +08:00
|
|
|
int fd = TEMP_FAILURE_RETRY(open(fname, O_RDONLY | O_CLOEXEC));
|
2016-05-08 09:09:43 +08:00
|
|
|
if (fd == -1) {
|
2016-09-10 09:20:32 +08:00
|
|
|
LOG_E("open('%s', O_RDONLY|O_CLOEXEC)", fname);
|
2016-05-08 09:09:43 +08:00
|
|
|
return -1;
|
|
|
|
}
|
2018-02-10 01:45:50 +08:00
|
|
|
ssize_t ret = readFromFd(fd, buf, len);
|
2016-07-29 21:38:22 +08:00
|
|
|
close(fd);
|
|
|
|
return ret;
|
2016-05-08 09:09:43 +08:00
|
|
|
}
|
|
|
|
|
2018-11-24 23:23:45 +08:00
|
|
|
bool writeToFd(int fd, const void* buf, size_t len) {
|
2017-10-09 05:00:45 +08:00
|
|
|
const uint8_t* charbuf = (const uint8_t*)buf;
|
2016-02-28 09:34:43 +08:00
|
|
|
|
|
|
|
size_t writtenSz = 0;
|
|
|
|
while (writtenSz < len) {
|
2018-02-11 06:54:36 +08:00
|
|
|
ssize_t sz = TEMP_FAILURE_RETRY(write(fd, &charbuf[writtenSz], len - writtenSz));
|
|
|
|
if (sz < 0) {
|
|
|
|
return false;
|
|
|
|
}
|
2016-02-28 09:34:43 +08:00
|
|
|
writtenSz += sz;
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2022-11-23 05:15:01 +08:00
|
|
|
bool writeBufToFile(
|
|
|
|
const char* filename, const void* buf, size_t len, int open_flags, bool log_errors) {
|
2016-05-09 21:16:26 +08:00
|
|
|
int fd;
|
|
|
|
TEMP_FAILURE_RETRY(fd = open(filename, open_flags, 0644));
|
2016-02-28 09:34:43 +08:00
|
|
|
if (fd == -1) {
|
2022-11-10 12:43:44 +08:00
|
|
|
if (log_errors) {
|
|
|
|
PLOG_E("Couldn't open '%s' for writing", filename);
|
|
|
|
}
|
2016-02-28 09:34:43 +08:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2018-02-12 22:17:33 +08:00
|
|
|
if (!writeToFd(fd, buf, len)) {
|
2022-11-10 12:43:44 +08:00
|
|
|
if (log_errors) {
|
2022-11-23 05:15:01 +08:00
|
|
|
PLOG_E(
|
|
|
|
"Couldn't write '%zu' bytes to file '%s' (fd='%d')", len, filename, fd);
|
2022-11-10 12:43:44 +08:00
|
|
|
}
|
2016-07-29 21:38:22 +08:00
|
|
|
close(fd);
|
2018-02-17 22:27:00 +08:00
|
|
|
if (open_flags & O_CREAT) {
|
|
|
|
unlink(filename);
|
|
|
|
}
|
2016-02-28 09:34:43 +08:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
LOG_D("Written '%zu' bytes to '%s'", len, filename);
|
|
|
|
|
2016-07-29 21:38:22 +08:00
|
|
|
close(fd);
|
2016-02-28 09:34:43 +08:00
|
|
|
return true;
|
|
|
|
}
|
2016-08-19 00:59:06 +08:00
|
|
|
|
2018-02-10 01:45:50 +08:00
|
|
|
bool createDirRecursively(const char* dir) {
|
2016-08-19 03:04:25 +08:00
|
|
|
if (dir[0] != '/') {
|
|
|
|
LOG_W("The directory path must start with '/': '%s' provided", dir);
|
|
|
|
return false;
|
|
|
|
}
|
2016-08-19 00:59:06 +08:00
|
|
|
|
2019-01-06 07:03:36 +08:00
|
|
|
int prev_dir_fd = TEMP_FAILURE_RETRY(open("/", O_RDONLY | O_CLOEXEC | O_DIRECTORY));
|
2016-08-19 03:04:25 +08:00
|
|
|
if (prev_dir_fd == -1) {
|
2017-07-02 09:39:56 +08:00
|
|
|
PLOG_W("open('/', O_RDONLY | O_CLOEXEC)");
|
2016-08-19 03:04:25 +08:00
|
|
|
return false;
|
2016-08-19 00:59:06 +08:00
|
|
|
}
|
|
|
|
|
2016-08-19 03:04:25 +08:00
|
|
|
char path[PATH_MAX];
|
2024-03-14 23:39:17 +08:00
|
|
|
snprintf(path, sizeof(path), "%s/", dir);
|
2017-10-09 05:00:45 +08:00
|
|
|
char* curr = path;
|
2016-08-19 00:59:06 +08:00
|
|
|
for (;;) {
|
|
|
|
while (*curr == '/') {
|
|
|
|
curr++;
|
|
|
|
}
|
|
|
|
|
2017-10-09 05:00:45 +08:00
|
|
|
char* next = strchr(curr, '/');
|
2023-10-20 20:15:36 +08:00
|
|
|
if (next == nullptr) {
|
2016-08-19 00:59:06 +08:00
|
|
|
close(prev_dir_fd);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
*next = '\0';
|
|
|
|
|
|
|
|
if (mkdirat(prev_dir_fd, curr, 0755) == -1 && errno != EEXIST) {
|
2017-07-02 09:39:56 +08:00
|
|
|
PLOG_W("mkdir('%s', 0755)", curr);
|
2016-08-19 03:04:25 +08:00
|
|
|
close(prev_dir_fd);
|
2016-08-19 00:59:06 +08:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2017-02-15 05:14:08 +08:00
|
|
|
int dir_fd = TEMP_FAILURE_RETRY(openat(prev_dir_fd, curr, O_DIRECTORY | O_CLOEXEC));
|
2016-08-19 00:59:06 +08:00
|
|
|
if (dir_fd == -1) {
|
2017-07-02 09:39:56 +08:00
|
|
|
PLOG_W("openat('%d', '%s', O_DIRECTORY | O_CLOEXEC)", prev_dir_fd, curr);
|
2016-08-19 00:59:06 +08:00
|
|
|
close(prev_dir_fd);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
close(prev_dir_fd);
|
|
|
|
prev_dir_fd = dir_fd;
|
|
|
|
curr = next + 1;
|
|
|
|
}
|
|
|
|
}
|
2017-02-08 07:36:32 +08:00
|
|
|
|
2018-05-24 00:19:17 +08:00
|
|
|
std::string* StrAppend(std::string* str, const char* format, ...) {
|
|
|
|
char* strp;
|
|
|
|
|
|
|
|
va_list args;
|
|
|
|
va_start(args, format);
|
|
|
|
int ret = vasprintf(&strp, format, args);
|
|
|
|
va_end(args);
|
|
|
|
|
|
|
|
if (ret == -1) {
|
|
|
|
PLOG_E("Memory allocation failed during asprintf()");
|
|
|
|
str->append(" [ERROR: mem_allocation_failed] ");
|
|
|
|
return str;
|
|
|
|
}
|
|
|
|
|
|
|
|
str->append(strp, ret);
|
|
|
|
free(strp);
|
2018-06-16 08:16:24 +08:00
|
|
|
return str;
|
|
|
|
}
|
|
|
|
|
|
|
|
std::string StrPrintf(const char* format, ...) {
|
|
|
|
char* strp;
|
|
|
|
|
|
|
|
va_list args;
|
|
|
|
va_start(args, format);
|
|
|
|
int ret = vasprintf(&strp, format, args);
|
|
|
|
va_end(args);
|
|
|
|
|
|
|
|
if (ret == -1) {
|
|
|
|
PLOG_E("Memory allocation failed during asprintf()");
|
|
|
|
return "[ERROR: mem_allocation_failed]";
|
|
|
|
}
|
|
|
|
|
|
|
|
std::string str(strp, ret);
|
|
|
|
free(strp);
|
2018-05-24 00:19:17 +08:00
|
|
|
return str;
|
|
|
|
}
|
|
|
|
|
2022-08-09 18:05:33 +08:00
|
|
|
const std::string StrQuote(const std::string& str) {
|
|
|
|
std::ostringstream ss;
|
|
|
|
ss << std::quoted(str, '\'');
|
|
|
|
return ss.str();
|
|
|
|
}
|
|
|
|
|
2018-02-10 01:45:50 +08:00
|
|
|
bool isANumber(const char* s) {
|
2018-02-12 23:28:45 +08:00
|
|
|
for (size_t i = 0; s[i]; s++) {
|
2017-05-27 05:07:47 +08:00
|
|
|
if (!isdigit(s[i]) && s[i] != 'x') {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
2017-06-19 23:01:50 +08:00
|
|
|
|
2023-10-22 00:37:57 +08:00
|
|
|
bool StrEq(const std::string_view& s1, const std::string_view& s2) {
|
|
|
|
return (s1 == s2);
|
|
|
|
}
|
|
|
|
|
2017-06-19 23:01:50 +08:00
|
|
|
static __thread pthread_once_t rndThreadOnce = PTHREAD_ONCE_INIT;
|
|
|
|
static __thread uint64_t rndX;
|
|
|
|
|
|
|
|
/* MMIX LCG PRNG */
|
|
|
|
static const uint64_t a = 6364136223846793005ULL;
|
|
|
|
static const uint64_t c = 1442695040888963407ULL;
|
|
|
|
|
2018-02-10 01:45:50 +08:00
|
|
|
static void rndInitThread(void) {
|
2017-06-22 01:18:02 +08:00
|
|
|
#if defined(__NR_getrandom)
|
2023-09-15 21:38:37 +08:00
|
|
|
if (TEMP_FAILURE_RETRY(util::syscall(__NR_getrandom, (uintptr_t)&rndX, sizeof(rndX), 0)) ==
|
|
|
|
sizeof(rndX)) {
|
2017-06-22 01:18:02 +08:00
|
|
|
return;
|
|
|
|
}
|
2017-10-09 05:00:45 +08:00
|
|
|
#endif /* defined(__NR_getrandom) */
|
2019-04-18 05:10:18 +08:00
|
|
|
int fd = TEMP_FAILURE_RETRY(open("/dev/urandom", O_RDONLY | O_CLOEXEC));
|
2017-06-19 23:01:50 +08:00
|
|
|
if (fd == -1) {
|
2023-09-20 02:31:57 +08:00
|
|
|
PLOG_D("Couldn't open /dev/urandom for reading. Using gettimeofday "
|
|
|
|
"fall-back");
|
2017-06-22 01:18:02 +08:00
|
|
|
struct timeval tv;
|
|
|
|
gettimeofday(&tv, NULL);
|
2017-10-09 05:00:45 +08:00
|
|
|
rndX = tv.tv_usec + ((uint64_t)tv.tv_sec << 32);
|
2017-06-22 01:18:02 +08:00
|
|
|
return;
|
2017-06-19 23:01:50 +08:00
|
|
|
}
|
2018-02-10 01:45:50 +08:00
|
|
|
if (readFromFd(fd, (uint8_t*)&rndX, sizeof(rndX)) != sizeof(rndX)) {
|
2017-06-19 23:01:50 +08:00
|
|
|
PLOG_F("Couldn't read '%zu' bytes from /dev/urandom", sizeof(rndX));
|
|
|
|
close(fd);
|
|
|
|
}
|
|
|
|
close(fd);
|
|
|
|
}
|
|
|
|
|
2018-02-10 01:45:50 +08:00
|
|
|
uint64_t rnd64(void) {
|
|
|
|
pthread_once(&rndThreadOnce, rndInitThread);
|
2017-06-19 23:01:50 +08:00
|
|
|
rndX = a * rndX + c;
|
|
|
|
return rndX;
|
|
|
|
}
|
2017-06-20 06:16:38 +08:00
|
|
|
|
2018-02-11 04:19:47 +08:00
|
|
|
const std::string sigName(int signo) {
|
|
|
|
std::string res;
|
2017-09-29 19:07:42 +08:00
|
|
|
|
2018-05-22 20:27:18 +08:00
|
|
|
struct {
|
2017-10-09 05:03:02 +08:00
|
|
|
const int signo;
|
|
|
|
const char* const name;
|
2018-05-22 20:27:18 +08:00
|
|
|
} static const sigNames[] = {
|
2023-09-15 14:47:16 +08:00
|
|
|
NS_VALSTR_STRUCT(SIGHUP),
|
2017-10-26 06:26:02 +08:00
|
|
|
NS_VALSTR_STRUCT(SIGINT),
|
2023-09-15 14:47:16 +08:00
|
|
|
NS_VALSTR_STRUCT(SIGQUIT),
|
2017-10-26 06:26:02 +08:00
|
|
|
NS_VALSTR_STRUCT(SIGILL),
|
2023-09-15 14:47:16 +08:00
|
|
|
NS_VALSTR_STRUCT(SIGTRAP),
|
2017-10-26 06:26:02 +08:00
|
|
|
NS_VALSTR_STRUCT(SIGABRT),
|
2023-09-15 14:47:16 +08:00
|
|
|
NS_VALSTR_STRUCT(SIGIOT),
|
|
|
|
NS_VALSTR_STRUCT(SIGBUS),
|
2017-10-26 06:26:02 +08:00
|
|
|
NS_VALSTR_STRUCT(SIGFPE),
|
|
|
|
NS_VALSTR_STRUCT(SIGKILL),
|
2023-09-15 14:47:16 +08:00
|
|
|
NS_VALSTR_STRUCT(SIGUSR1),
|
|
|
|
NS_VALSTR_STRUCT(SIGSEGV),
|
|
|
|
NS_VALSTR_STRUCT(SIGUSR2),
|
2017-10-26 06:26:02 +08:00
|
|
|
NS_VALSTR_STRUCT(SIGPIPE),
|
|
|
|
NS_VALSTR_STRUCT(SIGALRM),
|
2023-09-15 14:47:16 +08:00
|
|
|
NS_VALSTR_STRUCT(SIGTERM),
|
|
|
|
NS_VALSTR_STRUCT(SIGSTKFLT),
|
|
|
|
NS_VALSTR_STRUCT(SIGCHLD),
|
|
|
|
NS_VALSTR_STRUCT(SIGCONT),
|
2017-10-26 06:26:02 +08:00
|
|
|
NS_VALSTR_STRUCT(SIGSTOP),
|
|
|
|
NS_VALSTR_STRUCT(SIGTSTP),
|
|
|
|
NS_VALSTR_STRUCT(SIGTTIN),
|
|
|
|
NS_VALSTR_STRUCT(SIGTTOU),
|
2023-09-15 14:47:16 +08:00
|
|
|
NS_VALSTR_STRUCT(SIGURG),
|
2017-10-26 06:26:02 +08:00
|
|
|
NS_VALSTR_STRUCT(SIGXCPU),
|
|
|
|
NS_VALSTR_STRUCT(SIGXFSZ),
|
|
|
|
NS_VALSTR_STRUCT(SIGVTALRM),
|
|
|
|
NS_VALSTR_STRUCT(SIGPROF),
|
|
|
|
NS_VALSTR_STRUCT(SIGWINCH),
|
2023-09-15 14:47:16 +08:00
|
|
|
NS_VALSTR_STRUCT(SIGPOLL),
|
2023-08-29 15:09:51 +08:00
|
|
|
NS_VALSTR_STRUCT(SIGPWR),
|
2023-09-15 14:47:16 +08:00
|
|
|
NS_VALSTR_STRUCT(SIGSYS),
|
2017-10-09 05:03:02 +08:00
|
|
|
};
|
2017-09-29 19:07:42 +08:00
|
|
|
|
2018-05-22 20:27:18 +08:00
|
|
|
for (const auto& i : sigNames) {
|
|
|
|
if (signo == i.signo) {
|
|
|
|
res.append(i.name);
|
2018-02-11 04:19:47 +08:00
|
|
|
return res;
|
2017-09-29 19:07:42 +08:00
|
|
|
}
|
2017-06-20 06:16:38 +08:00
|
|
|
}
|
2017-09-29 19:07:42 +08:00
|
|
|
|
2023-09-15 14:47:16 +08:00
|
|
|
if (signo >= SIGRTMIN) {
|
2018-02-11 04:19:47 +08:00
|
|
|
res.append("SIG");
|
|
|
|
res.append(std::to_string(signo));
|
|
|
|
res.append("-RTMIN+");
|
|
|
|
res.append(std::to_string(signo - SIGRTMIN));
|
|
|
|
return res;
|
2017-06-22 00:46:19 +08:00
|
|
|
}
|
2018-02-11 04:19:47 +08:00
|
|
|
|
|
|
|
res.append("SIGUNKNOWN(");
|
|
|
|
res.append(std::to_string(signo));
|
|
|
|
res.append(")");
|
|
|
|
return res;
|
2017-06-22 00:46:19 +08:00
|
|
|
}
|
|
|
|
|
2023-10-10 07:17:42 +08:00
|
|
|
const std::string rLimName(int res) {
|
|
|
|
std::string ret;
|
|
|
|
|
|
|
|
struct {
|
|
|
|
const int res;
|
|
|
|
const char* const name;
|
|
|
|
} static const rLimNames[] = {
|
|
|
|
NS_VALSTR_STRUCT(RLIMIT_CPU),
|
|
|
|
NS_VALSTR_STRUCT(RLIMIT_FSIZE),
|
|
|
|
NS_VALSTR_STRUCT(RLIMIT_DATA),
|
|
|
|
NS_VALSTR_STRUCT(RLIMIT_STACK),
|
|
|
|
NS_VALSTR_STRUCT(RLIMIT_CORE),
|
|
|
|
NS_VALSTR_STRUCT(RLIMIT_RSS),
|
|
|
|
NS_VALSTR_STRUCT(RLIMIT_NOFILE),
|
|
|
|
NS_VALSTR_STRUCT(RLIMIT_AS),
|
|
|
|
NS_VALSTR_STRUCT(RLIMIT_NPROC),
|
|
|
|
NS_VALSTR_STRUCT(RLIMIT_MEMLOCK),
|
|
|
|
NS_VALSTR_STRUCT(RLIMIT_LOCKS),
|
|
|
|
NS_VALSTR_STRUCT(RLIMIT_SIGPENDING),
|
|
|
|
NS_VALSTR_STRUCT(RLIMIT_MSGQUEUE),
|
|
|
|
NS_VALSTR_STRUCT(RLIMIT_NICE),
|
|
|
|
NS_VALSTR_STRUCT(RLIMIT_RTPRIO),
|
|
|
|
NS_VALSTR_STRUCT(RLIMIT_RTTIME),
|
|
|
|
};
|
|
|
|
|
|
|
|
for (const auto& i : rLimNames) {
|
|
|
|
if (res == i.res) {
|
|
|
|
ret.append(i.name);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
ret.append("RLIMITUNKNOWN(");
|
|
|
|
ret.append(std::to_string(res));
|
|
|
|
ret.append(")");
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2018-02-11 04:19:47 +08:00
|
|
|
const std::string timeToStr(time_t t) {
|
|
|
|
char timestr[128];
|
2017-06-22 00:46:19 +08:00
|
|
|
struct tm utctime;
|
|
|
|
localtime_r(&t, &utctime);
|
|
|
|
if (strftime(timestr, sizeof(timestr) - 1, "%FT%T%z", &utctime) == 0) {
|
|
|
|
return "[Time conv error]";
|
2017-06-20 06:16:38 +08:00
|
|
|
}
|
2017-06-22 00:46:19 +08:00
|
|
|
return timestr;
|
2017-06-20 06:16:38 +08:00
|
|
|
}
|
2018-02-10 01:45:50 +08:00
|
|
|
|
2018-02-20 21:16:28 +08:00
|
|
|
std::vector<std::string> strSplit(const std::string str, char delim) {
|
|
|
|
std::vector<std::string> vec;
|
2018-02-11 21:56:30 +08:00
|
|
|
std::istringstream stream(str);
|
|
|
|
for (std::string word; std::getline(stream, word, delim);) {
|
2018-02-20 21:16:28 +08:00
|
|
|
vec.push_back(word);
|
2018-02-11 21:56:30 +08:00
|
|
|
}
|
2018-02-20 21:16:28 +08:00
|
|
|
return vec;
|
2018-02-11 21:56:30 +08:00
|
|
|
}
|
|
|
|
|
2019-01-22 05:25:37 +08:00
|
|
|
long syscall(long sysno, uintptr_t a0, uintptr_t a1, uintptr_t a2, uintptr_t a3, uintptr_t a4,
|
|
|
|
uintptr_t a5) {
|
2019-01-22 05:42:34 +08:00
|
|
|
return ::syscall(sysno, a0, a1, a2, a3, a4, a5);
|
2019-01-22 05:25:37 +08:00
|
|
|
}
|
|
|
|
|
2023-09-30 00:11:40 +08:00
|
|
|
long setrlimit(int res, const struct rlimit64& newlim) {
|
|
|
|
return util::syscall(__NR_prlimit64, 0, res, (uintptr_t)&newlim, (uintptr_t) nullptr);
|
|
|
|
}
|
|
|
|
|
2023-12-03 06:24:16 +08:00
|
|
|
long getrlimit(int res, struct rlimit64* curlim) {
|
|
|
|
*curlim = {};
|
2023-09-30 00:11:40 +08:00
|
|
|
return util::syscall(__NR_prlimit64, 0, res, (uintptr_t) nullptr, (uintptr_t)curlim);
|
|
|
|
}
|
|
|
|
|
2018-02-10 01:45:50 +08:00
|
|
|
} // namespace util
|