systemd: merge branch systemd into master
This commit is contained in:
@@ -1788,10 +1788,10 @@ shared_systemd_libnm_systemd_shared_la_SOURCES = \
|
||||
shared/systemd/sd-adapt-shared/locale-util.h \
|
||||
shared/systemd/sd-adapt-shared/memfd-util.h \
|
||||
shared/systemd/sd-adapt-shared/missing_fs.h \
|
||||
shared/systemd/sd-adapt-shared/missing_keyctl.h \
|
||||
shared/systemd/sd-adapt-shared/missing_magic.h \
|
||||
shared/systemd/sd-adapt-shared/missing_network.h \
|
||||
shared/systemd/sd-adapt-shared/missing_sched.h \
|
||||
shared/systemd/sd-adapt-shared/missing_syscall.h \
|
||||
shared/systemd/sd-adapt-shared/missing_timerfd.h \
|
||||
shared/systemd/sd-adapt-shared/mkdir.h \
|
||||
shared/systemd/sd-adapt-shared/namespace-util.h \
|
||||
@@ -1849,6 +1849,7 @@ shared_systemd_libnm_systemd_shared_la_SOURCES = \
|
||||
shared/systemd/src/basic/missing_random.h \
|
||||
shared/systemd/src/basic/missing_socket.h \
|
||||
shared/systemd/src/basic/missing_stat.h \
|
||||
shared/systemd/src/basic/missing_syscall.h \
|
||||
shared/systemd/src/basic/missing_type.h \
|
||||
shared/systemd/src/basic/parse-util.c \
|
||||
shared/systemd/src/basic/parse-util.h \
|
||||
@@ -1861,6 +1862,7 @@ shared_systemd_libnm_systemd_shared_la_SOURCES = \
|
||||
shared/systemd/src/basic/random-util.c \
|
||||
shared/systemd/src/basic/random-util.h \
|
||||
shared/systemd/src/basic/set.h \
|
||||
shared/systemd/src/basic/signal-util.c \
|
||||
shared/systemd/src/basic/signal-util.h \
|
||||
shared/systemd/src/basic/siphash24.h \
|
||||
shared/systemd/src/basic/socket-util.c \
|
||||
|
@@ -251,3 +251,7 @@
|
||||
|
||||
/* Define to `int' if <sys/types.h> does not define. */
|
||||
#mesondefine pid_t
|
||||
|
||||
#mesondefine HAVE_PIDFD_OPEN
|
||||
#mesondefine HAVE_PIDFD_SEND_SIGNAL
|
||||
#mesondefine HAVE_RT_SIGQUEUEINFO
|
||||
|
27
configure.ac
27
configure.ac
@@ -91,6 +91,33 @@ AC_CHECK_DECLS([
|
||||
#include <sys/mman.h>
|
||||
]])
|
||||
|
||||
AC_CHECK_DECLS([
|
||||
pidfd_open],
|
||||
[], [], [[
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <signal.h>
|
||||
#include <sys/wait.h>
|
||||
]])
|
||||
|
||||
AC_CHECK_DECLS([
|
||||
pidfd_send_signal],
|
||||
[], [], [[
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <signal.h>
|
||||
#include <sys/wait.h>
|
||||
]])
|
||||
|
||||
AC_CHECK_DECLS([
|
||||
rt_sigqueueinfo],
|
||||
[], [], [[
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <signal.h>
|
||||
#include <sys/wait.h>
|
||||
]])
|
||||
|
||||
AC_CHECK_HEADERS(sys/auxv.h)
|
||||
|
||||
AC_CHECK_DECLS([getrandom],
|
||||
|
14
meson.build
14
meson.build
@@ -110,8 +110,18 @@ use_sys_random = cc.has_function('getrandom', prefix: '#include <sys/random.h>')
|
||||
config_h.set10('USE_SYS_RANDOM_H', use_sys_random)
|
||||
config_h.set10('HAVE_GETRANDOM', use_sys_random or cc.has_function('getrandom', prefix: '#include <linux/random.h>'))
|
||||
|
||||
# functions
|
||||
# FIXME secure_getenv check is not useful?
|
||||
config_h.set10('HAVE_PIDFD_OPEN', cc.has_function('pidfd_open', prefix: '''#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <signal.h>
|
||||
#include <sys/wait.h>'''))
|
||||
config_h.set10('HAVE_PIDFD_SEND_SIGNAL', cc.has_function('pidfd_send_signal', prefix: '''#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <signal.h>
|
||||
#include <sys/wait.h>'''))
|
||||
config_h.set10('HAVE_RT_SIGQUEUEINFO', cc.has_function('rt_sigqueueinfo', prefix: '''#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <signal.h>
|
||||
#include <sys/wait.h>'''))
|
||||
config_h.set('HAVE_SECURE_GETENV', cc.has_function('secure_getenv'))
|
||||
config_h.set('HAVE___SECURE_GETENV', cc.has_function('__secure_getenv'))
|
||||
config_h.set10('HAVE_DECL_REALLOCARRAY', cc.has_function('reallocarray', prefix: '#include <malloc.h>'))
|
||||
|
@@ -187,10 +187,11 @@ libnm_udev_aux_dep = declare_dependency(
|
||||
)
|
||||
|
||||
sources = files(
|
||||
'systemd/nm-sd-utils-shared.c',
|
||||
'systemd/src/basic/alloc-util.c',
|
||||
'systemd/src/basic/escape.c',
|
||||
'systemd/src/basic/env-file.c',
|
||||
'systemd/src/basic/env-util.c',
|
||||
'systemd/src/basic/escape.c',
|
||||
'systemd/src/basic/ether-addr-util.c',
|
||||
'systemd/src/basic/extract-word.c',
|
||||
'systemd/src/basic/fd-util.c',
|
||||
@@ -210,6 +211,7 @@ sources = files(
|
||||
'systemd/src/basic/prioq.c',
|
||||
'systemd/src/basic/process-util.c',
|
||||
'systemd/src/basic/random-util.c',
|
||||
'systemd/src/basic/signal-util.c',
|
||||
'systemd/src/basic/socket-util.c',
|
||||
'systemd/src/basic/stat-util.c',
|
||||
'systemd/src/basic/string-table.c',
|
||||
@@ -221,7 +223,6 @@ sources = files(
|
||||
'systemd/src/basic/utf8.c',
|
||||
'systemd/src/basic/util.c',
|
||||
'systemd/src/shared/dns-domain.c',
|
||||
'systemd/nm-sd-utils-shared.c',
|
||||
)
|
||||
|
||||
incs = include_directories(
|
||||
|
@@ -122,6 +122,24 @@ static inline pid_t _nm_gettid(void) {
|
||||
#define HAVE_EXPLICIT_BZERO 0
|
||||
#endif
|
||||
|
||||
#if defined(HAVE_DECL_PIDFD_OPEN) && HAVE_DECL_PIDFD_OPEN == 1
|
||||
#define HAVE_PIDFD_OPEN 1
|
||||
#else
|
||||
#define HAVE_PIDFD_OPEN 0
|
||||
#endif
|
||||
|
||||
#if defined(HAVE_DECL_PIDFD_SEND_SIGNAL) && HAVE_DECL_PIDFD_SEND_SIGNAL == 1
|
||||
#define HAVE_PIDFD_SEND_SIGNAL 1
|
||||
#else
|
||||
#define HAVE_PIDFD_SEND_SIGNAL 0
|
||||
#endif
|
||||
|
||||
#if defined(HAVE_DECL_RT_SIGQUEUEINFO) && HAVE_DECL_RT_SIGQUEUEINFO == 1
|
||||
#define HAVE_RT_SIGQUEUEINFO 1
|
||||
#else
|
||||
#define HAVE_RT_SIGQUEUEINFO 0
|
||||
#endif
|
||||
|
||||
#endif /* (NETWORKMANAGER_COMPILATION) & NM_NETWORKMANAGER_COMPILATION_WITH_SYSTEMD */
|
||||
|
||||
/*****************************************************************************/
|
||||
|
@@ -101,3 +101,11 @@ static inline bool ERRNO_IS_PRIVILEGE(int r) {
|
||||
EACCES,
|
||||
EPERM);
|
||||
}
|
||||
|
||||
/* Three difference errors for "not enough disk space" */
|
||||
static inline bool ERRNO_IS_DISK_SPACE(int r) {
|
||||
return IN_SET(abs(r),
|
||||
ENOSPC,
|
||||
EDQUOT,
|
||||
EFBIG);
|
||||
}
|
||||
|
@@ -551,6 +551,7 @@ int get_files_in_directory(const char *path, char ***list) {
|
||||
|
||||
return n;
|
||||
}
|
||||
#endif /* NM_IGNORED */
|
||||
|
||||
static int getenv_tmp_dir(const char **ret_path) {
|
||||
const char *n;
|
||||
@@ -622,6 +623,7 @@ static int tmp_dir_internal(const char *def, const char **ret) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if 0 /* NM_IGNORED */
|
||||
int var_tmp_dir(const char **ret) {
|
||||
|
||||
/* Returns the location for "larger" temporary files, that is backed by physical storage if available, and thus
|
||||
@@ -631,6 +633,7 @@ int var_tmp_dir(const char **ret) {
|
||||
|
||||
return tmp_dir_internal("/var/tmp", ret);
|
||||
}
|
||||
#endif /* NM_IGNORED */
|
||||
|
||||
int tmp_dir(const char **ret) {
|
||||
|
||||
@@ -640,6 +643,7 @@ int tmp_dir(const char **ret) {
|
||||
return tmp_dir_internal("/tmp", ret);
|
||||
}
|
||||
|
||||
#if 0 /* NM_IGNORED */
|
||||
int unlink_or_warn(const char *filename) {
|
||||
if (unlink(filename) < 0 && errno != ENOENT)
|
||||
/* If the file doesn't exist and the fs simply was read-only (in which
|
||||
|
@@ -172,6 +172,11 @@ static inline size_t ALIGN_TO(size_t l, size_t ali) {
|
||||
|
||||
/* align to next higher power-of-2 (except for: 0 => 0, overflow => 0) */
|
||||
static inline unsigned long ALIGN_POWER2(unsigned long u) {
|
||||
|
||||
/* Avoid subtraction overflow */
|
||||
if (u == 0)
|
||||
return 0;
|
||||
|
||||
/* clz(0) is undefined */
|
||||
if (u == 1)
|
||||
return 1;
|
||||
@@ -183,6 +188,29 @@ static inline unsigned long ALIGN_POWER2(unsigned long u) {
|
||||
return 1UL << (sizeof(u) * 8 - __builtin_clzl(u - 1UL));
|
||||
}
|
||||
|
||||
static inline size_t GREEDY_ALLOC_ROUND_UP(size_t l) {
|
||||
size_t m;
|
||||
|
||||
/* Round up allocation sizes a bit to some reasonable, likely larger value. This is supposed to be
|
||||
* used for cases which are likely called in an allocation loop of some form, i.e. that repetitively
|
||||
* grow stuff, for example strv_extend() and suchlike.
|
||||
*
|
||||
* Note the difference to GREEDY_REALLOC() here, as this helper operates on a single size value only,
|
||||
* and rounds up to next multiple of 2, needing no further counter.
|
||||
*
|
||||
* Note the benefits of direct ALIGN_POWER2() usage: type-safety for size_t, sane handling for very
|
||||
* small (i.e. <= 2) and safe handling for very large (i.e. > SSIZE_MAX) values. */
|
||||
|
||||
if (l <= 2)
|
||||
return 2; /* Never allocate less than 2 of something. */
|
||||
|
||||
m = ALIGN_POWER2(l);
|
||||
if (m == 0) /* overflow? */
|
||||
return l;
|
||||
|
||||
return m;
|
||||
}
|
||||
|
||||
#ifndef __COVERITY__
|
||||
# define VOID_0 ((void)0)
|
||||
#else
|
||||
|
@@ -80,14 +80,21 @@ static inline void* explicit_bzero_safe(void *p, size_t l) {
|
||||
void *explicit_bzero_safe(void *p, size_t l);
|
||||
#endif
|
||||
|
||||
static inline void erase_and_freep(void *p) {
|
||||
void *ptr = *(void**) p;
|
||||
static inline void* erase_and_free(void *p) {
|
||||
size_t l;
|
||||
|
||||
if (ptr) {
|
||||
size_t l = malloc_usable_size(ptr);
|
||||
explicit_bzero_safe(ptr, l);
|
||||
free(ptr);
|
||||
}
|
||||
if (!p)
|
||||
return NULL;
|
||||
|
||||
l = malloc_usable_size(p);
|
||||
explicit_bzero_safe(p, l);
|
||||
free(p);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static inline void erase_and_freep(void *p) {
|
||||
erase_and_free(*(void**) p);
|
||||
}
|
||||
|
||||
/* Use with _cleanup_ to erase a single 'char' when leaving scope */
|
||||
|
574
shared/systemd/src/basic/missing_syscall.h
Normal file
574
shared/systemd/src/basic/missing_syscall.h
Normal file
@@ -0,0 +1,574 @@
|
||||
/* SPDX-License-Identifier: LGPL-2.1+ */
|
||||
#pragma once
|
||||
|
||||
/* Missing glibc definitions to access certain kernel APIs */
|
||||
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <signal.h>
|
||||
#include <sys/syscall.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/wait.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#ifdef ARCH_MIPS
|
||||
#include <asm/sgidefs.h>
|
||||
#endif
|
||||
|
||||
#include "missing_keyctl.h"
|
||||
#include "missing_stat.h"
|
||||
|
||||
#if 0 /* NM_IGNORED */
|
||||
|
||||
/* linux/kcmp.h */
|
||||
#ifndef KCMP_FILE /* 3f4994cfc15f38a3159c6e3a4b3ab2e1481a6b02 (3.19) */
|
||||
#define KCMP_FILE 0
|
||||
#endif
|
||||
|
||||
#if !HAVE_PIVOT_ROOT
|
||||
static inline int missing_pivot_root(const char *new_root, const char *put_old) {
|
||||
return syscall(__NR_pivot_root, new_root, put_old);
|
||||
}
|
||||
|
||||
# define pivot_root missing_pivot_root
|
||||
#endif
|
||||
|
||||
/* ======================================================================= */
|
||||
|
||||
#if !HAVE_MEMFD_CREATE
|
||||
/* may be (invalid) negative number due to libseccomp, see PR 13319 */
|
||||
# if ! (defined __NR_memfd_create && __NR_memfd_create >= 0)
|
||||
# if defined __NR_memfd_create
|
||||
# undef __NR_memfd_create
|
||||
# endif
|
||||
# if defined __x86_64__
|
||||
# define __NR_memfd_create 319
|
||||
# elif defined __arm__
|
||||
# define __NR_memfd_create 385
|
||||
# elif defined __aarch64__
|
||||
# define __NR_memfd_create 279
|
||||
# elif defined __s390__
|
||||
# define __NR_memfd_create 350
|
||||
# elif defined _MIPS_SIM
|
||||
# if _MIPS_SIM == _MIPS_SIM_ABI32
|
||||
# define __NR_memfd_create 4354
|
||||
# endif
|
||||
# if _MIPS_SIM == _MIPS_SIM_NABI32
|
||||
# define __NR_memfd_create 6318
|
||||
# endif
|
||||
# if _MIPS_SIM == _MIPS_SIM_ABI64
|
||||
# define __NR_memfd_create 5314
|
||||
# endif
|
||||
# elif defined __i386__
|
||||
# define __NR_memfd_create 356
|
||||
# elif defined __arc__
|
||||
# define __NR_memfd_create 279
|
||||
# else
|
||||
# warning "__NR_memfd_create unknown for your architecture"
|
||||
# endif
|
||||
# endif
|
||||
|
||||
static inline int missing_memfd_create(const char *name, unsigned int flags) {
|
||||
# ifdef __NR_memfd_create
|
||||
return syscall(__NR_memfd_create, name, flags);
|
||||
# else
|
||||
errno = ENOSYS;
|
||||
return -1;
|
||||
# endif
|
||||
}
|
||||
|
||||
# define memfd_create missing_memfd_create
|
||||
#endif
|
||||
|
||||
/* ======================================================================= */
|
||||
|
||||
#if !HAVE_GETRANDOM
|
||||
/* may be (invalid) negative number due to libseccomp, see PR 13319 */
|
||||
# if ! (defined __NR_getrandom && __NR_getrandom >= 0)
|
||||
# if defined __NR_getrandom
|
||||
# undef __NR_getrandom
|
||||
# endif
|
||||
# if defined __x86_64__
|
||||
# define __NR_getrandom 318
|
||||
# elif defined(__i386__)
|
||||
# define __NR_getrandom 355
|
||||
# elif defined(__arm__)
|
||||
# define __NR_getrandom 384
|
||||
# elif defined(__aarch64__)
|
||||
# define __NR_getrandom 278
|
||||
# elif defined(__ia64__)
|
||||
# define __NR_getrandom 1339
|
||||
# elif defined(__m68k__)
|
||||
# define __NR_getrandom 352
|
||||
# elif defined(__s390x__)
|
||||
# define __NR_getrandom 349
|
||||
# elif defined(__powerpc__)
|
||||
# define __NR_getrandom 359
|
||||
# elif defined _MIPS_SIM
|
||||
# if _MIPS_SIM == _MIPS_SIM_ABI32
|
||||
# define __NR_getrandom 4353
|
||||
# endif
|
||||
# if _MIPS_SIM == _MIPS_SIM_NABI32
|
||||
# define __NR_getrandom 6317
|
||||
# endif
|
||||
# if _MIPS_SIM == _MIPS_SIM_ABI64
|
||||
# define __NR_getrandom 5313
|
||||
# endif
|
||||
# elif defined(__arc__)
|
||||
# define __NR_getrandom 278
|
||||
# else
|
||||
# warning "__NR_getrandom unknown for your architecture"
|
||||
# endif
|
||||
# endif
|
||||
|
||||
static inline int missing_getrandom(void *buffer, size_t count, unsigned flags) {
|
||||
# ifdef __NR_getrandom
|
||||
return syscall(__NR_getrandom, buffer, count, flags);
|
||||
# else
|
||||
errno = ENOSYS;
|
||||
return -1;
|
||||
# endif
|
||||
}
|
||||
|
||||
# define getrandom missing_getrandom
|
||||
#endif
|
||||
|
||||
/* ======================================================================= */
|
||||
|
||||
#if !HAVE_GETTID
|
||||
static inline pid_t missing_gettid(void) {
|
||||
return (pid_t) syscall(__NR_gettid);
|
||||
}
|
||||
|
||||
# define gettid missing_gettid
|
||||
#endif
|
||||
|
||||
/* ======================================================================= */
|
||||
|
||||
#if !HAVE_NAME_TO_HANDLE_AT
|
||||
/* may be (invalid) negative number due to libseccomp, see PR 13319 */
|
||||
# if ! (defined __NR_name_to_handle_at && __NR_name_to_handle_at >= 0)
|
||||
# if defined __NR_name_to_handle_at
|
||||
# undef __NR_name_to_handle_at
|
||||
# endif
|
||||
# if defined(__x86_64__)
|
||||
# define __NR_name_to_handle_at 303
|
||||
# elif defined(__i386__)
|
||||
# define __NR_name_to_handle_at 341
|
||||
# elif defined(__arm__)
|
||||
# define __NR_name_to_handle_at 370
|
||||
# elif defined(__powerpc__)
|
||||
# define __NR_name_to_handle_at 345
|
||||
# elif defined(__arc__)
|
||||
# define __NR_name_to_handle_at 264
|
||||
# else
|
||||
# error "__NR_name_to_handle_at is not defined"
|
||||
# endif
|
||||
# endif
|
||||
|
||||
struct file_handle {
|
||||
unsigned int handle_bytes;
|
||||
int handle_type;
|
||||
unsigned char f_handle[0];
|
||||
};
|
||||
|
||||
static inline int missing_name_to_handle_at(int fd, const char *name, struct file_handle *handle, int *mnt_id, int flags) {
|
||||
# ifdef __NR_name_to_handle_at
|
||||
return syscall(__NR_name_to_handle_at, fd, name, handle, mnt_id, flags);
|
||||
# else
|
||||
errno = ENOSYS;
|
||||
return -1;
|
||||
# endif
|
||||
}
|
||||
|
||||
# define name_to_handle_at missing_name_to_handle_at
|
||||
#endif
|
||||
|
||||
/* ======================================================================= */
|
||||
|
||||
#if !HAVE_SETNS
|
||||
/* may be (invalid) negative number due to libseccomp, see PR 13319 */
|
||||
# if ! (defined __NR_setns && __NR_setns >= 0)
|
||||
# if defined __NR_setns
|
||||
# undef __NR_setns
|
||||
# endif
|
||||
# if defined(__x86_64__)
|
||||
# define __NR_setns 308
|
||||
# elif defined(__i386__)
|
||||
# define __NR_setns 346
|
||||
# elif defined(__arc__)
|
||||
# define __NR_setns 268
|
||||
# else
|
||||
# error "__NR_setns is not defined"
|
||||
# endif
|
||||
# endif
|
||||
|
||||
static inline int missing_setns(int fd, int nstype) {
|
||||
# ifdef __NR_setns
|
||||
return syscall(__NR_setns, fd, nstype);
|
||||
# else
|
||||
errno = ENOSYS;
|
||||
return -1;
|
||||
# endif
|
||||
}
|
||||
|
||||
# define setns missing_setns
|
||||
#endif
|
||||
|
||||
/* ======================================================================= */
|
||||
|
||||
static inline pid_t raw_getpid(void) {
|
||||
#if defined(__alpha__)
|
||||
return (pid_t) syscall(__NR_getxpid);
|
||||
#else
|
||||
return (pid_t) syscall(__NR_getpid);
|
||||
#endif
|
||||
}
|
||||
|
||||
/* ======================================================================= */
|
||||
|
||||
#if !HAVE_RENAMEAT2
|
||||
/* may be (invalid) negative number due to libseccomp, see PR 13319 */
|
||||
# if ! (defined __NR_renameat2 && __NR_renameat2 >= 0)
|
||||
# if defined __NR_renameat2
|
||||
# undef __NR_renameat2
|
||||
# endif
|
||||
# if defined __x86_64__
|
||||
# define __NR_renameat2 316
|
||||
# elif defined __arm__
|
||||
# define __NR_renameat2 382
|
||||
# elif defined __aarch64__
|
||||
# define __NR_renameat2 276
|
||||
# elif defined _MIPS_SIM
|
||||
# if _MIPS_SIM == _MIPS_SIM_ABI32
|
||||
# define __NR_renameat2 4351
|
||||
# endif
|
||||
# if _MIPS_SIM == _MIPS_SIM_NABI32
|
||||
# define __NR_renameat2 6315
|
||||
# endif
|
||||
# if _MIPS_SIM == _MIPS_SIM_ABI64
|
||||
# define __NR_renameat2 5311
|
||||
# endif
|
||||
# elif defined __i386__
|
||||
# define __NR_renameat2 353
|
||||
# elif defined __powerpc64__
|
||||
# define __NR_renameat2 357
|
||||
# elif defined __s390__ || defined __s390x__
|
||||
# define __NR_renameat2 347
|
||||
# elif defined __arc__
|
||||
# define __NR_renameat2 276
|
||||
# else
|
||||
# warning "__NR_renameat2 unknown for your architecture"
|
||||
# endif
|
||||
# endif
|
||||
|
||||
static inline int missing_renameat2(int oldfd, const char *oldname, int newfd, const char *newname, unsigned flags) {
|
||||
# ifdef __NR_renameat2
|
||||
return syscall(__NR_renameat2, oldfd, oldname, newfd, newname, flags);
|
||||
# else
|
||||
errno = ENOSYS;
|
||||
return -1;
|
||||
# endif
|
||||
}
|
||||
|
||||
# define renameat2 missing_renameat2
|
||||
#endif
|
||||
|
||||
/* ======================================================================= */
|
||||
|
||||
#if !HAVE_KCMP
|
||||
static inline int missing_kcmp(pid_t pid1, pid_t pid2, int type, unsigned long idx1, unsigned long idx2) {
|
||||
# if defined __NR_kcmp && __NR_kcmp >= 0
|
||||
return syscall(__NR_kcmp, pid1, pid2, type, idx1, idx2);
|
||||
# else
|
||||
errno = ENOSYS;
|
||||
return -1;
|
||||
# endif
|
||||
}
|
||||
|
||||
# define kcmp missing_kcmp
|
||||
#endif
|
||||
|
||||
/* ======================================================================= */
|
||||
|
||||
#if !HAVE_KEYCTL
|
||||
static inline long missing_keyctl(int cmd, unsigned long arg2, unsigned long arg3, unsigned long arg4, unsigned long arg5) {
|
||||
# if defined __NR_keyctl && __NR_keyctl >= 0
|
||||
return syscall(__NR_keyctl, cmd, arg2, arg3, arg4, arg5);
|
||||
# else
|
||||
errno = ENOSYS;
|
||||
return -1;
|
||||
# endif
|
||||
|
||||
# define keyctl missing_keyctl
|
||||
}
|
||||
|
||||
static inline key_serial_t missing_add_key(const char *type, const char *description, const void *payload, size_t plen, key_serial_t ringid) {
|
||||
# if defined __NR_add_key && __NR_add_key >= 0
|
||||
return syscall(__NR_add_key, type, description, payload, plen, ringid);
|
||||
# else
|
||||
errno = ENOSYS;
|
||||
return -1;
|
||||
# endif
|
||||
|
||||
# define add_key missing_add_key
|
||||
}
|
||||
|
||||
static inline key_serial_t missing_request_key(const char *type, const char *description, const char * callout_info, key_serial_t destringid) {
|
||||
# if defined __NR_request_key && __NR_request_key >= 0
|
||||
return syscall(__NR_request_key, type, description, callout_info, destringid);
|
||||
# else
|
||||
errno = ENOSYS;
|
||||
return -1;
|
||||
# endif
|
||||
|
||||
# define request_key missing_request_key
|
||||
}
|
||||
#endif
|
||||
|
||||
/* ======================================================================= */
|
||||
|
||||
#if !HAVE_COPY_FILE_RANGE
|
||||
/* may be (invalid) negative number due to libseccomp, see PR 13319 */
|
||||
# if ! (defined __NR_copy_file_range && __NR_copy_file_range >= 0)
|
||||
# if defined __NR_copy_file_range
|
||||
# undef __NR_copy_file_range
|
||||
# endif
|
||||
# if defined(__x86_64__)
|
||||
# define __NR_copy_file_range 326
|
||||
# elif defined(__i386__)
|
||||
# define __NR_copy_file_range 377
|
||||
# elif defined __s390__
|
||||
# define __NR_copy_file_range 375
|
||||
# elif defined __arm__
|
||||
# define __NR_copy_file_range 391
|
||||
# elif defined __aarch64__
|
||||
# define __NR_copy_file_range 285
|
||||
# elif defined __powerpc__
|
||||
# define __NR_copy_file_range 379
|
||||
# elif defined __arc__
|
||||
# define __NR_copy_file_range 285
|
||||
# else
|
||||
# warning "__NR_copy_file_range not defined for your architecture"
|
||||
# endif
|
||||
# endif
|
||||
|
||||
static inline ssize_t missing_copy_file_range(int fd_in, loff_t *off_in,
|
||||
int fd_out, loff_t *off_out,
|
||||
size_t len,
|
||||
unsigned int flags) {
|
||||
# ifdef __NR_copy_file_range
|
||||
return syscall(__NR_copy_file_range, fd_in, off_in, fd_out, off_out, len, flags);
|
||||
# else
|
||||
errno = ENOSYS;
|
||||
return -1;
|
||||
# endif
|
||||
}
|
||||
|
||||
# define copy_file_range missing_copy_file_range
|
||||
#endif
|
||||
|
||||
/* ======================================================================= */
|
||||
|
||||
#if !HAVE_BPF
|
||||
/* may be (invalid) negative number due to libseccomp, see PR 13319 */
|
||||
# if ! (defined __NR_bpf && __NR_bpf >= 0)
|
||||
# if defined __NR_bpf
|
||||
# undef __NR_bpf
|
||||
# endif
|
||||
# if defined __i386__
|
||||
# define __NR_bpf 357
|
||||
# elif defined __x86_64__
|
||||
# define __NR_bpf 321
|
||||
# elif defined __aarch64__
|
||||
# define __NR_bpf 280
|
||||
# elif defined __arm__
|
||||
# define __NR_bpf 386
|
||||
# elif defined __sparc__
|
||||
# define __NR_bpf 349
|
||||
# elif defined __s390__
|
||||
# define __NR_bpf 351
|
||||
# elif defined __tilegx__
|
||||
# define __NR_bpf 280
|
||||
# else
|
||||
# warning "__NR_bpf not defined for your architecture"
|
||||
# endif
|
||||
# endif
|
||||
|
||||
union bpf_attr;
|
||||
|
||||
static inline int missing_bpf(int cmd, union bpf_attr *attr, size_t size) {
|
||||
#ifdef __NR_bpf
|
||||
return (int) syscall(__NR_bpf, cmd, attr, size);
|
||||
#else
|
||||
errno = ENOSYS;
|
||||
return -1;
|
||||
#endif
|
||||
}
|
||||
|
||||
# define bpf missing_bpf
|
||||
#endif
|
||||
|
||||
/* ======================================================================= */
|
||||
|
||||
#ifndef __IGNORE_pkey_mprotect
|
||||
/* may be (invalid) negative number due to libseccomp, see PR 13319 */
|
||||
# if ! (defined __NR_pkey_mprotect && __NR_pkey_mprotect >= 0)
|
||||
# if defined __NR_pkey_mprotect
|
||||
# undef __NR_pkey_mprotect
|
||||
# endif
|
||||
# if defined __i386__
|
||||
# define __NR_pkey_mprotect 380
|
||||
# elif defined __x86_64__
|
||||
# define __NR_pkey_mprotect 329
|
||||
# elif defined __arm__
|
||||
# define __NR_pkey_mprotect 394
|
||||
# elif defined __aarch64__
|
||||
# define __NR_pkey_mprotect 394
|
||||
# elif defined __powerpc__
|
||||
# define __NR_pkey_mprotect 386
|
||||
# elif defined __s390__
|
||||
# define __NR_pkey_mprotect 384
|
||||
# elif defined _MIPS_SIM
|
||||
# if _MIPS_SIM == _MIPS_SIM_ABI32
|
||||
# define __NR_pkey_mprotect 4363
|
||||
# endif
|
||||
# if _MIPS_SIM == _MIPS_SIM_NABI32
|
||||
# define __NR_pkey_mprotect 6327
|
||||
# endif
|
||||
# if _MIPS_SIM == _MIPS_SIM_ABI64
|
||||
# define __NR_pkey_mprotect 5323
|
||||
# endif
|
||||
# else
|
||||
# warning "__NR_pkey_mprotect not defined for your architecture"
|
||||
# endif
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/* ======================================================================= */
|
||||
|
||||
#if !HAVE_STATX
|
||||
/* may be (invalid) negative number due to libseccomp, see PR 13319 */
|
||||
# if ! (defined __NR_statx && __NR_statx >= 0)
|
||||
# if defined __NR_statx
|
||||
# undef __NR_statx
|
||||
# endif
|
||||
# if defined __aarch64__ || defined __arm__
|
||||
# define __NR_statx 397
|
||||
# elif defined __alpha__
|
||||
# define __NR_statx 522
|
||||
# elif defined __i386__ || defined __powerpc64__
|
||||
# define __NR_statx 383
|
||||
# elif defined __sparc__
|
||||
# define __NR_statx 360
|
||||
# elif defined __x86_64__
|
||||
# define __NR_statx 332
|
||||
# else
|
||||
# warning "__NR_statx not defined for your architecture"
|
||||
# endif
|
||||
# endif
|
||||
|
||||
struct statx;
|
||||
#endif
|
||||
|
||||
/* This typedef is supposed to be always defined. */
|
||||
typedef struct statx struct_statx;
|
||||
|
||||
#if !HAVE_STATX
|
||||
static inline ssize_t missing_statx(int dfd, const char *filename, unsigned flags, unsigned int mask, struct statx *buffer) {
|
||||
# ifdef __NR_statx
|
||||
return syscall(__NR_statx, dfd, filename, flags, mask, buffer);
|
||||
# else
|
||||
errno = ENOSYS;
|
||||
return -1;
|
||||
# endif
|
||||
}
|
||||
|
||||
# define statx missing_statx
|
||||
#endif
|
||||
|
||||
#if !HAVE_SET_MEMPOLICY
|
||||
|
||||
enum {
|
||||
MPOL_DEFAULT,
|
||||
MPOL_PREFERRED,
|
||||
MPOL_BIND,
|
||||
MPOL_INTERLEAVE,
|
||||
MPOL_LOCAL,
|
||||
};
|
||||
|
||||
static inline long missing_set_mempolicy(int mode, const unsigned long *nodemask,
|
||||
unsigned long maxnode) {
|
||||
long i;
|
||||
# if defined __NR_set_mempolicy && __NR_set_mempolicy >= 0
|
||||
i = syscall(__NR_set_mempolicy, mode, nodemask, maxnode);
|
||||
# else
|
||||
errno = ENOSYS;
|
||||
i = -1;
|
||||
# endif
|
||||
return i;
|
||||
}
|
||||
|
||||
# define set_mempolicy missing_set_mempolicy
|
||||
#endif
|
||||
|
||||
#if !HAVE_GET_MEMPOLICY
|
||||
static inline long missing_get_mempolicy(int *mode, unsigned long *nodemask,
|
||||
unsigned long maxnode, void *addr,
|
||||
unsigned long flags) {
|
||||
long i;
|
||||
# ifdef __NR_get_mempolicy
|
||||
i = syscall(__NR_get_mempolicy, mode, nodemask, maxnode, addr, flags);
|
||||
# else
|
||||
errno = ENOSYS;
|
||||
i = -1;
|
||||
# endif
|
||||
return i;
|
||||
}
|
||||
|
||||
#define get_mempolicy missing_get_mempolicy
|
||||
#endif
|
||||
|
||||
#endif /* NM_IGNORED */
|
||||
|
||||
#if !HAVE_PIDFD_OPEN
|
||||
/* may be (invalid) negative number due to libseccomp, see PR 13319 */
|
||||
# if ! (defined __NR_pidfd_open && __NR_pidfd_open >= 0)
|
||||
# if defined __NR_pidfd_open
|
||||
# undef __NR_pidfd_open
|
||||
# endif
|
||||
# define __NR_pidfd_open 434
|
||||
#endif
|
||||
static inline int pidfd_open(pid_t pid, unsigned flags) {
|
||||
#ifdef __NR_pidfd_open
|
||||
return syscall(__NR_pidfd_open, pid, flags);
|
||||
#else
|
||||
errno = ENOSYS;
|
||||
return -1;
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
#if !HAVE_PIDFD_SEND_SIGNAL
|
||||
/* may be (invalid) negative number due to libseccomp, see PR 13319 */
|
||||
# if ! (defined __NR_pidfd_send_signal && __NR_pidfd_send_signal >= 0)
|
||||
# if defined __NR_pidfd_send_signal
|
||||
# undef __NR_pidfd_send_signal
|
||||
# endif
|
||||
# define __NR_pidfd_send_signal 424
|
||||
#endif
|
||||
static inline int pidfd_send_signal(int fd, int sig, siginfo_t *info, unsigned flags) {
|
||||
#ifdef __NR_pidfd_open
|
||||
return syscall(__NR_pidfd_send_signal, fd, sig, info, flags);
|
||||
#else
|
||||
errno = ENOSYS;
|
||||
return -1;
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
#if !HAVE_RT_SIGQUEUEINFO
|
||||
static inline int rt_sigqueueinfo(pid_t tgid, int sig, siginfo_t *info) {
|
||||
return syscall(__NR_rt_sigqueueinfo, tgid, sig, info);
|
||||
}
|
||||
#endif
|
@@ -369,7 +369,6 @@ int safe_atou_full(const char *s, unsigned base, unsigned *ret_u) {
|
||||
unsigned long l;
|
||||
|
||||
assert(s);
|
||||
assert(ret_u);
|
||||
assert(base <= 16);
|
||||
|
||||
/* strtoul() is happy to parse negative values, and silently
|
||||
@@ -393,7 +392,9 @@ int safe_atou_full(const char *s, unsigned base, unsigned *ret_u) {
|
||||
if ((unsigned long) (unsigned) l != l)
|
||||
return -ERANGE;
|
||||
|
||||
*ret_u = (unsigned) l;
|
||||
if (ret_u)
|
||||
*ret_u = (unsigned) l;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -402,7 +403,6 @@ int safe_atoi(const char *s, int *ret_i) {
|
||||
long l;
|
||||
|
||||
assert(s);
|
||||
assert(ret_i);
|
||||
|
||||
errno = 0;
|
||||
l = strtol(s, &x, 0);
|
||||
@@ -413,7 +413,9 @@ int safe_atoi(const char *s, int *ret_i) {
|
||||
if ((long) (int) l != l)
|
||||
return -ERANGE;
|
||||
|
||||
*ret_i = (int) l;
|
||||
if (ret_i)
|
||||
*ret_i = (int) l;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -422,7 +424,6 @@ int safe_atollu(const char *s, long long unsigned *ret_llu) {
|
||||
unsigned long long l;
|
||||
|
||||
assert(s);
|
||||
assert(ret_llu);
|
||||
|
||||
s += strspn(s, WHITESPACE);
|
||||
|
||||
@@ -435,7 +436,9 @@ int safe_atollu(const char *s, long long unsigned *ret_llu) {
|
||||
if (*s == '-')
|
||||
return -ERANGE;
|
||||
|
||||
*ret_llu = l;
|
||||
if (ret_llu)
|
||||
*ret_llu = l;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -444,7 +447,6 @@ int safe_atolli(const char *s, long long int *ret_lli) {
|
||||
long long l;
|
||||
|
||||
assert(s);
|
||||
assert(ret_lli);
|
||||
|
||||
errno = 0;
|
||||
l = strtoll(s, &x, 0);
|
||||
@@ -453,7 +455,9 @@ int safe_atolli(const char *s, long long int *ret_lli) {
|
||||
if (!x || x == s || *x != 0)
|
||||
return -EINVAL;
|
||||
|
||||
*ret_lli = l;
|
||||
if (ret_lli)
|
||||
*ret_lli = l;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -462,7 +466,6 @@ int safe_atou8(const char *s, uint8_t *ret) {
|
||||
unsigned long l;
|
||||
|
||||
assert(s);
|
||||
assert(ret);
|
||||
|
||||
s += strspn(s, WHITESPACE);
|
||||
|
||||
@@ -477,7 +480,8 @@ int safe_atou8(const char *s, uint8_t *ret) {
|
||||
if ((unsigned long) (uint8_t) l != l)
|
||||
return -ERANGE;
|
||||
|
||||
*ret = (uint8_t) l;
|
||||
if (ret)
|
||||
*ret = (uint8_t) l;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -511,7 +515,6 @@ int safe_atoi16(const char *s, int16_t *ret) {
|
||||
long l;
|
||||
|
||||
assert(s);
|
||||
assert(ret);
|
||||
|
||||
errno = 0;
|
||||
l = strtol(s, &x, 0);
|
||||
@@ -522,7 +525,9 @@ int safe_atoi16(const char *s, int16_t *ret) {
|
||||
if ((long) (int16_t) l != l)
|
||||
return -ERANGE;
|
||||
|
||||
*ret = (int16_t) l;
|
||||
if (ret)
|
||||
*ret = (int16_t) l;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -533,7 +538,6 @@ int safe_atod(const char *s, double *ret_d) {
|
||||
double d = 0;
|
||||
|
||||
assert(s);
|
||||
assert(ret_d);
|
||||
|
||||
loc = newlocale(LC_NUMERIC_MASK, "C", (locale_t) 0);
|
||||
if (loc == (locale_t) 0)
|
||||
@@ -546,7 +550,9 @@ int safe_atod(const char *s, double *ret_d) {
|
||||
if (!x || x == s || *x != 0)
|
||||
return -EINVAL;
|
||||
|
||||
*ret_d = (double) d;
|
||||
if (ret_d)
|
||||
*ret_d = (double) d;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@@ -540,6 +540,7 @@ bool path_equal(const char *a, const char *b) {
|
||||
bool path_equal_or_files_same(const char *a, const char *b, int flags) {
|
||||
return path_equal(a, b) || files_same(a, b, flags) > 0;
|
||||
}
|
||||
#endif /* NM_IGNORED */
|
||||
|
||||
char* path_join_internal(const char *first, ...) {
|
||||
char *joined, *q;
|
||||
@@ -599,6 +600,7 @@ char* path_join_internal(const char *first, ...) {
|
||||
return joined;
|
||||
}
|
||||
|
||||
#if 0 /* NM_IGNORED */
|
||||
int find_binary(const char *name, char **ret) {
|
||||
int last_error, r;
|
||||
const char *p;
|
||||
|
@@ -44,6 +44,7 @@
|
||||
#include "rlimit-util.h"
|
||||
#include "signal-util.h"
|
||||
#include "stat-util.h"
|
||||
#include "stdio-util.h"
|
||||
#include "string-table.h"
|
||||
#include "string-util.h"
|
||||
#include "terminal-util.h"
|
||||
@@ -1347,6 +1348,12 @@ int safe_fork_full(
|
||||
log_full_errno(prio, r, "Failed to connect stdin/stdout to /dev/null: %m");
|
||||
_exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
} else if (flags & FORK_STDOUT_TO_STDERR) {
|
||||
if (dup2(STDERR_FILENO, STDOUT_FILENO) < 0) {
|
||||
log_full_errno(prio, errno, "Failed to connect stdout to stderr: %m");
|
||||
_exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
if (flags & FORK_RLIMIT_NOFILE_SAFE) {
|
||||
@@ -1498,6 +1505,38 @@ int set_oom_score_adjust(int value) {
|
||||
WRITE_STRING_FILE_VERIFY_ON_FAILURE|WRITE_STRING_FILE_DISABLE_BUFFER);
|
||||
}
|
||||
|
||||
int pidfd_get_pid(int fd, pid_t *ret) {
|
||||
char path[STRLEN("/proc/self/fdinfo/") + DECIMAL_STR_MAX(int)];
|
||||
_cleanup_free_ char *fdinfo = NULL;
|
||||
char *p;
|
||||
int r;
|
||||
|
||||
if (fd < 0)
|
||||
return -EBADF;
|
||||
|
||||
xsprintf(path, "/proc/self/fdinfo/%i", fd);
|
||||
|
||||
r = read_full_file(path, &fdinfo, NULL);
|
||||
if (r == -ENOENT) /* if fdinfo doesn't exist we assume the process does not exist */
|
||||
return -ESRCH;
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
p = startswith(fdinfo, "Pid:");
|
||||
if (!p) {
|
||||
p = strstr(fdinfo, "\nPid:");
|
||||
if (!p)
|
||||
return -ENOTTY; /* not a pidfd? */
|
||||
|
||||
p += 5;
|
||||
}
|
||||
|
||||
p += strspn(p, WHITESPACE);
|
||||
p[strcspn(p, WHITESPACE)] = 0;
|
||||
|
||||
return parse_pid(p, ret);
|
||||
}
|
||||
|
||||
static const char *const ioprio_class_table[] = {
|
||||
[IOPRIO_CLASS_NONE] = "none",
|
||||
[IOPRIO_CLASS_RT] = "realtime",
|
||||
|
@@ -149,16 +149,17 @@ void reset_cached_pid(void);
|
||||
int must_be_root(void);
|
||||
|
||||
typedef enum ForkFlags {
|
||||
FORK_RESET_SIGNALS = 1 << 0, /* Reset all signal handlers and signal mask */
|
||||
FORK_CLOSE_ALL_FDS = 1 << 1, /* Close all open file descriptors in the child, except for 0,1,2 */
|
||||
FORK_DEATHSIG = 1 << 2, /* Set PR_DEATHSIG in the child */
|
||||
FORK_NULL_STDIO = 1 << 3, /* Connect 0,1,2 to /dev/null */
|
||||
FORK_REOPEN_LOG = 1 << 4, /* Reopen log connection */
|
||||
FORK_LOG = 1 << 5, /* Log above LOG_DEBUG log level about failures */
|
||||
FORK_WAIT = 1 << 6, /* Wait until child exited */
|
||||
FORK_NEW_MOUNTNS = 1 << 7, /* Run child in its own mount namespace */
|
||||
FORK_MOUNTNS_SLAVE = 1 << 8, /* Make child's mount namespace MS_SLAVE */
|
||||
FORK_RLIMIT_NOFILE_SAFE = 1 << 9, /* Set RLIMIT_NOFILE soft limit to 1K for select() compat */
|
||||
FORK_RESET_SIGNALS = 1 << 0, /* Reset all signal handlers and signal mask */
|
||||
FORK_CLOSE_ALL_FDS = 1 << 1, /* Close all open file descriptors in the child, except for 0,1,2 */
|
||||
FORK_DEATHSIG = 1 << 2, /* Set PR_DEATHSIG in the child */
|
||||
FORK_NULL_STDIO = 1 << 3, /* Connect 0,1,2 to /dev/null */
|
||||
FORK_REOPEN_LOG = 1 << 4, /* Reopen log connection */
|
||||
FORK_LOG = 1 << 5, /* Log above LOG_DEBUG log level about failures */
|
||||
FORK_WAIT = 1 << 6, /* Wait until child exited */
|
||||
FORK_NEW_MOUNTNS = 1 << 7, /* Run child in its own mount namespace */
|
||||
FORK_MOUNTNS_SLAVE = 1 << 8, /* Make child's mount namespace MS_SLAVE */
|
||||
FORK_RLIMIT_NOFILE_SAFE = 1 << 9, /* Set RLIMIT_NOFILE soft limit to 1K for select() compat */
|
||||
FORK_STDOUT_TO_STDERR = 1 << 10, /* Make stdout a copy of stderr */
|
||||
} ForkFlags;
|
||||
|
||||
int safe_fork_full(const char *name, const int except_fds[], size_t n_except_fds, ForkFlags flags, pid_t *ret_pid);
|
||||
@@ -199,3 +200,5 @@ assert_cc(TASKS_MAX <= (unsigned long) PID_T_MAX);
|
||||
(pid) = 0; \
|
||||
_pid_; \
|
||||
})
|
||||
|
||||
int pidfd_get_pid(int fd, pid_t *ret);
|
||||
|
308
shared/systemd/src/basic/signal-util.c
Normal file
308
shared/systemd/src/basic/signal-util.c
Normal file
@@ -0,0 +1,308 @@
|
||||
/* SPDX-License-Identifier: LGPL-2.1+ */
|
||||
|
||||
#include "nm-sd-adapt-shared.h"
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
#include "macro.h"
|
||||
#include "parse-util.h"
|
||||
#include "signal-util.h"
|
||||
#include "stdio-util.h"
|
||||
#include "string-table.h"
|
||||
#include "string-util.h"
|
||||
|
||||
#if 0 /* NM_IGNORED */
|
||||
int reset_all_signal_handlers(void) {
|
||||
static const struct sigaction sa = {
|
||||
.sa_handler = SIG_DFL,
|
||||
.sa_flags = SA_RESTART,
|
||||
};
|
||||
int sig, r = 0;
|
||||
|
||||
for (sig = 1; sig < _NSIG; sig++) {
|
||||
|
||||
/* These two cannot be caught... */
|
||||
if (IN_SET(sig, SIGKILL, SIGSTOP))
|
||||
continue;
|
||||
|
||||
/* On Linux the first two RT signals are reserved by
|
||||
* glibc, and sigaction() will return EINVAL for them. */
|
||||
if (sigaction(sig, &sa, NULL) < 0)
|
||||
if (errno != EINVAL && r >= 0)
|
||||
r = -errno;
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
int reset_signal_mask(void) {
|
||||
sigset_t ss;
|
||||
|
||||
if (sigemptyset(&ss) < 0)
|
||||
return -errno;
|
||||
|
||||
if (sigprocmask(SIG_SETMASK, &ss, NULL) < 0)
|
||||
return -errno;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sigaction_many_ap(const struct sigaction *sa, int sig, va_list ap) {
|
||||
int r = 0;
|
||||
|
||||
/* negative signal ends the list. 0 signal is skipped. */
|
||||
|
||||
if (sig < 0)
|
||||
return 0;
|
||||
|
||||
if (sig > 0) {
|
||||
if (sigaction(sig, sa, NULL) < 0)
|
||||
r = -errno;
|
||||
}
|
||||
|
||||
while ((sig = va_arg(ap, int)) >= 0) {
|
||||
|
||||
if (sig == 0)
|
||||
continue;
|
||||
|
||||
if (sigaction(sig, sa, NULL) < 0) {
|
||||
if (r >= 0)
|
||||
r = -errno;
|
||||
}
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
int sigaction_many(const struct sigaction *sa, ...) {
|
||||
va_list ap;
|
||||
int r;
|
||||
|
||||
va_start(ap, sa);
|
||||
r = sigaction_many_ap(sa, 0, ap);
|
||||
va_end(ap);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
int ignore_signals(int sig, ...) {
|
||||
|
||||
static const struct sigaction sa = {
|
||||
.sa_handler = SIG_IGN,
|
||||
.sa_flags = SA_RESTART,
|
||||
};
|
||||
|
||||
va_list ap;
|
||||
int r;
|
||||
|
||||
va_start(ap, sig);
|
||||
r = sigaction_many_ap(&sa, sig, ap);
|
||||
va_end(ap);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
int default_signals(int sig, ...) {
|
||||
|
||||
static const struct sigaction sa = {
|
||||
.sa_handler = SIG_DFL,
|
||||
.sa_flags = SA_RESTART,
|
||||
};
|
||||
|
||||
va_list ap;
|
||||
int r;
|
||||
|
||||
va_start(ap, sig);
|
||||
r = sigaction_many_ap(&sa, sig, ap);
|
||||
va_end(ap);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static int sigset_add_many_ap(sigset_t *ss, va_list ap) {
|
||||
int sig, r = 0;
|
||||
|
||||
assert(ss);
|
||||
|
||||
while ((sig = va_arg(ap, int)) >= 0) {
|
||||
|
||||
if (sig == 0)
|
||||
continue;
|
||||
|
||||
if (sigaddset(ss, sig) < 0) {
|
||||
if (r >= 0)
|
||||
r = -errno;
|
||||
}
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
int sigset_add_many(sigset_t *ss, ...) {
|
||||
va_list ap;
|
||||
int r;
|
||||
|
||||
va_start(ap, ss);
|
||||
r = sigset_add_many_ap(ss, ap);
|
||||
va_end(ap);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
int sigprocmask_many(int how, sigset_t *old, ...) {
|
||||
va_list ap;
|
||||
sigset_t ss;
|
||||
int r;
|
||||
|
||||
if (sigemptyset(&ss) < 0)
|
||||
return -errno;
|
||||
|
||||
va_start(ap, old);
|
||||
r = sigset_add_many_ap(&ss, ap);
|
||||
va_end(ap);
|
||||
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (sigprocmask(how, &ss, old) < 0)
|
||||
return -errno;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const char *const __signal_table[] = {
|
||||
[SIGHUP] = "HUP",
|
||||
[SIGINT] = "INT",
|
||||
[SIGQUIT] = "QUIT",
|
||||
[SIGILL] = "ILL",
|
||||
[SIGTRAP] = "TRAP",
|
||||
[SIGABRT] = "ABRT",
|
||||
[SIGBUS] = "BUS",
|
||||
[SIGFPE] = "FPE",
|
||||
[SIGKILL] = "KILL",
|
||||
[SIGUSR1] = "USR1",
|
||||
[SIGSEGV] = "SEGV",
|
||||
[SIGUSR2] = "USR2",
|
||||
[SIGPIPE] = "PIPE",
|
||||
[SIGALRM] = "ALRM",
|
||||
[SIGTERM] = "TERM",
|
||||
#ifdef SIGSTKFLT
|
||||
[SIGSTKFLT] = "STKFLT", /* Linux on SPARC doesn't know SIGSTKFLT */
|
||||
#endif
|
||||
[SIGCHLD] = "CHLD",
|
||||
[SIGCONT] = "CONT",
|
||||
[SIGSTOP] = "STOP",
|
||||
[SIGTSTP] = "TSTP",
|
||||
[SIGTTIN] = "TTIN",
|
||||
[SIGTTOU] = "TTOU",
|
||||
[SIGURG] = "URG",
|
||||
[SIGXCPU] = "XCPU",
|
||||
[SIGXFSZ] = "XFSZ",
|
||||
[SIGVTALRM] = "VTALRM",
|
||||
[SIGPROF] = "PROF",
|
||||
[SIGWINCH] = "WINCH",
|
||||
[SIGIO] = "IO",
|
||||
[SIGPWR] = "PWR",
|
||||
[SIGSYS] = "SYS"
|
||||
};
|
||||
|
||||
DEFINE_PRIVATE_STRING_TABLE_LOOKUP(__signal, int);
|
||||
|
||||
const char *signal_to_string(int signo) {
|
||||
static thread_local char buf[STRLEN("RTMIN+") + DECIMAL_STR_MAX(int) + 1];
|
||||
const char *name;
|
||||
|
||||
name = __signal_to_string(signo);
|
||||
if (name)
|
||||
return name;
|
||||
|
||||
if (signo >= SIGRTMIN && signo <= SIGRTMAX)
|
||||
xsprintf(buf, "RTMIN+%d", signo - SIGRTMIN);
|
||||
else
|
||||
xsprintf(buf, "%d", signo);
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
int signal_from_string(const char *s) {
|
||||
const char *p;
|
||||
int signo, r;
|
||||
|
||||
/* Check that the input is a signal number. */
|
||||
if (safe_atoi(s, &signo) >= 0) {
|
||||
if (SIGNAL_VALID(signo))
|
||||
return signo;
|
||||
else
|
||||
return -ERANGE;
|
||||
}
|
||||
|
||||
/* Drop "SIG" prefix. */
|
||||
if (startswith(s, "SIG"))
|
||||
s += 3;
|
||||
|
||||
/* Check that the input is a signal name. */
|
||||
signo = __signal_from_string(s);
|
||||
if (signo > 0)
|
||||
return signo;
|
||||
|
||||
/* Check that the input is RTMIN or
|
||||
* RTMIN+n (0 <= n <= SIGRTMAX-SIGRTMIN). */
|
||||
p = startswith(s, "RTMIN");
|
||||
if (p) {
|
||||
if (*p == '\0')
|
||||
return SIGRTMIN;
|
||||
if (*p != '+')
|
||||
return -EINVAL;
|
||||
|
||||
r = safe_atoi(p, &signo);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (signo < 0 || signo > SIGRTMAX - SIGRTMIN)
|
||||
return -ERANGE;
|
||||
|
||||
return signo + SIGRTMIN;
|
||||
}
|
||||
|
||||
/* Check that the input is RTMAX or
|
||||
* RTMAX-n (0 <= n <= SIGRTMAX-SIGRTMIN). */
|
||||
p = startswith(s, "RTMAX");
|
||||
if (p) {
|
||||
if (*p == '\0')
|
||||
return SIGRTMAX;
|
||||
if (*p != '-')
|
||||
return -EINVAL;
|
||||
|
||||
r = safe_atoi(p, &signo);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (signo > 0 || signo < SIGRTMIN - SIGRTMAX)
|
||||
return -ERANGE;
|
||||
|
||||
return signo + SIGRTMAX;
|
||||
}
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
void nop_signal_handler(int sig) {
|
||||
/* nothing here */
|
||||
}
|
||||
#endif /* NM_IGNORED */
|
||||
|
||||
int signal_is_blocked(int sig) {
|
||||
sigset_t ss;
|
||||
int r;
|
||||
|
||||
r = pthread_sigmask(SIG_SETMASK, NULL, &ss);
|
||||
if (r != 0)
|
||||
return -r;
|
||||
|
||||
r = sigismember(&ss, sig);
|
||||
if (r < 0)
|
||||
return -errno;
|
||||
|
||||
return r;
|
||||
}
|
@@ -41,3 +41,5 @@ static inline const char* signal_to_string_with_check(int n) {
|
||||
|
||||
return signal_to_string(n);
|
||||
}
|
||||
|
||||
int signal_is_blocked(int sig);
|
||||
|
@@ -31,6 +31,7 @@ int is_symlink(const char *path) {
|
||||
|
||||
return !!S_ISLNK(info.st_mode);
|
||||
}
|
||||
#endif /* NM_IGNORED */
|
||||
|
||||
int is_dir(const char* path, bool follow) {
|
||||
struct stat st;
|
||||
@@ -48,6 +49,7 @@ int is_dir(const char* path, bool follow) {
|
||||
return !!S_ISDIR(st.st_mode);
|
||||
}
|
||||
|
||||
#if 0 /* NM_IGNORED */
|
||||
int is_dir_fd(int fd) {
|
||||
struct stat st;
|
||||
|
||||
|
@@ -1072,3 +1072,15 @@ bool string_is_safe(const char *p) {
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#if 0 /* NM_IGNORED */
|
||||
char* string_erase(char *x) {
|
||||
if (!x)
|
||||
return NULL;
|
||||
|
||||
/* A delicious drop of snake-oil! To be called on memory where we stored passphrases or so, after we
|
||||
* used them. */
|
||||
explicit_bzero_safe(x, strlen(x));
|
||||
return x;
|
||||
}
|
||||
#endif /* NM_IGNORED */
|
||||
|
@@ -278,3 +278,5 @@ static inline char* str_realloc(char **p) {
|
||||
|
||||
return (*p = t);
|
||||
}
|
||||
|
||||
char* string_erase(char *x);
|
||||
|
@@ -195,7 +195,10 @@ int strv_extend_strv(char ***a, char **b, bool filter_duplicates) {
|
||||
p = strv_length(*a);
|
||||
q = strv_length(b);
|
||||
|
||||
t = reallocarray(*a, p + q + 1, sizeof(char *));
|
||||
if (p >= SIZE_MAX - q)
|
||||
return -ENOMEM;
|
||||
|
||||
t = reallocarray(*a, GREEDY_ALLOC_ROUND_UP(p + q + 1), sizeof(char *));
|
||||
if (!t)
|
||||
return -ENOMEM;
|
||||
|
||||
@@ -389,19 +392,18 @@ char *strv_join_prefix(char **l, const char *separator, const char *prefix) {
|
||||
|
||||
int strv_push(char ***l, char *value) {
|
||||
char **c;
|
||||
size_t n, m;
|
||||
size_t n;
|
||||
|
||||
if (!value)
|
||||
return 0;
|
||||
|
||||
n = strv_length(*l);
|
||||
|
||||
/* Increase and check for overflow */
|
||||
m = n + 2;
|
||||
if (m < n)
|
||||
/* Check for overflow */
|
||||
if (n > SIZE_MAX-2)
|
||||
return -ENOMEM;
|
||||
|
||||
c = reallocarray(*l, m, sizeof(char*));
|
||||
c = reallocarray(*l, GREEDY_ALLOC_ROUND_UP(n + 2), sizeof(char*));
|
||||
if (!c)
|
||||
return -ENOMEM;
|
||||
|
||||
@@ -414,19 +416,19 @@ int strv_push(char ***l, char *value) {
|
||||
|
||||
int strv_push_pair(char ***l, char *a, char *b) {
|
||||
char **c;
|
||||
size_t n, m;
|
||||
size_t n;
|
||||
|
||||
if (!a && !b)
|
||||
return 0;
|
||||
|
||||
n = strv_length(*l);
|
||||
|
||||
/* increase and check for overflow */
|
||||
m = n + !!a + !!b + 1;
|
||||
if (m < n)
|
||||
/* Check for overflow */
|
||||
if (n > SIZE_MAX-3)
|
||||
return -ENOMEM;
|
||||
|
||||
c = reallocarray(*l, m, sizeof(char*));
|
||||
/* increase and check for overflow */
|
||||
c = reallocarray(*l, GREEDY_ALLOC_ROUND_UP(n + !!a + !!b + 1), sizeof(char*));
|
||||
if (!c)
|
||||
return -ENOMEM;
|
||||
|
||||
@@ -856,8 +858,10 @@ int strv_extend_n(char ***l, const char *value, size_t n) {
|
||||
/* Adds the value n times to l */
|
||||
|
||||
k = strv_length(*l);
|
||||
if (n >= SIZE_MAX - k)
|
||||
return -ENOMEM;
|
||||
|
||||
nl = reallocarray(*l, k + n + 1, sizeof(char *));
|
||||
nl = reallocarray(*l, GREEDY_ALLOC_ROUND_UP(k + n + 1), sizeof(char *));
|
||||
if (!nl)
|
||||
return -ENOMEM;
|
||||
|
||||
|
@@ -21,50 +21,60 @@
|
||||
#include "tmpfile-util.h"
|
||||
#include "umask-util.h"
|
||||
|
||||
int fopen_temporary(const char *path, FILE **_f, char **_temp_path) {
|
||||
FILE *f;
|
||||
char *t;
|
||||
int r, fd;
|
||||
int fopen_temporary(const char *path, FILE **ret_f, char **ret_temp_path) {
|
||||
_cleanup_fclose_ FILE *f = NULL;
|
||||
_cleanup_free_ char *t = NULL;
|
||||
_cleanup_close_ int fd = -1;
|
||||
int r;
|
||||
|
||||
assert(path);
|
||||
assert(_f);
|
||||
assert(_temp_path);
|
||||
if (path) {
|
||||
r = tempfn_xxxxxx(path, NULL, &t);
|
||||
if (r < 0)
|
||||
return r;
|
||||
} else {
|
||||
const char *d;
|
||||
|
||||
r = tempfn_xxxxxx(path, NULL, &t);
|
||||
if (r < 0)
|
||||
return r;
|
||||
r = tmp_dir(&d);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
t = path_join(d, "XXXXXX");
|
||||
if (!t)
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
fd = mkostemp_safe(t);
|
||||
if (fd < 0) {
|
||||
free(t);
|
||||
if (fd < 0)
|
||||
return -errno;
|
||||
}
|
||||
|
||||
/* This assumes that returned FILE object is short-lived and used within the same single-threaded
|
||||
* context and never shared externally, hence locking is not necessary. */
|
||||
|
||||
r = fdopen_unlocked(fd, "w", &f);
|
||||
if (r < 0) {
|
||||
unlink(t);
|
||||
free(t);
|
||||
safe_close(fd);
|
||||
(void) unlink(t);
|
||||
return r;
|
||||
}
|
||||
|
||||
*_f = f;
|
||||
*_temp_path = t;
|
||||
TAKE_FD(fd);
|
||||
|
||||
if (ret_f)
|
||||
*ret_f = TAKE_PTR(f);
|
||||
|
||||
if (ret_temp_path)
|
||||
*ret_temp_path = TAKE_PTR(t);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* This is much like mkostemp() but is subject to umask(). */
|
||||
int mkostemp_safe(char *pattern) {
|
||||
_unused_ _cleanup_umask_ mode_t u = umask(0077);
|
||||
int fd;
|
||||
int fd = -1; /* avoid false maybe-uninitialized warning */
|
||||
|
||||
assert(pattern);
|
||||
|
||||
fd = mkostemp(pattern, O_CLOEXEC);
|
||||
RUN_WITH_UMASK(0077)
|
||||
fd = mkostemp(pattern, O_CLOEXEC);
|
||||
if (fd < 0)
|
||||
return -errno;
|
||||
|
||||
|
@@ -443,7 +443,7 @@ int sd_ipv4acd_is_running(sd_ipv4acd *acd) {
|
||||
return acd->state != IPV4ACD_STATE_INIT;
|
||||
}
|
||||
|
||||
int sd_ipv4acd_start(sd_ipv4acd *acd) {
|
||||
int sd_ipv4acd_start(sd_ipv4acd *acd, bool reset_conflicts) {
|
||||
int r;
|
||||
|
||||
assert_return(acd, -EINVAL);
|
||||
@@ -460,7 +460,9 @@ int sd_ipv4acd_start(sd_ipv4acd *acd) {
|
||||
safe_close(acd->fd);
|
||||
acd->fd = r;
|
||||
acd->defend_window = 0;
|
||||
acd->n_conflict = 0;
|
||||
|
||||
if (reset_conflicts)
|
||||
acd->n_conflict = 0;
|
||||
|
||||
r = sd_event_add_io(acd->event, &acd->receive_message_event_source, acd->fd, EPOLLIN, ipv4acd_on_packet, acd);
|
||||
if (r < 0)
|
||||
|
@@ -243,7 +243,7 @@ static int ipv4ll_start_internal(sd_ipv4ll *ll, bool reset_generation) {
|
||||
picked_address = true;
|
||||
}
|
||||
|
||||
r = sd_ipv4acd_start(ll->acd);
|
||||
r = sd_ipv4acd_start(ll->acd, reset_generation);
|
||||
if (r < 0) {
|
||||
|
||||
/* We couldn't start? If so, let's forget the picked address again, the user might make a change and
|
||||
|
@@ -34,7 +34,7 @@ typedef enum EventSourceType {
|
||||
* we know how to dispatch it */
|
||||
typedef enum WakeupType {
|
||||
WAKEUP_NONE,
|
||||
WAKEUP_EVENT_SOURCE,
|
||||
WAKEUP_EVENT_SOURCE, /* either I/O or pidfd wakeup */
|
||||
WAKEUP_CLOCK_DATA,
|
||||
WAKEUP_SIGNAL_DATA,
|
||||
WAKEUP_INOTIFY_DATA,
|
||||
@@ -96,6 +96,12 @@ struct sd_event_source {
|
||||
siginfo_t siginfo;
|
||||
pid_t pid;
|
||||
int options;
|
||||
int pidfd;
|
||||
bool registered:1; /* whether the pidfd is registered in the epoll */
|
||||
bool pidfd_owned:1; /* close pidfd when event source is freed */
|
||||
bool process_owned:1; /* kill+reap process when event source is freed */
|
||||
bool exited:1; /* true if process exited (i.e. if there's value in SIGKILLing it if we want to get rid of it) */
|
||||
bool waited:1; /* true if process was waited for (i.e. if there's value in waitid(P_PID)'ing it if we want to get rid of it) */
|
||||
} child;
|
||||
struct {
|
||||
sd_event_handler_t callback;
|
||||
|
@@ -11,6 +11,7 @@
|
||||
#include "sd-id128.h"
|
||||
|
||||
#include "alloc-util.h"
|
||||
#include "env-util.h"
|
||||
#include "event-source.h"
|
||||
#include "fd-util.h"
|
||||
#include "fs-util.h"
|
||||
@@ -30,6 +31,14 @@
|
||||
|
||||
#define DEFAULT_ACCURACY_USEC (250 * USEC_PER_MSEC)
|
||||
|
||||
static bool EVENT_SOURCE_WATCH_PIDFD(sd_event_source *s) {
|
||||
/* Returns true if this is a PID event source and can be implemented by watching EPOLLIN */
|
||||
return s &&
|
||||
s->type == SOURCE_CHILD &&
|
||||
s->child.pidfd >= 0 &&
|
||||
s->child.options == WEXITED;
|
||||
}
|
||||
|
||||
static const char* const event_source_type_table[_SOURCE_EVENT_SOURCE_TYPE_MAX] = {
|
||||
[SOURCE_IO] = "io",
|
||||
[SOURCE_TIME_REALTIME] = "realtime",
|
||||
@@ -358,8 +367,6 @@ static bool event_pid_changed(sd_event *e) {
|
||||
}
|
||||
|
||||
static void source_io_unregister(sd_event_source *s) {
|
||||
int r;
|
||||
|
||||
assert(s);
|
||||
assert(s->type == SOURCE_IO);
|
||||
|
||||
@@ -369,8 +376,7 @@ static void source_io_unregister(sd_event_source *s) {
|
||||
if (!s->io.registered)
|
||||
return;
|
||||
|
||||
r = epoll_ctl(s->event->epoll_fd, EPOLL_CTL_DEL, s->io.fd, NULL);
|
||||
if (r < 0)
|
||||
if (epoll_ctl(s->event->epoll_fd, EPOLL_CTL_DEL, s->io.fd, NULL) < 0)
|
||||
log_debug_errno(errno, "Failed to remove source %s (type %s) from epoll: %m",
|
||||
strna(s->description), event_source_type_to_string(s->type));
|
||||
|
||||
@@ -406,6 +412,51 @@ static int source_io_register(
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void source_child_pidfd_unregister(sd_event_source *s) {
|
||||
assert(s);
|
||||
assert(s->type == SOURCE_CHILD);
|
||||
|
||||
if (event_pid_changed(s->event))
|
||||
return;
|
||||
|
||||
if (!s->child.registered)
|
||||
return;
|
||||
|
||||
if (EVENT_SOURCE_WATCH_PIDFD(s))
|
||||
if (epoll_ctl(s->event->epoll_fd, EPOLL_CTL_DEL, s->child.pidfd, NULL) < 0)
|
||||
log_debug_errno(errno, "Failed to remove source %s (type %s) from epoll: %m",
|
||||
strna(s->description), event_source_type_to_string(s->type));
|
||||
|
||||
s->child.registered = false;
|
||||
}
|
||||
|
||||
static int source_child_pidfd_register(sd_event_source *s, int enabled) {
|
||||
int r;
|
||||
|
||||
assert(s);
|
||||
assert(s->type == SOURCE_CHILD);
|
||||
assert(enabled != SD_EVENT_OFF);
|
||||
|
||||
if (EVENT_SOURCE_WATCH_PIDFD(s)) {
|
||||
struct epoll_event ev;
|
||||
|
||||
ev = (struct epoll_event) {
|
||||
.events = EPOLLIN | (enabled == SD_EVENT_ONESHOT ? EPOLLONESHOT : 0),
|
||||
.data.ptr = s,
|
||||
};
|
||||
|
||||
if (s->child.registered)
|
||||
r = epoll_ctl(s->event->epoll_fd, EPOLL_CTL_MOD, s->child.pidfd, &ev);
|
||||
else
|
||||
r = epoll_ctl(s->event->epoll_fd, EPOLL_CTL_ADD, s->child.pidfd, &ev);
|
||||
if (r < 0)
|
||||
return -errno;
|
||||
}
|
||||
|
||||
s->child.registered = true;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static clockid_t event_source_type_to_clock(EventSourceType t) {
|
||||
|
||||
switch (t) {
|
||||
@@ -616,9 +667,8 @@ static void event_gc_signal_data(sd_event *e, const int64_t *priority, int sig)
|
||||
|
||||
assert(e);
|
||||
|
||||
/* Rechecks if the specified signal is still something we are
|
||||
* interested in. If not, we'll unmask it, and possibly drop
|
||||
* the signalfd for it. */
|
||||
/* Rechecks if the specified signal is still something we are interested in. If not, we'll unmask it,
|
||||
* and possibly drop the signalfd for it. */
|
||||
|
||||
if (sig == SIGCHLD &&
|
||||
e->n_enabled_child_sources > 0)
|
||||
@@ -709,9 +759,13 @@ static void source_disconnect(sd_event_source *s) {
|
||||
}
|
||||
|
||||
(void) hashmap_remove(s->event->child_sources, PID_TO_PTR(s->child.pid));
|
||||
event_gc_signal_data(s->event, &s->priority, SIGCHLD);
|
||||
}
|
||||
|
||||
if (EVENT_SOURCE_WATCH_PIDFD(s))
|
||||
source_child_pidfd_unregister(s);
|
||||
else
|
||||
event_gc_signal_data(s->event, &s->priority, SIGCHLD);
|
||||
|
||||
break;
|
||||
|
||||
case SOURCE_DEFER:
|
||||
@@ -792,6 +846,44 @@ static void source_free(sd_event_source *s) {
|
||||
if (s->type == SOURCE_IO && s->io.owned)
|
||||
s->io.fd = safe_close(s->io.fd);
|
||||
|
||||
if (s->type == SOURCE_CHILD) {
|
||||
/* Eventually the kernel will do this automatically for us, but for now let's emulate this (unreliably) in userspace. */
|
||||
|
||||
if (s->child.process_owned) {
|
||||
|
||||
if (!s->child.exited) {
|
||||
bool sent = false;
|
||||
|
||||
if (s->child.pidfd >= 0) {
|
||||
if (pidfd_send_signal(s->child.pidfd, SIGKILL, NULL, 0) < 0) {
|
||||
if (errno == ESRCH) /* Already dead */
|
||||
sent = true;
|
||||
else if (!ERRNO_IS_NOT_SUPPORTED(errno))
|
||||
log_debug_errno(errno, "Failed to kill process " PID_FMT " via pidfd_send_signal(), re-trying via kill(): %m",
|
||||
s->child.pid);
|
||||
} else
|
||||
sent = true;
|
||||
}
|
||||
|
||||
if (!sent)
|
||||
if (kill(s->child.pid, SIGKILL) < 0)
|
||||
if (errno != ESRCH) /* Already dead */
|
||||
log_debug_errno(errno, "Failed to kill process " PID_FMT " via kill(), ignoring: %m",
|
||||
s->child.pid);
|
||||
}
|
||||
|
||||
if (!s->child.waited) {
|
||||
siginfo_t si = {};
|
||||
|
||||
/* Reap the child if we can */
|
||||
(void) waitid(P_PID, s->child.pid, &si, WEXITED);
|
||||
}
|
||||
}
|
||||
|
||||
if (s->child.pidfd_owned)
|
||||
s->child.pidfd = safe_close(s->child.pidfd);
|
||||
}
|
||||
|
||||
if (s->destroy_callback)
|
||||
s->destroy_callback(s->userdata);
|
||||
|
||||
@@ -1076,7 +1168,6 @@ _public_ int sd_event_add_signal(
|
||||
|
||||
_cleanup_(source_freep) sd_event_source *s = NULL;
|
||||
struct signal_data *d;
|
||||
sigset_t ss;
|
||||
int r;
|
||||
|
||||
assert_return(e, -EINVAL);
|
||||
@@ -1088,11 +1179,10 @@ _public_ int sd_event_add_signal(
|
||||
if (!callback)
|
||||
callback = signal_exit_callback;
|
||||
|
||||
r = pthread_sigmask(SIG_SETMASK, NULL, &ss);
|
||||
if (r != 0)
|
||||
return -r;
|
||||
|
||||
if (!sigismember(&ss, sig))
|
||||
r = signal_is_blocked(sig);
|
||||
if (r < 0)
|
||||
return r;
|
||||
if (r == 0)
|
||||
return -EBUSY;
|
||||
|
||||
if (!e->signal_sources) {
|
||||
@@ -1126,7 +1216,11 @@ _public_ int sd_event_add_signal(
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif /* NM_IGNORED */
|
||||
|
||||
static bool shall_use_pidfd(void) {
|
||||
/* Mostly relevant for debugging, i.e. this is used in test-event.c to test the event loop once with and once without pidfd */
|
||||
return getenv_bool_secure("SYSTEMD_PIDFD") != 0;
|
||||
}
|
||||
|
||||
_public_ int sd_event_add_child(
|
||||
sd_event *e,
|
||||
@@ -1148,6 +1242,20 @@ _public_ int sd_event_add_child(
|
||||
assert_return(e->state != SD_EVENT_FINISHED, -ESTALE);
|
||||
assert_return(!event_pid_changed(e), -ECHILD);
|
||||
|
||||
if (e->n_enabled_child_sources == 0) {
|
||||
/* Caller must block SIGCHLD before using us to watch children, even if pidfd is available,
|
||||
* for compatibility with pre-pidfd and because we don't want the reap the child processes
|
||||
* ourselves, i.e. call waitid(), and don't want Linux' default internal logic for that to
|
||||
* take effect.
|
||||
*
|
||||
* (As an optimization we only do this check on the first child event source created.) */
|
||||
r = signal_is_blocked(SIGCHLD);
|
||||
if (r < 0)
|
||||
return r;
|
||||
if (r == 0)
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
r = hashmap_ensure_allocated(&e->child_sources, NULL);
|
||||
if (r < 0)
|
||||
return r;
|
||||
@@ -1159,32 +1267,147 @@ _public_ int sd_event_add_child(
|
||||
if (!s)
|
||||
return -ENOMEM;
|
||||
|
||||
s->wakeup = WAKEUP_EVENT_SOURCE;
|
||||
s->child.pid = pid;
|
||||
s->child.options = options;
|
||||
s->child.callback = callback;
|
||||
s->userdata = userdata;
|
||||
s->enabled = SD_EVENT_ONESHOT;
|
||||
|
||||
/* We always take a pidfd here if we can, even if we wait for anything else than WEXITED, so that we
|
||||
* pin the PID, and make regular waitid() handling race-free. */
|
||||
|
||||
if (shall_use_pidfd()) {
|
||||
s->child.pidfd = pidfd_open(s->child.pid, 0);
|
||||
if (s->child.pidfd < 0) {
|
||||
/* Propagate errors unless the syscall is not supported or blocked */
|
||||
if (!ERRNO_IS_NOT_SUPPORTED(errno) && !ERRNO_IS_PRIVILEGE(errno))
|
||||
return -errno;
|
||||
} else
|
||||
s->child.pidfd_owned = true; /* If we allocate the pidfd we own it by default */
|
||||
} else
|
||||
s->child.pidfd = -1;
|
||||
|
||||
r = hashmap_put(e->child_sources, PID_TO_PTR(pid), s);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
e->n_enabled_child_sources++;
|
||||
|
||||
if (EVENT_SOURCE_WATCH_PIDFD(s)) {
|
||||
/* We have a pidfd and we only want to watch for exit */
|
||||
|
||||
r = source_child_pidfd_register(s, s->enabled);
|
||||
if (r < 0) {
|
||||
e->n_enabled_child_sources--;
|
||||
return r;
|
||||
}
|
||||
} else {
|
||||
/* We have no pidfd or we shall wait for some other event than WEXITED */
|
||||
|
||||
r = event_make_signal_data(e, SIGCHLD, NULL);
|
||||
if (r < 0) {
|
||||
e->n_enabled_child_sources--;
|
||||
return r;
|
||||
}
|
||||
|
||||
e->need_process_child = true;
|
||||
}
|
||||
|
||||
if (ret)
|
||||
*ret = s;
|
||||
|
||||
TAKE_PTR(s);
|
||||
return 0;
|
||||
}
|
||||
|
||||
_public_ int sd_event_add_child_pidfd(
|
||||
sd_event *e,
|
||||
sd_event_source **ret,
|
||||
int pidfd,
|
||||
int options,
|
||||
sd_event_child_handler_t callback,
|
||||
void *userdata) {
|
||||
|
||||
|
||||
_cleanup_(source_freep) sd_event_source *s = NULL;
|
||||
pid_t pid;
|
||||
int r;
|
||||
|
||||
assert_return(e, -EINVAL);
|
||||
assert_return(e = event_resolve(e), -ENOPKG);
|
||||
assert_return(pidfd >= 0, -EBADF);
|
||||
assert_return(!(options & ~(WEXITED|WSTOPPED|WCONTINUED)), -EINVAL);
|
||||
assert_return(options != 0, -EINVAL);
|
||||
assert_return(callback, -EINVAL);
|
||||
assert_return(e->state != SD_EVENT_FINISHED, -ESTALE);
|
||||
assert_return(!event_pid_changed(e), -ECHILD);
|
||||
|
||||
if (e->n_enabled_child_sources == 0) {
|
||||
r = signal_is_blocked(SIGCHLD);
|
||||
if (r < 0)
|
||||
return r;
|
||||
if (r == 0)
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
r = hashmap_ensure_allocated(&e->child_sources, NULL);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = pidfd_get_pid(pidfd, &pid);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (hashmap_contains(e->child_sources, PID_TO_PTR(pid)))
|
||||
return -EBUSY;
|
||||
|
||||
s = source_new(e, !ret, SOURCE_CHILD);
|
||||
if (!s)
|
||||
return -ENOMEM;
|
||||
|
||||
s->wakeup = WAKEUP_EVENT_SOURCE;
|
||||
s->child.pidfd = pidfd;
|
||||
s->child.pid = pid;
|
||||
s->child.options = options;
|
||||
s->child.callback = callback;
|
||||
s->child.pidfd_owned = false; /* If we got the pidfd passed in we don't own it by default (similar to the IO fd case) */
|
||||
s->userdata = userdata;
|
||||
s->enabled = SD_EVENT_ONESHOT;
|
||||
|
||||
r = hashmap_put(e->child_sources, PID_TO_PTR(pid), s);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
e->n_enabled_child_sources++;
|
||||
|
||||
r = event_make_signal_data(e, SIGCHLD, NULL);
|
||||
if (r < 0) {
|
||||
e->n_enabled_child_sources--;
|
||||
return r;
|
||||
}
|
||||
if (EVENT_SOURCE_WATCH_PIDFD(s)) {
|
||||
/* We only want to watch for WEXITED */
|
||||
|
||||
e->need_process_child = true;
|
||||
r = source_child_pidfd_register(s, s->enabled);
|
||||
if (r < 0) {
|
||||
e->n_enabled_child_sources--;
|
||||
return r;
|
||||
}
|
||||
} else {
|
||||
/* We shall wait for some other event than WEXITED */
|
||||
|
||||
r = event_make_signal_data(e, SIGCHLD, NULL);
|
||||
if (r < 0) {
|
||||
e->n_enabled_child_sources--;
|
||||
return r;
|
||||
}
|
||||
|
||||
e->need_process_child = true;
|
||||
}
|
||||
|
||||
if (ret)
|
||||
*ret = s;
|
||||
TAKE_PTR(s);
|
||||
|
||||
TAKE_PTR(s);
|
||||
return 0;
|
||||
}
|
||||
#endif /* NM_IGNORED */
|
||||
|
||||
_public_ int sd_event_add_defer(
|
||||
sd_event *e,
|
||||
@@ -1769,7 +1992,7 @@ _public_ int sd_event_source_set_io_fd(sd_event_source *s, int fd) {
|
||||
return r;
|
||||
}
|
||||
|
||||
epoll_ctl(s->event->epoll_fd, EPOLL_CTL_DEL, saved_fd, NULL);
|
||||
(void) epoll_ctl(s->event->epoll_fd, EPOLL_CTL_DEL, saved_fd, NULL);
|
||||
}
|
||||
|
||||
return 0;
|
||||
@@ -2030,7 +2253,11 @@ _public_ int sd_event_source_set_enabled(sd_event_source *s, int m) {
|
||||
assert(s->event->n_enabled_child_sources > 0);
|
||||
s->event->n_enabled_child_sources--;
|
||||
|
||||
event_gc_signal_data(s->event, &s->priority, SIGCHLD);
|
||||
if (EVENT_SOURCE_WATCH_PIDFD(s))
|
||||
source_child_pidfd_unregister(s);
|
||||
else
|
||||
event_gc_signal_data(s->event, &s->priority, SIGCHLD);
|
||||
|
||||
break;
|
||||
|
||||
case SOURCE_EXIT:
|
||||
@@ -2104,12 +2331,25 @@ _public_ int sd_event_source_set_enabled(sd_event_source *s, int m) {
|
||||
|
||||
s->enabled = m;
|
||||
|
||||
r = event_make_signal_data(s->event, SIGCHLD, NULL);
|
||||
if (r < 0) {
|
||||
s->enabled = SD_EVENT_OFF;
|
||||
s->event->n_enabled_child_sources--;
|
||||
event_gc_signal_data(s->event, &s->priority, SIGCHLD);
|
||||
return r;
|
||||
if (EVENT_SOURCE_WATCH_PIDFD(s)) {
|
||||
/* yes, we have pidfd */
|
||||
|
||||
r = source_child_pidfd_register(s, s->enabled);
|
||||
if (r < 0) {
|
||||
s->enabled = SD_EVENT_OFF;
|
||||
s->event->n_enabled_child_sources--;
|
||||
return r;
|
||||
}
|
||||
} else {
|
||||
/* no pidfd, or something other to watch for than WEXITED */
|
||||
|
||||
r = event_make_signal_data(s->event, SIGCHLD, NULL);
|
||||
if (r < 0) {
|
||||
s->enabled = SD_EVENT_OFF;
|
||||
s->event->n_enabled_child_sources--;
|
||||
event_gc_signal_data(s->event, &s->priority, SIGCHLD);
|
||||
return r;
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
@@ -2232,6 +2472,98 @@ _public_ int sd_event_source_get_child_pid(sd_event_source *s, pid_t *pid) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
_public_ int sd_event_source_get_child_pidfd(sd_event_source *s) {
|
||||
assert_return(s, -EINVAL);
|
||||
assert_return(s->type == SOURCE_CHILD, -EDOM);
|
||||
assert_return(!event_pid_changed(s->event), -ECHILD);
|
||||
|
||||
if (s->child.pidfd < 0)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
return s->child.pidfd;
|
||||
}
|
||||
|
||||
_public_ int sd_event_source_send_child_signal(sd_event_source *s, int sig, const siginfo_t *si, unsigned flags) {
|
||||
assert_return(s, -EINVAL);
|
||||
assert_return(s->type == SOURCE_CHILD, -EDOM);
|
||||
assert_return(!event_pid_changed(s->event), -ECHILD);
|
||||
assert_return(SIGNAL_VALID(sig), -EINVAL);
|
||||
|
||||
/* If we already have seen indication the process exited refuse sending a signal early. This way we
|
||||
* can be sure we don't accidentally kill the wrong process on PID reuse when pidfds are not
|
||||
* available. */
|
||||
if (s->child.exited)
|
||||
return -ESRCH;
|
||||
|
||||
if (s->child.pidfd >= 0) {
|
||||
siginfo_t copy;
|
||||
|
||||
/* pidfd_send_signal() changes the siginfo_t argument. This is weird, let's hence copy the
|
||||
* structure here */
|
||||
if (si)
|
||||
copy = *si;
|
||||
|
||||
if (pidfd_send_signal(s->child.pidfd, sig, si ? © : NULL, 0) < 0) {
|
||||
/* Let's propagate the error only if the system call is not implemented or prohibited */
|
||||
if (!ERRNO_IS_NOT_SUPPORTED(errno) && !ERRNO_IS_PRIVILEGE(errno))
|
||||
return -errno;
|
||||
} else
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Flags are only supported for pidfd_send_signal(), not for rt_sigqueueinfo(), hence let's refuse
|
||||
* this here. */
|
||||
if (flags != 0)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
if (si) {
|
||||
/* We use rt_sigqueueinfo() only if siginfo_t is specified. */
|
||||
siginfo_t copy = *si;
|
||||
|
||||
if (rt_sigqueueinfo(s->child.pid, sig, ©) < 0)
|
||||
return -errno;
|
||||
} else if (kill(s->child.pid, sig) < 0)
|
||||
return -errno;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
_public_ int sd_event_source_get_child_pidfd_own(sd_event_source *s) {
|
||||
assert_return(s, -EINVAL);
|
||||
assert_return(s->type == SOURCE_CHILD, -EDOM);
|
||||
|
||||
if (s->child.pidfd < 0)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
return s->child.pidfd_owned;
|
||||
}
|
||||
|
||||
_public_ int sd_event_source_set_child_pidfd_own(sd_event_source *s, int own) {
|
||||
assert_return(s, -EINVAL);
|
||||
assert_return(s->type == SOURCE_CHILD, -EDOM);
|
||||
|
||||
if (s->child.pidfd < 0)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
s->child.pidfd_owned = own;
|
||||
return 0;
|
||||
}
|
||||
|
||||
_public_ int sd_event_source_get_child_process_own(sd_event_source *s) {
|
||||
assert_return(s, -EINVAL);
|
||||
assert_return(s->type == SOURCE_CHILD, -EDOM);
|
||||
|
||||
return s->child.process_owned;
|
||||
}
|
||||
|
||||
_public_ int sd_event_source_set_child_process_own(sd_event_source *s, int own) {
|
||||
assert_return(s, -EINVAL);
|
||||
assert_return(s->type == SOURCE_CHILD, -EDOM);
|
||||
|
||||
s->child.process_owned = own;
|
||||
return 0;
|
||||
}
|
||||
|
||||
_public_ int sd_event_source_get_inotify_mask(sd_event_source *s, uint32_t *mask) {
|
||||
assert_return(s, -EINVAL);
|
||||
assert_return(mask, -EINVAL);
|
||||
@@ -2542,6 +2874,12 @@ static int process_child(sd_event *e) {
|
||||
if (s->enabled == SD_EVENT_OFF)
|
||||
continue;
|
||||
|
||||
if (s->child.exited)
|
||||
continue;
|
||||
|
||||
if (EVENT_SOURCE_WATCH_PIDFD(s)) /* There's a usable pidfd known for this event source? then don't waitid() for it here */
|
||||
continue;
|
||||
|
||||
zero(s->child.siginfo);
|
||||
r = waitid(P_PID, s->child.pid, &s->child.siginfo,
|
||||
WNOHANG | (s->child.options & WEXITED ? WNOWAIT : 0) | s->child.options);
|
||||
@@ -2551,6 +2889,9 @@ static int process_child(sd_event *e) {
|
||||
if (s->child.siginfo.si_pid != 0) {
|
||||
bool zombie = IN_SET(s->child.siginfo.si_code, CLD_EXITED, CLD_KILLED, CLD_DUMPED);
|
||||
|
||||
if (zombie)
|
||||
s->child.exited = true;
|
||||
|
||||
if (!zombie && (s->child.options & WEXITED)) {
|
||||
/* If the child isn't dead then let's
|
||||
* immediately remove the state change
|
||||
@@ -2570,6 +2911,33 @@ static int process_child(sd_event *e) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int process_pidfd(sd_event *e, sd_event_source *s, uint32_t revents) {
|
||||
assert(e);
|
||||
assert(s);
|
||||
assert(s->type == SOURCE_CHILD);
|
||||
|
||||
if (s->pending)
|
||||
return 0;
|
||||
|
||||
if (s->enabled == SD_EVENT_OFF)
|
||||
return 0;
|
||||
|
||||
if (!EVENT_SOURCE_WATCH_PIDFD(s))
|
||||
return 0;
|
||||
|
||||
zero(s->child.siginfo);
|
||||
if (waitid(P_PID, s->child.pid, &s->child.siginfo, WNOHANG | WNOWAIT | s->child.options) < 0)
|
||||
return -errno;
|
||||
|
||||
if (s->child.siginfo.si_pid == 0)
|
||||
return 0;
|
||||
|
||||
if (IN_SET(s->child.siginfo.si_code, CLD_EXITED, CLD_KILLED, CLD_DUMPED))
|
||||
s->child.exited = true;
|
||||
|
||||
return source_set_pending(s, true);
|
||||
}
|
||||
|
||||
static int process_signal(sd_event *e, struct signal_data *d, uint32_t events) {
|
||||
bool read_one = false;
|
||||
int r;
|
||||
@@ -2854,8 +3222,10 @@ static int source_dispatch(sd_event_source *s) {
|
||||
r = s->child.callback(s, &s->child.siginfo, s->userdata);
|
||||
|
||||
/* Now, reap the PID for good. */
|
||||
if (zombie)
|
||||
if (zombie) {
|
||||
(void) waitid(P_PID, s->child.pid, &s->child.siginfo, WNOHANG|WEXITED);
|
||||
s->child.waited = true;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
@@ -3056,6 +3426,11 @@ _public_ int sd_event_prepare(sd_event *e) {
|
||||
assert_return(e->state != SD_EVENT_FINISHED, -ESTALE);
|
||||
assert_return(e->state == SD_EVENT_INITIAL, -EBUSY);
|
||||
|
||||
/* Let's check that if we are a default event loop we are executed in the correct thread. We only do
|
||||
* this check here once, since gettid() is typically not cached, and thus want to minimize
|
||||
* syscalls */
|
||||
assert_return(!e->default_event_ptr || e->tid == gettid(), -EREMOTEIO);
|
||||
|
||||
if (e->exit_requested)
|
||||
goto pending;
|
||||
|
||||
@@ -3151,12 +3526,33 @@ _public_ int sd_event_wait(sd_event *e, uint64_t timeout) {
|
||||
|
||||
switch (*t) {
|
||||
|
||||
case WAKEUP_EVENT_SOURCE:
|
||||
r = process_io(e, ev_queue[i].data.ptr, ev_queue[i].events);
|
||||
case WAKEUP_EVENT_SOURCE: {
|
||||
sd_event_source *s = ev_queue[i].data.ptr;
|
||||
|
||||
assert(s);
|
||||
|
||||
switch (s->type) {
|
||||
|
||||
case SOURCE_IO:
|
||||
r = process_io(e, s, ev_queue[i].events);
|
||||
break;
|
||||
|
||||
case SOURCE_CHILD:
|
||||
r = process_pidfd(e, s, ev_queue[i].events);
|
||||
break;
|
||||
|
||||
default:
|
||||
assert_not_reached("Unexpected event source type");
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case WAKEUP_CLOCK_DATA: {
|
||||
struct clock_data *d = ev_queue[i].data.ptr;
|
||||
|
||||
assert(d);
|
||||
|
||||
r = flush_timer(e, d->fd, ev_queue[i].events, &d->next);
|
||||
break;
|
||||
}
|
||||
@@ -3481,7 +3877,7 @@ _public_ int sd_event_set_watchdog(sd_event *e, int b) {
|
||||
|
||||
} else {
|
||||
if (e->watchdog_fd >= 0) {
|
||||
epoll_ctl(e->epoll_fd, EPOLL_CTL_DEL, e->watchdog_fd, NULL);
|
||||
(void) epoll_ctl(e->epoll_fd, EPOLL_CTL_DEL, e->watchdog_fd, NULL);
|
||||
e->watchdog_fd = safe_close(e->watchdog_fd);
|
||||
}
|
||||
}
|
||||
|
@@ -14,7 +14,7 @@
|
||||
#include "stdio-util.h"
|
||||
|
||||
#if 0 /* NM_IGNORED */
|
||||
char *id128_to_uuid_string(sd_id128_t id, char s[37]) {
|
||||
char *id128_to_uuid_string(sd_id128_t id, char s[static ID128_UUID_STRING_MAX]) {
|
||||
unsigned n, k = 0;
|
||||
|
||||
assert(s);
|
||||
|
@@ -8,7 +8,9 @@
|
||||
#include "hash-funcs.h"
|
||||
#include "macro.h"
|
||||
|
||||
char *id128_to_uuid_string(sd_id128_t id, char s[37]);
|
||||
#define ID128_UUID_STRING_MAX 37
|
||||
|
||||
char *id128_to_uuid_string(sd_id128_t id, char s[static ID128_UUID_STRING_MAX]);
|
||||
|
||||
bool id128_is_valid(const char *s) _pure_;
|
||||
|
||||
|
@@ -23,6 +23,7 @@
|
||||
#include <sys/inotify.h>
|
||||
#include <sys/signalfd.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/wait.h>
|
||||
#include <time.h>
|
||||
|
||||
#include "_sd-common.h"
|
||||
@@ -89,6 +90,7 @@ int sd_event_add_io(sd_event *e, sd_event_source **s, int fd, uint32_t events, s
|
||||
int sd_event_add_time(sd_event *e, sd_event_source **s, clockid_t clock, uint64_t usec, uint64_t accuracy, sd_event_time_handler_t callback, void *userdata);
|
||||
int sd_event_add_signal(sd_event *e, sd_event_source **s, int sig, sd_event_signal_handler_t callback, void *userdata);
|
||||
int sd_event_add_child(sd_event *e, sd_event_source **s, pid_t pid, int options, sd_event_child_handler_t callback, void *userdata);
|
||||
int sd_event_add_child_pidfd(sd_event *e, sd_event_source **s, int pidfd, int options, sd_event_child_handler_t callback, void *userdata);
|
||||
int sd_event_add_inotify(sd_event *e, sd_event_source **s, const char *path, uint32_t mask, sd_event_inotify_handler_t callback, void *userdata);
|
||||
int sd_event_add_defer(sd_event *e, sd_event_source **s, sd_event_handler_t callback, void *userdata);
|
||||
int sd_event_add_post(sd_event *e, sd_event_source **s, sd_event_handler_t callback, void *userdata);
|
||||
@@ -141,6 +143,16 @@ int sd_event_source_set_time_accuracy(sd_event_source *s, uint64_t usec);
|
||||
int sd_event_source_get_time_clock(sd_event_source *s, clockid_t *clock);
|
||||
int sd_event_source_get_signal(sd_event_source *s);
|
||||
int sd_event_source_get_child_pid(sd_event_source *s, pid_t *pid);
|
||||
int sd_event_source_get_child_pidfd(sd_event_source *s);
|
||||
int sd_event_source_get_child_pidfd_own(sd_event_source *s);
|
||||
int sd_event_source_set_child_pidfd_own(sd_event_source *s, int own);
|
||||
int sd_event_source_get_child_process_own(sd_event_source *s);
|
||||
int sd_event_source_set_child_process_own(sd_event_source *s, int own);
|
||||
#if defined _GNU_SOURCE || (defined _POSIX_C_SOURCE && _POSIX_C_SOURCE >= 199309L)
|
||||
int sd_event_source_send_child_signal(sd_event_source *s, int sig, const siginfo_t *si, unsigned flags);
|
||||
#else
|
||||
int sd_event_source_send_child_signal(sd_event_source *s, int sig, const void *si, unsigned flags);
|
||||
#endif
|
||||
int sd_event_source_get_inotify_mask(sd_event_source *s, uint32_t *ret);
|
||||
int sd_event_source_set_destroy_callback(sd_event_source *s, sd_event_destroy_t callback);
|
||||
int sd_event_source_get_destroy_callback(sd_event_source *s, sd_event_destroy_t *ret);
|
||||
|
@@ -20,6 +20,7 @@
|
||||
|
||||
#include <net/ethernet.h>
|
||||
#include <netinet/in.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "sd-event.h"
|
||||
|
||||
@@ -44,7 +45,7 @@ int sd_ipv4acd_set_mac(sd_ipv4acd *acd, const struct ether_addr *addr);
|
||||
int sd_ipv4acd_set_ifindex(sd_ipv4acd *acd, int interface_index);
|
||||
int sd_ipv4acd_set_address(sd_ipv4acd *acd, const struct in_addr *address);
|
||||
int sd_ipv4acd_is_running(sd_ipv4acd *acd);
|
||||
int sd_ipv4acd_start(sd_ipv4acd *acd);
|
||||
int sd_ipv4acd_start(sd_ipv4acd *acd, bool reset_conflicts);
|
||||
int sd_ipv4acd_stop(sd_ipv4acd *acd);
|
||||
sd_ipv4acd *sd_ipv4acd_ref(sd_ipv4acd *acd);
|
||||
sd_ipv4acd *sd_ipv4acd_unref(sd_ipv4acd *acd);
|
||||
|
Reference in New Issue
Block a user