mirror of
https://github.com/lxc/incus.git
synced 2026-02-05 09:46:19 +01:00
New clang-14 reports errors for directly casting from an integer to a pointer. Use uintptr_t to fix that problem and adhere to the casting rules. Fixes: https://github.com/lxc/incus/issues/1395 Signed-off-by: Christian Brauner <brauner@kernel.org>
233 lines
4.9 KiB
C
233 lines
4.9 KiB
C
#ifndef __INCUS_PROCESS_UTILS_H
|
|
#define __INCUS_PROCESS_UTILS_H
|
|
|
|
#ifndef _GNU_SOURCE
|
|
#define _GNU_SOURCE 1
|
|
#endif
|
|
#include <linux/sched.h>
|
|
#include <sched.h>
|
|
#include <inttypes.h>
|
|
#include <signal.h>
|
|
#include <stdbool.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <sys/prctl.h>
|
|
#include <sys/syscall.h>
|
|
#include <sys/wait.h>
|
|
#include <unistd.h>
|
|
|
|
#include "compiler.h"
|
|
#include "file_utils.h"
|
|
#include "memory_utils.h"
|
|
#include "syscall_numbers.h"
|
|
|
|
#ifndef PIDFD_THREAD
|
|
#define PIDFD_THREAD O_EXCL
|
|
#endif
|
|
|
|
static inline int incus_pidfd_open(pid_t pid, unsigned int flags)
|
|
{
|
|
return syscall(__NR_pidfd_open, pid, flags);
|
|
}
|
|
|
|
static inline int incus_pidfd_send_signal(int pidfd, int sig, siginfo_t *info,
|
|
unsigned int flags)
|
|
{
|
|
return syscall(__NR_pidfd_send_signal, pidfd, sig, info, flags);
|
|
}
|
|
|
|
static inline bool process_still_alive(int pidfd)
|
|
{
|
|
return incus_pidfd_send_signal(pidfd, 0, NULL, 0) == 0;
|
|
}
|
|
|
|
static inline int wait_for_pid(pid_t pid)
|
|
{
|
|
int status, ret;
|
|
|
|
again:
|
|
ret = waitpid(pid, &status, 0);
|
|
if (ret == -1) {
|
|
if (errno == EINTR)
|
|
goto again;
|
|
return -1;
|
|
}
|
|
if (ret != pid)
|
|
goto again;
|
|
if (!WIFEXITED(status) || WEXITSTATUS(status) != 0)
|
|
return -1;
|
|
return 0;
|
|
}
|
|
|
|
static inline int wait_for_pid_status_nointr(pid_t pid)
|
|
{
|
|
int status, ret;
|
|
|
|
again:
|
|
ret = waitpid(pid, &status, 0);
|
|
if (ret == -1) {
|
|
if (errno == EINTR)
|
|
goto again;
|
|
|
|
return -1;
|
|
}
|
|
|
|
if (ret != pid)
|
|
goto again;
|
|
|
|
return status;
|
|
}
|
|
|
|
static inline int append_null_to_list(void ***list)
|
|
{
|
|
int newentry = 0;
|
|
void **new_list;
|
|
|
|
if (*list)
|
|
for (; (*list)[newentry]; newentry++)
|
|
;
|
|
|
|
new_list = realloc(*list, (newentry + 2) * sizeof(void **));
|
|
if (!new_list)
|
|
return ret_errno(ENOMEM);
|
|
|
|
*list = new_list;
|
|
(*list)[newentry + 1] = NULL;
|
|
return newentry;
|
|
}
|
|
|
|
static inline int push_vargs(char ***list, char *entry)
|
|
{
|
|
__do_free char *copy = NULL;
|
|
int newentry;
|
|
|
|
copy = strdup(entry);
|
|
if (!copy)
|
|
return ret_errno(ENOMEM);
|
|
|
|
newentry = append_null_to_list((void ***)list);
|
|
if (newentry < 0)
|
|
return newentry;
|
|
|
|
(*list)[newentry] = move_ptr(copy);
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* Sets the process title to the specified title. Note that this may fail if
|
|
* the kernel doesn't support PR_SET_MM_MAP (kernels <3.18).
|
|
*/
|
|
static inline int setproctitle(char *title)
|
|
{
|
|
__do_fclose FILE *f = NULL;
|
|
int i, fd, len;
|
|
char *buf_ptr, *tmp_proctitle;
|
|
char buf[LXC_LINELEN];
|
|
int ret = 0;
|
|
ssize_t bytes_read = 0;
|
|
static char *proctitle = NULL;
|
|
|
|
/*
|
|
* We don't really need to know all of this stuff, but unfortunately
|
|
* PR_SET_MM_MAP requires us to set it all at once, so we have to
|
|
* figure it out anyway.
|
|
*/
|
|
uint64_t start_data, end_data, start_brk, start_code, end_code,
|
|
start_stack, arg_start, arg_end, env_start, env_end, brk_val;
|
|
struct prctl_mm_map prctl_map;
|
|
|
|
f = fopen("/proc/self/stat", "r");
|
|
if (!f)
|
|
return -1;
|
|
|
|
fd = fileno(f);
|
|
if (fd < 0)
|
|
return -1;
|
|
|
|
bytes_read = read_nointr(fd, buf, sizeof(buf) - 1);
|
|
if (bytes_read <= 0)
|
|
return -1;
|
|
|
|
buf[bytes_read] = '\0';
|
|
|
|
/*
|
|
* executable names may contain spaces, so we search backwards for the
|
|
* ), which is the kernel's marker for "end of executable name". this
|
|
* puts the pointer at the end of the second field.
|
|
*/
|
|
buf_ptr = strrchr(buf, ')');
|
|
if (!buf_ptr)
|
|
return -1;
|
|
|
|
/* Skip the space and the next 23 fields, column 26-28 are start_code,
|
|
* end_code, and start_stack */
|
|
for (i = 0; i < 24; i++) {
|
|
buf_ptr = strchr(buf_ptr + 1, ' ');
|
|
if (!buf_ptr)
|
|
return -1;
|
|
}
|
|
|
|
i = sscanf(buf_ptr, "%" PRIu64 " %" PRIu64 " %" PRIu64, &start_code, &end_code, &start_stack);
|
|
if (i != 3)
|
|
return -1;
|
|
|
|
/* Skip the next 19 fields, column 45-51 are start_data to arg_end */
|
|
for (i = 0; i < 19; i++) {
|
|
buf_ptr = strchr(buf_ptr + 1, ' ');
|
|
if (!buf_ptr)
|
|
return -1;
|
|
}
|
|
|
|
i = sscanf(buf_ptr, "%" PRIu64 " %" PRIu64 " %" PRIu64 " %*u %*u %" PRIu64 " %" PRIu64, &start_data,
|
|
&end_data, &start_brk, &env_start, &env_end);
|
|
if (i != 5)
|
|
return -1;
|
|
|
|
/* Include the null byte here, because in the calculations below we
|
|
* want to have room for it. */
|
|
len = strlen(title) + 1;
|
|
|
|
tmp_proctitle = realloc(proctitle, len);
|
|
if (!tmp_proctitle)
|
|
return -1;
|
|
|
|
proctitle = tmp_proctitle;
|
|
|
|
arg_start = (unsigned long)proctitle;
|
|
arg_end = arg_start + len;
|
|
|
|
brk_val = syscall(__NR_brk, 0);
|
|
|
|
prctl_map = (struct prctl_mm_map){
|
|
.start_code = start_code,
|
|
.end_code = end_code,
|
|
.start_stack = start_stack,
|
|
.start_data = start_data,
|
|
.end_data = end_data,
|
|
.start_brk = start_brk,
|
|
.brk = brk_val,
|
|
.arg_start = arg_start,
|
|
.arg_end = arg_end,
|
|
.env_start = env_start,
|
|
.env_end = env_end,
|
|
.auxv = NULL,
|
|
.auxv_size = 0,
|
|
.exe_fd = -1,
|
|
};
|
|
|
|
ret = prctl(PR_SET_MM, prctl_arg(PR_SET_MM_MAP), prctl_arg(&prctl_map),
|
|
prctl_arg(sizeof(prctl_map)), prctl_arg(0));
|
|
if (ret == 0) {
|
|
char *dest;
|
|
|
|
dest = (char *)(uintptr_t)arg_start;
|
|
memcpy(dest, title, len - 1);
|
|
dest[len - 1] = '\0';
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
#endif /* __INCUS_PROCESS_UTILS_H */
|