mirror of
https://gitlab.freedesktop.org/NetworkManager/NetworkManager
synced 2024-09-29 21:04:22 +00:00
merge: branch 'ff/sync_systemd'
https://gitlab.freedesktop.org/NetworkManager/NetworkManager/-/merge_requests/1923
This commit is contained in:
commit
5e043966a1
|
@ -223,7 +223,7 @@ int device_set_syspath(sd_device *device, const char *_syspath, bool verify) {
|
|||
/* Only operate on sysfs, i.e. refuse going down into /sys/fs/cgroup/ or similar places where
|
||||
* things are not arranged as kobjects in kernel, and hence don't necessarily have
|
||||
* kobject/attribute structure. */
|
||||
r = getenv_bool_secure("SYSTEMD_DEVICE_VERIFY_SYSFS");
|
||||
r = secure_getenv_bool("SYSTEMD_DEVICE_VERIFY_SYSFS");
|
||||
if (r < 0 && r != -ENXIO)
|
||||
log_debug_errno(r, "Failed to parse $SYSTEMD_DEVICE_VERIFY_SYSFS value: %m");
|
||||
if (r != 0) {
|
||||
|
|
|
@ -1579,7 +1579,7 @@ static int child_exit_callback(sd_event_source *s, const siginfo_t *si, void *us
|
|||
|
||||
static bool shall_use_pidfd(void) {
|
||||
/* Mostly relevant for debugging, i.e. this is used in test-event.c to test the event loop once with and once without pidfd */
|
||||
return getenv_bool_secure("SYSTEMD_PIDFD") != 0;
|
||||
return secure_getenv_bool("SYSTEMD_PIDFD") != 0;
|
||||
}
|
||||
|
||||
_public_ int sd_event_add_child(
|
||||
|
@ -4923,13 +4923,13 @@ _public_ int sd_event_get_state(sd_event *e) {
|
|||
_public_ int sd_event_get_exit_code(sd_event *e, int *code) {
|
||||
assert_return(e, -EINVAL);
|
||||
assert_return(e = event_resolve(e), -ENOPKG);
|
||||
assert_return(code, -EINVAL);
|
||||
assert_return(!event_origin_changed(e), -ECHILD);
|
||||
|
||||
if (!e->exit_requested)
|
||||
return -ENODATA;
|
||||
|
||||
*code = e->exit_code;
|
||||
if (code)
|
||||
*code = e->exit_code;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -143,7 +143,7 @@ int id128_read_at(int dir_fd, const char *path, Id128Flag f, sd_id128_t *ret) {
|
|||
assert(dir_fd >= 0 || dir_fd == AT_FDCWD);
|
||||
assert(path);
|
||||
|
||||
fd = xopenat(dir_fd, path, O_RDONLY|O_CLOEXEC|O_NOCTTY, /* xopen_flags = */ 0, /* mode = */ 0);
|
||||
fd = xopenat(dir_fd, path, O_RDONLY|O_CLOEXEC|O_NOCTTY);
|
||||
if (fd < 0)
|
||||
return fd;
|
||||
|
||||
|
@ -190,7 +190,7 @@ int id128_write_at(int dir_fd, const char *path, Id128Flag f, sd_id128_t id) {
|
|||
assert(dir_fd >= 0 || dir_fd == AT_FDCWD);
|
||||
assert(path);
|
||||
|
||||
fd = xopenat(dir_fd, path, O_WRONLY|O_CREAT|O_CLOEXEC|O_NOCTTY|O_TRUNC, /* xopen_flags = */ 0, 0444);
|
||||
fd = xopenat_full(dir_fd, path, O_WRONLY|O_CREAT|O_CLOEXEC|O_NOCTTY|O_TRUNC, /* xopen_flags = */ 0, 0444);
|
||||
if (fd < 0)
|
||||
return fd;
|
||||
|
||||
|
|
|
@ -3,7 +3,6 @@
|
|||
#define foosddhcpduidhfoo
|
||||
|
||||
/***
|
||||
Copyright © 2013 Intel Corporation. All rights reserved.
|
||||
systemd is free software; you can redistribute it and/or modify it
|
||||
under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation; either version 2.1 of the License, or
|
||||
|
|
|
@ -26,35 +26,14 @@
|
|||
#include <sys/types.h>
|
||||
|
||||
#include "sd-event.h"
|
||||
#include "sd-ndisc-protocol.h"
|
||||
#include "sd-ndisc-router.h"
|
||||
|
||||
#include "_sd-common.h"
|
||||
|
||||
_SD_BEGIN_DECLARATIONS;
|
||||
|
||||
/* Neighbor Discovery Options, RFC 4861, Section 4.6 and
|
||||
* https://www.iana.org/assignments/icmpv6-parameters/icmpv6-parameters.xhtml#icmpv6-parameters-5 */
|
||||
enum {
|
||||
SD_NDISC_OPTION_SOURCE_LL_ADDRESS = 1,
|
||||
SD_NDISC_OPTION_TARGET_LL_ADDRESS = 2,
|
||||
SD_NDISC_OPTION_PREFIX_INFORMATION = 3,
|
||||
SD_NDISC_OPTION_MTU = 5,
|
||||
SD_NDISC_OPTION_ROUTE_INFORMATION = 24,
|
||||
SD_NDISC_OPTION_RDNSS = 25,
|
||||
SD_NDISC_OPTION_FLAGS_EXTENSION = 26,
|
||||
SD_NDISC_OPTION_DNSSL = 31,
|
||||
SD_NDISC_OPTION_CAPTIVE_PORTAL = 37,
|
||||
SD_NDISC_OPTION_PREF64 = 38
|
||||
};
|
||||
|
||||
/* Route preference, RFC 4191, Section 2.1 */
|
||||
enum {
|
||||
SD_NDISC_PREFERENCE_LOW = 3U,
|
||||
SD_NDISC_PREFERENCE_MEDIUM = 0U,
|
||||
SD_NDISC_PREFERENCE_HIGH = 1U
|
||||
};
|
||||
|
||||
typedef struct sd_ndisc sd_ndisc;
|
||||
typedef struct sd_ndisc_router sd_ndisc_router;
|
||||
|
||||
__extension__ typedef enum sd_ndisc_event_t {
|
||||
SD_NDISC_EVENT_TIMEOUT,
|
||||
|
@ -64,14 +43,16 @@ __extension__ typedef enum sd_ndisc_event_t {
|
|||
_SD_ENUM_FORCE_S64(NDISC_EVENT)
|
||||
} sd_ndisc_event_t;
|
||||
|
||||
typedef void (*sd_ndisc_callback_t)(sd_ndisc *nd, sd_ndisc_event_t event, sd_ndisc_router *rt, void *userdata);
|
||||
typedef void (*sd_ndisc_callback_t)(sd_ndisc *nd, sd_ndisc_event_t event, void *message, void *userdata);
|
||||
|
||||
int sd_ndisc_new(sd_ndisc **ret);
|
||||
sd_ndisc *sd_ndisc_ref(sd_ndisc *nd);
|
||||
sd_ndisc *sd_ndisc_unref(sd_ndisc *nd);
|
||||
_SD_DEFINE_POINTER_CLEANUP_FUNC(sd_ndisc, sd_ndisc_unref);
|
||||
|
||||
int sd_ndisc_start(sd_ndisc *nd);
|
||||
int sd_ndisc_stop(sd_ndisc *nd);
|
||||
int sd_ndisc_is_running(sd_ndisc *nd);
|
||||
|
||||
int sd_ndisc_attach_event(sd_ndisc *nd, sd_event *event, int64_t priority);
|
||||
int sd_ndisc_detach_event(sd_ndisc *nd);
|
||||
|
@ -81,69 +62,9 @@ int sd_ndisc_set_callback(sd_ndisc *nd, sd_ndisc_callback_t cb, void *userdata);
|
|||
int sd_ndisc_set_ifindex(sd_ndisc *nd, int interface_index);
|
||||
int sd_ndisc_set_ifname(sd_ndisc *nd, const char *interface_name);
|
||||
int sd_ndisc_get_ifname(sd_ndisc *nd, const char **ret);
|
||||
int sd_ndisc_set_link_local_address(sd_ndisc *nd, const struct in6_addr *addr);
|
||||
int sd_ndisc_set_mac(sd_ndisc *nd, const struct ether_addr *mac_addr);
|
||||
|
||||
sd_ndisc_router *sd_ndisc_router_ref(sd_ndisc_router *rt);
|
||||
sd_ndisc_router *sd_ndisc_router_unref(sd_ndisc_router *rt);
|
||||
|
||||
int sd_ndisc_router_get_address(sd_ndisc_router *rt, struct in6_addr *ret);
|
||||
int sd_ndisc_router_get_timestamp(sd_ndisc_router *rt, clockid_t clock, uint64_t *ret);
|
||||
int sd_ndisc_router_get_raw(sd_ndisc_router *rt, const void **ret, size_t *ret_size);
|
||||
|
||||
int sd_ndisc_router_get_hop_limit(sd_ndisc_router *rt, uint8_t *ret);
|
||||
int sd_ndisc_router_get_icmp6_ratelimit(sd_ndisc_router *rt, uint64_t *ret);
|
||||
int sd_ndisc_router_get_flags(sd_ndisc_router *rt, uint64_t *ret);
|
||||
int sd_ndisc_router_get_preference(sd_ndisc_router *rt, unsigned *ret);
|
||||
int sd_ndisc_router_get_lifetime(sd_ndisc_router *rt, uint64_t *ret);
|
||||
int sd_ndisc_router_get_lifetime_timestamp(sd_ndisc_router *rt, clockid_t clock, uint64_t *ret);
|
||||
int sd_ndisc_router_get_retransmission_time(sd_ndisc_router *rt, uint64_t *ret);
|
||||
int sd_ndisc_router_get_mtu(sd_ndisc_router *rt, uint32_t *ret);
|
||||
|
||||
/* Generic option access */
|
||||
int sd_ndisc_router_option_rewind(sd_ndisc_router *rt);
|
||||
int sd_ndisc_router_option_next(sd_ndisc_router *rt);
|
||||
int sd_ndisc_router_option_get_type(sd_ndisc_router *rt, uint8_t *ret);
|
||||
int sd_ndisc_router_option_is_type(sd_ndisc_router *rt, uint8_t type);
|
||||
int sd_ndisc_router_option_get_raw(sd_ndisc_router *rt, const void **ret, size_t *ret_size);
|
||||
|
||||
/* Specific option access: SD_NDISC_OPTION_PREFIX_INFORMATION */
|
||||
int sd_ndisc_router_prefix_get_valid_lifetime(sd_ndisc_router *rt, uint64_t *ret);
|
||||
int sd_ndisc_router_prefix_get_valid_lifetime_timestamp(sd_ndisc_router *rt, clockid_t clock, uint64_t *ret);
|
||||
int sd_ndisc_router_prefix_get_preferred_lifetime(sd_ndisc_router *rt, uint64_t *ret);
|
||||
int sd_ndisc_router_prefix_get_preferred_lifetime_timestamp(sd_ndisc_router *rt, clockid_t clock, uint64_t *ret);
|
||||
int sd_ndisc_router_prefix_get_flags(sd_ndisc_router *rt, uint8_t *ret);
|
||||
int sd_ndisc_router_prefix_get_address(sd_ndisc_router *rt, struct in6_addr *ret);
|
||||
int sd_ndisc_router_prefix_get_prefixlen(sd_ndisc_router *rt, unsigned *ret);
|
||||
|
||||
/* Specific option access: SD_NDISC_OPTION_ROUTE_INFORMATION */
|
||||
int sd_ndisc_router_route_get_lifetime(sd_ndisc_router *rt, uint64_t *ret);
|
||||
int sd_ndisc_router_route_get_lifetime_timestamp(sd_ndisc_router *rt, clockid_t clock, uint64_t *ret);
|
||||
int sd_ndisc_router_route_get_address(sd_ndisc_router *rt, struct in6_addr *ret);
|
||||
int sd_ndisc_router_route_get_prefixlen(sd_ndisc_router *rt, unsigned *ret);
|
||||
int sd_ndisc_router_route_get_preference(sd_ndisc_router *rt, unsigned *ret);
|
||||
|
||||
/* Specific option access: SD_NDISC_OPTION_RDNSS */
|
||||
int sd_ndisc_router_rdnss_get_addresses(sd_ndisc_router *rt, const struct in6_addr **ret);
|
||||
int sd_ndisc_router_rdnss_get_lifetime(sd_ndisc_router *rt, uint64_t *ret);
|
||||
int sd_ndisc_router_rdnss_get_lifetime_timestamp(sd_ndisc_router *rt, clockid_t clock, uint64_t *ret);
|
||||
|
||||
/* Specific option access: SD_NDISC_OPTION_DNSSL */
|
||||
int sd_ndisc_router_dnssl_get_domains(sd_ndisc_router *rt, char ***ret);
|
||||
int sd_ndisc_router_dnssl_get_lifetime(sd_ndisc_router *rt, uint64_t *ret);
|
||||
int sd_ndisc_router_dnssl_get_lifetime_timestamp(sd_ndisc_router *rt, clockid_t clock, uint64_t *ret);
|
||||
|
||||
/* Specific option access: SD_NDISC_OPTION_CAPTIVE_PORTAL */
|
||||
int sd_ndisc_router_captive_portal_get_uri(sd_ndisc_router *rt, const char **ret, size_t *ret_size);
|
||||
|
||||
/* Specific option access: SD_NDISC_OPTION_PREF64 */
|
||||
int sd_ndisc_router_prefix64_get_prefix(sd_ndisc_router *rt, struct in6_addr *ret);
|
||||
int sd_ndisc_router_prefix64_get_prefixlen(sd_ndisc_router *rt, unsigned *ret);
|
||||
int sd_ndisc_router_prefix64_get_lifetime(sd_ndisc_router *rt, uint64_t *ret);
|
||||
int sd_ndisc_router_prefix64_get_lifetime_timestamp(sd_ndisc_router *rt, clockid_t clock, uint64_t *ret);
|
||||
|
||||
_SD_DEFINE_POINTER_CLEANUP_FUNC(sd_ndisc, sd_ndisc_unref);
|
||||
_SD_DEFINE_POINTER_CLEANUP_FUNC(sd_ndisc_router, sd_ndisc_router_unref);
|
||||
|
||||
_SD_END_DECLARATIONS;
|
||||
|
||||
#endif
|
||||
|
|
|
@ -312,19 +312,17 @@ char **strv_env_delete(char **x, size_t n_lists, ...) {
|
|||
return TAKE_PTR(t);
|
||||
}
|
||||
|
||||
char **strv_env_unset(char **l, const char *p) {
|
||||
char **f, **t;
|
||||
char** strv_env_unset(char **l, const char *p) {
|
||||
assert(p);
|
||||
|
||||
if (!l)
|
||||
return NULL;
|
||||
|
||||
assert(p);
|
||||
|
||||
/* Drops every occurrence of the env var setting p in the
|
||||
* string list. Edits in-place. */
|
||||
|
||||
char **f, **t;
|
||||
for (f = t = l; *f; f++) {
|
||||
|
||||
if (env_match(*f, p)) {
|
||||
free(*f);
|
||||
continue;
|
||||
|
@ -337,14 +335,13 @@ char **strv_env_unset(char **l, const char *p) {
|
|||
return l;
|
||||
}
|
||||
|
||||
char **strv_env_unset_many(char **l, ...) {
|
||||
char **f, **t;
|
||||
|
||||
char** strv_env_unset_many_internal(char **l, ...) {
|
||||
if (!l)
|
||||
return NULL;
|
||||
|
||||
/* Like strv_env_unset() but applies many at once. Edits in-place. */
|
||||
|
||||
char **f, **t;
|
||||
for (f = t = l; *f; f++) {
|
||||
bool found = false;
|
||||
const char *p;
|
||||
|
@ -352,12 +349,11 @@ char **strv_env_unset_many(char **l, ...) {
|
|||
|
||||
va_start(ap, l);
|
||||
|
||||
while ((p = va_arg(ap, const char*))) {
|
||||
while ((p = va_arg(ap, const char*)))
|
||||
if (env_match(*f, p)) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
va_end(ap);
|
||||
|
||||
|
@ -972,7 +968,7 @@ int getenv_bool(const char *p) {
|
|||
return parse_boolean(e);
|
||||
}
|
||||
|
||||
int getenv_bool_secure(const char *p) {
|
||||
int secure_getenv_bool(const char *p) {
|
||||
const char *e;
|
||||
|
||||
e = secure_getenv(p);
|
||||
|
@ -982,8 +978,7 @@ int getenv_bool_secure(const char *p) {
|
|||
return parse_boolean(e);
|
||||
}
|
||||
|
||||
#if 0 /* NM_IGNORED */
|
||||
int getenv_uint64_secure(const char *p, uint64_t *ret) {
|
||||
int secure_getenv_uint64(const char *p, uint64_t *ret) {
|
||||
const char *e;
|
||||
|
||||
assert(p);
|
||||
|
@ -1017,6 +1012,7 @@ int putenv_dup(const char *assignment, bool override) {
|
|||
return RET_NERRNO(setenv(n, e + 1, override));
|
||||
}
|
||||
|
||||
#if 0 /* NM_IGNORED */
|
||||
int setenv_systemd_exec_pid(bool update_only) {
|
||||
const char *e;
|
||||
int r;
|
||||
|
@ -1037,6 +1033,17 @@ int setenv_systemd_exec_pid(bool update_only) {
|
|||
return 1;
|
||||
}
|
||||
|
||||
int setenv_systemd_log_level(void) {
|
||||
_cleanup_free_ char *val = NULL;
|
||||
int r;
|
||||
|
||||
r = log_level_to_string_alloc(log_get_max_level(), &val);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
return RET_NERRNO(setenv("SYSTEMD_LOG_LEVEL", val, /* overwrite= */ true));
|
||||
}
|
||||
|
||||
int getenv_path_list(const char *name, char ***ret_paths) {
|
||||
_cleanup_strv_free_ char **l = NULL;
|
||||
const char *e;
|
||||
|
|
|
@ -43,8 +43,9 @@ char** _strv_env_merge(char **first, ...);
|
|||
#define strv_env_merge(first, ...) _strv_env_merge(first, __VA_ARGS__, POINTER_MAX)
|
||||
char **strv_env_delete(char **x, size_t n_lists, ...); /* New copy */
|
||||
|
||||
char **strv_env_unset(char **l, const char *p); /* In place ... */
|
||||
char **strv_env_unset_many(char **l, ...) _sentinel_;
|
||||
char** strv_env_unset(char **l, const char *p); /* In place ... */
|
||||
char** strv_env_unset_many_internal(char **l, ...) _sentinel_;
|
||||
#define strv_env_unset_many(l, ...) strv_env_unset_many_internal(l, __VA_ARGS__, NULL)
|
||||
int strv_env_replace_consume(char ***l, char *p); /* In place ... */
|
||||
int strv_env_replace_strdup(char ***l, const char *assignment);
|
||||
int strv_env_replace_strdup_passthrough(char ***l, const char *assignment);
|
||||
|
@ -61,9 +62,9 @@ static inline char* strv_env_get(char * const *x, const char *n) {
|
|||
char *strv_env_pairs_get(char **l, const char *name) _pure_;
|
||||
|
||||
int getenv_bool(const char *p);
|
||||
int getenv_bool_secure(const char *p);
|
||||
int secure_getenv_bool(const char *p);
|
||||
|
||||
int getenv_uint64_secure(const char *p, uint64_t *ret);
|
||||
int secure_getenv_uint64(const char *p, uint64_t *ret);
|
||||
|
||||
/* Like setenv, but calls unsetenv if value == NULL. */
|
||||
int set_unset_env(const char *name, const char *value, bool overwrite);
|
||||
|
@ -72,6 +73,7 @@ int set_unset_env(const char *name, const char *value, bool overwrite);
|
|||
int putenv_dup(const char *assignment, bool override);
|
||||
|
||||
int setenv_systemd_exec_pid(bool update_only);
|
||||
int setenv_systemd_log_level(void);
|
||||
|
||||
/* Parses and does sanity checks on an environment variable containing
|
||||
* PATH-like colon-separated absolute paths */
|
||||
|
|
|
@ -247,52 +247,43 @@ int extract_first_word_and_warn(
|
|||
* Let's make sure that ExtractFlags fits into an unsigned int. */
|
||||
assert_cc(sizeof(enum ExtractFlags) <= sizeof(unsigned));
|
||||
|
||||
int extract_many_words(const char **p, const char *separators, unsigned flags, ...) {
|
||||
int extract_many_words_internal(const char **p, const char *separators, unsigned flags, ...) {
|
||||
va_list ap;
|
||||
char **l;
|
||||
int n = 0, i, c, r;
|
||||
unsigned n = 0;
|
||||
int r;
|
||||
|
||||
/* Parses a number of words from a string, stripping any
|
||||
* quotes if necessary. */
|
||||
/* Parses a number of words from a string, stripping any quotes if necessary. */
|
||||
|
||||
assert(p);
|
||||
|
||||
/* Count how many words are expected */
|
||||
va_start(ap, flags);
|
||||
for (;;) {
|
||||
if (!va_arg(ap, char **))
|
||||
break;
|
||||
while (va_arg(ap, char**))
|
||||
n++;
|
||||
}
|
||||
va_end(ap);
|
||||
|
||||
if (n <= 0)
|
||||
if (n == 0)
|
||||
return 0;
|
||||
|
||||
/* Read all words into a temporary array */
|
||||
l = newa0(char*, n);
|
||||
for (c = 0; c < n; c++) {
|
||||
char **l = newa0(char*, n);
|
||||
unsigned c;
|
||||
|
||||
for (c = 0; c < n; c++) {
|
||||
r = extract_first_word(p, &l[c], separators, flags);
|
||||
if (r < 0) {
|
||||
free_many_charp(l, c);
|
||||
return r;
|
||||
}
|
||||
|
||||
if (r == 0)
|
||||
break;
|
||||
}
|
||||
|
||||
/* If we managed to parse all words, return them in the passed
|
||||
* in parameters */
|
||||
/* If we managed to parse all words, return them in the passed in parameters */
|
||||
va_start(ap, flags);
|
||||
for (i = 0; i < n; i++) {
|
||||
char **v;
|
||||
|
||||
v = va_arg(ap, char **);
|
||||
assert(v);
|
||||
|
||||
*v = l[i];
|
||||
FOREACH_ARRAY(i, l, n) {
|
||||
char **v = ASSERT_PTR(va_arg(ap, char**));
|
||||
*v = *i;
|
||||
}
|
||||
va_end(ap);
|
||||
|
||||
|
|
|
@ -19,4 +19,7 @@ typedef enum ExtractFlags {
|
|||
|
||||
int extract_first_word(const char **p, char **ret, const char *separators, ExtractFlags flags);
|
||||
int extract_first_word_and_warn(const char **p, char **ret, const char *separators, ExtractFlags flags, const char *unit, const char *filename, unsigned line, const char *rvalue);
|
||||
int extract_many_words(const char **p, const char *separators, unsigned flags, ...) _sentinel_;
|
||||
|
||||
int extract_many_words_internal(const char **p, const char *separators, unsigned flags, ...) _sentinel_;
|
||||
#define extract_many_words(p, separators, flags, ...) \
|
||||
extract_many_words_internal(p, separators, flags, ##__VA_ARGS__, NULL)
|
||||
|
|
|
@ -311,7 +311,7 @@ static int close_all_fds_special_case(const int except[], size_t n_except) {
|
|||
case 0:
|
||||
/* Close everything. Yay! */
|
||||
|
||||
if (close_range(3, -1, 0) >= 0)
|
||||
if (close_range(3, INT_MAX, 0) >= 0)
|
||||
return 1;
|
||||
|
||||
if (ERRNO_IS_NOT_SUPPORTED(errno) || ERRNO_IS_PRIVILEGE(errno)) {
|
||||
|
@ -422,7 +422,7 @@ int close_all_fds(const int except[], size_t n_except) {
|
|||
if (sorted[n_sorted-1] >= INT_MAX) /* Dont let the addition below overflow */
|
||||
return 0;
|
||||
|
||||
if (close_range(sorted[n_sorted-1] + 1, -1, 0) >= 0)
|
||||
if (close_range(sorted[n_sorted-1] + 1, INT_MAX, 0) >= 0)
|
||||
return 0;
|
||||
|
||||
if (!ERRNO_IS_NOT_SUPPORTED(errno) && !ERRNO_IS_PRIVILEGE(errno))
|
||||
|
@ -467,6 +467,53 @@ int close_all_fds(const int except[], size_t n_except) {
|
|||
return r;
|
||||
}
|
||||
|
||||
int pack_fds(int fds[], size_t n_fds) {
|
||||
if (n_fds <= 0)
|
||||
return 0;
|
||||
|
||||
/* Shifts around the fds in the provided array such that they
|
||||
* all end up packed next to each-other, in order, starting
|
||||
* from SD_LISTEN_FDS_START. This must be called after close_all_fds();
|
||||
* it is likely to freeze up otherwise. You should probably use safe_fork_full
|
||||
* with FORK_CLOSE_ALL_FDS|FORK_PACK_FDS set, to ensure that this is done correctly.
|
||||
* The fds array is modified in place with the new FD numbers. */
|
||||
|
||||
assert(fds);
|
||||
|
||||
for (int start = 0;;) {
|
||||
int restart_from = -1;
|
||||
|
||||
for (int i = start; i < (int) n_fds; i++) {
|
||||
int nfd;
|
||||
|
||||
/* Already at right index? */
|
||||
if (fds[i] == i + 3)
|
||||
continue;
|
||||
|
||||
nfd = fcntl(fds[i], F_DUPFD, i + 3);
|
||||
if (nfd < 0)
|
||||
return -errno;
|
||||
|
||||
safe_close(fds[i]);
|
||||
fds[i] = nfd;
|
||||
|
||||
/* Hmm, the fd we wanted isn't free? Then
|
||||
* let's remember that and try again from here */
|
||||
if (nfd != i + 3 && restart_from < 0)
|
||||
restart_from = i;
|
||||
}
|
||||
|
||||
if (restart_from < 0)
|
||||
break;
|
||||
|
||||
start = restart_from;
|
||||
}
|
||||
|
||||
assert(fds[0] == 3);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int same_fd(int a, int b) {
|
||||
struct stat sta, stb;
|
||||
pid_t pid;
|
||||
|
@ -875,6 +922,38 @@ int fd_is_opath(int fd) {
|
|||
return FLAGS_SET(r, O_PATH);
|
||||
}
|
||||
|
||||
int fd_verify_safe_flags(int fd) {
|
||||
int flags, unexpected_flags;
|
||||
|
||||
/* Check if an extrinsic fd is safe to work on (by a privileged service). This ensures that clients
|
||||
* can't trick a privileged service into giving access to a file the client doesn't already have
|
||||
* access to (especially via something like O_PATH).
|
||||
*
|
||||
* O_NOFOLLOW: For some reason the kernel will return this flag from fcntl; it doesn't go away
|
||||
* immediately after open(). It should have no effect whatsoever to an already-opened FD,
|
||||
* and since we refuse O_PATH it should be safe.
|
||||
*
|
||||
* RAW_O_LARGEFILE: glibc secretly sets this and neglects to hide it from us if we call fcntl.
|
||||
* See comment in missing_fcntl.h for more details about this.
|
||||
*
|
||||
* O_DIRECTORY: this is set for directories, which are totally fine
|
||||
*/
|
||||
|
||||
assert(fd >= 0);
|
||||
|
||||
flags = fcntl(fd, F_GETFL);
|
||||
if (flags < 0)
|
||||
return -errno;
|
||||
|
||||
unexpected_flags = flags & ~(O_ACCMODE|O_NOFOLLOW|RAW_O_LARGEFILE|O_DIRECTORY);
|
||||
if (unexpected_flags != 0)
|
||||
return log_debug_errno(SYNTHETIC_ERRNO(EREMOTEIO),
|
||||
"Unexpected flags set for extrinsic fd: 0%o",
|
||||
(unsigned) unexpected_flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int read_nr_open(void) {
|
||||
_cleanup_free_ char *nr_open = NULL;
|
||||
int r;
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
#include <sys/socket.h>
|
||||
|
||||
#include "macro.h"
|
||||
#include "missing_fcntl.h"
|
||||
#include "stdio-util.h"
|
||||
|
||||
/* maximum length of fdname */
|
||||
|
@ -77,6 +78,8 @@ int get_max_fd(void);
|
|||
int close_all_fds(const int except[], size_t n_except);
|
||||
int close_all_fds_without_malloc(const int except[], size_t n_except);
|
||||
|
||||
int pack_fds(int fds[], size_t n);
|
||||
|
||||
int same_fd(int a, int b);
|
||||
|
||||
void cmsg_close_all(struct msghdr *mh);
|
||||
|
@ -109,7 +112,10 @@ static inline int make_null_stdio(void) {
|
|||
|
||||
int fd_reopen(int fd, int flags);
|
||||
int fd_reopen_condition(int fd, int flags, int mask, int *ret_new_fd);
|
||||
|
||||
int fd_is_opath(int fd);
|
||||
int fd_verify_safe_flags(int fd);
|
||||
|
||||
int read_nr_open(void);
|
||||
int fd_get_diskseq(int fd, uint64_t *ret);
|
||||
|
||||
|
|
|
@ -18,6 +18,14 @@ assert_cc(sizeof(uid_t) == sizeof(uint32_t));
|
|||
assert_cc(sizeof(gid_t) == sizeof(uint32_t));
|
||||
#define GID_FMT "%" PRIu32
|
||||
|
||||
/* Note: the lifetime of the compound literal is the immediately surrounding block,
|
||||
* see C11 §6.5.2.5, and
|
||||
* https://stackoverflow.com/questions/34880638/compound-literal-lifetime-and-if-blocks */
|
||||
#define FORMAT_UID(uid) \
|
||||
snprintf_ok((char[DECIMAL_STR_MAX(uid_t)]){}, DECIMAL_STR_MAX(uid_t), UID_FMT, uid)
|
||||
#define FORMAT_GID(gid) \
|
||||
snprintf_ok((char[DECIMAL_STR_MAX(gid_t)]){}, DECIMAL_STR_MAX(gid_t), GID_FMT, gid)
|
||||
|
||||
#if SIZEOF_TIME_T == 8
|
||||
# define PRI_TIME PRIi64
|
||||
#elif SIZEOF_TIME_T == 4
|
||||
|
|
|
@ -120,7 +120,11 @@ int rename_noreplace(int olddirfd, const char *oldpath, int newdirfd, const char
|
|||
int readlinkat_malloc(int fd, const char *p, char **ret) {
|
||||
size_t l = PATH_MAX;
|
||||
|
||||
assert(p);
|
||||
assert(fd >= 0 || fd == AT_FDCWD);
|
||||
|
||||
if (fd < 0 && isempty(p))
|
||||
return -EISDIR; /* In this case, the fd points to the current working directory, and is
|
||||
* definitely not a symlink. Let's return earlier. */
|
||||
|
||||
for (;;) {
|
||||
_cleanup_free_ char *c = NULL;
|
||||
|
@ -130,7 +134,7 @@ int readlinkat_malloc(int fd, const char *p, char **ret) {
|
|||
if (!c)
|
||||
return -ENOMEM;
|
||||
|
||||
n = readlinkat(fd, p, c, l);
|
||||
n = readlinkat(fd, strempty(p), c, l);
|
||||
if (n < 0)
|
||||
return -errno;
|
||||
|
||||
|
@ -1060,7 +1064,7 @@ int open_mkdir_at(int dirfd, const char *path, int flags, mode_t mode) {
|
|||
path = fname;
|
||||
}
|
||||
|
||||
fd = xopenat(dirfd, path, flags|O_CREAT|O_DIRECTORY|O_NOFOLLOW, /* xopen_flags = */ 0, mode);
|
||||
fd = xopenat_full(dirfd, path, flags|O_CREAT|O_DIRECTORY|O_NOFOLLOW, /* xopen_flags = */ 0, mode);
|
||||
if (IN_SET(fd, -ELOOP, -ENOTDIR))
|
||||
return -EEXIST;
|
||||
if (fd < 0)
|
||||
|
@ -1116,7 +1120,7 @@ int openat_report_new(int dirfd, const char *pathname, int flags, mode_t mode, b
|
|||
}
|
||||
}
|
||||
|
||||
int xopenat(int dir_fd, const char *path, int open_flags, XOpenFlags xopen_flags, mode_t mode) {
|
||||
int xopenat_full(int dir_fd, const char *path, int open_flags, XOpenFlags xopen_flags, mode_t mode) {
|
||||
_cleanup_close_ int fd = -EBADF;
|
||||
bool made = false;
|
||||
int r;
|
||||
|
@ -1198,7 +1202,7 @@ int xopenat(int dir_fd, const char *path, int open_flags, XOpenFlags xopen_flags
|
|||
}
|
||||
|
||||
#if 0 /* NM_IGNORED */
|
||||
int xopenat_lock(
|
||||
int xopenat_lock_full(
|
||||
int dir_fd,
|
||||
const char *path,
|
||||
int open_flags,
|
||||
|
@ -1221,7 +1225,7 @@ int xopenat_lock(
|
|||
for (;;) {
|
||||
struct stat st;
|
||||
|
||||
fd = xopenat(dir_fd, path, open_flags, xopen_flags, mode);
|
||||
fd = xopenat_full(dir_fd, path, open_flags, xopen_flags, mode);
|
||||
if (fd < 0)
|
||||
return fd;
|
||||
|
||||
|
|
|
@ -137,6 +137,12 @@ typedef enum XOpenFlags {
|
|||
XO_SUBVOLUME = 1 << 1,
|
||||
} XOpenFlags;
|
||||
|
||||
int xopenat(int dir_fd, const char *path, int open_flags, XOpenFlags xopen_flags, mode_t mode);
|
||||
int xopenat_full(int dir_fd, const char *path, int open_flags, XOpenFlags xopen_flags, mode_t mode);
|
||||
static inline int xopenat(int dir_fd, const char *path, int open_flags) {
|
||||
return xopenat_full(dir_fd, path, open_flags, 0, 0);
|
||||
}
|
||||
|
||||
int xopenat_lock(int dir_fd, const char *path, int open_flags, XOpenFlags xopen_flags, mode_t mode, LockType locktype, int operation);
|
||||
int xopenat_lock_full(int dir_fd, const char *path, int open_flags, XOpenFlags xopen_flags, mode_t mode, LockType locktype, int operation);
|
||||
static inline int xopenat_lock(int dir_fd, const char *path, int open_flags, LockType locktype, int operation) {
|
||||
return xopenat_lock_full(dir_fd, path, open_flags, 0, 0, locktype, operation);
|
||||
}
|
||||
|
|
|
@ -43,6 +43,8 @@ const char *special_glyph_full(SpecialGlyph code, bool force_utf) {
|
|||
[SPECIAL_GLYPH_TREE_SPACE] = " ",
|
||||
[SPECIAL_GLYPH_TREE_TOP] = ",-",
|
||||
[SPECIAL_GLYPH_VERTICAL_DOTTED] = ":",
|
||||
[SPECIAL_GLYPH_HORIZONTAL_DOTTED] = "-",
|
||||
[SPECIAL_GLYPH_HORIZONTAL_FAT] = "=",
|
||||
[SPECIAL_GLYPH_TRIANGULAR_BULLET] = ">",
|
||||
[SPECIAL_GLYPH_BLACK_CIRCLE] = "*",
|
||||
[SPECIAL_GLYPH_WHITE_CIRCLE] = "*",
|
||||
|
@ -76,6 +78,10 @@ const char *special_glyph_full(SpecialGlyph code, bool force_utf) {
|
|||
[SPECIAL_GLYPH_SPARKLES] = "*",
|
||||
[SPECIAL_GLYPH_LOW_BATTERY] = "!",
|
||||
[SPECIAL_GLYPH_WARNING_SIGN] = "!",
|
||||
[SPECIAL_GLYPH_RED_CIRCLE] = "o",
|
||||
[SPECIAL_GLYPH_YELLOW_CIRCLE] = "o",
|
||||
[SPECIAL_GLYPH_BLUE_CIRCLE] = "o",
|
||||
[SPECIAL_GLYPH_GREEN_CIRCLE] = "o",
|
||||
},
|
||||
|
||||
/* UTF-8 */
|
||||
|
@ -89,6 +95,8 @@ const char *special_glyph_full(SpecialGlyph code, bool force_utf) {
|
|||
|
||||
/* Single glyphs in both cases */
|
||||
[SPECIAL_GLYPH_VERTICAL_DOTTED] = u8"┆",
|
||||
[SPECIAL_GLYPH_HORIZONTAL_DOTTED] = u8"┄",
|
||||
[SPECIAL_GLYPH_HORIZONTAL_FAT] = u8"━",
|
||||
[SPECIAL_GLYPH_TRIANGULAR_BULLET] = u8"‣",
|
||||
[SPECIAL_GLYPH_BLACK_CIRCLE] = u8"●",
|
||||
[SPECIAL_GLYPH_WHITE_CIRCLE] = u8"○",
|
||||
|
@ -138,6 +146,11 @@ const char *special_glyph_full(SpecialGlyph code, bool force_utf) {
|
|||
[SPECIAL_GLYPH_WARNING_SIGN] = u8"⚠️",
|
||||
[SPECIAL_GLYPH_COMPUTER_DISK] = u8"💽",
|
||||
[SPECIAL_GLYPH_WORLD] = u8"🌍",
|
||||
|
||||
[SPECIAL_GLYPH_RED_CIRCLE] = u8"🔴",
|
||||
[SPECIAL_GLYPH_YELLOW_CIRCLE] = u8"🟡",
|
||||
[SPECIAL_GLYPH_BLUE_CIRCLE] = u8"🔵",
|
||||
[SPECIAL_GLYPH_GREEN_CIRCLE] = u8"🟢",
|
||||
},
|
||||
};
|
||||
|
||||
|
|
|
@ -13,6 +13,8 @@ typedef enum SpecialGlyph {
|
|||
SPECIAL_GLYPH_TREE_SPACE,
|
||||
SPECIAL_GLYPH_TREE_TOP,
|
||||
SPECIAL_GLYPH_VERTICAL_DOTTED,
|
||||
SPECIAL_GLYPH_HORIZONTAL_DOTTED,
|
||||
SPECIAL_GLYPH_HORIZONTAL_FAT,
|
||||
SPECIAL_GLYPH_TRIANGULAR_BULLET,
|
||||
SPECIAL_GLYPH_BLACK_CIRCLE,
|
||||
SPECIAL_GLYPH_WHITE_CIRCLE,
|
||||
|
@ -49,6 +51,10 @@ typedef enum SpecialGlyph {
|
|||
SPECIAL_GLYPH_WARNING_SIGN,
|
||||
SPECIAL_GLYPH_COMPUTER_DISK,
|
||||
SPECIAL_GLYPH_WORLD,
|
||||
SPECIAL_GLYPH_RED_CIRCLE,
|
||||
SPECIAL_GLYPH_YELLOW_CIRCLE,
|
||||
SPECIAL_GLYPH_BLUE_CIRCLE,
|
||||
SPECIAL_GLYPH_GREEN_CIRCLE,
|
||||
_SPECIAL_GLYPH_MAX,
|
||||
_SPECIAL_GLYPH_INVALID = -EINVAL,
|
||||
} SpecialGlyph;
|
||||
|
|
|
@ -2126,24 +2126,27 @@ static int hashmap_entry_compare(
|
|||
return compare((*a)->key, (*b)->key);
|
||||
}
|
||||
|
||||
int _hashmap_dump_sorted(HashmapBase *h, void ***ret, size_t *ret_n) {
|
||||
_cleanup_free_ struct hashmap_base_entry **entries = NULL;
|
||||
static int _hashmap_dump_entries_sorted(
|
||||
HashmapBase *h,
|
||||
void ***ret,
|
||||
size_t *ret_n) {
|
||||
_cleanup_free_ void **entries = NULL;
|
||||
Iterator iter;
|
||||
unsigned idx;
|
||||
size_t n = 0;
|
||||
|
||||
assert(ret);
|
||||
assert(ret_n);
|
||||
|
||||
if (_hashmap_size(h) == 0) {
|
||||
*ret = NULL;
|
||||
if (ret_n)
|
||||
*ret_n = 0;
|
||||
*ret_n = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* We append one more element than needed so that the resulting array can be used as a strv. We
|
||||
* don't count this entry in the returned size. */
|
||||
entries = new(struct hashmap_base_entry*, _hashmap_size(h) + 1);
|
||||
entries = new(void*, _hashmap_size(h) + 1);
|
||||
if (!entries)
|
||||
return -ENOMEM;
|
||||
|
||||
|
@ -2153,13 +2156,47 @@ int _hashmap_dump_sorted(HashmapBase *h, void ***ret, size_t *ret_n) {
|
|||
assert(n == _hashmap_size(h));
|
||||
entries[n] = NULL;
|
||||
|
||||
typesafe_qsort_r(entries, n, hashmap_entry_compare, h->hash_ops->compare);
|
||||
typesafe_qsort_r((struct hashmap_base_entry**) entries, n,
|
||||
hashmap_entry_compare, h->hash_ops->compare);
|
||||
|
||||
*ret = TAKE_PTR(entries);
|
||||
*ret_n = n;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int _hashmap_dump_keys_sorted(HashmapBase *h, void ***ret, size_t *ret_n) {
|
||||
_cleanup_free_ void **entries = NULL;
|
||||
size_t n;
|
||||
int r;
|
||||
|
||||
r = _hashmap_dump_entries_sorted(h, &entries, &n);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
/* Reuse the array. */
|
||||
FOREACH_ARRAY(e, entries, n)
|
||||
*e = entry_value(h, *e);
|
||||
*e = (void*) (*(struct hashmap_base_entry**) e)->key;
|
||||
|
||||
*ret = (void**) TAKE_PTR(entries);
|
||||
*ret = TAKE_PTR(entries);
|
||||
if (ret_n)
|
||||
*ret_n = n;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int _hashmap_dump_sorted(HashmapBase *h, void ***ret, size_t *ret_n) {
|
||||
_cleanup_free_ void **entries = NULL;
|
||||
size_t n;
|
||||
int r;
|
||||
|
||||
r = _hashmap_dump_entries_sorted(h, &entries, &n);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
/* Reuse the array. */
|
||||
FOREACH_ARRAY(e, entries, n)
|
||||
*e = entry_value(h, *(struct hashmap_base_entry**) e);
|
||||
|
||||
*ret = TAKE_PTR(entries);
|
||||
if (ret_n)
|
||||
*ret_n = n;
|
||||
return 0;
|
||||
|
|
|
@ -39,8 +39,8 @@ typedef struct IteratedCache IteratedCache; /* Caches the iterated order of on
|
|||
* by hashmap users, so the definition has to be here. Do not use its fields
|
||||
* directly. */
|
||||
typedef struct {
|
||||
unsigned idx; /* index of an entry to be iterated next */
|
||||
const void *next_key; /* expected value of that entry's key pointer */
|
||||
unsigned idx; /* index of an entry to be iterated next */
|
||||
#if ENABLE_DEBUG_HASHMAP
|
||||
unsigned put_count; /* hashmap's put_count recorded at start of iteration */
|
||||
unsigned rem_count; /* hashmap's rem_count in previous iteration */
|
||||
|
@ -409,6 +409,14 @@ static inline int set_dump_sorted(Set *h, void ***ret, size_t *ret_n) {
|
|||
return _hashmap_dump_sorted(HASHMAP_BASE(h), ret, ret_n);
|
||||
}
|
||||
|
||||
int _hashmap_dump_keys_sorted(HashmapBase *h, void ***ret, size_t *ret_n);
|
||||
static inline int hashmap_dump_keys_sorted(Hashmap *h, void ***ret, size_t *ret_n) {
|
||||
return _hashmap_dump_keys_sorted(HASHMAP_BASE(h), ret, ret_n);
|
||||
}
|
||||
static inline int ordered_hashmap_dump_keys_sorted(OrderedHashmap *h, void ***ret, size_t *ret_n) {
|
||||
return _hashmap_dump_keys_sorted(HASHMAP_BASE(h), ret, ret_n);
|
||||
}
|
||||
|
||||
/*
|
||||
* Hashmaps are iterated in unpredictable order.
|
||||
* OrderedHashmaps are an exception to this. They are iterated in the order
|
||||
|
|
|
@ -93,14 +93,26 @@ bool in6_addr_is_link_local_all_nodes(const struct in6_addr *a) {
|
|||
be32toh(a->s6_addr32[3]) == UINT32_C(0x00000001);
|
||||
}
|
||||
|
||||
bool in4_addr_is_multicast(const struct in_addr *a) {
|
||||
assert(a);
|
||||
|
||||
return IN_MULTICAST(be32toh(a->s_addr));
|
||||
}
|
||||
|
||||
bool in6_addr_is_multicast(const struct in6_addr *a) {
|
||||
assert(a);
|
||||
|
||||
return IN6_IS_ADDR_MULTICAST(a);
|
||||
}
|
||||
|
||||
int in_addr_is_multicast(int family, const union in_addr_union *u) {
|
||||
assert(u);
|
||||
|
||||
if (family == AF_INET)
|
||||
return IN_MULTICAST(be32toh(u->in.s_addr));
|
||||
return in4_addr_is_multicast(&u->in);
|
||||
|
||||
if (family == AF_INET6)
|
||||
return IN6_IS_ADDR_MULTICAST(&u->in6);
|
||||
return in6_addr_is_multicast(&u->in6);
|
||||
|
||||
return -EAFNOSUPPORT;
|
||||
}
|
||||
|
|
|
@ -40,6 +40,8 @@ static inline bool in_addr_data_is_set(const struct in_addr_data *a) {
|
|||
return in_addr_data_is_null(a);
|
||||
}
|
||||
|
||||
bool in4_addr_is_multicast(const struct in_addr *a);
|
||||
bool in6_addr_is_multicast(const struct in6_addr *a);
|
||||
int in_addr_is_multicast(int family, const union in_addr_union *u);
|
||||
|
||||
bool in4_addr_is_link_local(const struct in_addr *a);
|
||||
|
|
|
@ -263,7 +263,10 @@ bool locale_is_valid(const char *name) {
|
|||
if (!filename_is_valid(name))
|
||||
return false;
|
||||
|
||||
if (!string_is_safe(name))
|
||||
/* Locales look like: ll_CC.ENC@variant, where ll and CC are alphabetic, ENC is alphanumeric with
|
||||
* dashes, and variant seems to be alphabetic.
|
||||
* See: https://www.gnu.org/software/gettext/manual/html_node/Locale-Names.html */
|
||||
if (!in_charset(name, ALPHANUMERICAL "_.-@"))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
|
@ -296,7 +299,7 @@ bool is_locale_utf8(void) {
|
|||
if (cached_answer >= 0)
|
||||
goto out;
|
||||
|
||||
r = getenv_bool_secure("SYSTEMD_UTF8");
|
||||
r = secure_getenv_bool("SYSTEMD_UTF8");
|
||||
if (r >= 0) {
|
||||
cached_answer = r;
|
||||
goto out;
|
||||
|
|
|
@ -524,7 +524,7 @@ typedef struct LogRateLimit {
|
|||
RateLimit ratelimit;
|
||||
} LogRateLimit;
|
||||
|
||||
#define log_ratelimit_internal(_level, _error, _ratelimit, _format, _file, _line, _func, ...) \
|
||||
#define log_ratelimit_internal(_level, _error, _ratelimit, _file, _line, _func, _format, ...) \
|
||||
({ \
|
||||
int _log_ratelimit_error = (_error); \
|
||||
int _log_ratelimit_level = (_level); \
|
||||
|
@ -548,7 +548,7 @@ typedef struct LogRateLimit {
|
|||
({ \
|
||||
int _level = (level), _e = (error); \
|
||||
_e = (log_get_max_level() >= LOG_PRI(_level)) \
|
||||
? log_ratelimit_internal(_level, _e, _ratelimit, format, PROJECT_FILE, __LINE__, __func__, ##__VA_ARGS__) \
|
||||
? log_ratelimit_internal(_level, _e, _ratelimit, PROJECT_FILE, __LINE__, __func__, format, ##__VA_ARGS__) \
|
||||
: -ERRNO_VALUE(_e); \
|
||||
_e < 0 ? _e : -ESTRPIPE; \
|
||||
})
|
||||
|
|
|
@ -69,9 +69,26 @@
|
|||
|
||||
/* So O_LARGEFILE is generally implied by glibc, and defined to zero hence, because we only build in LFS
|
||||
* mode. However, when invoking fcntl(F_GETFL) the flag is ORed into the result anyway — glibc does not mask
|
||||
* it away. Which sucks. Let's define the actual value here, so that we can mask it ourselves. */
|
||||
* it away. Which sucks. Let's define the actual value here, so that we can mask it ourselves.
|
||||
*
|
||||
* The precise definition is arch specific, so we use the values defined in the kernel (note that some
|
||||
* are hexa and others are octal; duplicated as-is from the kernel definitions):
|
||||
* - alpha, arm, arm64, m68k, mips, parisc, powerpc, sparc: each has a specific value;
|
||||
* - others: they use the "generic" value (defined in include/uapi/asm-generic/fcntl.h) */
|
||||
#if O_LARGEFILE != 0
|
||||
#define RAW_O_LARGEFILE O_LARGEFILE
|
||||
#else
|
||||
#define RAW_O_LARGEFILE 0100000
|
||||
#if defined(__alpha__) || defined(__arm__) || defined(__aarch64__) || defined(__m68k__)
|
||||
#define RAW_O_LARGEFILE 0400000
|
||||
#elif defined(__mips__)
|
||||
#define RAW_O_LARGEFILE 0x2000
|
||||
#elif defined(__parisc__) || defined(__hppa__)
|
||||
#define RAW_O_LARGEFILE 000004000
|
||||
#elif defined(__powerpc__)
|
||||
#define RAW_O_LARGEFILE 0200000
|
||||
#elif defined(__sparc__)
|
||||
#define RAW_O_LARGEFILE 0x40000
|
||||
#else
|
||||
#define RAW_O_LARGEFILE 00100000
|
||||
#endif
|
||||
#endif
|
||||
|
|
|
@ -419,23 +419,14 @@ static inline int missing_execveat(int dirfd, const char *pathname,
|
|||
/* ======================================================================= */
|
||||
|
||||
#if !HAVE_CLOSE_RANGE
|
||||
static inline int missing_close_range(int first_fd, int end_fd, unsigned flags) {
|
||||
static inline int missing_close_range(unsigned first_fd, unsigned end_fd, unsigned flags) {
|
||||
# ifdef __NR_close_range
|
||||
/* Kernel-side the syscall expects fds as unsigned integers (just like close() actually), while
|
||||
* userspace exclusively uses signed integers for fds. We don't know just yet how glibc is going to
|
||||
* wrap this syscall, but let's assume it's going to be similar to what they do for close(),
|
||||
* i.e. make the same unsigned → signed type change from the raw kernel syscall compared to the
|
||||
* userspace wrapper. There's only one caveat for this: unlike for close() there's the special
|
||||
* UINT_MAX fd value for the 'end_fd' argument. Let's safely map that to -1 here. And let's refuse
|
||||
* any other negative values. */
|
||||
if ((first_fd < 0) || (end_fd < 0 && end_fd != -1)) {
|
||||
errno = -EBADF;
|
||||
return -1;
|
||||
}
|
||||
|
||||
* userspace exclusively uses signed integers for fds. glibc chose to expose it 1:1 however, hence we
|
||||
* do so here too, even if we end up passing signed fds to it most of the time. */
|
||||
return syscall(__NR_close_range,
|
||||
(unsigned) first_fd,
|
||||
end_fd == -1 ? UINT_MAX : (unsigned) end_fd, /* Of course, the compiler should figure out that this is the identity mapping IRL */
|
||||
first_fd,
|
||||
end_fd,
|
||||
flags);
|
||||
# else
|
||||
errno = ENOSYS;
|
||||
|
|
|
@ -53,3 +53,5 @@ static inline bool userns_shift_range_valid(uid_t shift, uid_t range) {
|
|||
int userns_acquire(const char *uid_map, const char *gid_map);
|
||||
int netns_acquire(void);
|
||||
int in_same_namespace(pid_t pid1, pid_t pid2, NamespaceType type);
|
||||
|
||||
int parse_userns_uid_range(const char *s, uid_t *ret_uid_shift, uid_t *ret_uid_range);
|
||||
|
|
|
@ -514,7 +514,7 @@ static int get_process_link_contents(pid_t pid, const char *proc_file, char **re
|
|||
p = procfs_file_alloca(pid, proc_file);
|
||||
|
||||
r = readlink_malloc(p, ret);
|
||||
return r == -ENOENT ? -ESRCH : r;
|
||||
return (r == -ENOENT && proc_mounted() > 0) ? -ESRCH : r;
|
||||
}
|
||||
|
||||
int get_process_exe(pid_t pid, char **ret) {
|
||||
|
@ -1309,7 +1309,7 @@ int opinionated_personality(unsigned long *ret) {
|
|||
if (current < 0)
|
||||
return current;
|
||||
|
||||
if (((unsigned long) current & 0xffff) == PER_LINUX32)
|
||||
if (((unsigned long) current & OPINIONATED_PERSONALITY_MASK) == PER_LINUX32)
|
||||
*ret = PER_LINUX32;
|
||||
else
|
||||
*ret = PER_LINUX;
|
||||
|
@ -1476,7 +1476,7 @@ static int fork_flags_to_signal(ForkFlags flags) {
|
|||
int safe_fork_full(
|
||||
const char *name,
|
||||
const int stdio_fds[3],
|
||||
const int except_fds[],
|
||||
int except_fds[],
|
||||
size_t n_except_fds,
|
||||
ForkFlags flags,
|
||||
pid_t *ret_pid) {
|
||||
|
@ -1705,6 +1705,19 @@ int safe_fork_full(
|
|||
}
|
||||
}
|
||||
|
||||
if (flags & FORK_PACK_FDS) {
|
||||
/* FORK_CLOSE_ALL_FDS ensures that except_fds are the only FDs >= 3 that are
|
||||
* open, this is including the log. This is required by pack_fds, which will
|
||||
* get stuck in an infinite loop of any FDs other than except_fds are open. */
|
||||
assert(FLAGS_SET(flags, FORK_CLOSE_ALL_FDS));
|
||||
|
||||
r = pack_fds(except_fds, n_except_fds);
|
||||
if (r < 0) {
|
||||
log_full_errno(prio, r, "Failed to pack file descriptors: %m");
|
||||
_exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
if (flags & FORK_CLOEXEC_OFF) {
|
||||
r = fd_cloexec_many(except_fds, n_except_fds, false);
|
||||
if (r < 0) {
|
||||
|
@ -1744,7 +1757,7 @@ int safe_fork_full(
|
|||
int pidref_safe_fork_full(
|
||||
const char *name,
|
||||
const int stdio_fds[3],
|
||||
const int except_fds[],
|
||||
int except_fds[],
|
||||
size_t n_except_fds,
|
||||
ForkFlags flags,
|
||||
PidRef *ret_pid) {
|
||||
|
@ -1768,7 +1781,7 @@ int pidref_safe_fork_full(
|
|||
int namespace_fork(
|
||||
const char *outer_name,
|
||||
const char *inner_name,
|
||||
const int except_fds[],
|
||||
int except_fds[],
|
||||
size_t n_except_fds,
|
||||
ForkFlags flags,
|
||||
int pidns_fd,
|
||||
|
|
|
@ -101,12 +101,17 @@ bool is_main_thread(void);
|
|||
bool oom_score_adjust_is_valid(int oa);
|
||||
|
||||
#ifndef PERSONALITY_INVALID
|
||||
/* personality(7) documents that 0xffffffffUL is used for querying the
|
||||
/* personality(2) documents that 0xFFFFFFFFUL is used for querying the
|
||||
* current personality, hence let's use that here as error
|
||||
* indicator. */
|
||||
#define PERSONALITY_INVALID 0xffffffffLU
|
||||
#define PERSONALITY_INVALID 0xFFFFFFFFUL
|
||||
#endif
|
||||
|
||||
/* The personality() syscall returns a 32-bit value where the top three bytes are reserved for flags that
|
||||
* emulate historical or architectural quirks, and only the least significant byte reflects the actual
|
||||
* personality we're interested in. */
|
||||
#define OPINIONATED_PERSONALITY_MASK 0xFFUL
|
||||
|
||||
unsigned long personality_from_string(const char *p);
|
||||
const char *personality_to_string(unsigned long);
|
||||
|
||||
|
@ -182,12 +187,13 @@ typedef enum ForkFlags {
|
|||
FORK_KEEP_NOTIFY_SOCKET = 1 << 17, /* Unless this specified, $NOTIFY_SOCKET will be unset. */
|
||||
FORK_DETACH = 1 << 18, /* Double fork if needed to ensure PID1/subreaper is parent */
|
||||
FORK_NEW_NETNS = 1 << 19, /* Run child in its own network namespace 💣 DO NOT USE IN THREADED PROGRAMS! 💣 */
|
||||
FORK_PACK_FDS = 1 << 20, /* Rearrange the passed FDs to be FD 3,4,5,etc. Updates the array in place (combine with FORK_CLOSE_ALL_FDS!) */
|
||||
} ForkFlags;
|
||||
|
||||
int safe_fork_full(
|
||||
const char *name,
|
||||
const int stdio_fds[3],
|
||||
const int except_fds[],
|
||||
int except_fds[],
|
||||
size_t n_except_fds,
|
||||
ForkFlags flags,
|
||||
pid_t *ret_pid);
|
||||
|
@ -199,7 +205,7 @@ static inline int safe_fork(const char *name, ForkFlags flags, pid_t *ret_pid) {
|
|||
int pidref_safe_fork_full(
|
||||
const char *name,
|
||||
const int stdio_fds[3],
|
||||
const int except_fds[],
|
||||
int except_fds[],
|
||||
size_t n_except_fds,
|
||||
ForkFlags flags,
|
||||
PidRef *ret_pid);
|
||||
|
@ -208,7 +214,18 @@ static inline int pidref_safe_fork(const char *name, ForkFlags flags, PidRef *re
|
|||
return pidref_safe_fork_full(name, NULL, NULL, 0, flags, ret_pid);
|
||||
}
|
||||
|
||||
int namespace_fork(const char *outer_name, const char *inner_name, const int except_fds[], size_t n_except_fds, ForkFlags flags, int pidns_fd, int mntns_fd, int netns_fd, int userns_fd, int root_fd, pid_t *ret_pid);
|
||||
int namespace_fork(
|
||||
const char *outer_name,
|
||||
const char *inner_name,
|
||||
int except_fds[],
|
||||
size_t n_except_fds,
|
||||
ForkFlags flags,
|
||||
int pidns_fd,
|
||||
int mntns_fd,
|
||||
int netns_fd,
|
||||
int userns_fd,
|
||||
int root_fd,
|
||||
pid_t *ret_pid);
|
||||
|
||||
int set_oom_score_adjust(int value);
|
||||
int get_oom_score_adjust(int *ret);
|
||||
|
|
|
@ -21,7 +21,7 @@ int reset_all_signal_handlers(void) {
|
|||
.sa_handler = SIG_DFL,
|
||||
.sa_flags = SA_RESTART,
|
||||
};
|
||||
int r = 0;
|
||||
int ret = 0, r;
|
||||
|
||||
for (int sig = 1; sig < _NSIG; sig++) {
|
||||
|
||||
|
@ -29,14 +29,14 @@ int reset_all_signal_handlers(void) {
|
|||
if (IN_SET(sig, SIGKILL, SIGSTOP))
|
||||
continue;
|
||||
|
||||
/* On Linux the first two RT signals are reserved by
|
||||
* glibc, and sigaction() will return EINVAL for them. */
|
||||
if (sigaction(sig, &sa, NULL) < 0)
|
||||
if (errno != EINVAL && r >= 0)
|
||||
r = -errno;
|
||||
/* On Linux the first two RT signals are reserved by glibc, and sigaction() will return
|
||||
* EINVAL for them. */
|
||||
r = RET_NERRNO(sigaction(sig, &sa, NULL));
|
||||
if (r != -EINVAL)
|
||||
RET_GATHER(ret, r);
|
||||
}
|
||||
|
||||
return r;
|
||||
return ret;
|
||||
}
|
||||
|
||||
int reset_signal_mask(void) {
|
||||
|
@ -60,10 +60,7 @@ int sigaction_many_internal(const struct sigaction *sa, ...) {
|
|||
if (sig == 0)
|
||||
continue;
|
||||
|
||||
if (sigaction(sig, sa, NULL) < 0) {
|
||||
if (r >= 0)
|
||||
r = -errno;
|
||||
}
|
||||
RET_GATHER(r, RET_NERRNO(sigaction(sig, sa, NULL)));
|
||||
}
|
||||
|
||||
va_end(ap);
|
||||
|
@ -90,7 +87,7 @@ static int sigset_add_many_ap(sigset_t *ss, va_list ap) {
|
|||
return r;
|
||||
}
|
||||
|
||||
int sigset_add_many(sigset_t *ss, ...) {
|
||||
int sigset_add_many_internal(sigset_t *ss, ...) {
|
||||
va_list ap;
|
||||
int r;
|
||||
|
||||
|
@ -101,7 +98,7 @@ int sigset_add_many(sigset_t *ss, ...) {
|
|||
return r;
|
||||
}
|
||||
|
||||
int sigprocmask_many(int how, sigset_t *old, ...) {
|
||||
int sigprocmask_many_internal(int how, sigset_t *old, ...) {
|
||||
va_list ap;
|
||||
sigset_t ss;
|
||||
int r;
|
||||
|
@ -116,10 +113,7 @@ int sigprocmask_many(int how, sigset_t *old, ...) {
|
|||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (sigprocmask(how, &ss, old) < 0)
|
||||
return -errno;
|
||||
|
||||
return 0;
|
||||
return RET_NERRNO(sigprocmask(how, &ss, old));
|
||||
}
|
||||
|
||||
static const char *const static_signal_table[] = {
|
||||
|
|
|
@ -31,8 +31,11 @@ int sigaction_many_internal(const struct sigaction *sa, ...);
|
|||
#define sigaction_many(sa, ...) \
|
||||
sigaction_many_internal(sa, __VA_ARGS__, -1)
|
||||
|
||||
int sigset_add_many(sigset_t *ss, ...);
|
||||
int sigprocmask_many(int how, sigset_t *old, ...);
|
||||
int sigset_add_many_internal(sigset_t *ss, ...);
|
||||
#define sigset_add_many(...) sigset_add_many_internal(__VA_ARGS__, -1)
|
||||
|
||||
int sigprocmask_many_internal(int how, sigset_t *old, ...);
|
||||
#define sigprocmask_many(...) sigprocmask_many_internal(__VA_ARGS__, -1)
|
||||
|
||||
const char *signal_to_string(int i) _const_;
|
||||
int signal_from_string(const char *s) _pure_;
|
||||
|
@ -46,7 +49,7 @@ static inline void block_signals_reset(sigset_t *ss) {
|
|||
#define BLOCK_SIGNALS(...) \
|
||||
_cleanup_(block_signals_reset) _unused_ sigset_t _saved_sigset = ({ \
|
||||
sigset_t _t; \
|
||||
assert_se(sigprocmask_many(SIG_BLOCK, &_t, __VA_ARGS__, -1) >= 0); \
|
||||
assert_se(sigprocmask_many(SIG_BLOCK, &_t, __VA_ARGS__) >= 0); \
|
||||
_t; \
|
||||
})
|
||||
|
||||
|
|
|
@ -27,46 +27,130 @@
|
|||
#include "stat-util.h"
|
||||
#include "string-util.h"
|
||||
|
||||
#if 0 /* NM_IGNORED */
|
||||
int is_symlink(const char *path) {
|
||||
struct stat info;
|
||||
|
||||
assert(path);
|
||||
|
||||
if (lstat(path, &info) < 0)
|
||||
return -errno;
|
||||
|
||||
return !!S_ISLNK(info.st_mode);
|
||||
}
|
||||
#endif /* NM_IGNORED */
|
||||
|
||||
int is_dir_full(int atfd, const char* path, bool follow) {
|
||||
static int verify_stat_at(
|
||||
int fd,
|
||||
const char *path,
|
||||
bool follow,
|
||||
int (*verify_func)(const struct stat *st),
|
||||
bool verify) {
|
||||
struct stat st;
|
||||
int r;
|
||||
|
||||
assert(atfd >= 0 || atfd == AT_FDCWD);
|
||||
assert(atfd >= 0 || path);
|
||||
assert(fd >= 0 || fd == AT_FDCWD);
|
||||
assert(!isempty(path) || !follow);
|
||||
assert(verify_func);
|
||||
|
||||
if (path)
|
||||
r = fstatat(atfd, path, &st, follow ? 0 : AT_SYMLINK_NOFOLLOW);
|
||||
else
|
||||
r = fstat(atfd, &st);
|
||||
if (r < 0)
|
||||
if (fstatat(fd, strempty(path), &st,
|
||||
(isempty(path) ? AT_EMPTY_PATH : 0) | (follow ? 0 : AT_SYMLINK_NOFOLLOW)) < 0)
|
||||
return -errno;
|
||||
|
||||
return !!S_ISDIR(st.st_mode);
|
||||
r = verify_func(&st);
|
||||
return verify ? r : r >= 0;
|
||||
}
|
||||
|
||||
int stat_verify_regular(const struct stat *st) {
|
||||
assert(st);
|
||||
|
||||
/* Checks whether the specified stat() structure refers to a regular file. If not returns an
|
||||
* appropriate error code. */
|
||||
|
||||
if (S_ISDIR(st->st_mode))
|
||||
return -EISDIR;
|
||||
|
||||
if (S_ISLNK(st->st_mode))
|
||||
return -ELOOP;
|
||||
|
||||
if (!S_ISREG(st->st_mode))
|
||||
return -EBADFD;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int verify_regular_at(int fd, const char *path, bool follow) {
|
||||
return verify_stat_at(fd, path, follow, stat_verify_regular, true);
|
||||
}
|
||||
|
||||
int fd_verify_regular(int fd) {
|
||||
assert(fd >= 0);
|
||||
return verify_regular_at(fd, NULL, false);
|
||||
}
|
||||
|
||||
int stat_verify_directory(const struct stat *st) {
|
||||
assert(st);
|
||||
|
||||
if (S_ISLNK(st->st_mode))
|
||||
return -ELOOP;
|
||||
|
||||
if (!S_ISDIR(st->st_mode))
|
||||
return -ENOTDIR;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int fd_verify_directory(int fd) {
|
||||
assert(fd >= 0);
|
||||
return verify_stat_at(fd, NULL, false, stat_verify_directory, true);
|
||||
}
|
||||
|
||||
int is_dir_at(int fd, const char *path, bool follow) {
|
||||
return verify_stat_at(fd, path, follow, stat_verify_directory, false);
|
||||
}
|
||||
|
||||
int is_dir(const char *path, bool follow) {
|
||||
assert(!isempty(path));
|
||||
return is_dir_at(AT_FDCWD, path, follow);
|
||||
}
|
||||
|
||||
int stat_verify_symlink(const struct stat *st) {
|
||||
assert(st);
|
||||
|
||||
if (S_ISDIR(st->st_mode))
|
||||
return -EISDIR;
|
||||
|
||||
if (!S_ISLNK(st->st_mode))
|
||||
return -ENOLINK;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int is_symlink(const char *path) {
|
||||
assert(!isempty(path));
|
||||
return verify_stat_at(AT_FDCWD, path, false, stat_verify_symlink, false);
|
||||
}
|
||||
|
||||
int stat_verify_linked(const struct stat *st) {
|
||||
assert(st);
|
||||
|
||||
if (st->st_nlink <= 0)
|
||||
return -EIDRM; /* recognizable error. */
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int fd_verify_linked(int fd) {
|
||||
assert(fd >= 0);
|
||||
return verify_stat_at(fd, NULL, false, stat_verify_linked, true);
|
||||
}
|
||||
|
||||
int stat_verify_device_node(const struct stat *st) {
|
||||
assert(st);
|
||||
|
||||
if (S_ISLNK(st->st_mode))
|
||||
return -ELOOP;
|
||||
|
||||
if (S_ISDIR(st->st_mode))
|
||||
return -EISDIR;
|
||||
|
||||
if (!S_ISBLK(st->st_mode) && !S_ISCHR(st->st_mode))
|
||||
return -ENOTTY;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if 0 /* NM_IGNORED */
|
||||
int is_device_node(const char *path) {
|
||||
struct stat info;
|
||||
|
||||
assert(path);
|
||||
|
||||
if (lstat(path, &info) < 0)
|
||||
return -errno;
|
||||
|
||||
return !!(S_ISBLK(info.st_mode) || S_ISCHR(info.st_mode));
|
||||
assert(!isempty(path));
|
||||
return verify_stat_at(AT_FDCWD, path, false, stat_verify_device_node, false);
|
||||
}
|
||||
|
||||
int dir_is_empty_at(int dir_fd, const char *path, bool ignore_hidden_or_backup) {
|
||||
|
@ -268,72 +352,6 @@ int path_is_network_fs(const char *path) {
|
|||
}
|
||||
#endif /* NM_IGNORED */
|
||||
|
||||
int stat_verify_regular(const struct stat *st) {
|
||||
assert(st);
|
||||
|
||||
/* Checks whether the specified stat() structure refers to a regular file. If not returns an appropriate error
|
||||
* code. */
|
||||
|
||||
if (S_ISDIR(st->st_mode))
|
||||
return -EISDIR;
|
||||
|
||||
if (S_ISLNK(st->st_mode))
|
||||
return -ELOOP;
|
||||
|
||||
if (!S_ISREG(st->st_mode))
|
||||
return -EBADFD;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int fd_verify_regular(int fd) {
|
||||
struct stat st;
|
||||
|
||||
assert(fd >= 0);
|
||||
|
||||
if (fstat(fd, &st) < 0)
|
||||
return -errno;
|
||||
|
||||
return stat_verify_regular(&st);
|
||||
}
|
||||
|
||||
#if 0 /* NM_IGNORED */
|
||||
int verify_regular_at(int dir_fd, const char *path, bool follow) {
|
||||
struct stat st;
|
||||
|
||||
assert(dir_fd >= 0 || dir_fd == AT_FDCWD);
|
||||
assert(path);
|
||||
|
||||
if (fstatat(dir_fd, path, &st, (isempty(path) ? AT_EMPTY_PATH : 0) | (follow ? 0 : AT_SYMLINK_NOFOLLOW)) < 0)
|
||||
return -errno;
|
||||
|
||||
return stat_verify_regular(&st);
|
||||
}
|
||||
|
||||
int stat_verify_directory(const struct stat *st) {
|
||||
assert(st);
|
||||
|
||||
if (S_ISLNK(st->st_mode))
|
||||
return -ELOOP;
|
||||
|
||||
if (!S_ISDIR(st->st_mode))
|
||||
return -ENOTDIR;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int fd_verify_directory(int fd) {
|
||||
struct stat st;
|
||||
|
||||
assert(fd >= 0);
|
||||
|
||||
if (fstat(fd, &st) < 0)
|
||||
return -errno;
|
||||
|
||||
return stat_verify_directory(&st);
|
||||
}
|
||||
#endif /* NM_IGNORED */
|
||||
|
||||
int proc_mounted(void) {
|
||||
int r;
|
||||
|
||||
|
@ -480,7 +498,7 @@ int xstatfsat(int dir_fd, const char *path, struct statfs *ret) {
|
|||
assert(dir_fd >= 0 || dir_fd == AT_FDCWD);
|
||||
assert(ret);
|
||||
|
||||
fd = xopenat(dir_fd, path, O_PATH|O_CLOEXEC|O_NOCTTY, /* xopen_flags = */ 0, /* mode = */ 0);
|
||||
fd = xopenat(dir_fd, path, O_PATH|O_CLOEXEC|O_NOCTTY);
|
||||
if (fd < 0)
|
||||
return fd;
|
||||
|
||||
|
|
|
@ -14,14 +14,22 @@
|
|||
#include "siphash24.h"
|
||||
#include "time-util.h"
|
||||
|
||||
int stat_verify_regular(const struct stat *st);
|
||||
int verify_regular_at(int fd, const char *path, bool follow);
|
||||
int fd_verify_regular(int fd);
|
||||
|
||||
int stat_verify_directory(const struct stat *st);
|
||||
int fd_verify_directory(int fd);
|
||||
int is_dir_at(int fd, const char *path, bool follow);
|
||||
int is_dir(const char *path, bool follow);
|
||||
|
||||
int stat_verify_symlink(const struct stat *st);
|
||||
int is_symlink(const char *path);
|
||||
int is_dir_full(int atfd, const char *fname, bool follow);
|
||||
static inline int is_dir(const char *path, bool follow) {
|
||||
return is_dir_full(AT_FDCWD, path, follow);
|
||||
}
|
||||
static inline int is_dir_fd(int fd) {
|
||||
return is_dir_full(fd, NULL, false);
|
||||
}
|
||||
|
||||
int stat_verify_linked(const struct stat *st);
|
||||
int fd_verify_linked(int fd);
|
||||
|
||||
int stat_verify_device_node(const struct stat *st);
|
||||
int is_device_node(const char *path);
|
||||
|
||||
int dir_is_empty_at(int dir_fd, const char *path, bool ignore_hidden_or_backup);
|
||||
|
@ -72,13 +80,6 @@ int path_is_network_fs(const char *path);
|
|||
*/
|
||||
#define F_TYPE_EQUAL(a, b) (a == (typeof(a)) b)
|
||||
|
||||
int stat_verify_regular(const struct stat *st);
|
||||
int fd_verify_regular(int fd);
|
||||
int verify_regular_at(int dir_fd, const char *path, bool follow);
|
||||
|
||||
int stat_verify_directory(const struct stat *st);
|
||||
int fd_verify_directory(int fd);
|
||||
|
||||
int proc_mounted(void);
|
||||
|
||||
bool stat_inode_same(const struct stat *a, const struct stat *b);
|
||||
|
|
|
@ -625,6 +625,9 @@ char *cellescape(char *buf, size_t len, const char *s) {
|
|||
char* strshorten(char *s, size_t l) {
|
||||
assert(s);
|
||||
|
||||
if (l >= SIZE_MAX-1) /* Would not change anything */
|
||||
return s;
|
||||
|
||||
if (strnlen(s, l+1) > l)
|
||||
s[l] = 0;
|
||||
|
||||
|
|
|
@ -363,7 +363,7 @@ int strv_split_colon_pairs(char ***t, const char *s) {
|
|||
|
||||
const char *p = tuple;
|
||||
r = extract_many_words(&p, ":", EXTRACT_CUNESCAPE|EXTRACT_UNESCAPE_SEPARATORS,
|
||||
&first, &second, NULL);
|
||||
&first, &second);
|
||||
if (r < 0)
|
||||
return r;
|
||||
if (r == 0)
|
||||
|
|
|
@ -1434,7 +1434,7 @@ static int get_timezones_from_zone1970_tab(char ***ret) {
|
|||
|
||||
/* Line format is:
|
||||
* 'country codes' 'coordinates' 'timezone' 'comments' */
|
||||
r = extract_many_words(&p, NULL, 0, &cc, &co, &tz, NULL);
|
||||
r = extract_many_words(&p, NULL, 0, &cc, &co, &tz);
|
||||
if (r < 0)
|
||||
continue;
|
||||
|
||||
|
@ -1479,7 +1479,7 @@ static int get_timezones_from_tzdata_zi(char ***ret) {
|
|||
* Link line format is:
|
||||
* 'Link' 'target' 'alias'
|
||||
* See 'man zic' for more detail. */
|
||||
r = extract_many_words(&p, NULL, 0, &type, &f1, &f2, NULL);
|
||||
r = extract_many_words(&p, NULL, 0, &type, &f1, &f2);
|
||||
if (r < 0)
|
||||
continue;
|
||||
|
||||
|
@ -1579,7 +1579,7 @@ int verify_timezone(const char *name, int log_level) {
|
|||
|
||||
r = fd_verify_regular(fd);
|
||||
if (r < 0)
|
||||
return log_full_errno(log_level, r, "Timezone file '%s' is not a regular file: %m", t);
|
||||
return log_full_errno(log_level, r, "Timezone file '%s' is not a regular file: %m", t);
|
||||
|
||||
r = loop_read_exact(fd, buf, 4, false);
|
||||
if (r < 0)
|
||||
|
|
|
@ -264,6 +264,30 @@
|
|||
})
|
||||
#endif /* NM_IGNORED */
|
||||
|
||||
#define ADD_SAFE(ret, a, b) (!__builtin_add_overflow(a, b, ret))
|
||||
#define INC_SAFE(a, b) __INC_SAFE(UNIQ, a, b)
|
||||
#define __INC_SAFE(q, a, b) \
|
||||
({ \
|
||||
const typeof(a) UNIQ_T(A, q) = (a); \
|
||||
ADD_SAFE(UNIQ_T(A, q), *UNIQ_T(A, q), b); \
|
||||
})
|
||||
|
||||
#define SUB_SAFE(ret, a, b) (!__builtin_sub_overflow(a, b, ret))
|
||||
#define DEC_SAFE(a, b) __DEC_SAFE(UNIQ, a, b)
|
||||
#define __DEC_SAFE(q, a, b) \
|
||||
({ \
|
||||
const typeof(a) UNIQ_T(A, q) = (a); \
|
||||
SUB_SAFE(UNIQ_T(A, q), *UNIQ_T(A, q), b); \
|
||||
})
|
||||
|
||||
#define MUL_SAFE(ret, a, b) (!__builtin_mul_overflow(a, b, ret))
|
||||
#define MUL_ASSIGN_SAFE(a, b) __MUL_ASSIGN_SAFE(UNIQ, a, b)
|
||||
#define __MUL_ASSIGN_SAFE(q, a, b) \
|
||||
({ \
|
||||
const typeof(a) UNIQ_T(A, q) = (a); \
|
||||
MUL_SAFE(UNIQ_T(A, q), *UNIQ_T(A, q), b); \
|
||||
})
|
||||
|
||||
#define LESS_BY(a, b) __LESS_BY(UNIQ, (a), UNIQ, (b))
|
||||
#define __LESS_BY(aq, a, bq, b) \
|
||||
({ \
|
||||
|
@ -313,7 +337,7 @@
|
|||
const typeof(y) UNIQ_T(A, q) = (y); \
|
||||
const typeof(x) UNIQ_T(B, q) = DIV_ROUND_UP((x), UNIQ_T(A, q)); \
|
||||
typeof(x) UNIQ_T(C, q); \
|
||||
__builtin_mul_overflow(UNIQ_T(B, q), UNIQ_T(A, q), &UNIQ_T(C, q)) ? (typeof(x)) -1 : UNIQ_T(C, q); \
|
||||
MUL_SAFE(&UNIQ_T(C, q), UNIQ_T(B, q), UNIQ_T(A, q)) ? UNIQ_T(C, q) : (typeof(x)) -1; \
|
||||
})
|
||||
#define ROUND_UP(x, y) __ROUND_UP(UNIQ, (x), (y))
|
||||
|
||||
|
|
Loading…
Reference in a new issue