You've already forked ReZygisk
mirror of
https://github.com/PerformanC/ReZygisk.git
synced 2025-09-06 06:37:01 +00:00
improve: port common code to C
This commit ports even more C++ code to C99, now, the codes available in the "common" folder.
This commit is contained in:
@@ -0,0 +1,365 @@
|
||||
// #include <unistd.h>
|
||||
// #include <sys/types.h>
|
||||
// #include <sys/stat.h>
|
||||
// #include <dirent.h>
|
||||
// #include <fcntl.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdbool.h>
|
||||
#include <sys/socket.h>
|
||||
|
||||
#include <linux/un.h>
|
||||
|
||||
#include "logging.h"
|
||||
#include "socket_utils.h"
|
||||
|
||||
#include "daemon.h"
|
||||
|
||||
char daemon_path[PATH_MAX];
|
||||
|
||||
void rezygiskd_init(const char *path) {
|
||||
snprintf(daemon_path, sizeof(daemon_path), "%s/%s", path, SOCKET_FILE_NAME);
|
||||
}
|
||||
|
||||
void rezygiskd_get_path(char *buf, size_t buf_size) {
|
||||
size_t fileless_daemon_path = strlen(daemon_path) - strlen("/") - strlen(SOCKET_FILE_NAME);
|
||||
|
||||
strncpy(buf, daemon_path, buf_size > fileless_daemon_path ? fileless_daemon_path : buf_size);
|
||||
buf[fileless_daemon_path] = '\0';
|
||||
}
|
||||
|
||||
int rezygiskd_connect(uint8_t retry) {
|
||||
retry++;
|
||||
|
||||
int fd = socket(PF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0);
|
||||
if (fd == -1) {
|
||||
PLOGE("socket create");
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
struct sockaddr_un addr = {
|
||||
.sun_family = AF_UNIX,
|
||||
.sun_path = { 0 }
|
||||
};
|
||||
|
||||
/*
|
||||
INFO: Application must assume that sun_path can hold _POSIX_PATH_MAX characters.
|
||||
|
||||
Sources:
|
||||
- https://pubs.opengroup.org/onlinepubs/009696699/basedefs/sys/un.h.html
|
||||
*/
|
||||
strcpy(addr.sun_path, daemon_path);
|
||||
socklen_t socklen = sizeof(addr);
|
||||
|
||||
while (--retry) {
|
||||
int ret = connect(fd, (struct sockaddr *)&addr, socklen);
|
||||
if (ret == 0) return fd;
|
||||
if (retry) {
|
||||
PLOGE("Retrying to connect to ReZygiskd, sleep 1s");
|
||||
|
||||
sleep(1);
|
||||
}
|
||||
}
|
||||
|
||||
close(fd);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
bool rezygiskd_ping() {
|
||||
int fd = rezygiskd_connect(5);
|
||||
if (fd == -1) {
|
||||
PLOGE("connection to ReZygiskd");
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
write_uint8_t(fd, (uint8_t)PingHeartbeat);
|
||||
|
||||
close(fd);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
uint32_t rezygiskd_get_process_flags(uid_t uid) {
|
||||
int fd = rezygiskd_connect(1);
|
||||
if (fd == -1) {
|
||||
PLOGE("connection to ReZygiskd");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
write_uint8_t(fd, (uint8_t)GetProcessFlags);
|
||||
write_uint32_t(fd, (uint32_t)uid);
|
||||
|
||||
uint32_t res = 0;
|
||||
read_uint32_t(fd, &res);
|
||||
|
||||
close(fd);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
void rezygiskd_get_info(struct rezygisk_info *info) {
|
||||
int fd = rezygiskd_connect(1);
|
||||
if (fd == -1) {
|
||||
PLOGE("connection to ReZygiskd");
|
||||
|
||||
info->running = false;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
info->running = true;
|
||||
|
||||
write_uint8_t(fd, (uint8_t)GetInfo);
|
||||
|
||||
uint32_t flags = 0;
|
||||
read_uint32_t(fd, &flags);
|
||||
|
||||
if (flags & (1 << 27)) info->root_impl = ROOT_IMPL_APATCH;
|
||||
else if (flags & (1 << 29)) info->root_impl = ROOT_IMPL_KERNELSU;
|
||||
else if (flags & (1 << 30)) info->root_impl = ROOT_IMPL_MAGISK;
|
||||
else info->root_impl = ROOT_IMPL_NONE;
|
||||
|
||||
read_uint32_t(fd, (uint32_t *)&info->pid);
|
||||
|
||||
read_size_t(fd, &info->modules->modules_count);
|
||||
if (info->modules->modules_count == 0) {
|
||||
info->modules->modules = NULL;
|
||||
|
||||
close(fd);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
info->modules->modules = (char **)malloc(sizeof(char *) * info->modules->modules_count);
|
||||
if (info->modules->modules == NULL) {
|
||||
PLOGE("allocating modules name memory");
|
||||
|
||||
free(info->modules);
|
||||
info->modules = NULL;
|
||||
info->modules->modules_count = 0;
|
||||
|
||||
close(fd);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < info->modules->modules_count; i++) {
|
||||
char *module_name = read_string(fd);
|
||||
if (module_name == NULL) {
|
||||
PLOGE("reading module name");
|
||||
|
||||
info->modules->modules_count = i;
|
||||
|
||||
free_rezygisk_info(info);
|
||||
|
||||
info->modules = NULL;
|
||||
info->modules->modules_count = 0;
|
||||
|
||||
close(fd);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
char module_path[PATH_MAX];
|
||||
snprintf(module_path, sizeof(module_path), "/data/adb/modules/%s/module.prop", module_name);
|
||||
|
||||
FILE *module_prop = fopen(module_path, "r");
|
||||
if (!module_prop) {
|
||||
PLOGE("failed to open module prop file %s", module_path);
|
||||
|
||||
info->modules->modules_count = i;
|
||||
|
||||
free_rezygisk_info(info);
|
||||
|
||||
info->modules = NULL;
|
||||
info->modules->modules_count = 0;
|
||||
|
||||
close(fd);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
char line[1024];
|
||||
while (fgets(line, sizeof(line), module_prop) != NULL) {
|
||||
if (strncmp(line, "name=", strlen("name=")) != 0) continue;
|
||||
|
||||
info->modules->modules[i] = strndup(line + 5, strlen(line) - 6);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
fclose(module_prop);
|
||||
}
|
||||
|
||||
close(fd);
|
||||
}
|
||||
|
||||
void free_rezygisk_info(struct rezygisk_info *info) {
|
||||
if (info->modules->modules) {
|
||||
for (size_t i = 0; i < info->modules->modules_count; i++) {
|
||||
free(info->modules->modules[i]);
|
||||
}
|
||||
|
||||
free(info->modules->modules);
|
||||
}
|
||||
|
||||
free(info->modules);
|
||||
}
|
||||
|
||||
bool rezygiskd_read_modules(struct zygisk_modules *modules) {
|
||||
int fd = rezygiskd_connect(1);
|
||||
if (fd == -1) {
|
||||
PLOGE("connection to ReZygiskd");
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
write_uint8_t(fd, (uint8_t)ReadModules);
|
||||
|
||||
size_t len = 0;
|
||||
read_size_t(fd, &len);
|
||||
|
||||
modules->modules = malloc(len * sizeof(char *));
|
||||
if (!modules->modules) {
|
||||
PLOGE("allocating modules name memory");
|
||||
|
||||
close(fd);
|
||||
|
||||
return false;
|
||||
}
|
||||
modules->modules_count = len;
|
||||
|
||||
for (size_t i = 0; i < len; i++) {
|
||||
char *lib_path = read_string(fd);
|
||||
if (!lib_path) {
|
||||
PLOGE("reading module lib_path");
|
||||
|
||||
close(fd);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
modules->modules[i] = lib_path;
|
||||
}
|
||||
|
||||
close(fd);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void free_modules(struct zygisk_modules *modules) {
|
||||
if (modules->modules) {
|
||||
for (size_t i = 0; i < modules->modules_count; i++) {
|
||||
free(modules->modules[i]);
|
||||
}
|
||||
|
||||
free(modules->modules);
|
||||
}
|
||||
}
|
||||
|
||||
int rezygiskd_connect_companion(size_t index) {
|
||||
int fd = rezygiskd_connect(1);
|
||||
if (fd == -1) {
|
||||
PLOGE("connection to ReZygiskd");
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
write_uint8_t(fd, (uint8_t)RequestCompanionSocket);
|
||||
write_size_t(fd, index);
|
||||
|
||||
uint8_t res = 0;
|
||||
read_uint8_t(fd, &res);
|
||||
|
||||
if (res == 1) return fd;
|
||||
else {
|
||||
close(fd);
|
||||
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
int rezygiskd_get_module_dir(size_t index) {
|
||||
int fd = rezygiskd_connect(1);
|
||||
if (fd == -1) {
|
||||
PLOGE("connection to ReZygiskd");
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
write_uint8_t(fd, (uint8_t)GetModuleDir);
|
||||
write_size_t(fd, index);
|
||||
|
||||
int dirfd = read_fd(fd);
|
||||
|
||||
close(fd);
|
||||
|
||||
return dirfd;
|
||||
}
|
||||
|
||||
void rezygiskd_zygote_restart() {
|
||||
int fd = rezygiskd_connect(1);
|
||||
if (fd == -1) {
|
||||
if (errno == ENOENT) LOGD("Could not notify ZygoteRestart (maybe it hasn't been created)");
|
||||
else PLOGE("Could not notify ZygoteRestart");
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (!write_uint8_t(fd, (uint8_t)ZygoteRestart))
|
||||
PLOGE("Failed to request ZygoteRestart");
|
||||
|
||||
close(fd);
|
||||
}
|
||||
|
||||
void rezygiskd_system_server_started() {
|
||||
int fd = rezygiskd_connect(1);
|
||||
if (fd == -1) {
|
||||
PLOGE("Failed to report system server started");
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (!write_uint8_t(fd, (uint8_t)SystemServerStarted))
|
||||
PLOGE("Failed to request SystemServerStarted");
|
||||
|
||||
close(fd);
|
||||
}
|
||||
|
||||
bool rezygiskd_update_mns(enum mount_namespace_state nms_state, char *buf, size_t buf_size) {
|
||||
int fd = rezygiskd_connect(1);
|
||||
if (fd == -1) {
|
||||
PLOGE("connection to ReZygiskd");
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
write_uint8_t(fd, (uint8_t)UpdateMountNamespace);
|
||||
write_uint32_t(fd, (uint32_t)getpid());
|
||||
write_uint8_t(fd, (uint8_t)nms_state);
|
||||
|
||||
uint32_t target_pid = 0;
|
||||
read_uint32_t(fd, &target_pid);
|
||||
if (target_pid == 0) {
|
||||
close(fd);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
int target_fd = read_fd(fd);
|
||||
if (target_fd == -1) {
|
||||
close(fd);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
snprintf(buf, buf_size, "/proc/%u/fd/%u", target_pid, target_fd);
|
||||
|
||||
close(fd);
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -1,279 +0,0 @@
|
||||
#include <linux/un.h>
|
||||
#include <sys/socket.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <dirent.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
#include "daemon.h"
|
||||
#include "socket_utils.h"
|
||||
|
||||
namespace zygiskd {
|
||||
static std::string TMP_PATH;
|
||||
void Init(const char *path) {
|
||||
TMP_PATH = path;
|
||||
}
|
||||
|
||||
std::string GetTmpPath() {
|
||||
return TMP_PATH;
|
||||
}
|
||||
|
||||
int Connect(uint8_t retry) {
|
||||
retry++;
|
||||
|
||||
int fd = socket(PF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0);
|
||||
struct sockaddr_un addr = {
|
||||
.sun_family = AF_UNIX,
|
||||
.sun_path = { 0 }
|
||||
};
|
||||
|
||||
auto socket_path = TMP_PATH + kCPSocketName;
|
||||
strcpy(addr.sun_path, socket_path.c_str());
|
||||
socklen_t socklen = sizeof(addr);
|
||||
|
||||
while (--retry) {
|
||||
int r = connect(fd, (struct sockaddr *)&addr, socklen);
|
||||
if (r == 0) return fd;
|
||||
if (retry) {
|
||||
PLOGE("Retrying to connect to zygiskd, sleep 1s");
|
||||
|
||||
sleep(1);
|
||||
}
|
||||
}
|
||||
|
||||
close(fd);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
bool PingHeartbeat() {
|
||||
int fd = Connect(5);
|
||||
if (fd == -1) {
|
||||
PLOGE("Connect to zygiskd");
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
socket_utils::write_u8(fd, (uint8_t) SocketAction::PingHeartBeat);
|
||||
|
||||
close(fd);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
uint32_t GetProcessFlags(uid_t uid) {
|
||||
int fd = Connect(1);
|
||||
if (fd == -1) {
|
||||
PLOGE("GetProcessFlags");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
socket_utils::write_u8(fd, (uint8_t) SocketAction::GetProcessFlags);
|
||||
socket_utils::write_u32(fd, uid);
|
||||
|
||||
uint32_t res = socket_utils::read_u32(fd);
|
||||
|
||||
close(fd);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
std::vector<ModuleInfo> ReadModules() {
|
||||
std::vector<ModuleInfo> modules;
|
||||
int fd = Connect(1);
|
||||
if (fd == -1) {
|
||||
PLOGE("ReadModules");
|
||||
|
||||
return modules;
|
||||
}
|
||||
|
||||
socket_utils::write_u8(fd, (uint8_t) SocketAction::ReadModules);
|
||||
size_t len = socket_utils::read_usize(fd);
|
||||
for (size_t i = 0; i < len; i++) {
|
||||
std::string lib_path = socket_utils::read_string(fd);
|
||||
std::string name = socket_utils::read_string(fd);
|
||||
modules.emplace_back(lib_path, name);
|
||||
}
|
||||
|
||||
close(fd);
|
||||
|
||||
return modules;
|
||||
}
|
||||
|
||||
int ConnectCompanion(size_t index) {
|
||||
int fd = Connect(1);
|
||||
if (fd == -1) {
|
||||
PLOGE("ConnectCompanion");
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
socket_utils::write_u8(fd, (uint8_t) SocketAction::RequestCompanionSocket);
|
||||
socket_utils::write_usize(fd, index);
|
||||
|
||||
uint8_t res = socket_utils::read_u8(fd);
|
||||
|
||||
if (res == 1) return fd;
|
||||
else {
|
||||
close(fd);
|
||||
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
int GetModuleDir(size_t index) {
|
||||
int fd = Connect(1);
|
||||
if (fd == -1) {
|
||||
PLOGE("GetModuleDir");
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
socket_utils::write_u8(fd, (uint8_t) SocketAction::GetModuleDir);
|
||||
socket_utils::write_usize(fd, index);
|
||||
int nfd = socket_utils::recv_fd(fd);
|
||||
|
||||
close(fd);
|
||||
|
||||
return nfd;
|
||||
}
|
||||
|
||||
void ZygoteRestart() {
|
||||
int fd = Connect(1);
|
||||
if (fd == -1) {
|
||||
if (errno == ENOENT) LOGD("Could not notify ZygoteRestart (maybe it hasn't been created)");
|
||||
else PLOGE("Could not notify ZygoteRestart");
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (!socket_utils::write_u8(fd, (uint8_t) SocketAction::ZygoteRestart))
|
||||
PLOGE("Failed to request ZygoteRestart");
|
||||
|
||||
close(fd);
|
||||
}
|
||||
|
||||
void SystemServerStarted() {
|
||||
int fd = Connect(1);
|
||||
if (fd == -1) PLOGE("Failed to report system server started");
|
||||
else {
|
||||
if (!socket_utils::write_u8(fd, (uint8_t) SocketAction::SystemServerStarted))
|
||||
PLOGE("Failed to report system server started");
|
||||
}
|
||||
|
||||
close(fd);
|
||||
}
|
||||
|
||||
void GetInfo(struct zygote_info *info) {
|
||||
/* TODO: Optimize and avoid re-connect twice here */
|
||||
int fd = Connect(1);
|
||||
|
||||
if (fd != -1) {
|
||||
info->running = true;
|
||||
|
||||
socket_utils::write_u8(fd, (uint8_t) SocketAction::GetInfo);
|
||||
|
||||
int flags = socket_utils::read_u32(fd);
|
||||
|
||||
if (flags & (1 << 27)) {
|
||||
info->root_impl = ZYGOTE_ROOT_IMPL_APATCH;
|
||||
} else if (flags & (1 << 29)) {
|
||||
info->root_impl = ZYGOTE_ROOT_IMPL_KERNELSU;
|
||||
} else if (flags & (1 << 30)) {
|
||||
info->root_impl = ZYGOTE_ROOT_IMPL_MAGISK;
|
||||
} else {
|
||||
info->root_impl = ZYGOTE_ROOT_IMPL_NONE;
|
||||
}
|
||||
|
||||
info->pid = socket_utils::read_u32(fd);
|
||||
|
||||
info->modules = (struct zygote_modules *)malloc(sizeof(struct zygote_modules));
|
||||
if (info->modules == NULL) {
|
||||
info->modules->modules_count = 0;
|
||||
|
||||
close(fd);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
info->modules->modules_count = socket_utils::read_usize(fd);
|
||||
|
||||
if (info->modules->modules_count == 0) {
|
||||
info->modules->modules = NULL;
|
||||
|
||||
close(fd);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
info->modules->modules = (char **)malloc(sizeof(char *) * info->modules->modules_count);
|
||||
if (info->modules->modules == NULL) {
|
||||
free(info->modules);
|
||||
info->modules = NULL;
|
||||
info->modules->modules_count = 0;
|
||||
|
||||
close(fd);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < info->modules->modules_count; i++) {
|
||||
/* INFO by ThePedroo: Ugly solution to read with std::string existance (temporary) */
|
||||
std::string name = socket_utils::read_string(fd);
|
||||
|
||||
char module_path[PATH_MAX];
|
||||
snprintf(module_path, sizeof(module_path), "/data/adb/modules/%s/module.prop", name.c_str());
|
||||
|
||||
FILE *module_prop = fopen(module_path, "r");
|
||||
if (module_prop == NULL) {
|
||||
info->modules->modules[i] = strdup(name.c_str());
|
||||
} else {
|
||||
char line[1024];
|
||||
while (fgets(line, sizeof(line), module_prop) != NULL) {
|
||||
if (strncmp(line, "name=", 5) == 0) {
|
||||
info->modules->modules[i] = strndup(line + 5, strlen(line) - 6);
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
fclose(module_prop);
|
||||
}
|
||||
}
|
||||
|
||||
close(fd);
|
||||
} else info->running = false;
|
||||
}
|
||||
|
||||
std::string UpdateMountNamespace(enum mount_namespace_state nms_state) {
|
||||
int fd = Connect(1);
|
||||
if (fd == -1) {
|
||||
PLOGE("UpdateMountNamespace");
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
socket_utils::write_u8(fd, (uint8_t) SocketAction::UpdateMountNamespace);
|
||||
socket_utils::write_u32(fd, getpid());
|
||||
socket_utils::write_u8(fd, (uint8_t)nms_state);
|
||||
|
||||
uint32_t target_pid = socket_utils::read_u32(fd);
|
||||
int target_fd = 0;
|
||||
|
||||
if (target_pid == 0) goto error;
|
||||
|
||||
target_fd = (int)socket_utils::read_u32(fd);
|
||||
if (target_fd == 0) goto error;
|
||||
|
||||
close(fd);
|
||||
|
||||
return "/proc/" + std::to_string(target_pid) + "/fd/" + std::to_string(target_fd);
|
||||
|
||||
error:
|
||||
close(fd);
|
||||
|
||||
return "";
|
||||
}
|
||||
}
|
||||
@@ -1,119 +0,0 @@
|
||||
#include <sys/sysmacros.h>
|
||||
|
||||
#include "files.hpp"
|
||||
#include "misc.hpp"
|
||||
|
||||
using namespace std::string_view_literals;
|
||||
|
||||
void file_readline(bool trim, FILE *fp, const std::function<bool(std::string_view)> &fn) {
|
||||
size_t len = 1024;
|
||||
char *buf = (char *) malloc(len);
|
||||
char *start;
|
||||
ssize_t read;
|
||||
while ((read = getline(&buf, &len, fp)) >= 0) {
|
||||
start = buf;
|
||||
if (trim) {
|
||||
while (read && "\n\r "sv.find(buf[read - 1]) != std::string::npos)
|
||||
--read;
|
||||
buf[read] = '\0';
|
||||
while (*start == ' ')
|
||||
++start;
|
||||
}
|
||||
if (!fn(start))
|
||||
break;
|
||||
}
|
||||
free(buf);
|
||||
}
|
||||
|
||||
void file_readline(const char *file, const std::function<bool(std::string_view)> &fn) {
|
||||
FILE *fp = fopen(file, "re");
|
||||
if (!fp) {
|
||||
PLOGE("Failed to open file %s", file);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
file_readline(false, fp, fn);
|
||||
|
||||
fclose(fp);
|
||||
}
|
||||
|
||||
std::vector<mount_info> parse_mount_info(const char *pid) {
|
||||
char buf[PATH_MAX] = {};
|
||||
snprintf(buf, sizeof(buf), "/proc/%s/mountinfo", pid);
|
||||
std::vector<mount_info> result;
|
||||
|
||||
file_readline(buf, [&result](std::string_view line) -> bool {
|
||||
int root_start = 0, root_end = 0;
|
||||
int target_start = 0, target_end = 0;
|
||||
int vfs_option_start = 0, vfs_option_end = 0;
|
||||
int type_start = 0, type_end = 0;
|
||||
int source_start = 0, source_end = 0;
|
||||
int fs_option_start = 0, fs_option_end = 0;
|
||||
int optional_start = 0, optional_end = 0;
|
||||
unsigned int id, parent, maj, min;
|
||||
sscanf(line.data(),
|
||||
"%u " // (1) id
|
||||
"%u " // (2) parent
|
||||
"%u:%u " // (3) maj:min
|
||||
"%n%*s%n " // (4) mountroot
|
||||
"%n%*s%n " // (5) target
|
||||
"%n%*s%n" // (6) vfs options (fs-independent)
|
||||
"%n%*[^-]%n - " // (7) optional fields
|
||||
"%n%*s%n " // (8) FS type
|
||||
"%n%*s%n " // (9) source
|
||||
"%n%*s%n", // (10) fs options (fs specific)
|
||||
&id, &parent, &maj, &min, &root_start, &root_end, &target_start,
|
||||
&target_end, &vfs_option_start, &vfs_option_end,
|
||||
&optional_start, &optional_end, &type_start, &type_end,
|
||||
&source_start, &source_end, &fs_option_start, &fs_option_end);
|
||||
|
||||
auto root = line.substr(root_start, root_end - root_start);
|
||||
auto target = line.substr(target_start, target_end - target_start);
|
||||
auto vfs_option =
|
||||
line.substr(vfs_option_start, vfs_option_end - vfs_option_start);
|
||||
++optional_start;
|
||||
--optional_end;
|
||||
auto optional = line.substr(
|
||||
optional_start,
|
||||
optional_end - optional_start > 0 ? optional_end - optional_start : 0);
|
||||
|
||||
auto type = line.substr(type_start, type_end - type_start);
|
||||
auto source = line.substr(source_start, source_end - source_start);
|
||||
auto fs_option =
|
||||
line.substr(fs_option_start, fs_option_end - fs_option_start);
|
||||
|
||||
unsigned int shared = 0;
|
||||
unsigned int master = 0;
|
||||
unsigned int propagate_from = 0;
|
||||
if (auto pos = optional.find("shared:"); pos != std::string_view::npos) {
|
||||
shared = parse_int(optional.substr(pos + 7));
|
||||
}
|
||||
if (auto pos = optional.find("master:"); pos != std::string_view::npos) {
|
||||
master = parse_int(optional.substr(pos + 7));
|
||||
}
|
||||
if (auto pos = optional.find("propagate_from:");
|
||||
pos != std::string_view::npos) {
|
||||
propagate_from = parse_int(optional.substr(pos + 15));
|
||||
}
|
||||
|
||||
result.emplace_back(mount_info {
|
||||
.id = id,
|
||||
.parent = parent,
|
||||
.device = static_cast<dev_t>(makedev(maj, min)),
|
||||
.root {root},
|
||||
.target {target},
|
||||
.vfs_option {vfs_option},
|
||||
.optional {
|
||||
.shared = shared,
|
||||
.master = master,
|
||||
.propagate_from = propagate_from,
|
||||
},
|
||||
.type {type},
|
||||
.source {source},
|
||||
.fs_option {fs_option},
|
||||
});
|
||||
return true;
|
||||
});
|
||||
return result;
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
int parse_int(const char *str) {
|
||||
int val = 0;
|
||||
|
||||
char *c = (char *)str;
|
||||
while (*c) {
|
||||
if (*c > '9' || *c < '0')
|
||||
return -1;
|
||||
|
||||
val = val * 10 + *c - '0';
|
||||
c++;
|
||||
}
|
||||
|
||||
return val;
|
||||
}
|
||||
@@ -1,49 +0,0 @@
|
||||
#include "misc.hpp"
|
||||
|
||||
int new_daemon_thread(thread_entry entry, void *arg) {
|
||||
pthread_t thread;
|
||||
pthread_attr_t attr;
|
||||
pthread_attr_init(&attr);
|
||||
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
|
||||
errno = pthread_create(&thread, &attr, entry, arg);
|
||||
if (errno) {
|
||||
PLOGE("pthread_create");
|
||||
}
|
||||
return errno;
|
||||
}
|
||||
|
||||
int parse_int(std::string_view s) {
|
||||
int val = 0;
|
||||
for (char c : s) {
|
||||
if (!c) break;
|
||||
if (c > '9' || c < '0')
|
||||
return -1;
|
||||
val = val * 10 + c - '0';
|
||||
}
|
||||
return val;
|
||||
}
|
||||
|
||||
std::list<std::string> split_str(std::string_view s, std::string_view delimiter) {
|
||||
std::list<std::string> ret;
|
||||
size_t pos = 0;
|
||||
while (pos < s.size()) {
|
||||
auto next = s.find(delimiter, pos);
|
||||
if (next == std::string_view::npos) {
|
||||
ret.emplace_back(s.substr(pos));
|
||||
break;
|
||||
}
|
||||
ret.emplace_back(s.substr(pos, next - pos));
|
||||
pos = next + delimiter.size();
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
std::string join_str(const std::list<std::string>& list, std::string_view delimiter) {
|
||||
std::string ret;
|
||||
for (auto& s : list) {
|
||||
if (!ret.empty())
|
||||
ret += delimiter;
|
||||
ret += s;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
@@ -0,0 +1,95 @@
|
||||
#include <stdlib.h>
|
||||
#include <errno.h>
|
||||
#include <sys/socket.h>
|
||||
|
||||
#include <unistd.h>
|
||||
|
||||
#include "logging.h"
|
||||
|
||||
#include "socket_utils.h"
|
||||
|
||||
/* TODO: Standardize how to log errors */
|
||||
int read_fd(int fd) {
|
||||
char cmsgbuf[CMSG_SPACE(sizeof(int))];
|
||||
|
||||
int cnt = 1;
|
||||
struct iovec iov = {
|
||||
.iov_base = &cnt,
|
||||
.iov_len = sizeof(cnt)
|
||||
};
|
||||
|
||||
struct msghdr msg = {
|
||||
.msg_iov = &iov,
|
||||
.msg_iovlen = 1,
|
||||
.msg_control = cmsgbuf,
|
||||
.msg_controllen = sizeof(cmsgbuf)
|
||||
};
|
||||
|
||||
ssize_t ret = recvmsg(fd, &msg, MSG_WAITALL);
|
||||
if (ret == -1) {
|
||||
PLOGE("recvmsg");
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
struct cmsghdr *cmsg = CMSG_FIRSTHDR(&msg);
|
||||
if (cmsg == NULL) {
|
||||
PLOGE("CMSG_FIRSTHDR");
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
int sendfd;
|
||||
memcpy(&sendfd, CMSG_DATA(cmsg), sizeof(int));
|
||||
|
||||
return sendfd;
|
||||
}
|
||||
|
||||
char *read_string(int fd) {
|
||||
size_t str_len = 0;
|
||||
ssize_t read_bytes = read(fd, &str_len, sizeof(size_t));
|
||||
if (read_bytes != (ssize_t)sizeof(size_t)) {
|
||||
LOGE("Failed to read string length: Not all bytes were read (%zd != %zu).\n", read_bytes, sizeof(size_t));
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
char *buf = malloc(str_len + 1);
|
||||
if (buf == NULL) {
|
||||
PLOGE("allocate memory for string");
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
read_bytes = read(fd, buf, str_len);
|
||||
if (read_bytes != (ssize_t)str_len) {
|
||||
LOGE("Failed to read string: Promised bytes doesn't exist (%zd != %zu).\n", read_bytes, str_len);
|
||||
|
||||
free(buf);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (str_len > 0) buf[str_len] = '\0';
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
#define write_func(type) \
|
||||
ssize_t write_## type(int fd, type val) { \
|
||||
return write(fd, &val, sizeof(type)); \
|
||||
}
|
||||
|
||||
#define read_func(type) \
|
||||
ssize_t read_## type(int fd, type *val) { \
|
||||
return read(fd, val, sizeof(type)); \
|
||||
}
|
||||
|
||||
write_func(uint8_t)
|
||||
read_func(uint8_t)
|
||||
|
||||
write_func(uint32_t)
|
||||
read_func(uint32_t)
|
||||
|
||||
write_func(size_t)
|
||||
read_func(size_t)
|
||||
@@ -1,137 +0,0 @@
|
||||
#include <cstddef>
|
||||
#include <sys/socket.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "socket_utils.h"
|
||||
|
||||
namespace socket_utils {
|
||||
ssize_t xread(int fd, void* buf, size_t count) {
|
||||
size_t read_sz = 0;
|
||||
ssize_t ret;
|
||||
do {
|
||||
ret = read(fd, (std::byte*) buf + read_sz, count - read_sz);
|
||||
if (ret < 0) {
|
||||
if (errno == EINTR) continue;
|
||||
PLOGE("read");
|
||||
return ret;
|
||||
}
|
||||
read_sz += ret;
|
||||
} while (read_sz != count && ret != 0);
|
||||
if (read_sz != count) {
|
||||
PLOGE("read (%zu != %zu)", count, read_sz);
|
||||
}
|
||||
return read_sz;
|
||||
}
|
||||
|
||||
size_t xwrite(int fd, const void* buf, size_t count) {
|
||||
size_t write_sz = 0;
|
||||
ssize_t ret;
|
||||
do {
|
||||
ret = write(fd, (std::byte*) buf + write_sz, count - write_sz);
|
||||
if (ret < 0) {
|
||||
if (errno == EINTR) continue;
|
||||
PLOGE("write");
|
||||
return write_sz;
|
||||
}
|
||||
write_sz += ret;
|
||||
} while (write_sz != count && ret != 0);
|
||||
if (write_sz != count) {
|
||||
PLOGE("write (%zu != %zu)", count, write_sz);
|
||||
}
|
||||
return write_sz;
|
||||
}
|
||||
|
||||
ssize_t xrecvmsg(int sockfd, struct msghdr* msg, int flags) {
|
||||
int rec = recvmsg(sockfd, msg, flags);
|
||||
if (rec < 0) PLOGE("recvmsg");
|
||||
return rec;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
inline T read_exact_or(int fd, T fail) {
|
||||
T res;
|
||||
return sizeof(T) == xread(fd, &res, sizeof(T)) ? res : fail;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
inline bool write_exact(int fd, T val) {
|
||||
return sizeof(T) == xwrite(fd, &val, sizeof(T));
|
||||
}
|
||||
|
||||
uint8_t read_u8(int fd) {
|
||||
return read_exact_or<uint8_t>(fd, 0);
|
||||
}
|
||||
|
||||
uint32_t read_u32(int fd) {
|
||||
return read_exact_or<uint32_t>(fd, 0);
|
||||
}
|
||||
|
||||
size_t read_usize(int fd) {
|
||||
return read_exact_or<size_t>(fd, 0);
|
||||
}
|
||||
|
||||
bool write_usize(int fd, size_t val) {
|
||||
return write_exact<size_t>(fd, val);
|
||||
}
|
||||
|
||||
std::string read_string(int fd) {
|
||||
size_t len = read_usize(fd);
|
||||
|
||||
char buf[len + 1];
|
||||
xread(fd, buf, len);
|
||||
|
||||
buf[len] = '\0';
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
bool write_u8(int fd, uint8_t val) {
|
||||
return write_exact<uint8_t>(fd, val);
|
||||
}
|
||||
|
||||
void* recv_fds(int sockfd, char* cmsgbuf, size_t bufsz, int cnt) {
|
||||
iovec iov = {
|
||||
.iov_base = &cnt,
|
||||
.iov_len = sizeof(cnt),
|
||||
};
|
||||
msghdr msg = {
|
||||
.msg_iov = &iov,
|
||||
.msg_iovlen = 1,
|
||||
.msg_control = cmsgbuf,
|
||||
.msg_controllen = bufsz
|
||||
};
|
||||
|
||||
xrecvmsg(sockfd, &msg, MSG_WAITALL);
|
||||
cmsghdr* cmsg = CMSG_FIRSTHDR(&msg);
|
||||
|
||||
if (msg.msg_controllen != bufsz ||
|
||||
cmsg == nullptr ||
|
||||
// TODO: pass from rust: 20, expected: 16
|
||||
// cmsg->cmsg_len != CMSG_LEN(sizeof(int) * cnt) ||
|
||||
cmsg->cmsg_level != SOL_SOCKET ||
|
||||
cmsg->cmsg_type != SCM_RIGHTS) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return CMSG_DATA(cmsg);
|
||||
}
|
||||
|
||||
int recv_fd(int sockfd) {
|
||||
char cmsgbuf[CMSG_SPACE(sizeof(int))];
|
||||
|
||||
void* data = recv_fds(sockfd, cmsgbuf, sizeof(cmsgbuf), 1);
|
||||
if (data == nullptr) return -1;
|
||||
|
||||
int result;
|
||||
memcpy(&result, data, sizeof(int));
|
||||
return result;
|
||||
}
|
||||
|
||||
bool write_u32(int fd, uint32_t val) {
|
||||
return write_exact<uint32_t>(fd, val);
|
||||
}
|
||||
|
||||
bool write_string(int fd, std::string_view str) {
|
||||
return write_usize(fd, str.size()) && str.size() == xwrite(fd, str.data(), str.size());
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user