mirror of
https://gitlab.freedesktop.org/NetworkManager/NetworkManager
synced 2024-07-22 10:46:59 +00:00
systemd: merge branch systemd into master
This commit is contained in:
commit
e75d62ce76
|
@ -1819,6 +1819,7 @@ shared_systemd_libnm_systemd_shared_la_SOURCES = \
|
|||
shared/systemd/nm-sd-utils-shared.c \
|
||||
shared/systemd/nm-sd-utils-shared.h \
|
||||
shared/systemd/sd-adapt-shared/architecture.h \
|
||||
shared/systemd/sd-adapt-shared/arphrd-list.h \
|
||||
shared/systemd/sd-adapt-shared/build.h \
|
||||
shared/systemd/sd-adapt-shared/copy.h \
|
||||
shared/systemd/sd-adapt-shared/def.h \
|
||||
|
@ -1850,6 +1851,7 @@ shared_systemd_libnm_systemd_shared_la_SOURCES = \
|
|||
shared/systemd/src/basic/alloc-util.c \
|
||||
shared/systemd/src/basic/alloc-util.h \
|
||||
shared/systemd/src/basic/async.h \
|
||||
shared/systemd/src/basic/cgroup-util.h \
|
||||
shared/systemd/src/basic/env-file.c \
|
||||
shared/systemd/src/basic/env-file.h \
|
||||
shared/systemd/src/basic/env-util.c \
|
||||
|
|
3
shared/systemd/sd-adapt-shared/arphrd-list.h
Normal file
3
shared/systemd/sd-adapt-shared/arphrd-list.h
Normal file
|
@ -0,0 +1,3 @@
|
|||
#pragma once
|
||||
|
||||
/* dummy header */
|
|
@ -84,6 +84,8 @@ G_STMT_START { \
|
|||
#include <sys/syscall.h>
|
||||
#include <sys/ioctl.h>
|
||||
|
||||
#define ENABLE_GSHADOW FALSE
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
/* systemd cannot be compiled with "-Wdeclaration-after-statement". In particular
|
||||
|
|
251
shared/systemd/src/basic/cgroup-util.h
Normal file
251
shared/systemd/src/basic/cgroup-util.h
Normal file
|
@ -0,0 +1,251 @@
|
|||
/* SPDX-License-Identifier: LGPL-2.1+ */
|
||||
#pragma once
|
||||
|
||||
#include <dirent.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <sys/statfs.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include "def.h"
|
||||
#include "set.h"
|
||||
|
||||
#define SYSTEMD_CGROUP_CONTROLLER_LEGACY "name=systemd"
|
||||
#define SYSTEMD_CGROUP_CONTROLLER_HYBRID "name=unified"
|
||||
#define SYSTEMD_CGROUP_CONTROLLER "_systemd"
|
||||
|
||||
/* An enum of well known cgroup controllers */
|
||||
typedef enum CGroupController {
|
||||
/* Original cgroup controllers */
|
||||
CGROUP_CONTROLLER_CPU,
|
||||
CGROUP_CONTROLLER_CPUACCT, /* v1 only */
|
||||
CGROUP_CONTROLLER_CPUSET, /* v2 only */
|
||||
CGROUP_CONTROLLER_IO, /* v2 only */
|
||||
CGROUP_CONTROLLER_BLKIO, /* v1 only */
|
||||
CGROUP_CONTROLLER_MEMORY,
|
||||
CGROUP_CONTROLLER_DEVICES, /* v1 only */
|
||||
CGROUP_CONTROLLER_PIDS,
|
||||
|
||||
/* BPF-based pseudo-controllers, v2 only */
|
||||
CGROUP_CONTROLLER_BPF_FIREWALL,
|
||||
CGROUP_CONTROLLER_BPF_DEVICES,
|
||||
|
||||
_CGROUP_CONTROLLER_MAX,
|
||||
_CGROUP_CONTROLLER_INVALID = -1,
|
||||
} CGroupController;
|
||||
|
||||
#define CGROUP_CONTROLLER_TO_MASK(c) (1U << (c))
|
||||
|
||||
/* A bit mask of well known cgroup controllers */
|
||||
typedef enum CGroupMask {
|
||||
CGROUP_MASK_CPU = CGROUP_CONTROLLER_TO_MASK(CGROUP_CONTROLLER_CPU),
|
||||
CGROUP_MASK_CPUACCT = CGROUP_CONTROLLER_TO_MASK(CGROUP_CONTROLLER_CPUACCT),
|
||||
CGROUP_MASK_CPUSET = CGROUP_CONTROLLER_TO_MASK(CGROUP_CONTROLLER_CPUSET),
|
||||
CGROUP_MASK_IO = CGROUP_CONTROLLER_TO_MASK(CGROUP_CONTROLLER_IO),
|
||||
CGROUP_MASK_BLKIO = CGROUP_CONTROLLER_TO_MASK(CGROUP_CONTROLLER_BLKIO),
|
||||
CGROUP_MASK_MEMORY = CGROUP_CONTROLLER_TO_MASK(CGROUP_CONTROLLER_MEMORY),
|
||||
CGROUP_MASK_DEVICES = CGROUP_CONTROLLER_TO_MASK(CGROUP_CONTROLLER_DEVICES),
|
||||
CGROUP_MASK_PIDS = CGROUP_CONTROLLER_TO_MASK(CGROUP_CONTROLLER_PIDS),
|
||||
CGROUP_MASK_BPF_FIREWALL = CGROUP_CONTROLLER_TO_MASK(CGROUP_CONTROLLER_BPF_FIREWALL),
|
||||
CGROUP_MASK_BPF_DEVICES = CGROUP_CONTROLLER_TO_MASK(CGROUP_CONTROLLER_BPF_DEVICES),
|
||||
|
||||
/* All real cgroup v1 controllers */
|
||||
CGROUP_MASK_V1 = CGROUP_MASK_CPU|CGROUP_MASK_CPUACCT|CGROUP_MASK_BLKIO|CGROUP_MASK_MEMORY|CGROUP_MASK_DEVICES|CGROUP_MASK_PIDS,
|
||||
|
||||
/* All real cgroup v2 controllers */
|
||||
CGROUP_MASK_V2 = CGROUP_MASK_CPU|CGROUP_MASK_CPUSET|CGROUP_MASK_IO|CGROUP_MASK_MEMORY|CGROUP_MASK_PIDS,
|
||||
|
||||
/* All cgroup v2 BPF pseudo-controllers */
|
||||
CGROUP_MASK_BPF = CGROUP_MASK_BPF_FIREWALL|CGROUP_MASK_BPF_DEVICES,
|
||||
|
||||
_CGROUP_MASK_ALL = CGROUP_CONTROLLER_TO_MASK(_CGROUP_CONTROLLER_MAX) - 1
|
||||
} CGroupMask;
|
||||
|
||||
static inline CGroupMask CGROUP_MASK_EXTEND_JOINED(CGroupMask mask) {
|
||||
/* We always mount "cpu" and "cpuacct" in the same hierarchy. Hence, when one bit is set also set the other */
|
||||
|
||||
if (mask & (CGROUP_MASK_CPU|CGROUP_MASK_CPUACCT))
|
||||
mask |= (CGROUP_MASK_CPU|CGROUP_MASK_CPUACCT);
|
||||
|
||||
return mask;
|
||||
}
|
||||
|
||||
CGroupMask get_cpu_accounting_mask(void);
|
||||
bool cpu_accounting_is_cheap(void);
|
||||
|
||||
/* Special values for all weight knobs on unified hierarchy */
|
||||
#define CGROUP_WEIGHT_INVALID ((uint64_t) -1)
|
||||
#define CGROUP_WEIGHT_MIN UINT64_C(1)
|
||||
#define CGROUP_WEIGHT_MAX UINT64_C(10000)
|
||||
#define CGROUP_WEIGHT_DEFAULT UINT64_C(100)
|
||||
|
||||
#define CGROUP_LIMIT_MIN UINT64_C(0)
|
||||
#define CGROUP_LIMIT_MAX ((uint64_t) -1)
|
||||
|
||||
static inline bool CGROUP_WEIGHT_IS_OK(uint64_t x) {
|
||||
return
|
||||
x == CGROUP_WEIGHT_INVALID ||
|
||||
(x >= CGROUP_WEIGHT_MIN && x <= CGROUP_WEIGHT_MAX);
|
||||
}
|
||||
|
||||
/* IO limits on unified hierarchy */
|
||||
typedef enum CGroupIOLimitType {
|
||||
CGROUP_IO_RBPS_MAX,
|
||||
CGROUP_IO_WBPS_MAX,
|
||||
CGROUP_IO_RIOPS_MAX,
|
||||
CGROUP_IO_WIOPS_MAX,
|
||||
|
||||
_CGROUP_IO_LIMIT_TYPE_MAX,
|
||||
_CGROUP_IO_LIMIT_TYPE_INVALID = -1
|
||||
} CGroupIOLimitType;
|
||||
|
||||
extern const uint64_t cgroup_io_limit_defaults[_CGROUP_IO_LIMIT_TYPE_MAX];
|
||||
|
||||
const char* cgroup_io_limit_type_to_string(CGroupIOLimitType t) _const_;
|
||||
CGroupIOLimitType cgroup_io_limit_type_from_string(const char *s) _pure_;
|
||||
|
||||
/* Special values for the cpu.shares attribute */
|
||||
#define CGROUP_CPU_SHARES_INVALID ((uint64_t) -1)
|
||||
#define CGROUP_CPU_SHARES_MIN UINT64_C(2)
|
||||
#define CGROUP_CPU_SHARES_MAX UINT64_C(262144)
|
||||
#define CGROUP_CPU_SHARES_DEFAULT UINT64_C(1024)
|
||||
|
||||
static inline bool CGROUP_CPU_SHARES_IS_OK(uint64_t x) {
|
||||
return
|
||||
x == CGROUP_CPU_SHARES_INVALID ||
|
||||
(x >= CGROUP_CPU_SHARES_MIN && x <= CGROUP_CPU_SHARES_MAX);
|
||||
}
|
||||
|
||||
/* Special values for the blkio.weight attribute */
|
||||
#define CGROUP_BLKIO_WEIGHT_INVALID ((uint64_t) -1)
|
||||
#define CGROUP_BLKIO_WEIGHT_MIN UINT64_C(10)
|
||||
#define CGROUP_BLKIO_WEIGHT_MAX UINT64_C(1000)
|
||||
#define CGROUP_BLKIO_WEIGHT_DEFAULT UINT64_C(500)
|
||||
|
||||
static inline bool CGROUP_BLKIO_WEIGHT_IS_OK(uint64_t x) {
|
||||
return
|
||||
x == CGROUP_BLKIO_WEIGHT_INVALID ||
|
||||
(x >= CGROUP_BLKIO_WEIGHT_MIN && x <= CGROUP_BLKIO_WEIGHT_MAX);
|
||||
}
|
||||
|
||||
typedef enum CGroupUnified {
|
||||
CGROUP_UNIFIED_UNKNOWN = -1,
|
||||
CGROUP_UNIFIED_NONE = 0, /* Both systemd and controllers on legacy */
|
||||
CGROUP_UNIFIED_SYSTEMD = 1, /* Only systemd on unified */
|
||||
CGROUP_UNIFIED_ALL = 2, /* Both systemd and controllers on unified */
|
||||
} CGroupUnified;
|
||||
|
||||
/*
|
||||
* General rules:
|
||||
*
|
||||
* We accept named hierarchies in the syntax "foo" and "name=foo".
|
||||
*
|
||||
* We expect that named hierarchies do not conflict in name with a
|
||||
* kernel hierarchy, modulo the "name=" prefix.
|
||||
*
|
||||
* We always generate "normalized" controller names, i.e. without the
|
||||
* "name=" prefix.
|
||||
*
|
||||
* We require absolute cgroup paths. When returning, we will always
|
||||
* generate paths with multiple adjacent / removed.
|
||||
*/
|
||||
|
||||
int cg_enumerate_processes(const char *controller, const char *path, FILE **_f);
|
||||
int cg_read_pid(FILE *f, pid_t *_pid);
|
||||
int cg_read_event(const char *controller, const char *path, const char *event,
|
||||
char **val);
|
||||
|
||||
int cg_enumerate_subgroups(const char *controller, const char *path, DIR **_d);
|
||||
int cg_read_subgroup(DIR *d, char **fn);
|
||||
|
||||
typedef enum CGroupFlags {
|
||||
CGROUP_SIGCONT = 1 << 0,
|
||||
CGROUP_IGNORE_SELF = 1 << 1,
|
||||
CGROUP_REMOVE = 1 << 2,
|
||||
} CGroupFlags;
|
||||
|
||||
typedef int (*cg_kill_log_func_t)(pid_t pid, int sig, void *userdata);
|
||||
|
||||
int cg_kill(const char *controller, const char *path, int sig, CGroupFlags flags, Set *s, cg_kill_log_func_t kill_log, void *userdata);
|
||||
int cg_kill_recursive(const char *controller, const char *path, int sig, CGroupFlags flags, Set *s, cg_kill_log_func_t kill_log, void *userdata);
|
||||
|
||||
int cg_split_spec(const char *spec, char **ret_controller, char **ret_path);
|
||||
int cg_mangle_path(const char *path, char **result);
|
||||
|
||||
int cg_get_path(const char *controller, const char *path, const char *suffix, char **fs);
|
||||
int cg_get_path_and_check(const char *controller, const char *path, const char *suffix, char **fs);
|
||||
|
||||
int cg_pid_get_path(const char *controller, pid_t pid, char **path);
|
||||
|
||||
int cg_rmdir(const char *controller, const char *path);
|
||||
|
||||
int cg_set_attribute(const char *controller, const char *path, const char *attribute, const char *value);
|
||||
int cg_get_attribute(const char *controller, const char *path, const char *attribute, char **ret);
|
||||
int cg_get_keyed_attribute(const char *controller, const char *path, const char *attribute, char **keys, char **values);
|
||||
|
||||
int cg_set_access(const char *controller, const char *path, uid_t uid, gid_t gid);
|
||||
|
||||
int cg_set_xattr(const char *controller, const char *path, const char *name, const void *value, size_t size, int flags);
|
||||
int cg_get_xattr(const char *controller, const char *path, const char *name, void *value, size_t size);
|
||||
int cg_remove_xattr(const char *controller, const char *path, const char *name);
|
||||
|
||||
int cg_install_release_agent(const char *controller, const char *agent);
|
||||
int cg_uninstall_release_agent(const char *controller);
|
||||
|
||||
int cg_is_empty(const char *controller, const char *path);
|
||||
int cg_is_empty_recursive(const char *controller, const char *path);
|
||||
|
||||
int cg_get_root_path(char **path);
|
||||
|
||||
int cg_path_get_session(const char *path, char **session);
|
||||
int cg_path_get_owner_uid(const char *path, uid_t *uid);
|
||||
int cg_path_get_unit(const char *path, char **unit);
|
||||
int cg_path_get_user_unit(const char *path, char **unit);
|
||||
int cg_path_get_machine_name(const char *path, char **machine);
|
||||
int cg_path_get_slice(const char *path, char **slice);
|
||||
int cg_path_get_user_slice(const char *path, char **slice);
|
||||
|
||||
int cg_shift_path(const char *cgroup, const char *cached_root, const char **shifted);
|
||||
int cg_pid_get_path_shifted(pid_t pid, const char *cached_root, char **cgroup);
|
||||
|
||||
int cg_pid_get_session(pid_t pid, char **session);
|
||||
int cg_pid_get_owner_uid(pid_t pid, uid_t *uid);
|
||||
int cg_pid_get_unit(pid_t pid, char **unit);
|
||||
int cg_pid_get_user_unit(pid_t pid, char **unit);
|
||||
int cg_pid_get_machine_name(pid_t pid, char **machine);
|
||||
int cg_pid_get_slice(pid_t pid, char **slice);
|
||||
int cg_pid_get_user_slice(pid_t pid, char **slice);
|
||||
|
||||
int cg_path_decode_unit(const char *cgroup, char **unit);
|
||||
|
||||
char *cg_escape(const char *p);
|
||||
char *cg_unescape(const char *p) _pure_;
|
||||
|
||||
bool cg_controller_is_valid(const char *p);
|
||||
|
||||
int cg_slice_to_path(const char *unit, char **ret);
|
||||
|
||||
typedef const char* (*cg_migrate_callback_t)(CGroupMask mask, void *userdata);
|
||||
|
||||
int cg_mask_supported(CGroupMask *ret);
|
||||
int cg_mask_from_string(const char *s, CGroupMask *ret);
|
||||
int cg_mask_to_string(CGroupMask mask, char **ret);
|
||||
|
||||
int cg_kernel_controllers(Set **controllers);
|
||||
|
||||
bool cg_ns_supported(void);
|
||||
|
||||
int cg_all_unified(void);
|
||||
int cg_hybrid_unified(void);
|
||||
int cg_unified_controller(const char *controller);
|
||||
int cg_unified_cached(bool flush);
|
||||
static inline int cg_unified(void) {
|
||||
return cg_unified_cached(true);
|
||||
}
|
||||
|
||||
const char* cgroup_controller_to_string(CGroupController c) _const_;
|
||||
CGroupController cgroup_controller_from_string(const char *s) _pure_;
|
||||
|
||||
bool is_cgroup_fs(const struct statfs *s);
|
||||
bool fd_is_cgroup_fs(int fd);
|
|
@ -104,7 +104,7 @@ char *cescape(const char *s) {
|
|||
return cescape_length(s, strlen(s));
|
||||
}
|
||||
|
||||
int cunescape_one(const char *p, size_t length, char32_t *ret, bool *eight_bit) {
|
||||
int cunescape_one(const char *p, size_t length, char32_t *ret, bool *eight_bit, bool accept_nul) {
|
||||
int r = 1;
|
||||
|
||||
assert(p);
|
||||
|
@ -173,7 +173,7 @@ int cunescape_one(const char *p, size_t length, char32_t *ret, bool *eight_bit)
|
|||
return -EINVAL;
|
||||
|
||||
/* Don't allow NUL bytes */
|
||||
if (a == 0 && b == 0)
|
||||
if (a == 0 && b == 0 && !accept_nul)
|
||||
return -EINVAL;
|
||||
|
||||
*ret = (a << 4U) | b;
|
||||
|
@ -201,7 +201,7 @@ int cunescape_one(const char *p, size_t length, char32_t *ret, bool *eight_bit)
|
|||
c = ((uint32_t) a[0] << 12U) | ((uint32_t) a[1] << 8U) | ((uint32_t) a[2] << 4U) | (uint32_t) a[3];
|
||||
|
||||
/* Don't allow 0 chars */
|
||||
if (c == 0)
|
||||
if (c == 0 && !accept_nul)
|
||||
return -EINVAL;
|
||||
|
||||
*ret = c;
|
||||
|
@ -229,7 +229,7 @@ int cunescape_one(const char *p, size_t length, char32_t *ret, bool *eight_bit)
|
|||
((uint32_t) a[4] << 12U) | ((uint32_t) a[5] << 8U) | ((uint32_t) a[6] << 4U) | (uint32_t) a[7];
|
||||
|
||||
/* Don't allow 0 chars */
|
||||
if (c == 0)
|
||||
if (c == 0 && !accept_nul)
|
||||
return -EINVAL;
|
||||
|
||||
/* Don't allow invalid code points */
|
||||
|
@ -269,7 +269,7 @@ int cunescape_one(const char *p, size_t length, char32_t *ret, bool *eight_bit)
|
|||
return -EINVAL;
|
||||
|
||||
/* don't allow NUL bytes */
|
||||
if (a == 0 && b == 0 && c == 0)
|
||||
if (a == 0 && b == 0 && c == 0 && !accept_nul)
|
||||
return -EINVAL;
|
||||
|
||||
/* Don't allow bytes above 255 */
|
||||
|
@ -290,6 +290,7 @@ int cunescape_one(const char *p, size_t length, char32_t *ret, bool *eight_bit)
|
|||
return r;
|
||||
}
|
||||
|
||||
#if 0 /* NM_IGNORED */
|
||||
int cunescape_length_with_prefix(const char *s, size_t length, const char *prefix, UnescapeFlags flags, char **ret) {
|
||||
char *r, *t;
|
||||
const char *f;
|
||||
|
@ -335,7 +336,7 @@ int cunescape_length_with_prefix(const char *s, size_t length, const char *prefi
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
k = cunescape_one(f + 1, remaining - 1, &u, &eight_bit);
|
||||
k = cunescape_one(f + 1, remaining - 1, &u, &eight_bit, flags & UNESCAPE_ACCEPT_NUL);
|
||||
if (k < 0) {
|
||||
if (flags & UNESCAPE_RELAX) {
|
||||
/* Invalid escape code, let's take it literal then */
|
||||
|
@ -362,15 +363,6 @@ int cunescape_length_with_prefix(const char *s, size_t length, const char *prefi
|
|||
return t - r;
|
||||
}
|
||||
|
||||
int cunescape_length(const char *s, size_t length, UnescapeFlags flags, char **ret) {
|
||||
return cunescape_length_with_prefix(s, length, NULL, flags, ret);
|
||||
}
|
||||
|
||||
int cunescape(const char *s, UnescapeFlags flags, char **ret) {
|
||||
return cunescape_length(s, strlen(s), flags, ret);
|
||||
}
|
||||
|
||||
#if 0 /* NM_IGNORED */
|
||||
char *xescape_full(const char *s, const char *bad, size_t console_width, bool eight_bits) {
|
||||
char *ans, *t, *prev, *prev2;
|
||||
const char *f;
|
||||
|
|
|
@ -29,22 +29,27 @@
|
|||
#define SHELL_NEED_ESCAPE_POSIX "\\\'"
|
||||
|
||||
typedef enum UnescapeFlags {
|
||||
UNESCAPE_RELAX = 1,
|
||||
UNESCAPE_RELAX = 1 << 0,
|
||||
UNESCAPE_ACCEPT_NUL = 1 << 1,
|
||||
} UnescapeFlags;
|
||||
|
||||
typedef enum EscapeStyle {
|
||||
ESCAPE_BACKSLASH = 1,
|
||||
ESCAPE_POSIX = 2,
|
||||
ESCAPE_POSIX = 2,
|
||||
} EscapeStyle;
|
||||
|
||||
char *cescape(const char *s);
|
||||
char *cescape_length(const char *s, size_t n);
|
||||
int cescape_char(char c, char *buf);
|
||||
|
||||
int cunescape(const char *s, UnescapeFlags flags, char **ret);
|
||||
int cunescape_length(const char *s, size_t length, UnescapeFlags flags, char **ret);
|
||||
int cunescape_length_with_prefix(const char *s, size_t length, const char *prefix, UnescapeFlags flags, char **ret);
|
||||
int cunescape_one(const char *p, size_t length, char32_t *ret, bool *eight_bit);
|
||||
static inline int cunescape_length(const char *s, size_t length, UnescapeFlags flags, char **ret) {
|
||||
return cunescape_length_with_prefix(s, length, NULL, flags, ret);
|
||||
}
|
||||
static inline int cunescape(const char *s, UnescapeFlags flags, char **ret) {
|
||||
return cunescape_length(s, strlen(s), flags, ret);
|
||||
}
|
||||
int cunescape_one(const char *p, size_t length, char32_t *ret, bool *eight_bit, bool accept_nul);
|
||||
|
||||
char *xescape_full(const char *s, const char *bad, size_t console_width, bool eight_bits);
|
||||
static inline char *xescape(const char *s, const char *bad) {
|
||||
|
|
|
@ -92,7 +92,7 @@ int extract_first_word(const char **p, char **ret, const char *separators, Extra
|
|||
bool eight_bit = false;
|
||||
char32_t u;
|
||||
|
||||
r = cunescape_one(*p, (size_t) -1, &u, &eight_bit);
|
||||
r = cunescape_one(*p, (size_t) -1, &u, &eight_bit, false);
|
||||
if (r < 0) {
|
||||
if (flags & EXTRACT_CUNESCAPE_RELAX) {
|
||||
s[sz++] = '\\';
|
||||
|
|
|
@ -139,16 +139,21 @@ static int write_string_file_atomic(
|
|||
assert(fn);
|
||||
assert(line);
|
||||
|
||||
/* Note that we'd really like to use O_TMPFILE here, but can't really, since we want replacement
|
||||
* semantics here, and O_TMPFILE can't offer that. i.e. rename() replaces but linkat() doesn't. */
|
||||
|
||||
r = fopen_temporary(fn, &f, &p);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
(void) fchmod_umask(fileno(f), 0644);
|
||||
|
||||
r = write_string_stream_ts(f, line, flags, ts);
|
||||
if (r < 0)
|
||||
goto fail;
|
||||
|
||||
r = fchmod_umask(fileno(f), FLAGS_SET(flags, WRITE_STRING_FILE_MODE_0600) ? 0600 : 0644);
|
||||
if (r < 0)
|
||||
goto fail;
|
||||
|
||||
if (rename(p, fn) < 0) {
|
||||
r = -errno;
|
||||
goto fail;
|
||||
|
@ -168,7 +173,7 @@ int write_string_file_ts(
|
|||
struct timespec *ts) {
|
||||
|
||||
_cleanup_fclose_ FILE *f = NULL;
|
||||
int q, r;
|
||||
int q, r, fd;
|
||||
|
||||
assert(fn);
|
||||
assert(line);
|
||||
|
@ -193,26 +198,20 @@ int write_string_file_ts(
|
|||
} else
|
||||
assert(!ts);
|
||||
|
||||
if (flags & WRITE_STRING_FILE_CREATE) {
|
||||
r = fopen_unlocked(fn, "we", &f);
|
||||
if (r < 0)
|
||||
goto fail;
|
||||
} else {
|
||||
int fd;
|
||||
/* We manually build our own version of fopen(..., "we") that works without O_CREAT and with O_NOFOLLOW if needed. */
|
||||
fd = open(fn, O_WRONLY|O_CLOEXEC|O_NOCTTY |
|
||||
(FLAGS_SET(flags, WRITE_STRING_FILE_NOFOLLOW) ? O_NOFOLLOW : 0) |
|
||||
(FLAGS_SET(flags, WRITE_STRING_FILE_CREATE) ? O_CREAT : 0),
|
||||
(FLAGS_SET(flags, WRITE_STRING_FILE_MODE_0600) ? 0600 : 0666));
|
||||
if (fd < 0) {
|
||||
r = -errno;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* We manually build our own version of fopen(..., "we") that
|
||||
* works without O_CREAT */
|
||||
fd = open(fn, O_WRONLY|O_CLOEXEC|O_NOCTTY | ((flags & WRITE_STRING_FILE_NOFOLLOW) ? O_NOFOLLOW : 0));
|
||||
if (fd < 0) {
|
||||
r = -errno;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
r = fdopen_unlocked(fd, "w", &f);
|
||||
if (r < 0) {
|
||||
safe_close(fd);
|
||||
goto fail;
|
||||
}
|
||||
r = fdopen_unlocked(fd, "w", &f);
|
||||
if (r < 0) {
|
||||
safe_close(fd);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (flags & WRITE_STRING_FILE_DISABLE_BUFFER)
|
||||
|
@ -547,17 +546,19 @@ finalize:
|
|||
return r;
|
||||
}
|
||||
|
||||
int read_full_file_full(const char *filename, ReadFullFileFlags flags, char **contents, size_t *size) {
|
||||
int read_full_file_full(int dir_fd, const char *filename, ReadFullFileFlags flags, char **contents, size_t *size) {
|
||||
_cleanup_fclose_ FILE *f = NULL;
|
||||
int r;
|
||||
|
||||
assert(filename);
|
||||
assert(contents);
|
||||
|
||||
r = fopen_unlocked(filename, "re", &f);
|
||||
r = xfopenat(dir_fd, filename, "re", 0, &f);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
(void) __fsetlocking(f, FSETLOCKING_BYCALLER);
|
||||
|
||||
return read_full_stream_full(f, filename, flags, contents, size);
|
||||
}
|
||||
|
||||
|
@ -686,6 +687,81 @@ DIR *xopendirat(int fd, const char *name, int flags) {
|
|||
return d;
|
||||
}
|
||||
|
||||
static int mode_to_flags(const char *mode) {
|
||||
const char *p;
|
||||
int flags;
|
||||
|
||||
if ((p = startswith(mode, "r+")))
|
||||
flags = O_RDWR;
|
||||
else if ((p = startswith(mode, "r")))
|
||||
flags = O_RDONLY;
|
||||
else if ((p = startswith(mode, "w+")))
|
||||
flags = O_RDWR|O_CREAT|O_TRUNC;
|
||||
else if ((p = startswith(mode, "w")))
|
||||
flags = O_WRONLY|O_CREAT|O_TRUNC;
|
||||
else if ((p = startswith(mode, "a+")))
|
||||
flags = O_RDWR|O_CREAT|O_APPEND;
|
||||
else if ((p = startswith(mode, "a")))
|
||||
flags = O_WRONLY|O_CREAT|O_APPEND;
|
||||
else
|
||||
return -EINVAL;
|
||||
|
||||
for (; *p != 0; p++) {
|
||||
|
||||
switch (*p) {
|
||||
|
||||
case 'e':
|
||||
flags |= O_CLOEXEC;
|
||||
break;
|
||||
|
||||
case 'x':
|
||||
flags |= O_EXCL;
|
||||
break;
|
||||
|
||||
case 'm':
|
||||
/* ignore this here, fdopen() might care later though */
|
||||
break;
|
||||
|
||||
case 'c': /* not sure what to do about this one */
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
return flags;
|
||||
}
|
||||
|
||||
int xfopenat(int dir_fd, const char *path, const char *mode, int flags, FILE **ret) {
|
||||
FILE *f;
|
||||
|
||||
/* A combination of fopen() with openat() */
|
||||
|
||||
if (dir_fd == AT_FDCWD && flags == 0) {
|
||||
f = fopen(path, mode);
|
||||
if (!f)
|
||||
return -errno;
|
||||
} else {
|
||||
int fd, mode_flags;
|
||||
|
||||
mode_flags = mode_to_flags(mode);
|
||||
if (mode_flags < 0)
|
||||
return mode_flags;
|
||||
|
||||
fd = openat(dir_fd, path, mode_flags | flags);
|
||||
if (fd < 0)
|
||||
return -errno;
|
||||
|
||||
f = fdopen(fd, mode);
|
||||
if (!f) {
|
||||
safe_close(fd);
|
||||
return -errno;
|
||||
}
|
||||
}
|
||||
|
||||
*ret = f;
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if 0 /* NM_IGNORED */
|
||||
static int search_and_fopen_internal(const char *path, const char *mode, const char *root, char **search, FILE **_f) {
|
||||
char **i;
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
#include <stddef.h>
|
||||
#include <stdio.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/fcntl.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include "macro.h"
|
||||
|
@ -22,6 +23,7 @@ typedef enum {
|
|||
WRITE_STRING_FILE_DISABLE_BUFFER = 1 << 5,
|
||||
WRITE_STRING_FILE_NOFOLLOW = 1 << 6,
|
||||
WRITE_STRING_FILE_MKDIR_0755 = 1 << 7,
|
||||
WRITE_STRING_FILE_MODE_0600 = 1 << 8,
|
||||
|
||||
/* And before you wonder, why write_string_file_atomic_label_ts() is a separate function instead of just one
|
||||
more flag here: it's about linking: we don't want to pull -lselinux into all users of write_string_file()
|
||||
|
@ -52,9 +54,9 @@ static inline int write_string_file(const char *fn, const char *line, WriteStrin
|
|||
int write_string_filef(const char *fn, WriteStringFileFlags flags, const char *format, ...) _printf_(3, 4);
|
||||
|
||||
int read_one_line_file(const char *filename, char **line);
|
||||
int read_full_file_full(const char *filename, ReadFullFileFlags flags, char **contents, size_t *size);
|
||||
int read_full_file_full(int dir_fd, const char *filename, ReadFullFileFlags flags, char **contents, size_t *size);
|
||||
static inline int read_full_file(const char *filename, char **contents, size_t *size) {
|
||||
return read_full_file_full(filename, 0, contents, size);
|
||||
return read_full_file_full(AT_FDCWD, filename, 0, contents, size);
|
||||
}
|
||||
int read_full_virtual_file(const char *filename, char **ret_contents, size_t *ret_size);
|
||||
int read_full_stream_full(FILE *f, const char *filename, ReadFullFileFlags flags, char **contents, size_t *size);
|
||||
|
@ -69,6 +71,7 @@ int executable_is_script(const char *path, char **interpreter);
|
|||
int get_proc_field(const char *filename, const char *pattern, const char *terminator, char **field);
|
||||
|
||||
DIR *xopendirat(int dirfd, const char *name, int flags);
|
||||
int xfopenat(int dir_fd, const char *path, const char *mode, int flags, FILE **ret);
|
||||
|
||||
int search_and_fopen(const char *path, const char *mode, const char *root, const char **search, FILE **_f);
|
||||
int search_and_fopen_nulstr(const char *path, const char *mode, const char *root, const char *search, FILE **_f);
|
||||
|
|
|
@ -5,30 +5,18 @@
|
|||
#include <net/if.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#if SIZEOF_PID_T == 4
|
||||
# define PID_PRI PRIi32
|
||||
#elif SIZEOF_PID_T == 2
|
||||
# define PID_PRI PRIi16
|
||||
#else
|
||||
# error Unknown pid_t size
|
||||
#endif
|
||||
#include "cgroup-util.h"
|
||||
#include "macro.h"
|
||||
|
||||
assert_cc(sizeof(pid_t) == sizeof(int32_t));
|
||||
#define PID_PRI PRIi32
|
||||
#define PID_FMT "%" PID_PRI
|
||||
|
||||
#if SIZEOF_UID_T == 4
|
||||
# define UID_FMT "%" PRIu32
|
||||
#elif SIZEOF_UID_T == 2
|
||||
# define UID_FMT "%" PRIu16
|
||||
#else
|
||||
# error Unknown uid_t size
|
||||
#endif
|
||||
assert_cc(sizeof(uid_t) == sizeof(uint32_t));
|
||||
#define UID_FMT "%" PRIu32
|
||||
|
||||
#if SIZEOF_GID_T == 4
|
||||
# define GID_FMT "%" PRIu32
|
||||
#elif SIZEOF_GID_T == 2
|
||||
# define GID_FMT "%" PRIu16
|
||||
#else
|
||||
# error Unknown gid_t size
|
||||
#endif
|
||||
assert_cc(sizeof(gid_t) == sizeof(uint32_t));
|
||||
#define GID_FMT "%" PRIu32
|
||||
|
||||
#if SIZEOF_TIME_T == 8
|
||||
# define PRI_TIME PRIi64
|
||||
|
@ -84,8 +72,15 @@ typedef enum {
|
|||
FORMAT_BYTES_TRAILING_B = 1 << 2,
|
||||
} FormatBytesFlag;
|
||||
|
||||
#define FORMAT_BYTES_MAX 8
|
||||
#define FORMAT_BYTES_MAX 16
|
||||
char *format_bytes_full(char *buf, size_t l, uint64_t t, FormatBytesFlag flag);
|
||||
static inline char *format_bytes(char *buf, size_t l, uint64_t t) {
|
||||
return format_bytes_full(buf, l, t, FORMAT_BYTES_USE_IEC | FORMAT_BYTES_BELOW_POINT | FORMAT_BYTES_TRAILING_B);
|
||||
}
|
||||
static inline char *format_bytes_cgroup_protection(char *buf, size_t l, uint64_t t) {
|
||||
if (t == CGROUP_LIMIT_MAX) {
|
||||
(void) snprintf(buf, l, "%s", "infinity");
|
||||
return buf;
|
||||
}
|
||||
return format_bytes(buf, l, t);
|
||||
}
|
||||
|
|
|
@ -276,7 +276,52 @@ int fchmod_and_chown(int fd, mode_t mode, uid_t uid, gid_t gid) {
|
|||
|
||||
return do_chown || do_chmod;
|
||||
}
|
||||
#endif /* NM_IGNORED */
|
||||
|
||||
int chmod_and_chown_unsafe(const char *path, mode_t mode, uid_t uid, gid_t gid) {
|
||||
bool do_chown, do_chmod;
|
||||
struct stat st;
|
||||
|
||||
assert(path);
|
||||
|
||||
/* Change ownership and access mode of the specified path, see description of fchmod_and_chown().
|
||||
* Should only be used on trusted paths. */
|
||||
|
||||
if (lstat(path, &st) < 0)
|
||||
return -errno;
|
||||
|
||||
do_chown =
|
||||
(uid != UID_INVALID && st.st_uid != uid) ||
|
||||
(gid != GID_INVALID && st.st_gid != gid);
|
||||
|
||||
do_chmod =
|
||||
!S_ISLNK(st.st_mode) && /* chmod is not defined on symlinks */
|
||||
((mode != MODE_INVALID && ((st.st_mode ^ mode) & 07777) != 0) ||
|
||||
do_chown); /* If we change ownership, make sure we reset the mode afterwards, since chown()
|
||||
* modifies the access mode too */
|
||||
|
||||
if (mode == MODE_INVALID)
|
||||
mode = st.st_mode; /* If we only shall do a chown(), save original mode, since chown() might break it. */
|
||||
else if ((mode & S_IFMT) != 0 && ((mode ^ st.st_mode) & S_IFMT) != 0)
|
||||
return -EINVAL; /* insist on the right file type if it was specified */
|
||||
|
||||
if (do_chown && do_chmod) {
|
||||
mode_t minimal = st.st_mode & mode; /* the subset of the old and the new mask */
|
||||
|
||||
if (((minimal ^ st.st_mode) & 07777) != 0)
|
||||
if (chmod(path, minimal & 07777) < 0)
|
||||
return -errno;
|
||||
}
|
||||
|
||||
if (do_chown)
|
||||
if (lchown(path, uid, gid) < 0)
|
||||
return -errno;
|
||||
|
||||
if (do_chmod)
|
||||
if (chmod(path, mode & 07777) < 0)
|
||||
return -errno;
|
||||
|
||||
return do_chown || do_chmod;
|
||||
}
|
||||
|
||||
int fchmod_umask(int fd, mode_t m) {
|
||||
mode_t u;
|
||||
|
@ -289,7 +334,6 @@ int fchmod_umask(int fd, mode_t m) {
|
|||
return r;
|
||||
}
|
||||
|
||||
#if 0 /* NM_IGNORED */
|
||||
int fchmod_opath(int fd, mode_t m) {
|
||||
char procfs_path[STRLEN("/proc/self/fd/") + DECIMAL_STR_MAX(int)];
|
||||
|
||||
|
@ -810,6 +854,14 @@ int chase_symlinks(const char *path, const char *original_root, unsigned flags,
|
|||
if (r < 0)
|
||||
return r;
|
||||
|
||||
/* Simplify the root directory, so that it has no duplicate slashes and nothing at the
|
||||
* end. While we won't resolve the root path we still simplify it. Note that dropping the
|
||||
* trailing slash should not change behaviour, since when opening it we specify O_DIRECTORY
|
||||
* anyway. Moreover at the end of this function after processing everything we'll always turn
|
||||
* the empty string back to "/". */
|
||||
delete_trailing_chars(root, "/");
|
||||
path_simplify(root, true);
|
||||
|
||||
if (flags & CHASE_PREFIX_ROOT) {
|
||||
/* We don't support relative paths in combination with a root directory */
|
||||
if (!path_is_absolute(path))
|
||||
|
@ -823,7 +875,7 @@ int chase_symlinks(const char *path, const char *original_root, unsigned flags,
|
|||
if (r < 0)
|
||||
return r;
|
||||
|
||||
fd = open("/", O_CLOEXEC|O_NOFOLLOW|O_PATH);
|
||||
fd = open(root ?: "/", O_CLOEXEC|O_DIRECTORY|O_PATH);
|
||||
if (fd < 0)
|
||||
return -errno;
|
||||
|
||||
|
@ -832,6 +884,31 @@ int chase_symlinks(const char *path, const char *original_root, unsigned flags,
|
|||
return -errno;
|
||||
}
|
||||
|
||||
if (root) {
|
||||
_cleanup_free_ char *absolute = NULL;
|
||||
const char *e;
|
||||
|
||||
/* If we are operating on a root directory, let's take the root directory as it is. */
|
||||
|
||||
e = path_startswith(buffer, root);
|
||||
if (!e)
|
||||
return log_full_errno(flags & CHASE_WARN ? LOG_WARNING : LOG_DEBUG,
|
||||
SYNTHETIC_ERRNO(ECHRNG),
|
||||
"Specified path '%s' is outside of specified root directory '%s', refusing to resolve.",
|
||||
path, root);
|
||||
|
||||
done = strdup(root);
|
||||
if (!done)
|
||||
return -ENOMEM;
|
||||
|
||||
/* Make sure "todo" starts with a slash */
|
||||
absolute = strjoin("/", e);
|
||||
if (!absolute)
|
||||
return -ENOMEM;
|
||||
|
||||
free_and_replace(buffer, absolute);
|
||||
}
|
||||
|
||||
todo = buffer;
|
||||
for (;;) {
|
||||
_cleanup_free_ char *first = NULL;
|
||||
|
@ -841,6 +918,15 @@ int chase_symlinks(const char *path, const char *original_root, unsigned flags,
|
|||
|
||||
/* Determine length of first component in the path */
|
||||
n = strspn(todo, "/"); /* The slashes */
|
||||
|
||||
if (n > 1) {
|
||||
/* If we are looking at more than a single slash then skip all but one, so that when
|
||||
* we are done with everything we have a normalized path with only single slashes
|
||||
* separating the path components. */
|
||||
todo += n - 1;
|
||||
n = 1;
|
||||
}
|
||||
|
||||
m = n + strcspn(todo + n, "/"); /* The entire length of the component */
|
||||
|
||||
/* Extract the first component. */
|
||||
|
@ -943,7 +1029,6 @@ int chase_symlinks(const char *path, const char *original_root, unsigned flags,
|
|||
if (fstat(child, &st) < 0)
|
||||
return -errno;
|
||||
if ((flags & CHASE_SAFE) &&
|
||||
(empty_or_root(root) || (size_t)(todo - buffer) > strlen(root)) &&
|
||||
unsafe_transition(&previous_stat, &st))
|
||||
return log_unsafe_transition(fd, child, path, flags);
|
||||
|
||||
|
@ -974,7 +1059,7 @@ int chase_symlinks(const char *path, const char *original_root, unsigned flags,
|
|||
* directory as base. */
|
||||
|
||||
safe_close(fd);
|
||||
fd = open(root ?: "/", O_CLOEXEC|O_NOFOLLOW|O_PATH);
|
||||
fd = open(root ?: "/", O_CLOEXEC|O_DIRECTORY|O_PATH);
|
||||
if (fd < 0)
|
||||
return -errno;
|
||||
|
||||
|
|
|
@ -34,6 +34,7 @@ int readlink_and_make_absolute(const char *p, char **r);
|
|||
|
||||
int chmod_and_chown(const char *path, mode_t mode, uid_t uid, gid_t gid);
|
||||
int fchmod_and_chown(int fd, mode_t mode, uid_t uid, gid_t gid);
|
||||
int chmod_and_chown_unsafe(const char *path, mode_t mode, uid_t uid, gid_t gid);
|
||||
|
||||
int fchmod_umask(int fd, mode_t mode);
|
||||
int fchmod_opath(int fd, mode_t m);
|
||||
|
|
|
@ -445,54 +445,6 @@ int in_addr_from_string_auto(const char *s, int *ret_family, union in_addr_union
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
#if 0 /* NM_IGNORED */
|
||||
int in_addr_ifindex_from_string_auto(const char *s, int *family, union in_addr_union *ret, int *ifindex) {
|
||||
_cleanup_free_ char *buf = NULL;
|
||||
const char *suffix;
|
||||
int r, ifi = 0;
|
||||
|
||||
assert(s);
|
||||
assert(family);
|
||||
assert(ret);
|
||||
|
||||
/* Similar to in_addr_from_string_auto() but also parses an optionally appended IPv6 zone suffix ("scope id")
|
||||
* if one is found. */
|
||||
|
||||
suffix = strchr(s, '%');
|
||||
if (suffix) {
|
||||
|
||||
if (ifindex) {
|
||||
/* If we shall return the interface index, try to parse it */
|
||||
r = parse_ifindex(suffix + 1, &ifi);
|
||||
if (r < 0) {
|
||||
unsigned u;
|
||||
|
||||
u = if_nametoindex(suffix + 1);
|
||||
if (u <= 0)
|
||||
return -errno;
|
||||
|
||||
ifi = (int) u;
|
||||
}
|
||||
}
|
||||
|
||||
buf = strndup(s, suffix - s);
|
||||
if (!buf)
|
||||
return -ENOMEM;
|
||||
|
||||
s = buf;
|
||||
}
|
||||
|
||||
r = in_addr_from_string_auto(s, family, ret);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (ifindex)
|
||||
*ifindex = ifi;
|
||||
|
||||
return r;
|
||||
}
|
||||
#endif /* NM_IGNORED */
|
||||
|
||||
unsigned char in4_addr_netmask_to_prefixlen(const struct in_addr *addr) {
|
||||
assert(addr);
|
||||
|
||||
|
|
|
@ -42,7 +42,7 @@ int in_addr_prefix_to_string(int family, const union in_addr_union *u, unsigned
|
|||
int in_addr_ifindex_to_string(int family, const union in_addr_union *u, int ifindex, char **ret);
|
||||
int in_addr_from_string(int family, const char *s, union in_addr_union *ret);
|
||||
int in_addr_from_string_auto(const char *s, int *ret_family, union in_addr_union *ret);
|
||||
int in_addr_ifindex_from_string_auto(const char *s, int *family, union in_addr_union *ret, int *ifindex);
|
||||
|
||||
unsigned char in4_addr_netmask_to_prefixlen(const struct in_addr *addr);
|
||||
struct in_addr* in4_addr_prefixlen_to_netmask(struct in_addr *addr, unsigned char prefixlen);
|
||||
int in4_addr_default_prefixlen(const struct in_addr *addr, unsigned char *prefixlen);
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
#include <string.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include "alloc-util.h"
|
||||
#include "macro.h"
|
||||
|
||||
size_t page_size(void) _pure_;
|
||||
|
@ -88,9 +89,7 @@ static inline void* erase_and_free(void *p) {
|
|||
|
||||
l = malloc_usable_size(p);
|
||||
explicit_bzero_safe(p, l);
|
||||
free(p);
|
||||
|
||||
return NULL;
|
||||
return mfree(p);
|
||||
}
|
||||
|
||||
static inline void erase_and_freep(void *p) {
|
||||
|
|
|
@ -82,11 +82,10 @@ int parse_mode(const char *s, mode_t *ret) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
int parse_ifindex(const char *s, int *ret) {
|
||||
int parse_ifindex(const char *s) {
|
||||
int ifi, r;
|
||||
|
||||
assert(s);
|
||||
assert(ret);
|
||||
|
||||
r = safe_atoi(s, &ifi);
|
||||
if (r < 0)
|
||||
|
@ -94,26 +93,7 @@ int parse_ifindex(const char *s, int *ret) {
|
|||
if (ifi <= 0)
|
||||
return -EINVAL;
|
||||
|
||||
*ret = ifi;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int parse_ifindex_or_ifname(const char *s, int *ret) {
|
||||
int r;
|
||||
|
||||
assert(s);
|
||||
assert(ret);
|
||||
|
||||
r = parse_ifindex(s, ret);
|
||||
if (r >= 0)
|
||||
return r;
|
||||
|
||||
r = (int) if_nametoindex(s);
|
||||
if (r <= 0)
|
||||
return -errno;
|
||||
|
||||
*ret = r;
|
||||
return 0;
|
||||
return ifi;
|
||||
}
|
||||
|
||||
int parse_mtu(int family, const char *s, uint32_t *ret) {
|
||||
|
@ -723,6 +703,22 @@ int parse_ip_port_range(const char *s, uint16_t *low, uint16_t *high) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
int parse_ip_prefix_length(const char *s, int *ret) {
|
||||
unsigned l;
|
||||
int r;
|
||||
|
||||
r = safe_atou(s, &l);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (l > 128)
|
||||
return -ERANGE;
|
||||
|
||||
*ret = (int) l;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int parse_dev(const char *s, dev_t *ret) {
|
||||
const char *major;
|
||||
unsigned x, y;
|
||||
|
|
|
@ -13,8 +13,7 @@ int parse_boolean(const char *v) _pure_;
|
|||
int parse_dev(const char *s, dev_t *ret);
|
||||
int parse_pid(const char *s, pid_t* ret_pid);
|
||||
int parse_mode(const char *s, mode_t *ret);
|
||||
int parse_ifindex(const char *s, int *ret);
|
||||
int parse_ifindex_or_ifname(const char *s, int *ret);
|
||||
int parse_ifindex(const char *s);
|
||||
int parse_mtu(int family, const char *s, uint32_t *ret);
|
||||
|
||||
int parse_size(const char *t, uint64_t base, uint64_t *size);
|
||||
|
@ -46,9 +45,13 @@ static inline int safe_atoux16(const char *s, uint16_t *ret) {
|
|||
|
||||
int safe_atoi16(const char *s, int16_t *ret);
|
||||
|
||||
static inline int safe_atou32(const char *s, uint32_t *ret_u) {
|
||||
static inline int safe_atou32_full(const char *s, unsigned base, uint32_t *ret_u) {
|
||||
assert_cc(sizeof(uint32_t) == sizeof(unsigned));
|
||||
return safe_atou(s, (unsigned*) ret_u);
|
||||
return safe_atou_full(s, base, (unsigned*) ret_u);
|
||||
}
|
||||
|
||||
static inline int safe_atou32(const char *s, uint32_t *ret_u) {
|
||||
return safe_atou32_full(s, 0, (unsigned*) ret_u);
|
||||
}
|
||||
|
||||
static inline int safe_atoi32(const char *s, int32_t *ret_i) {
|
||||
|
@ -113,4 +116,6 @@ int parse_nice(const char *p, int *ret);
|
|||
int parse_ip_port(const char *s, uint16_t *ret);
|
||||
int parse_ip_port_range(const char *s, uint16_t *low, uint16_t *high);
|
||||
|
||||
int parse_ip_prefix_length(const char *s, int *ret);
|
||||
|
||||
int parse_oom_score_adjust(const char *s, int *ret);
|
||||
|
|
|
@ -1128,4 +1128,30 @@ bool empty_or_root(const char *root) {
|
|||
|
||||
return root[strspn(root, "/")] == 0;
|
||||
}
|
||||
|
||||
bool path_strv_contains(char **l, const char *path) {
|
||||
char **i;
|
||||
|
||||
STRV_FOREACH(i, l)
|
||||
if (path_equal(*i, path))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool prefixed_path_strv_contains(char **l, const char *path) {
|
||||
char **i, *j;
|
||||
|
||||
STRV_FOREACH(i, l) {
|
||||
j = *i;
|
||||
if (*j == '-')
|
||||
j++;
|
||||
if (*j == '+')
|
||||
j++;
|
||||
if (path_equal(j, path))
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
#endif /* NM_IGNORED */
|
||||
|
|
|
@ -73,17 +73,7 @@ static inline bool path_equal_ptr(const char *a, const char *b) {
|
|||
}
|
||||
|
||||
/* Note: the search terminates on the first NULL item. */
|
||||
#define PATH_IN_SET(p, ...) \
|
||||
({ \
|
||||
char **_s; \
|
||||
bool _found = false; \
|
||||
STRV_FOREACH(_s, STRV_MAKE(__VA_ARGS__)) \
|
||||
if (path_equal(p, *_s)) { \
|
||||
_found = true; \
|
||||
break; \
|
||||
} \
|
||||
_found; \
|
||||
})
|
||||
#define PATH_IN_SET(p, ...) path_strv_contains(STRV_MAKE(__VA_ARGS__), p)
|
||||
|
||||
char* path_startswith_strv(const char *p, char **set);
|
||||
#define PATH_STARTSWITH_SET(p, ...) path_startswith_strv(p, STRV_MAKE(__VA_ARGS__))
|
||||
|
@ -183,3 +173,6 @@ bool empty_or_root(const char *root);
|
|||
static inline const char *empty_to_root(const char *path) {
|
||||
return isempty(path) ? "/" : path;
|
||||
}
|
||||
|
||||
bool path_strv_contains(char **l, const char *path);
|
||||
bool prefixed_path_strv_contains(char **l, const char *path);
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
#include "alloc-util.h"
|
||||
#include "architecture.h"
|
||||
#include "env-util.h"
|
||||
#include "errno-util.h"
|
||||
#include "escape.h"
|
||||
#include "fd-util.h"
|
||||
#include "fileio.h"
|
||||
|
@ -1537,6 +1538,62 @@ int pidfd_get_pid(int fd, pid_t *ret) {
|
|||
return parse_pid(p, ret);
|
||||
}
|
||||
|
||||
static int rlimit_to_nice(rlim_t limit) {
|
||||
if (limit <= 1)
|
||||
return PRIO_MAX-1; /* i.e. 19 */
|
||||
|
||||
if (limit >= -PRIO_MIN + PRIO_MAX)
|
||||
return PRIO_MIN; /* i.e. -20 */
|
||||
|
||||
return PRIO_MAX - (int) limit;
|
||||
}
|
||||
|
||||
int setpriority_closest(int priority) {
|
||||
int current, limit, saved_errno;
|
||||
struct rlimit highest;
|
||||
|
||||
/* Try to set requested nice level */
|
||||
if (setpriority(PRIO_PROCESS, 0, priority) >= 0)
|
||||
return 1;
|
||||
|
||||
/* Permission failed */
|
||||
saved_errno = -errno;
|
||||
if (!ERRNO_IS_PRIVILEGE(saved_errno))
|
||||
return saved_errno;
|
||||
|
||||
errno = 0;
|
||||
current = getpriority(PRIO_PROCESS, 0);
|
||||
if (errno != 0)
|
||||
return -errno;
|
||||
|
||||
if (priority == current)
|
||||
return 1;
|
||||
|
||||
/* Hmm, we'd expect that raising the nice level from our status quo would always work. If it doesn't,
|
||||
* then the whole setpriority() system call is blocked to us, hence let's propagate the error
|
||||
* right-away */
|
||||
if (priority > current)
|
||||
return saved_errno;
|
||||
|
||||
if (getrlimit(RLIMIT_NICE, &highest) < 0)
|
||||
return -errno;
|
||||
|
||||
limit = rlimit_to_nice(highest.rlim_cur);
|
||||
|
||||
/* We are already less nice than limit allows us */
|
||||
if (current < limit) {
|
||||
log_debug("Cannot raise nice level, permissions and the resource limit do not allow it.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Push to the allowed limit */
|
||||
if (setpriority(PRIO_PROCESS, 0, limit) < 0)
|
||||
return -errno;
|
||||
|
||||
log_debug("Cannot set requested nice level (%i), used next best (%i).", priority, limit);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const char *const ioprio_class_table[] = {
|
||||
[IOPRIO_CLASS_NONE] = "none",
|
||||
[IOPRIO_CLASS_RT] = "realtime",
|
||||
|
|
|
@ -174,7 +174,6 @@ int fork_agent(const char *name, const int except[], size_t n_except, pid_t *pid
|
|||
|
||||
int set_oom_score_adjust(int value);
|
||||
|
||||
#if SIZEOF_PID_T == 4
|
||||
/* The highest possibly (theoretic) pid_t value on this architecture. */
|
||||
#define PID_T_MAX ((pid_t) INT32_MAX)
|
||||
/* The maximum number of concurrent processes Linux allows on this architecture, as well as the highest valid PID value
|
||||
|
@ -184,12 +183,6 @@ int set_oom_score_adjust(int value);
|
|||
* these values are documented in proc(5) we feel quite confident that they are stable enough for the near future at
|
||||
* least to define them here too. */
|
||||
#define TASKS_MAX 4194303U
|
||||
#elif SIZEOF_PID_T == 2
|
||||
#define PID_T_MAX ((pid_t) INT16_MAX)
|
||||
#define TASKS_MAX 32767U
|
||||
#else
|
||||
#error "Unknown pid_t size"
|
||||
#endif
|
||||
|
||||
assert_cc(TASKS_MAX <= (unsigned long) PID_T_MAX);
|
||||
|
||||
|
@ -202,3 +195,5 @@ assert_cc(TASKS_MAX <= (unsigned long) PID_T_MAX);
|
|||
})
|
||||
|
||||
int pidfd_get_pid(int fd, pid_t *ret);
|
||||
|
||||
int setpriority_closest(int priority);
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
#include <elf.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <pthread.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
|
@ -30,6 +31,8 @@
|
|||
#include "siphash24.h"
|
||||
#include "time-util.h"
|
||||
|
||||
static bool srand_called = false;
|
||||
|
||||
int rdrand(unsigned long *ret) {
|
||||
|
||||
/* So, you are a "security researcher", and you wonder why we bother with using raw RDRAND here,
|
||||
|
@ -281,8 +284,12 @@ int genuine_random_bytes(void *p, size_t n, RandomFlags flags) {
|
|||
return loop_read_exact(fd, p, n, true);
|
||||
}
|
||||
|
||||
static void clear_srand_initialization(void) {
|
||||
srand_called = false;
|
||||
}
|
||||
|
||||
void initialize_srand(void) {
|
||||
static bool srand_called = false;
|
||||
static bool pthread_atfork_registered = false;
|
||||
unsigned x;
|
||||
#if HAVE_SYS_AUXV_H
|
||||
const void *auxv;
|
||||
|
@ -318,6 +325,11 @@ void initialize_srand(void) {
|
|||
|
||||
srand(x);
|
||||
srand_called = true;
|
||||
|
||||
if (!pthread_atfork_registered) {
|
||||
(void) pthread_atfork(NULL, NULL, clear_srand_initialization);
|
||||
pthread_atfork_registered = true;
|
||||
}
|
||||
}
|
||||
|
||||
/* INT_MAX gives us only 31 bits, so use 24 out of that. */
|
||||
|
|
|
@ -15,6 +15,9 @@
|
|||
#include <stdlib.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <unistd.h>
|
||||
#if 0 /* NM_IGNORED */
|
||||
#include <linux/if.h>
|
||||
#endif /* NM_IGNORED */
|
||||
|
||||
#include "alloc-util.h"
|
||||
#include "errno-util.h"
|
||||
|
@ -44,237 +47,16 @@
|
|||
#endif
|
||||
|
||||
static const char* const socket_address_type_table[] = {
|
||||
[SOCK_STREAM] = "Stream",
|
||||
[SOCK_DGRAM] = "Datagram",
|
||||
[SOCK_RAW] = "Raw",
|
||||
[SOCK_RDM] = "ReliableDatagram",
|
||||
[SOCK_STREAM] = "Stream",
|
||||
[SOCK_DGRAM] = "Datagram",
|
||||
[SOCK_RAW] = "Raw",
|
||||
[SOCK_RDM] = "ReliableDatagram",
|
||||
[SOCK_SEQPACKET] = "SequentialPacket",
|
||||
[SOCK_DCCP] = "DatagramCongestionControl",
|
||||
[SOCK_DCCP] = "DatagramCongestionControl",
|
||||
};
|
||||
|
||||
DEFINE_STRING_TABLE_LOOKUP(socket_address_type, int);
|
||||
|
||||
int socket_address_parse(SocketAddress *a, const char *s) {
|
||||
_cleanup_free_ char *n = NULL;
|
||||
char *e;
|
||||
int r;
|
||||
|
||||
assert(a);
|
||||
assert(s);
|
||||
|
||||
*a = (SocketAddress) {
|
||||
.type = SOCK_STREAM,
|
||||
};
|
||||
|
||||
if (*s == '[') {
|
||||
uint16_t port;
|
||||
|
||||
/* IPv6 in [x:.....:z]:p notation */
|
||||
|
||||
e = strchr(s+1, ']');
|
||||
if (!e)
|
||||
return -EINVAL;
|
||||
|
||||
n = strndup(s+1, e-s-1);
|
||||
if (!n)
|
||||
return -ENOMEM;
|
||||
|
||||
errno = 0;
|
||||
if (inet_pton(AF_INET6, n, &a->sockaddr.in6.sin6_addr) <= 0)
|
||||
return errno_or_else(EINVAL);
|
||||
|
||||
e++;
|
||||
if (*e != ':')
|
||||
return -EINVAL;
|
||||
|
||||
e++;
|
||||
r = parse_ip_port(e, &port);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
a->sockaddr.in6.sin6_family = AF_INET6;
|
||||
a->sockaddr.in6.sin6_port = htobe16(port);
|
||||
a->size = sizeof(struct sockaddr_in6);
|
||||
|
||||
} else if (*s == '/') {
|
||||
/* AF_UNIX socket */
|
||||
|
||||
size_t l;
|
||||
|
||||
l = strlen(s);
|
||||
if (l >= sizeof(a->sockaddr.un.sun_path)) /* Note that we refuse non-NUL-terminated sockets when
|
||||
* parsing (the kernel itself is less strict here in what it
|
||||
* accepts) */
|
||||
return -EINVAL;
|
||||
|
||||
a->sockaddr.un.sun_family = AF_UNIX;
|
||||
memcpy(a->sockaddr.un.sun_path, s, l);
|
||||
a->size = offsetof(struct sockaddr_un, sun_path) + l + 1;
|
||||
|
||||
} else if (*s == '@') {
|
||||
/* Abstract AF_UNIX socket */
|
||||
size_t l;
|
||||
|
||||
l = strlen(s+1);
|
||||
if (l >= sizeof(a->sockaddr.un.sun_path) - 1) /* Note that we refuse non-NUL-terminated sockets here
|
||||
* when parsing, even though abstract namespace sockets
|
||||
* explicitly allow embedded NUL bytes and don't consider
|
||||
* them special. But it's simply annoying to debug such
|
||||
* sockets. */
|
||||
return -EINVAL;
|
||||
|
||||
a->sockaddr.un.sun_family = AF_UNIX;
|
||||
memcpy(a->sockaddr.un.sun_path+1, s+1, l);
|
||||
a->size = offsetof(struct sockaddr_un, sun_path) + 1 + l;
|
||||
|
||||
} else if (startswith(s, "vsock:")) {
|
||||
/* AF_VSOCK socket in vsock:cid:port notation */
|
||||
const char *cid_start = s + STRLEN("vsock:");
|
||||
unsigned port;
|
||||
|
||||
e = strchr(cid_start, ':');
|
||||
if (!e)
|
||||
return -EINVAL;
|
||||
|
||||
r = safe_atou(e+1, &port);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
n = strndup(cid_start, e - cid_start);
|
||||
if (!n)
|
||||
return -ENOMEM;
|
||||
|
||||
if (!isempty(n)) {
|
||||
r = safe_atou(n, &a->sockaddr.vm.svm_cid);
|
||||
if (r < 0)
|
||||
return r;
|
||||
} else
|
||||
a->sockaddr.vm.svm_cid = VMADDR_CID_ANY;
|
||||
|
||||
a->sockaddr.vm.svm_family = AF_VSOCK;
|
||||
a->sockaddr.vm.svm_port = port;
|
||||
a->size = sizeof(struct sockaddr_vm);
|
||||
|
||||
} else {
|
||||
uint16_t port;
|
||||
|
||||
e = strchr(s, ':');
|
||||
if (e) {
|
||||
r = parse_ip_port(e + 1, &port);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
n = strndup(s, e-s);
|
||||
if (!n)
|
||||
return -ENOMEM;
|
||||
|
||||
/* IPv4 in w.x.y.z:p notation? */
|
||||
r = inet_pton(AF_INET, n, &a->sockaddr.in.sin_addr);
|
||||
if (r < 0)
|
||||
return -errno;
|
||||
|
||||
if (r > 0) {
|
||||
/* Gotcha, it's a traditional IPv4 address */
|
||||
a->sockaddr.in.sin_family = AF_INET;
|
||||
a->sockaddr.in.sin_port = htobe16(port);
|
||||
a->size = sizeof(struct sockaddr_in);
|
||||
} else {
|
||||
unsigned idx;
|
||||
|
||||
if (strlen(n) > IF_NAMESIZE-1)
|
||||
return -EINVAL;
|
||||
|
||||
/* Uh, our last resort, an interface name */
|
||||
idx = if_nametoindex(n);
|
||||
if (idx == 0)
|
||||
return -EINVAL;
|
||||
|
||||
a->sockaddr.in6.sin6_family = AF_INET6;
|
||||
a->sockaddr.in6.sin6_port = htobe16(port);
|
||||
a->sockaddr.in6.sin6_scope_id = idx;
|
||||
a->sockaddr.in6.sin6_addr = in6addr_any;
|
||||
a->size = sizeof(struct sockaddr_in6);
|
||||
}
|
||||
} else {
|
||||
|
||||
/* Just a port */
|
||||
r = parse_ip_port(s, &port);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (socket_ipv6_is_supported()) {
|
||||
a->sockaddr.in6.sin6_family = AF_INET6;
|
||||
a->sockaddr.in6.sin6_port = htobe16(port);
|
||||
a->sockaddr.in6.sin6_addr = in6addr_any;
|
||||
a->size = sizeof(struct sockaddr_in6);
|
||||
} else {
|
||||
a->sockaddr.in.sin_family = AF_INET;
|
||||
a->sockaddr.in.sin_port = htobe16(port);
|
||||
a->sockaddr.in.sin_addr.s_addr = INADDR_ANY;
|
||||
a->size = sizeof(struct sockaddr_in);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int socket_address_parse_and_warn(SocketAddress *a, const char *s) {
|
||||
SocketAddress b;
|
||||
int r;
|
||||
|
||||
/* Similar to socket_address_parse() but warns for IPv6 sockets when we don't support them. */
|
||||
|
||||
r = socket_address_parse(&b, s);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (!socket_ipv6_is_supported() && b.sockaddr.sa.sa_family == AF_INET6) {
|
||||
log_warning("Binding to IPv6 address not available since kernel does not support IPv6.");
|
||||
return -EAFNOSUPPORT;
|
||||
}
|
||||
|
||||
*a = b;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int socket_address_parse_netlink(SocketAddress *a, const char *s) {
|
||||
_cleanup_free_ char *word = NULL;
|
||||
unsigned group = 0;
|
||||
int family, r;
|
||||
|
||||
assert(a);
|
||||
assert(s);
|
||||
|
||||
zero(*a);
|
||||
a->type = SOCK_RAW;
|
||||
|
||||
r = extract_first_word(&s, &word, NULL, 0);
|
||||
if (r < 0)
|
||||
return r;
|
||||
if (r == 0)
|
||||
return -EINVAL;
|
||||
|
||||
family = netlink_family_from_string(word);
|
||||
if (family < 0)
|
||||
return -EINVAL;
|
||||
|
||||
if (!isempty(s)) {
|
||||
r = safe_atou(s, &group);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
a->sockaddr.nl.nl_family = AF_NETLINK;
|
||||
a->sockaddr.nl.nl_groups = group;
|
||||
|
||||
a->type = SOCK_RAW;
|
||||
a->size = sizeof(struct sockaddr_nl);
|
||||
a->protocol = family;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int socket_address_verify(const SocketAddress *a, bool strict) {
|
||||
assert(a);
|
||||
|
||||
|
@ -484,32 +266,6 @@ bool socket_address_equal(const SocketAddress *a, const SocketAddress *b) {
|
|||
return true;
|
||||
}
|
||||
|
||||
bool socket_address_is(const SocketAddress *a, const char *s, int type) {
|
||||
struct SocketAddress b;
|
||||
|
||||
assert(a);
|
||||
assert(s);
|
||||
|
||||
if (socket_address_parse(&b, s) < 0)
|
||||
return false;
|
||||
|
||||
b.type = type;
|
||||
|
||||
return socket_address_equal(a, &b);
|
||||
}
|
||||
|
||||
bool socket_address_is_netlink(const SocketAddress *a, const char *s) {
|
||||
struct SocketAddress b;
|
||||
|
||||
assert(a);
|
||||
assert(s);
|
||||
|
||||
if (socket_address_parse_netlink(&b, s) < 0)
|
||||
return false;
|
||||
|
||||
return socket_address_equal(a, &b);
|
||||
}
|
||||
|
||||
const char* socket_address_get_path(const SocketAddress *a) {
|
||||
assert(a);
|
||||
|
||||
|
@ -912,7 +668,7 @@ static const char* const ip_tos_table[] = {
|
|||
|
||||
DEFINE_STRING_TABLE_LOOKUP_WITH_FALLBACK(ip_tos, int, 0xff);
|
||||
|
||||
bool ifname_valid(const char *p) {
|
||||
bool ifname_valid_full(const char *p, bool alternative) {
|
||||
bool numeric = true;
|
||||
|
||||
/* Checks whether a network interface name is valid. This is inspired by dev_valid_name() in the kernel sources
|
||||
|
@ -922,8 +678,13 @@ bool ifname_valid(const char *p) {
|
|||
if (isempty(p))
|
||||
return false;
|
||||
|
||||
if (strlen(p) >= IFNAMSIZ)
|
||||
return false;
|
||||
if (alternative) {
|
||||
if (strlen(p) >= ALTIFNAMSIZ)
|
||||
return false;
|
||||
} else {
|
||||
if (strlen(p) >= IFNAMSIZ)
|
||||
return false;
|
||||
}
|
||||
|
||||
if (dot_or_dot_dot(p))
|
||||
return false;
|
||||
|
|
|
@ -43,6 +43,8 @@ union sockaddr_union {
|
|||
uint8_t un_buffer[sizeof(struct sockaddr_un) + 1];
|
||||
};
|
||||
|
||||
#define SUN_PATH_LEN (sizeof(((struct sockaddr_un){}).sun_path))
|
||||
|
||||
typedef struct SocketAddress {
|
||||
union sockaddr_union sockaddr;
|
||||
|
||||
|
@ -70,12 +72,6 @@ typedef enum SocketAddressBindIPv6Only {
|
|||
const char* socket_address_type_to_string(int t) _const_;
|
||||
int socket_address_type_from_string(const char *s) _pure_;
|
||||
|
||||
int socket_address_parse(SocketAddress *a, const char *s);
|
||||
int socket_address_parse_and_warn(SocketAddress *a, const char *s);
|
||||
int socket_address_parse_netlink(SocketAddress *a, const char *s);
|
||||
int socket_address_print(const SocketAddress *a, char **p);
|
||||
int socket_address_verify(const SocketAddress *a, bool strict) _pure_;
|
||||
|
||||
int sockaddr_un_unlink(const struct sockaddr_un *sa);
|
||||
|
||||
static inline int socket_address_unlink(const SocketAddress *a) {
|
||||
|
@ -96,11 +92,9 @@ int socket_address_listen(
|
|||
mode_t directory_mode,
|
||||
mode_t socket_mode,
|
||||
const char *label);
|
||||
int make_socket_fd(int log_level, const char* address, int type, int flags);
|
||||
|
||||
bool socket_address_is(const SocketAddress *a, const char *s, int type);
|
||||
bool socket_address_is_netlink(const SocketAddress *a, const char *s);
|
||||
|
||||
int socket_address_verify(const SocketAddress *a, bool strict) _pure_;
|
||||
int socket_address_print(const SocketAddress *a, char **p);
|
||||
bool socket_address_matches_fd(const SocketAddress *a, int fd);
|
||||
|
||||
bool socket_address_equal(const SocketAddress *a, const SocketAddress *b) _pure_;
|
||||
|
@ -132,7 +126,10 @@ int fd_inc_rcvbuf(int fd, size_t n);
|
|||
int ip_tos_to_string_alloc(int i, char **s);
|
||||
int ip_tos_from_string(const char *s);
|
||||
|
||||
bool ifname_valid(const char *p);
|
||||
bool ifname_valid_full(const char *p, bool alternative);
|
||||
static inline bool ifname_valid(const char *p) {
|
||||
return ifname_valid_full(p, false);
|
||||
}
|
||||
bool address_label_valid(const char *p);
|
||||
|
||||
int getpeercred(int fd, struct ucred *ucred);
|
||||
|
|
|
@ -44,7 +44,7 @@ ssize_t string_table_lookup(const char * const *table, size_t len, const char *k
|
|||
char *s; \
|
||||
if (i < 0 || i > max) \
|
||||
return -ERANGE; \
|
||||
if (i < (type) ELEMENTSOF(name##_table)) { \
|
||||
if (i < (type) ELEMENTSOF(name##_table) && name##_table[i]) { \
|
||||
s = strdup(name##_table[i]); \
|
||||
if (!s) \
|
||||
return -ENOMEM; \
|
||||
|
|
|
@ -1062,6 +1062,8 @@ bool string_is_safe(const char *p) {
|
|||
if (!p)
|
||||
return false;
|
||||
|
||||
/* Checks if the specified string contains no quotes or control characters */
|
||||
|
||||
for (t = p; *t; t++) {
|
||||
if (*t > 0 && *t < ' ') /* no control characters */
|
||||
return false;
|
||||
|
@ -1083,4 +1085,122 @@ char* string_erase(char *x) {
|
|||
explicit_bzero_safe(x, strlen(x));
|
||||
return x;
|
||||
}
|
||||
|
||||
int string_truncate_lines(const char *s, size_t n_lines, char **ret) {
|
||||
const char *p = s, *e = s;
|
||||
bool truncation_applied = false;
|
||||
char *copy;
|
||||
size_t n = 0;
|
||||
|
||||
assert(s);
|
||||
|
||||
/* Truncate after the specified number of lines. Returns > 0 if a truncation was applied or == 0 if
|
||||
* there were fewer lines in the string anyway. Trailing newlines on input are ignored, and not
|
||||
* generated either. */
|
||||
|
||||
for (;;) {
|
||||
size_t k;
|
||||
|
||||
k = strcspn(p, "\n");
|
||||
|
||||
if (p[k] == 0) {
|
||||
if (k == 0) /* final empty line */
|
||||
break;
|
||||
|
||||
if (n >= n_lines) /* above threshold */
|
||||
break;
|
||||
|
||||
e = p + k; /* last line to include */
|
||||
break;
|
||||
}
|
||||
|
||||
assert(p[k] == '\n');
|
||||
|
||||
if (n >= n_lines)
|
||||
break;
|
||||
|
||||
if (k > 0)
|
||||
e = p + k;
|
||||
|
||||
p += k + 1;
|
||||
n++;
|
||||
}
|
||||
|
||||
/* e points after the last character we want to keep */
|
||||
if (isempty(e))
|
||||
copy = strdup(s);
|
||||
else {
|
||||
if (!in_charset(e, "\n")) /* We only consider things truncated if we remove something that
|
||||
* isn't a new-line or a series of them */
|
||||
truncation_applied = true;
|
||||
|
||||
copy = strndup(s, e - s);
|
||||
}
|
||||
if (!copy)
|
||||
return -ENOMEM;
|
||||
|
||||
*ret = copy;
|
||||
return truncation_applied;
|
||||
}
|
||||
|
||||
int string_extract_line(const char *s, size_t i, char **ret) {
|
||||
const char *p = s;
|
||||
size_t c = 0;
|
||||
|
||||
/* Extract the i'nth line from the specified string. Returns > 0 if there are more lines after that,
|
||||
* and == 0 if we are looking at the last line or already beyond the last line. As special
|
||||
* optimization, if the first line is requested and the string only consists of one line we return
|
||||
* NULL, indicating the input string should be used as is, and avoid a memory allocation for a very
|
||||
* common case. */
|
||||
|
||||
for (;;) {
|
||||
const char *q;
|
||||
|
||||
q = strchr(p, '\n');
|
||||
if (i == c) {
|
||||
/* The line we are looking for! */
|
||||
|
||||
if (q) {
|
||||
char *m;
|
||||
|
||||
m = strndup(p, q - p);
|
||||
if (!m)
|
||||
return -ENOMEM;
|
||||
|
||||
*ret = m;
|
||||
return !isempty(q + 1); /* more coming? */
|
||||
} else {
|
||||
if (p == s)
|
||||
*ret = NULL; /* Just use the input string */
|
||||
else {
|
||||
char *m;
|
||||
|
||||
m = strdup(p);
|
||||
if (!m)
|
||||
return -ENOMEM;
|
||||
|
||||
*ret = m;
|
||||
}
|
||||
|
||||
return 0; /* The end */
|
||||
}
|
||||
}
|
||||
|
||||
if (!q) {
|
||||
char *m;
|
||||
|
||||
/* No more lines, return empty line */
|
||||
|
||||
m = strdup("");
|
||||
if (!m)
|
||||
return -ENOMEM;
|
||||
|
||||
*ret = m;
|
||||
return 0; /* The end */
|
||||
}
|
||||
|
||||
p = q + 1;
|
||||
c++;
|
||||
}
|
||||
}
|
||||
#endif /* NM_IGNORED */
|
||||
|
|
|
@ -280,3 +280,6 @@ static inline char* str_realloc(char **p) {
|
|||
}
|
||||
|
||||
char* string_erase(char *x);
|
||||
|
||||
int string_truncate_lines(const char *s, size_t n_lines, char **ret);
|
||||
int string_extract_line(const char *s, size_t i, char **ret);
|
||||
|
|
|
@ -18,8 +18,8 @@
|
|||
#include "string-util.h"
|
||||
#include "strv.h"
|
||||
|
||||
char *strv_find(char **l, const char *name) {
|
||||
char **i;
|
||||
char *strv_find(char * const *l, const char *name) {
|
||||
char * const *i;
|
||||
|
||||
assert(name);
|
||||
|
||||
|
@ -30,8 +30,8 @@ char *strv_find(char **l, const char *name) {
|
|||
return NULL;
|
||||
}
|
||||
|
||||
char *strv_find_prefix(char **l, const char *name) {
|
||||
char **i;
|
||||
char *strv_find_prefix(char * const *l, const char *name) {
|
||||
char * const *i;
|
||||
|
||||
assert(name);
|
||||
|
||||
|
@ -42,8 +42,8 @@ char *strv_find_prefix(char **l, const char *name) {
|
|||
return NULL;
|
||||
}
|
||||
|
||||
char *strv_find_startswith(char **l, const char *name) {
|
||||
char **i, *e;
|
||||
char *strv_find_startswith(char * const *l, const char *name) {
|
||||
char * const *i, *e;
|
||||
|
||||
assert(name);
|
||||
|
||||
|
@ -59,20 +59,15 @@ char *strv_find_startswith(char **l, const char *name) {
|
|||
return NULL;
|
||||
}
|
||||
|
||||
void strv_clear(char **l) {
|
||||
char **strv_free(char **l) {
|
||||
char **k;
|
||||
|
||||
if (!l)
|
||||
return;
|
||||
return NULL;
|
||||
|
||||
for (k = l; *k; k++)
|
||||
free(*k);
|
||||
|
||||
*l = NULL;
|
||||
}
|
||||
|
||||
char **strv_free(char **l) {
|
||||
strv_clear(l);
|
||||
return mfree(l);
|
||||
}
|
||||
|
||||
|
@ -183,8 +178,8 @@ char **strv_new_internal(const char *x, ...) {
|
|||
return r;
|
||||
}
|
||||
|
||||
int strv_extend_strv(char ***a, char **b, bool filter_duplicates) {
|
||||
char **s, **t;
|
||||
int strv_extend_strv(char ***a, char * const *b, bool filter_duplicates) {
|
||||
char * const *s, **t;
|
||||
size_t p, q, i = 0, j;
|
||||
|
||||
assert(a);
|
||||
|
@ -231,9 +226,9 @@ rollback:
|
|||
}
|
||||
|
||||
#if 0 /* NM_IGNORED */
|
||||
int strv_extend_strv_concat(char ***a, char **b, const char *suffix) {
|
||||
int strv_extend_strv_concat(char ***a, char * const *b, const char *suffix) {
|
||||
char * const *s;
|
||||
int r;
|
||||
char **s;
|
||||
|
||||
STRV_FOREACH(s, b) {
|
||||
char *v;
|
||||
|
@ -352,9 +347,9 @@ int strv_split_extract(char ***t, const char *s, const char *separators, Extract
|
|||
}
|
||||
#endif /* NM_IGNORED */
|
||||
|
||||
char *strv_join_prefix(char **l, const char *separator, const char *prefix) {
|
||||
char *strv_join_prefix(char * const *l, const char *separator, const char *prefix) {
|
||||
char * const *s;
|
||||
char *r, *e;
|
||||
char **s;
|
||||
size_t n, k, m;
|
||||
|
||||
if (!separator)
|
||||
|
@ -568,8 +563,8 @@ char **strv_uniq(char **l) {
|
|||
return l;
|
||||
}
|
||||
|
||||
bool strv_is_uniq(char **l) {
|
||||
char **i;
|
||||
bool strv_is_uniq(char * const *l) {
|
||||
char * const *i;
|
||||
|
||||
STRV_FOREACH(i, l)
|
||||
if (strv_find(i+1, *i))
|
||||
|
@ -674,7 +669,7 @@ char **strv_split_nulstr(const char *s) {
|
|||
}
|
||||
#endif /* NM_IGNORED */
|
||||
|
||||
int strv_make_nulstr(char **l, char **p, size_t *q) {
|
||||
int strv_make_nulstr(char * const *l, char **ret, size_t *ret_size) {
|
||||
/* A valid nulstr with two NULs at the end will be created, but
|
||||
* q will be the length without the two trailing NULs. Thus the output
|
||||
* string is a valid nulstr and can be iterated over using NULSTR_FOREACH,
|
||||
|
@ -684,10 +679,10 @@ int strv_make_nulstr(char **l, char **p, size_t *q) {
|
|||
|
||||
size_t n_allocated = 0, n = 0;
|
||||
_cleanup_free_ char *m = NULL;
|
||||
char **i;
|
||||
char * const *i;
|
||||
|
||||
assert(p);
|
||||
assert(q);
|
||||
assert(ret);
|
||||
assert(ret_size);
|
||||
|
||||
STRV_FOREACH(i, l) {
|
||||
size_t z;
|
||||
|
@ -711,16 +706,16 @@ int strv_make_nulstr(char **l, char **p, size_t *q) {
|
|||
m[n] = '\0';
|
||||
|
||||
assert(n > 0);
|
||||
*p = m;
|
||||
*q = n - 1;
|
||||
*ret = m;
|
||||
*ret_size = n - 1;
|
||||
|
||||
m = NULL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool strv_overlap(char **a, char **b) {
|
||||
char **i;
|
||||
bool strv_overlap(char * const *a, char * const *b) {
|
||||
char * const *i;
|
||||
|
||||
STRV_FOREACH(i, a)
|
||||
if (strv_contains(b, *i))
|
||||
|
@ -740,23 +735,30 @@ char **strv_sort(char **l) {
|
|||
}
|
||||
#endif /* NM_IGNORED */
|
||||
|
||||
bool strv_equal(char **a, char **b) {
|
||||
int strv_compare(char * const *a, char * const *b) {
|
||||
int r;
|
||||
|
||||
if (strv_isempty(a))
|
||||
return strv_isempty(b);
|
||||
if (strv_isempty(a)) {
|
||||
if (strv_isempty(b))
|
||||
return 0;
|
||||
else
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (strv_isempty(b))
|
||||
return false;
|
||||
return 1;
|
||||
|
||||
for ( ; *a || *b; ++a, ++b)
|
||||
if (!streq_ptr(*a, *b))
|
||||
return false;
|
||||
for ( ; *a || *b; ++a, ++b) {
|
||||
r = strcmp_ptr(*a, *b);
|
||||
if (r != 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
return true;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void strv_print(char **l) {
|
||||
char **s;
|
||||
void strv_print(char * const *l) {
|
||||
char * const *s;
|
||||
|
||||
STRV_FOREACH(s, l)
|
||||
puts(*s);
|
||||
|
@ -810,12 +812,13 @@ char **strv_shell_escape(char **l, const char *bad) {
|
|||
return l;
|
||||
}
|
||||
|
||||
bool strv_fnmatch(char* const* patterns, const char *s, int flags) {
|
||||
char* const* p;
|
||||
|
||||
STRV_FOREACH(p, patterns)
|
||||
if (fnmatch(*p, s, flags) == 0)
|
||||
bool strv_fnmatch_full(char* const* patterns, const char *s, int flags, size_t *matched_pos) {
|
||||
for (size_t i = 0; patterns && patterns[i]; i++)
|
||||
if (fnmatch(patterns[i], s, flags) == 0) {
|
||||
if (matched_pos)
|
||||
*matched_pos = i;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
@ -884,9 +887,9 @@ rollback:
|
|||
return -ENOMEM;
|
||||
}
|
||||
|
||||
int fputstrv(FILE *f, char **l, const char *separator, bool *space) {
|
||||
int fputstrv(FILE *f, char * const *l, const char *separator, bool *space) {
|
||||
bool b = false;
|
||||
char **s;
|
||||
char * const *s;
|
||||
int r;
|
||||
|
||||
/* Like fputs(), but for strv, and with a less stupid argument order */
|
||||
|
|
|
@ -13,9 +13,9 @@
|
|||
#include "macro.h"
|
||||
#include "string-util.h"
|
||||
|
||||
char *strv_find(char **l, const char *name) _pure_;
|
||||
char *strv_find_prefix(char **l, const char *name) _pure_;
|
||||
char *strv_find_startswith(char **l, const char *name) _pure_;
|
||||
char *strv_find(char * const *l, const char *name) _pure_;
|
||||
char *strv_find_prefix(char * const *l, const char *name) _pure_;
|
||||
char *strv_find_startswith(char * const *l, const char *name) _pure_;
|
||||
|
||||
char **strv_free(char **l);
|
||||
DEFINE_TRIVIAL_CLEANUP_FUNC(char**, strv_free);
|
||||
|
@ -25,13 +25,11 @@ char **strv_free_erase(char **l);
|
|||
DEFINE_TRIVIAL_CLEANUP_FUNC(char**, strv_free_erase);
|
||||
#define _cleanup_strv_free_erase_ _cleanup_(strv_free_erasep)
|
||||
|
||||
void strv_clear(char **l);
|
||||
|
||||
char **strv_copy(char * const *l);
|
||||
size_t strv_length(char * const *l) _pure_;
|
||||
|
||||
int strv_extend_strv(char ***a, char **b, bool filter_duplicates);
|
||||
int strv_extend_strv_concat(char ***a, char **b, const char *suffix);
|
||||
int strv_extend_strv(char ***a, char * const *b, bool filter_duplicates);
|
||||
int strv_extend_strv_concat(char ***a, char * const *b, const char *suffix);
|
||||
int strv_extend(char ***l, const char *value);
|
||||
int strv_extendf(char ***l, const char *format, ...) _printf_(2,0);
|
||||
int strv_extend_front(char ***l, const char *value);
|
||||
|
@ -49,9 +47,12 @@ int strv_consume_prepend(char ***l, char *value);
|
|||
|
||||
char **strv_remove(char **l, const char *s);
|
||||
char **strv_uniq(char **l);
|
||||
bool strv_is_uniq(char **l);
|
||||
bool strv_is_uniq(char * const *l);
|
||||
|
||||
bool strv_equal(char **a, char **b);
|
||||
int strv_compare(char * const *a, char * const *b);
|
||||
static inline bool strv_equal(char * const *a, char * const *b) {
|
||||
return strv_compare(a, b) == 0;
|
||||
}
|
||||
|
||||
#define strv_contains(l, s) (!!strv_find((l), (s)))
|
||||
|
||||
|
@ -77,16 +78,16 @@ char **strv_split_newlines(const char *s);
|
|||
|
||||
int strv_split_extract(char ***t, const char *s, const char *separators, ExtractFlags flags);
|
||||
|
||||
char *strv_join_prefix(char **l, const char *separator, const char *prefix);
|
||||
static inline char *strv_join(char **l, const char *separator) {
|
||||
char *strv_join_prefix(char * const *l, const char *separator, const char *prefix);
|
||||
static inline char *strv_join(char * const *l, const char *separator) {
|
||||
return strv_join_prefix(l, separator, NULL);
|
||||
}
|
||||
|
||||
char **strv_parse_nulstr(const char *s, size_t l);
|
||||
char **strv_split_nulstr(const char *s);
|
||||
int strv_make_nulstr(char **l, char **p, size_t *n);
|
||||
int strv_make_nulstr(char * const *l, char **p, size_t *n);
|
||||
|
||||
bool strv_overlap(char **a, char **b) _pure_;
|
||||
bool strv_overlap(char * const *a, char * const *b) _pure_;
|
||||
|
||||
#define STRV_FOREACH(s, l) \
|
||||
for ((s) = (l); (s) && *(s); (s)++)
|
||||
|
@ -103,7 +104,7 @@ bool strv_overlap(char **a, char **b) _pure_;
|
|||
for ((x) = (l), (y) = (x+1); (x) && *(x) && *(y); (x) += 2, (y) = (x + 1))
|
||||
|
||||
char **strv_sort(char **l);
|
||||
void strv_print(char **l);
|
||||
void strv_print(char * const *l);
|
||||
|
||||
#define STRV_MAKE(...) ((char**) ((const char*[]) { __VA_ARGS__, NULL }))
|
||||
|
||||
|
@ -177,12 +178,15 @@ void strv_print(char **l);
|
|||
char **strv_reverse(char **l);
|
||||
char **strv_shell_escape(char **l, const char *bad);
|
||||
|
||||
bool strv_fnmatch(char* const* patterns, const char *s, int flags);
|
||||
bool strv_fnmatch_full(char* const* patterns, const char *s, int flags, size_t *matched_pos);
|
||||
static inline bool strv_fnmatch(char* const* patterns, const char *s) {
|
||||
return strv_fnmatch_full(patterns, s, 0, NULL);
|
||||
}
|
||||
|
||||
static inline bool strv_fnmatch_or_empty(char* const* patterns, const char *s, int flags) {
|
||||
assert(s);
|
||||
return strv_isempty(patterns) ||
|
||||
strv_fnmatch(patterns, s, flags);
|
||||
strv_fnmatch_full(patterns, s, flags, NULL);
|
||||
}
|
||||
|
||||
char ***strv_free_free(char ***l);
|
||||
|
@ -192,7 +196,7 @@ char **strv_skip(char **l, size_t n);
|
|||
|
||||
int strv_extend_n(char ***l, const char *value, size_t n);
|
||||
|
||||
int fputstrv(FILE *f, char **l, const char *separator, bool *space);
|
||||
int fputstrv(FILE *f, char * const *l, const char *separator, bool *space);
|
||||
|
||||
#define strv_free_and_replace(a, b) \
|
||||
({ \
|
||||
|
|
|
@ -1507,9 +1507,30 @@ int time_change_fd(void) {
|
|||
if (fd < 0)
|
||||
return -errno;
|
||||
|
||||
if (timerfd_settime(fd, TFD_TIMER_ABSTIME|TFD_TIMER_CANCEL_ON_SET, &its, NULL) < 0)
|
||||
return -errno;
|
||||
if (timerfd_settime(fd, TFD_TIMER_ABSTIME|TFD_TIMER_CANCEL_ON_SET, &its, NULL) >= 0)
|
||||
return TAKE_FD(fd);
|
||||
|
||||
return TAKE_FD(fd);
|
||||
/* So apparently there are systems where time_t is 64bit, but the kernel actually doesn't support
|
||||
* 64bit time_t. In that case configuring a timer to TIME_T_MAX will fail with EOPNOTSUPP or a
|
||||
* similar error. If that's the case let's try with INT32_MAX instead, maybe that works. It's a bit
|
||||
* of a black magic thing though, but what can we do?
|
||||
*
|
||||
* We don't want this code on x86-64, hence let's conditionalize this for systems with 64bit time_t
|
||||
* but where "long" is shorter than 64bit, i.e. 32bit archs.
|
||||
*
|
||||
* See: https://github.com/systemd/systemd/issues/14362 */
|
||||
|
||||
#if SIZEOF_TIME_T == 8 && ULONG_MAX < UINT64_MAX
|
||||
if (ERRNO_IS_NOT_SUPPORTED(errno) || errno == EOVERFLOW) {
|
||||
static const struct itimerspec its32 = {
|
||||
.it_value.tv_sec = INT32_MAX,
|
||||
};
|
||||
|
||||
if (timerfd_settime(fd, TFD_TIMER_ABSTIME|TFD_TIMER_CANCEL_ON_SET, &its32, NULL) >= 0)
|
||||
return TAKE_FD(fd);
|
||||
}
|
||||
#endif
|
||||
|
||||
return -errno;
|
||||
}
|
||||
#endif /* NM_IGNORED */
|
||||
|
|
143
shared/systemd/src/basic/user-util.h
Normal file
143
shared/systemd/src/basic/user-util.h
Normal file
|
@ -0,0 +1,143 @@
|
|||
/* SPDX-License-Identifier: LGPL-2.1+ */
|
||||
#pragma once
|
||||
|
||||
#include <grp.h>
|
||||
#if ENABLE_GSHADOW
|
||||
#include <gshadow.h>
|
||||
#endif
|
||||
#include <pwd.h>
|
||||
#include <shadow.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
|
||||
bool uid_is_valid(uid_t uid);
|
||||
|
||||
static inline bool gid_is_valid(gid_t gid) {
|
||||
return uid_is_valid((uid_t) gid);
|
||||
}
|
||||
|
||||
int parse_uid(const char *s, uid_t* ret_uid);
|
||||
int parse_uid_range(const char *s, uid_t *ret_lower, uid_t *ret_upper);
|
||||
|
||||
static inline int parse_gid(const char *s, gid_t *ret_gid) {
|
||||
return parse_uid(s, (uid_t*) ret_gid);
|
||||
}
|
||||
|
||||
char* getlogname_malloc(void);
|
||||
char* getusername_malloc(void);
|
||||
|
||||
typedef enum UserCredsFlags {
|
||||
USER_CREDS_PREFER_NSS = 1 << 0, /* if set, only synthesize user records if database lacks them. Normally we bypass the userdb entirely for the records we can synthesize */
|
||||
USER_CREDS_ALLOW_MISSING = 1 << 1, /* if a numeric UID string is resolved, be OK if there's no record for it */
|
||||
USER_CREDS_CLEAN = 1 << 2, /* try to clean up shell and home fields with invalid data */
|
||||
} UserCredsFlags;
|
||||
|
||||
int get_user_creds(const char **username, uid_t *uid, gid_t *gid, const char **home, const char **shell, UserCredsFlags flags);
|
||||
int get_group_creds(const char **groupname, gid_t *gid, UserCredsFlags flags);
|
||||
|
||||
char* uid_to_name(uid_t uid);
|
||||
char* gid_to_name(gid_t gid);
|
||||
|
||||
int in_gid(gid_t gid);
|
||||
int in_group(const char *name);
|
||||
|
||||
int merge_gid_lists(const gid_t *list1, size_t size1, const gid_t *list2, size_t size2, gid_t **result);
|
||||
int getgroups_alloc(gid_t** gids);
|
||||
|
||||
int get_home_dir(char **ret);
|
||||
int get_shell(char **_ret);
|
||||
|
||||
int reset_uid_gid(void);
|
||||
|
||||
int take_etc_passwd_lock(const char *root);
|
||||
|
||||
#define UID_INVALID ((uid_t) -1)
|
||||
#define GID_INVALID ((gid_t) -1)
|
||||
|
||||
#define UID_NOBODY ((uid_t) 65534U)
|
||||
#define GID_NOBODY ((gid_t) 65534U)
|
||||
|
||||
#define ETC_PASSWD_LOCK_PATH "/etc/.pwd.lock"
|
||||
|
||||
#if 0 /* NM_ENABLED */
|
||||
static inline bool uid_is_system(uid_t uid) {
|
||||
return uid <= SYSTEM_UID_MAX;
|
||||
}
|
||||
|
||||
static inline bool gid_is_system(gid_t gid) {
|
||||
return gid <= SYSTEM_GID_MAX;
|
||||
}
|
||||
|
||||
static inline bool uid_is_dynamic(uid_t uid) {
|
||||
return DYNAMIC_UID_MIN <= uid && uid <= DYNAMIC_UID_MAX;
|
||||
}
|
||||
|
||||
static inline bool gid_is_dynamic(gid_t gid) {
|
||||
return uid_is_dynamic((uid_t) gid);
|
||||
}
|
||||
|
||||
static inline bool uid_is_container(uid_t uid) {
|
||||
return CONTAINER_UID_BASE_MIN <= uid && uid <= CONTAINER_UID_BASE_MAX;
|
||||
}
|
||||
|
||||
static inline bool gid_is_container(gid_t gid) {
|
||||
return uid_is_container((uid_t) gid);
|
||||
}
|
||||
#endif /* NM_ENABLED */
|
||||
|
||||
/* The following macros add 1 when converting things, since UID 0 is a valid UID, while the pointer
|
||||
* NULL is special */
|
||||
#define PTR_TO_UID(p) ((uid_t) (((uintptr_t) (p))-1))
|
||||
#define UID_TO_PTR(u) ((void*) (((uintptr_t) (u))+1))
|
||||
|
||||
#define PTR_TO_GID(p) ((gid_t) (((uintptr_t) (p))-1))
|
||||
#define GID_TO_PTR(u) ((void*) (((uintptr_t) (u))+1))
|
||||
|
||||
static inline bool userns_supported(void) {
|
||||
return access("/proc/self/uid_map", F_OK) >= 0;
|
||||
}
|
||||
|
||||
bool valid_user_group_name_full(const char *u, bool strict);
|
||||
bool valid_user_group_name_or_id_full(const char *u, bool strict);
|
||||
static inline bool valid_user_group_name(const char *u) {
|
||||
return valid_user_group_name_full(u, true);
|
||||
}
|
||||
static inline bool valid_user_group_name_or_id(const char *u) {
|
||||
return valid_user_group_name_or_id_full(u, true);
|
||||
}
|
||||
static inline bool valid_user_group_name_compat(const char *u) {
|
||||
return valid_user_group_name_full(u, false);
|
||||
}
|
||||
static inline bool valid_user_group_name_or_id_compat(const char *u) {
|
||||
return valid_user_group_name_or_id_full(u, false);
|
||||
}
|
||||
bool valid_gecos(const char *d);
|
||||
bool valid_home(const char *p);
|
||||
|
||||
static inline bool valid_shell(const char *p) {
|
||||
/* We have the same requirements, so just piggy-back on the home check.
|
||||
*
|
||||
* Let's ignore /etc/shells because this is only applicable to real and
|
||||
* not system users. It is also incompatible with the idea of empty /etc.
|
||||
*/
|
||||
return valid_home(p);
|
||||
}
|
||||
|
||||
int maybe_setgroups(size_t size, const gid_t *list);
|
||||
|
||||
bool synthesize_nobody(void);
|
||||
|
||||
int fgetpwent_sane(FILE *stream, struct passwd **pw);
|
||||
int fgetspent_sane(FILE *stream, struct spwd **sp);
|
||||
int fgetgrent_sane(FILE *stream, struct group **gr);
|
||||
int putpwent_sane(const struct passwd *pw, FILE *stream);
|
||||
int putspent_sane(const struct spwd *sp, FILE *stream);
|
||||
int putgrent_sane(const struct group *gr, FILE *stream);
|
||||
#if ENABLE_GSHADOW
|
||||
int fgetsgent_sane(FILE *stream, struct sgrp **sg);
|
||||
int putsgent_sane(const struct sgrp *sg, FILE *stream);
|
||||
#endif
|
||||
|
||||
bool is_nologin_shell(const char *shell);
|
|
@ -10,6 +10,7 @@
|
|||
#include "sd-ndisc.h"
|
||||
|
||||
#include "alloc-util.h"
|
||||
#include "arphrd-list.h"
|
||||
#include "condition.h"
|
||||
#include "conf-parser.h"
|
||||
#include "device-util.h"
|
||||
|
@ -106,6 +107,18 @@ static bool net_condition_test_strv(char * const *patterns, const char *string)
|
|||
return has_positive_rule ? match : true;
|
||||
}
|
||||
|
||||
static bool net_condition_test_ifname(char * const *patterns, const char *ifname, char * const *alternative_names) {
|
||||
if (net_condition_test_strv(patterns, ifname))
|
||||
return true;
|
||||
|
||||
char * const *p;
|
||||
STRV_FOREACH(p, alternative_names)
|
||||
if (net_condition_test_strv(patterns, *p))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static int net_condition_test_property(char * const *match_property, sd_device *device) {
|
||||
char * const *p;
|
||||
|
||||
|
@ -157,7 +170,29 @@ static const char *const wifi_iftype_table[NL80211_IFTYPE_MAX+1] = {
|
|||
|
||||
DEFINE_PRIVATE_STRING_TABLE_LOOKUP_TO_STRING(wifi_iftype, enum nl80211_iftype);
|
||||
|
||||
char *link_get_type_string(unsigned short iftype, sd_device *device) {
|
||||
const char *t, *devtype;
|
||||
char *p;
|
||||
|
||||
if (device &&
|
||||
sd_device_get_devtype(device, &devtype) >= 0 &&
|
||||
!isempty(devtype))
|
||||
return strdup(devtype);
|
||||
|
||||
t = arphrd_to_name(iftype);
|
||||
if (!t)
|
||||
return NULL;
|
||||
|
||||
p = strdup(t);
|
||||
if (!p)
|
||||
return NULL;
|
||||
|
||||
ascii_strlower(p);
|
||||
return p;
|
||||
}
|
||||
|
||||
bool net_match_config(Set *match_mac,
|
||||
Set *match_permanent_mac,
|
||||
char * const *match_paths,
|
||||
char * const *match_drivers,
|
||||
char * const *match_types,
|
||||
|
@ -166,20 +201,24 @@ bool net_match_config(Set *match_mac,
|
|||
char * const *match_wifi_iftype,
|
||||
char * const *match_ssid,
|
||||
Set *match_bssid,
|
||||
unsigned short iftype,
|
||||
sd_device *device,
|
||||
const struct ether_addr *dev_mac,
|
||||
const struct ether_addr *dev_permanent_mac,
|
||||
const char *dev_name,
|
||||
char * const *alternative_names,
|
||||
enum nl80211_iftype wifi_iftype,
|
||||
const char *ssid,
|
||||
const struct ether_addr *bssid) {
|
||||
|
||||
const char *dev_path = NULL, *dev_driver = NULL, *dev_type = NULL, *mac_str;
|
||||
const char *dev_path = NULL, *dev_driver = NULL, *mac_str;
|
||||
_cleanup_free_ char *dev_type;
|
||||
|
||||
dev_type = link_get_type_string(iftype, device);
|
||||
|
||||
if (device) {
|
||||
(void) sd_device_get_property_value(device, "ID_PATH", &dev_path);
|
||||
(void) sd_device_get_property_value(device, "ID_NET_DRIVER", &dev_driver);
|
||||
(void) sd_device_get_devtype(device, &dev_type);
|
||||
|
||||
if (!dev_name)
|
||||
(void) sd_device_get_sysname(device, &dev_name);
|
||||
if (!dev_mac &&
|
||||
|
@ -190,6 +229,12 @@ bool net_match_config(Set *match_mac,
|
|||
if (match_mac && (!dev_mac || !set_contains(match_mac, dev_mac)))
|
||||
return false;
|
||||
|
||||
if (match_permanent_mac &&
|
||||
(!dev_permanent_mac ||
|
||||
ether_addr_is_null(dev_permanent_mac) ||
|
||||
!set_contains(match_permanent_mac, dev_permanent_mac)))
|
||||
return false;
|
||||
|
||||
if (!net_condition_test_strv(match_paths, dev_path))
|
||||
return false;
|
||||
|
||||
|
@ -199,7 +244,7 @@ bool net_match_config(Set *match_mac,
|
|||
if (!net_condition_test_strv(match_types, dev_type))
|
||||
return false;
|
||||
|
||||
if (!net_condition_test_strv(match_names, dev_name))
|
||||
if (!net_condition_test_ifname(match_names, dev_name, alternative_names))
|
||||
return false;
|
||||
|
||||
if (!net_condition_test_property(match_property, device))
|
||||
|
@ -352,7 +397,7 @@ int config_parse_match_ifnames(
|
|||
return 0;
|
||||
}
|
||||
|
||||
if (!ifname_valid(word)) {
|
||||
if (!ifname_valid_full(word, ltype)) {
|
||||
log_syntax(unit, LOG_ERR, filename, line, 0,
|
||||
"Interface name is not valid or too long, ignoring assignment: %s", word);
|
||||
continue;
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
|
||||
#if 0 /* NM_IGNORED */
|
||||
bool net_match_config(Set *match_mac,
|
||||
Set *match_permanent_mac,
|
||||
char * const *match_path,
|
||||
char * const *match_driver,
|
||||
char * const *match_type,
|
||||
|
@ -25,9 +26,12 @@ bool net_match_config(Set *match_mac,
|
|||
char * const *match_wifi_iftype,
|
||||
char * const *match_ssid,
|
||||
Set *match_bssid,
|
||||
unsigned short iftype,
|
||||
sd_device *device,
|
||||
const struct ether_addr *dev_mac,
|
||||
const struct ether_addr *dev_permanent_mac,
|
||||
const char *dev_name,
|
||||
char * const *alternative_names,
|
||||
enum nl80211_iftype wifi_iftype,
|
||||
const char *ssid,
|
||||
const struct ether_addr *bssid);
|
||||
|
|
|
@ -91,7 +91,8 @@ struct sd_dhcp_client {
|
|||
usec_t start_time;
|
||||
uint64_t attempt;
|
||||
uint64_t max_attempts;
|
||||
OrderedHashmap *options;
|
||||
OrderedHashmap *extra_options;
|
||||
OrderedHashmap *vendor_options;
|
||||
usec_t request_sent;
|
||||
sd_event_source *timeout_t1;
|
||||
sd_event_source *timeout_t2;
|
||||
|
@ -545,17 +546,17 @@ int sd_dhcp_client_set_max_attempts(sd_dhcp_client *client, uint64_t max_attempt
|
|||
return 0;
|
||||
}
|
||||
|
||||
int sd_dhcp_client_set_dhcp_option(sd_dhcp_client *client, sd_dhcp_option *v) {
|
||||
int sd_dhcp_client_add_option(sd_dhcp_client *client, sd_dhcp_option *v) {
|
||||
int r;
|
||||
|
||||
assert_return(client, -EINVAL);
|
||||
assert_return(v, -EINVAL);
|
||||
|
||||
r = ordered_hashmap_ensure_allocated(&client->options, &dhcp_option_hash_ops);
|
||||
r = ordered_hashmap_ensure_allocated(&client->extra_options, &dhcp_option_hash_ops);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = ordered_hashmap_put(client->options, UINT_TO_PTR(v->option), v);
|
||||
r = ordered_hashmap_put(client->extra_options, UINT_TO_PTR(v->option), v);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
|
@ -563,6 +564,25 @@ int sd_dhcp_client_set_dhcp_option(sd_dhcp_client *client, sd_dhcp_option *v) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
int sd_dhcp_client_add_vendor_option(sd_dhcp_client *client, sd_dhcp_option *v) {
|
||||
int r;
|
||||
|
||||
assert_return(client, -EINVAL);
|
||||
assert_return(v, -EINVAL);
|
||||
|
||||
r = ordered_hashmap_ensure_allocated(&client->vendor_options, &dhcp_option_hash_ops);
|
||||
if (r < 0)
|
||||
return -ENOMEM;
|
||||
|
||||
r = ordered_hashmap_put(client->vendor_options, v, v);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
sd_dhcp_option_ref(v);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int sd_dhcp_client_get_lease(sd_dhcp_client *client, sd_dhcp_lease **ret) {
|
||||
assert_return(client, -EINVAL);
|
||||
|
||||
|
@ -648,7 +668,7 @@ static int client_message_init(
|
|||
assert(ret);
|
||||
assert(_optlen);
|
||||
assert(_optoffset);
|
||||
assert(IN_SET(type, DHCP_DISCOVER, DHCP_REQUEST, DHCP_RELEASE));
|
||||
assert(IN_SET(type, DHCP_DISCOVER, DHCP_REQUEST, DHCP_RELEASE, DHCP_DECLINE));
|
||||
|
||||
optlen = DHCP_MIN_OPTIONS_SIZE;
|
||||
size = sizeof(DHCPPacket) + optlen;
|
||||
|
@ -889,13 +909,22 @@ static int client_send_discover(sd_dhcp_client *client) {
|
|||
return r;
|
||||
}
|
||||
|
||||
ORDERED_HASHMAP_FOREACH(j, client->options, i) {
|
||||
ORDERED_HASHMAP_FOREACH(j, client->extra_options, i) {
|
||||
r = dhcp_option_append(&discover->dhcp, optlen, &optoffset, 0,
|
||||
j->option, j->length, j->data);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
if (!ordered_hashmap_isempty(client->vendor_options)) {
|
||||
r = dhcp_option_append(
|
||||
&discover->dhcp, optlen, &optoffset, 0,
|
||||
SD_DHCP_OPTION_VENDOR_SPECIFIC,
|
||||
ordered_hashmap_size(client->vendor_options), client->vendor_options);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
r = dhcp_option_append(&discover->dhcp, optlen, &optoffset, 0,
|
||||
SD_DHCP_OPTION_END, 0, NULL);
|
||||
if (r < 0)
|
||||
|
@ -1971,6 +2000,48 @@ int sd_dhcp_client_send_release(sd_dhcp_client *client) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
int sd_dhcp_client_send_decline(sd_dhcp_client *client) {
|
||||
assert_return(client, -EINVAL);
|
||||
assert_return(client->state != DHCP_STATE_STOPPED, -ESTALE);
|
||||
assert_return(client->lease, -EUNATCH);
|
||||
|
||||
_cleanup_free_ DHCPPacket *release = NULL;
|
||||
size_t optoffset, optlen;
|
||||
int r;
|
||||
|
||||
r = client_message_init(client, &release, DHCP_DECLINE, &optlen, &optoffset);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
release->dhcp.ciaddr = client->lease->address;
|
||||
memcpy(&release->dhcp.chaddr, &client->mac_addr, client->mac_addr_len);
|
||||
|
||||
r = dhcp_option_append(&release->dhcp, optlen, &optoffset, 0,
|
||||
SD_DHCP_OPTION_END, 0, NULL);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = dhcp_network_send_udp_socket(client->fd,
|
||||
client->lease->server_address,
|
||||
DHCP_PORT_SERVER,
|
||||
&release->dhcp,
|
||||
sizeof(DHCPMessage) + optoffset);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
log_dhcp_client(client, "DECLINE");
|
||||
|
||||
client_stop(client, SD_DHCP_CLIENT_EVENT_STOP);
|
||||
|
||||
if (client->state != DHCP_STATE_STOPPED) {
|
||||
r = sd_dhcp_client_start(client);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sd_dhcp_client_stop(sd_dhcp_client *client) {
|
||||
DHCP_CLIENT_DONT_DESTROY(client);
|
||||
|
||||
|
@ -2036,7 +2107,8 @@ static sd_dhcp_client *dhcp_client_free(sd_dhcp_client *client) {
|
|||
free(client->hostname);
|
||||
free(client->vendor_class_identifier);
|
||||
client->user_class = strv_free(client->user_class);
|
||||
ordered_hashmap_free(client->options);
|
||||
ordered_hashmap_free(client->extra_options);
|
||||
ordered_hashmap_free(client->vendor_options);
|
||||
return mfree(client);
|
||||
}
|
||||
|
||||
|
|
|
@ -681,8 +681,7 @@ static int client_timeout_resend_expire(sd_event_source *s, uint64_t usec, void
|
|||
}
|
||||
|
||||
static usec_t client_timeout_compute_random(usec_t val) {
|
||||
return val - val / 10 +
|
||||
(random_u32() % (2 * USEC_PER_SEC)) * val / 10 / USEC_PER_SEC;
|
||||
return val - (random_u32() % USEC_PER_SEC) * val / 10 / USEC_PER_SEC;
|
||||
}
|
||||
|
||||
static int client_timeout_resend(sd_event_source *s, uint64_t usec, void *userdata) {
|
||||
|
@ -692,7 +691,6 @@ static int client_timeout_resend(sd_event_source *s, uint64_t usec, void *userda
|
|||
usec_t max_retransmit_duration = 0;
|
||||
uint8_t max_retransmit_count = 0;
|
||||
char time_string[FORMAT_TIMESPAN_MAX];
|
||||
uint32_t expire = 0;
|
||||
|
||||
assert(s);
|
||||
assert(client);
|
||||
|
@ -741,8 +739,9 @@ static int client_timeout_resend(sd_event_source *s, uint64_t usec, void *userda
|
|||
max_retransmit_time = DHCP6_REB_MAX_RT;
|
||||
|
||||
if (event_source_is_enabled(client->timeout_resend_expire) <= 0) {
|
||||
r = dhcp6_lease_ia_rebind_expire(&client->lease->ia,
|
||||
&expire);
|
||||
uint32_t expire = 0;
|
||||
|
||||
r = dhcp6_lease_ia_rebind_expire(&client->lease->ia, &expire);
|
||||
if (r < 0) {
|
||||
client_stop(client, r);
|
||||
return 0;
|
||||
|
@ -757,7 +756,7 @@ static int client_timeout_resend(sd_event_source *s, uint64_t usec, void *userda
|
|||
return 0;
|
||||
}
|
||||
|
||||
if (max_retransmit_count &&
|
||||
if (max_retransmit_count > 0 &&
|
||||
client->retransmit_count >= max_retransmit_count) {
|
||||
client_stop(client, SD_DHCP6_CLIENT_EVENT_RETRANS_MAX);
|
||||
return 0;
|
||||
|
@ -771,7 +770,7 @@ static int client_timeout_resend(sd_event_source *s, uint64_t usec, void *userda
|
|||
if (r >= 0)
|
||||
client->retransmit_count++;
|
||||
|
||||
if (!client->retransmit_time) {
|
||||
if (client->retransmit_time == 0) {
|
||||
client->retransmit_time =
|
||||
client_timeout_compute_random(init_retransmit_time);
|
||||
|
||||
|
@ -779,7 +778,7 @@ static int client_timeout_resend(sd_event_source *s, uint64_t usec, void *userda
|
|||
client->retransmit_time += init_retransmit_time / 10;
|
||||
|
||||
} else {
|
||||
if (max_retransmit_time &&
|
||||
if (max_retransmit_time > 0 &&
|
||||
client->retransmit_time > max_retransmit_time / 2)
|
||||
client->retransmit_time = client_timeout_compute_random(max_retransmit_time);
|
||||
else
|
||||
|
@ -797,7 +796,7 @@ static int client_timeout_resend(sd_event_source *s, uint64_t usec, void *userda
|
|||
if (r < 0)
|
||||
goto error;
|
||||
|
||||
if (max_retransmit_duration && event_source_is_enabled(client->timeout_resend_expire) <= 0) {
|
||||
if (max_retransmit_duration > 0 && event_source_is_enabled(client->timeout_resend_expire) <= 0) {
|
||||
|
||||
log_dhcp6_client(client, "Max retransmission duration %"PRIu64" secs",
|
||||
max_retransmit_duration / USEC_PER_SEC);
|
||||
|
|
|
@ -117,6 +117,9 @@ struct sd_event {
|
|||
|
||||
unsigned n_sources;
|
||||
|
||||
struct epoll_event *event_queue;
|
||||
size_t event_queue_allocated;
|
||||
|
||||
LIST_HEAD(sd_event_source, sources);
|
||||
|
||||
usec_t last_run, last_log;
|
||||
|
@ -288,6 +291,8 @@ static sd_event *event_free(sd_event *e) {
|
|||
hashmap_free(e->child_sources);
|
||||
set_free(e->post_sources);
|
||||
|
||||
free(e->event_queue);
|
||||
|
||||
return mfree(e);
|
||||
}
|
||||
|
||||
|
@ -388,22 +393,20 @@ static int source_io_register(
|
|||
int enabled,
|
||||
uint32_t events) {
|
||||
|
||||
struct epoll_event ev;
|
||||
int r;
|
||||
|
||||
assert(s);
|
||||
assert(s->type == SOURCE_IO);
|
||||
assert(enabled != SD_EVENT_OFF);
|
||||
|
||||
ev = (struct epoll_event) {
|
||||
struct epoll_event ev = {
|
||||
.events = events | (enabled == SD_EVENT_ONESHOT ? EPOLLONESHOT : 0),
|
||||
.data.ptr = s,
|
||||
};
|
||||
int r;
|
||||
|
||||
if (s->io.registered)
|
||||
r = epoll_ctl(s->event->epoll_fd, EPOLL_CTL_MOD, s->io.fd, &ev);
|
||||
else
|
||||
r = epoll_ctl(s->event->epoll_fd, EPOLL_CTL_ADD, s->io.fd, &ev);
|
||||
r = epoll_ctl(s->event->epoll_fd,
|
||||
s->io.registered ? EPOLL_CTL_MOD : EPOLL_CTL_ADD,
|
||||
s->io.fd,
|
||||
&ev);
|
||||
if (r < 0)
|
||||
return -errno;
|
||||
|
||||
|
@ -438,9 +441,7 @@ static int source_child_pidfd_register(sd_event_source *s, int enabled) {
|
|||
assert(enabled != SD_EVENT_OFF);
|
||||
|
||||
if (EVENT_SOURCE_WATCH_PIDFD(s)) {
|
||||
struct epoll_event ev;
|
||||
|
||||
ev = (struct epoll_event) {
|
||||
struct epoll_event ev = {
|
||||
.events = EPOLLIN | (enabled == SD_EVENT_ONESHOT ? EPOLLONESHOT : 0),
|
||||
.data.ptr = s,
|
||||
};
|
||||
|
@ -546,7 +547,6 @@ static int event_make_signal_data(
|
|||
int sig,
|
||||
struct signal_data **ret) {
|
||||
|
||||
struct epoll_event ev;
|
||||
struct signal_data *d;
|
||||
bool added = false;
|
||||
sigset_t ss_copy;
|
||||
|
@ -613,7 +613,7 @@ static int event_make_signal_data(
|
|||
|
||||
d->fd = fd_move_above_stdio(r);
|
||||
|
||||
ev = (struct epoll_event) {
|
||||
struct epoll_event ev = {
|
||||
.events = EPOLLIN,
|
||||
.data.ptr = d,
|
||||
};
|
||||
|
@ -825,9 +825,7 @@ static void source_disconnect(sd_event_source *s) {
|
|||
if (s->prepare)
|
||||
prioq_remove(s->event->prepare, s, &s->prepare_index);
|
||||
|
||||
event = s->event;
|
||||
|
||||
s->event = NULL;
|
||||
event = TAKE_PTR(s->event);
|
||||
LIST_REMOVE(sources, event->sources, s);
|
||||
event->n_sources--;
|
||||
|
||||
|
@ -1041,33 +1039,31 @@ static int event_setup_timer_fd(
|
|||
struct clock_data *d,
|
||||
clockid_t clock) {
|
||||
|
||||
struct epoll_event ev;
|
||||
int r, fd;
|
||||
|
||||
assert(e);
|
||||
assert(d);
|
||||
|
||||
if (_likely_(d->fd >= 0))
|
||||
return 0;
|
||||
|
||||
_cleanup_close_ int fd = -1;
|
||||
int r;
|
||||
|
||||
fd = timerfd_create(clock, TFD_NONBLOCK|TFD_CLOEXEC);
|
||||
if (fd < 0)
|
||||
return -errno;
|
||||
|
||||
fd = fd_move_above_stdio(fd);
|
||||
|
||||
ev = (struct epoll_event) {
|
||||
struct epoll_event ev = {
|
||||
.events = EPOLLIN,
|
||||
.data.ptr = d,
|
||||
};
|
||||
|
||||
r = epoll_ctl(e->epoll_fd, EPOLL_CTL_ADD, fd, &ev);
|
||||
if (r < 0) {
|
||||
safe_close(fd);
|
||||
if (r < 0)
|
||||
return -errno;
|
||||
}
|
||||
|
||||
d->fd = fd;
|
||||
d->fd = TAKE_FD(fd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -1553,7 +1549,6 @@ static int event_make_inotify_data(
|
|||
|
||||
_cleanup_close_ int fd = -1;
|
||||
struct inotify_data *d;
|
||||
struct epoll_event ev;
|
||||
int r;
|
||||
|
||||
assert(e);
|
||||
|
@ -1592,7 +1587,7 @@ static int event_make_inotify_data(
|
|||
return r;
|
||||
}
|
||||
|
||||
ev = (struct epoll_event) {
|
||||
struct epoll_event ev = {
|
||||
.events = EPOLLIN,
|
||||
.data.ptr = d,
|
||||
};
|
||||
|
@ -3481,8 +3476,7 @@ pending:
|
|||
}
|
||||
|
||||
_public_ int sd_event_wait(sd_event *e, uint64_t timeout) {
|
||||
struct epoll_event *ev_queue;
|
||||
unsigned ev_queue_max;
|
||||
size_t event_queue_max;
|
||||
int r, m, i;
|
||||
|
||||
assert_return(e, -EINVAL);
|
||||
|
@ -3496,14 +3490,15 @@ _public_ int sd_event_wait(sd_event *e, uint64_t timeout) {
|
|||
return 1;
|
||||
}
|
||||
|
||||
ev_queue_max = MAX(e->n_sources, 1u);
|
||||
ev_queue = newa(struct epoll_event, ev_queue_max);
|
||||
event_queue_max = MAX(e->n_sources, 1u);
|
||||
if (!GREEDY_REALLOC(e->event_queue, e->event_queue_allocated, event_queue_max))
|
||||
return -ENOMEM;
|
||||
|
||||
/* If we still have inotify data buffered, then query the other fds, but don't wait on it */
|
||||
if (e->inotify_data_buffered)
|
||||
timeout = 0;
|
||||
|
||||
m = epoll_wait(e->epoll_fd, ev_queue, ev_queue_max,
|
||||
m = epoll_wait(e->epoll_fd, e->event_queue, event_queue_max,
|
||||
timeout == (uint64_t) -1 ? -1 : (int) DIV_ROUND_UP(timeout, USEC_PER_MSEC));
|
||||
if (m < 0) {
|
||||
if (errno == EINTR) {
|
||||
|
@ -3519,26 +3514,26 @@ _public_ int sd_event_wait(sd_event *e, uint64_t timeout) {
|
|||
|
||||
for (i = 0; i < m; i++) {
|
||||
|
||||
if (ev_queue[i].data.ptr == INT_TO_PTR(SOURCE_WATCHDOG))
|
||||
r = flush_timer(e, e->watchdog_fd, ev_queue[i].events, NULL);
|
||||
if (e->event_queue[i].data.ptr == INT_TO_PTR(SOURCE_WATCHDOG))
|
||||
r = flush_timer(e, e->watchdog_fd, e->event_queue[i].events, NULL);
|
||||
else {
|
||||
WakeupType *t = ev_queue[i].data.ptr;
|
||||
WakeupType *t = e->event_queue[i].data.ptr;
|
||||
|
||||
switch (*t) {
|
||||
|
||||
case WAKEUP_EVENT_SOURCE: {
|
||||
sd_event_source *s = ev_queue[i].data.ptr;
|
||||
sd_event_source *s = e->event_queue[i].data.ptr;
|
||||
|
||||
assert(s);
|
||||
|
||||
switch (s->type) {
|
||||
|
||||
case SOURCE_IO:
|
||||
r = process_io(e, s, ev_queue[i].events);
|
||||
r = process_io(e, s, e->event_queue[i].events);
|
||||
break;
|
||||
|
||||
case SOURCE_CHILD:
|
||||
r = process_pidfd(e, s, ev_queue[i].events);
|
||||
r = process_pidfd(e, s, e->event_queue[i].events);
|
||||
break;
|
||||
|
||||
default:
|
||||
|
@ -3549,20 +3544,20 @@ _public_ int sd_event_wait(sd_event *e, uint64_t timeout) {
|
|||
}
|
||||
|
||||
case WAKEUP_CLOCK_DATA: {
|
||||
struct clock_data *d = ev_queue[i].data.ptr;
|
||||
struct clock_data *d = e->event_queue[i].data.ptr;
|
||||
|
||||
assert(d);
|
||||
|
||||
r = flush_timer(e, d->fd, ev_queue[i].events, &d->next);
|
||||
r = flush_timer(e, d->fd, e->event_queue[i].events, &d->next);
|
||||
break;
|
||||
}
|
||||
|
||||
case WAKEUP_SIGNAL_DATA:
|
||||
r = process_signal(e, ev_queue[i].data.ptr, ev_queue[i].events);
|
||||
r = process_signal(e, e->event_queue[i].data.ptr, e->event_queue[i].events);
|
||||
break;
|
||||
|
||||
case WAKEUP_INOTIFY_DATA:
|
||||
r = event_inotify_data_read(e, ev_queue[i].data.ptr, ev_queue[i].events);
|
||||
r = event_inotify_data_read(e, e->event_queue[i].data.ptr, e->event_queue[i].events);
|
||||
break;
|
||||
|
||||
default:
|
||||
|
@ -3846,8 +3841,6 @@ _public_ int sd_event_set_watchdog(sd_event *e, int b) {
|
|||
return e->watchdog;
|
||||
|
||||
if (b) {
|
||||
struct epoll_event ev;
|
||||
|
||||
r = sd_watchdog_enabled(false, &e->watchdog_period);
|
||||
if (r <= 0)
|
||||
return r;
|
||||
|
@ -3864,7 +3857,7 @@ _public_ int sd_event_set_watchdog(sd_event *e, int b) {
|
|||
if (r < 0)
|
||||
goto fail;
|
||||
|
||||
ev = (struct epoll_event) {
|
||||
struct epoll_event ev = {
|
||||
.events = EPOLLIN,
|
||||
.data.ptr = INT_TO_PTR(SOURCE_WATCHDOG),
|
||||
};
|
||||
|
|
|
@ -195,5 +195,18 @@ int id128_compare_func(const sd_id128_t *a, const sd_id128_t *b) {
|
|||
return memcmp(a, b, 16);
|
||||
}
|
||||
|
||||
sd_id128_t id128_make_v4_uuid(sd_id128_t id) {
|
||||
/* Stolen from generate_random_uuid() of drivers/char/random.c
|
||||
* in the kernel sources */
|
||||
|
||||
/* Set UUID version to 4 --- truly random generation */
|
||||
id.bytes[6] = (id.bytes[6] & 0x0F) | 0x40;
|
||||
|
||||
/* Set the UUID variant to DCE */
|
||||
id.bytes[8] = (id.bytes[8] & 0x3F) | 0x80;
|
||||
|
||||
return id;
|
||||
}
|
||||
|
||||
DEFINE_HASH_OPS(id128_hash_ops, sd_id128_t, id128_hash_func, id128_compare_func);
|
||||
#endif /* NM_IGNORED */
|
||||
|
|
|
@ -30,3 +30,5 @@ int id128_write(const char *p, Id128Format f, sd_id128_t id, bool do_sync);
|
|||
void id128_hash_func(const sd_id128_t *p, struct siphash *state);
|
||||
int id128_compare_func(const sd_id128_t *a, const sd_id128_t *b) _pure_;
|
||||
extern const struct hash_ops id128_hash_ops;
|
||||
|
||||
sd_id128_t id128_make_v4_uuid(sd_id128_t id);
|
||||
|
|
|
@ -255,19 +255,6 @@ _public_ int sd_id128_get_invocation(sd_id128_t *ret) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
static sd_id128_t make_v4_uuid(sd_id128_t id) {
|
||||
/* Stolen from generate_random_uuid() of drivers/char/random.c
|
||||
* in the kernel sources */
|
||||
|
||||
/* Set UUID version to 4 --- truly random generation */
|
||||
id.bytes[6] = (id.bytes[6] & 0x0F) | 0x40;
|
||||
|
||||
/* Set the UUID variant to DCE */
|
||||
id.bytes[8] = (id.bytes[8] & 0x3F) | 0x80;
|
||||
|
||||
return id;
|
||||
}
|
||||
|
||||
_public_ int sd_id128_randomize(sd_id128_t *ret) {
|
||||
sd_id128_t t;
|
||||
int r;
|
||||
|
@ -284,7 +271,7 @@ _public_ int sd_id128_randomize(sd_id128_t *ret) {
|
|||
* only guarantee this for newly generated UUIDs, not for
|
||||
* pre-existing ones. */
|
||||
|
||||
*ret = make_v4_uuid(t);
|
||||
*ret = id128_make_v4_uuid(t);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -311,7 +298,7 @@ static int get_app_specific(sd_id128_t base, sd_id128_t app_id, sd_id128_t *ret)
|
|||
/* We chop off the trailing 16 bytes */
|
||||
memcpy(&result, p, MIN(khash_get_size(h), sizeof(result)));
|
||||
|
||||
*ret = make_v4_uuid(result);
|
||||
*ret = id128_make_v4_uuid(result);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -45,6 +45,18 @@ typedef void (*_sd_destroy_t)(void *userdata);
|
|||
# define _sd_pure_ __attribute__((__pure__))
|
||||
#endif
|
||||
|
||||
/* Note that strictly speaking __deprecated__ has been available before GCC 6. However, starting with GCC 6
|
||||
* it also works on enum values, which we are interested in. Since this is a developer-facing feature anyway
|
||||
* (as opposed to build engineer-facing), let's hence conditionalize this to gcc 6, given that the developers
|
||||
* are probably going to use something newer anyway. */
|
||||
#ifndef _sd_deprecated_
|
||||
# if __GNUC__ >= 6
|
||||
# define _sd_deprecated_ __attribute__((__deprecated__))
|
||||
# else
|
||||
# define _sd_deprecated_
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifndef _SD_STRINGIFY
|
||||
# define _SD_XSTRINGIFY(x) #x
|
||||
# define _SD_STRINGIFY(x) _SD_XSTRINGIFY(x)
|
||||
|
|
|
@ -179,11 +179,13 @@ int sd_dhcp_client_set_service_type(
|
|||
sd_dhcp_client *client,
|
||||
int type);
|
||||
|
||||
int sd_dhcp_client_set_dhcp_option(sd_dhcp_client *client, sd_dhcp_option *v);
|
||||
int sd_dhcp_client_add_option(sd_dhcp_client *client, sd_dhcp_option *v);
|
||||
int sd_dhcp_client_add_vendor_option(sd_dhcp_client *client, sd_dhcp_option *v);
|
||||
|
||||
int sd_dhcp_client_stop(sd_dhcp_client *client);
|
||||
int sd_dhcp_client_start(sd_dhcp_client *client);
|
||||
int sd_dhcp_client_send_release(sd_dhcp_client *client);
|
||||
int sd_dhcp_client_send_decline(sd_dhcp_client *client);
|
||||
int sd_dhcp_client_send_renew(sd_dhcp_client *client);
|
||||
|
||||
sd_dhcp_client *sd_dhcp_client_ref(sd_dhcp_client *client);
|
||||
|
|
Loading…
Reference in a new issue