mirror of
https://gitlab.freedesktop.org/NetworkManager/NetworkManager
synced 2024-10-01 13:55:36 +00:00
systemd: merge branch systemd into master
This commit is contained in:
commit
be8f7b5a5d
|
@ -1662,7 +1662,6 @@ shared_systemd_libnm_systemd_shared_la_SOURCES = \
|
|||
shared/systemd/sd-adapt-shared/device-nodes.h \
|
||||
shared/systemd/sd-adapt-shared/dirent-util.h \
|
||||
shared/systemd/sd-adapt-shared/errno-list.h \
|
||||
shared/systemd/sd-adapt-shared/format-util.h \
|
||||
shared/systemd/sd-adapt-shared/glob-util.h \
|
||||
shared/systemd/sd-adapt-shared/gunicode.h \
|
||||
shared/systemd/sd-adapt-shared/ioprio.h \
|
||||
|
@ -1702,6 +1701,8 @@ shared_systemd_libnm_systemd_shared_la_SOURCES = \
|
|||
shared/systemd/src/basic/fd-util.h \
|
||||
shared/systemd/src/basic/fileio.c \
|
||||
shared/systemd/src/basic/fileio.h \
|
||||
shared/systemd/src/basic/format-util.c \
|
||||
shared/systemd/src/basic/format-util.h \
|
||||
shared/systemd/src/basic/fs-util.c \
|
||||
shared/systemd/src/basic/fs-util.h \
|
||||
shared/systemd/src/basic/hash-funcs.c \
|
||||
|
|
|
@ -118,14 +118,26 @@
|
|||
/* Define to 1 if libsystemd-login is available */
|
||||
#mesondefine SESSION_TRACKING_SYSTEMD
|
||||
|
||||
/* The size of `pid_t', as computed by sizeof. */
|
||||
#mesondefine SIZEOF_PID_T
|
||||
|
||||
/* The size of `uid_t', as computed by sizeof. */
|
||||
#mesondefine SIZEOF_UID_T
|
||||
|
||||
/* The size of `gid_t', as computed by sizeof. */
|
||||
#mesondefine SIZEOF_GID_T
|
||||
|
||||
/* The size of `dev_t', as computed by sizeof. */
|
||||
#mesondefine SIZEOF_DEV_T
|
||||
|
||||
/* The size of `ino_t', as computed by sizeof. */
|
||||
#mesondefine SIZEOF_INO_T
|
||||
|
||||
/* The size of `time_t', as computed by sizeof. */
|
||||
#mesondefine SIZEOF_TIME_T
|
||||
|
||||
/* The size of `pid_t', as computed by sizeof. */
|
||||
#mesondefine SIZEOF_PID_T
|
||||
/* The size of `rlim_t', as computed by sizeof. */
|
||||
#mesondefine SIZEOF_RLIM_T
|
||||
|
||||
/* Define to 1 to use ConsoleKit2 suspend api */
|
||||
#mesondefine SUSPEND_RESUME_CONSOLEKIT
|
||||
|
|
|
@ -65,9 +65,13 @@ dnl
|
|||
dnl Checks for typedefs, structures, and compiler characteristics.
|
||||
dnl
|
||||
AC_TYPE_PID_T
|
||||
AC_CHECK_SIZEOF(dev_t)
|
||||
AC_CHECK_SIZEOF(time_t)
|
||||
AC_CHECK_SIZEOF(pid_t)
|
||||
AC_CHECK_SIZEOF(uid_t)
|
||||
AC_CHECK_SIZEOF(gid_t)
|
||||
AC_CHECK_SIZEOF(dev_t)
|
||||
AC_CHECK_SIZEOF(ino_t)
|
||||
AC_CHECK_SIZEOF(time_t)
|
||||
AC_CHECK_SIZEOF(rlim_t,,[[#include <sys/resource.h>]])
|
||||
|
||||
AC_CHECK_DECLS([
|
||||
explicit_bzero],
|
||||
|
|
10
meson.build
10
meson.build
|
@ -98,9 +98,13 @@ config_h.set10('HAVE_DECL_EXPLICIT_BZERO', cc.has_function('explicit_bzero', pre
|
|||
config_h.set10('HAVE_DECL_MEMFD_CREATE', cc.has_function('memfd_create', prefix: '#include <sys/mman.h>'))
|
||||
|
||||
# types
|
||||
config_h.set('SIZEOF_DEV_T', cc.sizeof('dev_t', prefix: '#include <sys/types.h>'))
|
||||
config_h.set('SIZEOF_TIME_T', cc.sizeof('time_t', prefix: '#include <sys/types.h>'))
|
||||
config_h.set('SIZEOF_PID_T', cc.sizeof('pid_t', prefix: '#include <sys/types.h>'))
|
||||
config_h.set('SIZEOF_PID_T', cc.sizeof('pid_t', prefix : '#include <sys/types.h>'))
|
||||
config_h.set('SIZEOF_UID_T', cc.sizeof('uid_t', prefix : '#include <sys/types.h>'))
|
||||
config_h.set('SIZEOF_GID_T', cc.sizeof('gid_t', prefix : '#include <sys/types.h>'))
|
||||
config_h.set('SIZEOF_DEV_T', cc.sizeof('dev_t', prefix : '#include <sys/types.h>'))
|
||||
config_h.set('SIZEOF_INO_T', cc.sizeof('ino_t', prefix : '#include <sys/types.h>'))
|
||||
config_h.set('SIZEOF_TIME_T', cc.sizeof('time_t', prefix : '#include <sys/time.h>'))
|
||||
config_h.set('SIZEOF_RLIM_T', cc.sizeof('rlim_t', prefix : '#include <sys/resource.h>'))
|
||||
|
||||
if not cc.has_type('pid_t', prefix: '#include <sys/types.h>')
|
||||
config_h.set('pid_t', 'int')
|
||||
|
|
|
@ -214,6 +214,7 @@ libnm_systemd_shared = static_library(
|
|||
'systemd/src/basic/extract-word.c',
|
||||
'systemd/src/basic/fd-util.c',
|
||||
'systemd/src/basic/fileio.c',
|
||||
'systemd/src/basic/format-util.c',
|
||||
'systemd/src/basic/fs-util.c',
|
||||
'systemd/src/basic/hash-funcs.c',
|
||||
'systemd/src/basic/hashmap.c',
|
||||
|
|
|
@ -75,7 +75,7 @@ bool env_value_is_valid(const char *e) {
|
|||
* either. Discounting the shortest possible variable name of
|
||||
* length 1, the equal sign and trailing NUL this hence leaves
|
||||
* ARG_MAX-3 as longest possible variable value. */
|
||||
if (strlen(e) > (size_t) sysconf(_SC_ARG_MAX) - 3)
|
||||
if (strlen(e) > sc_arg_max() - 3)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
|
@ -98,7 +98,7 @@ bool env_assignment_is_valid(const char *e) {
|
|||
* be > ARG_MAX, hence the individual variable assignments
|
||||
* cannot be either, but let's leave room for one trailing NUL
|
||||
* byte. */
|
||||
if (strlen(e) > (size_t) sysconf(_SC_ARG_MAX) - 1)
|
||||
if (strlen(e) > sc_arg_max() - 1)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
|
@ -691,7 +691,7 @@ char **replace_env_argv(char **argv, char **env) {
|
|||
if (e) {
|
||||
int r;
|
||||
|
||||
r = strv_split_extract(&m, e, WHITESPACE, EXTRACT_RELAX|EXTRACT_QUOTES);
|
||||
r = strv_split_extract(&m, e, WHITESPACE, EXTRACT_RELAX|EXTRACT_UNQUOTE);
|
||||
if (r < 0) {
|
||||
ret[k] = NULL;
|
||||
strv_free(ret);
|
||||
|
|
|
@ -4,10 +4,17 @@
|
|||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "macro.h"
|
||||
#include "string.h"
|
||||
|
||||
static inline size_t sc_arg_max(void) {
|
||||
long l = sysconf(_SC_ARG_MAX);
|
||||
assert(l > 0);
|
||||
return (size_t) l;
|
||||
}
|
||||
|
||||
bool env_name_is_valid(const char *e);
|
||||
bool env_value_is_valid(const char *e);
|
||||
bool env_assignment_is_valid(const char *e);
|
||||
|
|
|
@ -370,35 +370,82 @@ int cunescape(const char *s, UnescapeFlags flags, char **ret) {
|
|||
return cunescape_length(s, strlen(s), flags, ret);
|
||||
}
|
||||
|
||||
char *xescape(const char *s, const char *bad) {
|
||||
char *r, *t;
|
||||
#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;
|
||||
|
||||
/* Escapes all chars in bad, in addition to \ and all special
|
||||
* chars, in \xFF style escaping. May be reversed with
|
||||
* cunescape(). */
|
||||
/* Escapes all chars in bad, in addition to \ and all special chars, in \xFF style escaping. May be
|
||||
* reversed with cunescape(). If eight_bits is true, characters >= 127 are let through unchanged.
|
||||
* This corresponds to non-ASCII printable characters in pre-unicode encodings.
|
||||
*
|
||||
* If console_width is reached, output is truncated and "..." is appended. */
|
||||
|
||||
r = new(char, strlen(s) * 4 + 1);
|
||||
if (!r)
|
||||
if (console_width == 0)
|
||||
return strdup("");
|
||||
|
||||
ans = new(char, MIN(strlen(s), console_width) * 4 + 1);
|
||||
if (!ans)
|
||||
return NULL;
|
||||
|
||||
for (f = s, t = r; *f; f++) {
|
||||
memset(ans, '_', MIN(strlen(s), console_width) * 4);
|
||||
ans[MIN(strlen(s), console_width) * 4] = 0;
|
||||
|
||||
for (f = s, t = prev = prev2 = ans; ; f++) {
|
||||
char *tmp_t = t;
|
||||
|
||||
if (!*f) {
|
||||
*t = 0;
|
||||
return ans;
|
||||
}
|
||||
|
||||
if ((unsigned char) *f < ' ' || (!eight_bits && (unsigned char) *f >= 127) ||
|
||||
*f == '\\' || strchr(bad, *f)) {
|
||||
if ((size_t) (t - ans) + 4 > console_width)
|
||||
break;
|
||||
|
||||
if ((*f < ' ') || (*f >= 127) ||
|
||||
(*f == '\\') || strchr(bad, *f)) {
|
||||
*(t++) = '\\';
|
||||
*(t++) = 'x';
|
||||
*(t++) = hexchar(*f >> 4);
|
||||
*(t++) = hexchar(*f);
|
||||
} else
|
||||
} else {
|
||||
if ((size_t) (t - ans) + 1 > console_width)
|
||||
break;
|
||||
|
||||
*(t++) = *f;
|
||||
}
|
||||
|
||||
/* We might need to go back two cycles to fit three dots, so remember two positions */
|
||||
prev2 = prev;
|
||||
prev = tmp_t;
|
||||
}
|
||||
|
||||
*t = 0;
|
||||
/* We can just write where we want, since chars are one-byte */
|
||||
size_t c = MIN(console_width, 3u); /* If the console is too narrow, write fewer dots */
|
||||
size_t off;
|
||||
if (console_width - c >= (size_t) (t - ans))
|
||||
off = (size_t) (t - ans);
|
||||
else if (console_width - c >= (size_t) (prev - ans))
|
||||
off = (size_t) (prev - ans);
|
||||
else if (console_width - c >= (size_t) (prev2 - ans))
|
||||
off = (size_t) (prev2 - ans);
|
||||
else
|
||||
off = console_width - c;
|
||||
assert(off <= (size_t) (t - ans));
|
||||
|
||||
return r;
|
||||
memcpy(ans + off, "...", c);
|
||||
ans[off + c] = '\0';
|
||||
return ans;
|
||||
}
|
||||
|
||||
char *escape_non_printable_full(const char *str, size_t console_width, bool eight_bit) {
|
||||
if (eight_bit)
|
||||
return xescape_full(str, "", console_width, true);
|
||||
else
|
||||
return utf8_escape_non_printable_full(str, console_width);
|
||||
}
|
||||
#endif /* NM_IGNORED */
|
||||
|
||||
char *octescape(const char *s, size_t len) {
|
||||
char *r, *t;
|
||||
const char *f;
|
||||
|
|
|
@ -46,8 +46,12 @@ int cunescape_length(const char *s, size_t length, UnescapeFlags flags, char **r
|
|||
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);
|
||||
|
||||
char *xescape(const char *s, const char *bad);
|
||||
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) {
|
||||
return xescape_full(s, bad, SIZE_MAX, false);
|
||||
}
|
||||
char *octescape(const char *s, size_t len);
|
||||
char *escape_non_printable_full(const char *str, size_t console_width, bool eight_bit);
|
||||
|
||||
char *shell_escape(const char *s, const char *bad);
|
||||
char* shell_maybe_quote(const char *s, EscapeStyle style);
|
||||
|
|
|
@ -137,7 +137,7 @@ int extract_first_word(const char **p, char **ret, const char *separators, Extra
|
|||
for (;; (*p)++, c = **p) {
|
||||
if (c == 0)
|
||||
goto finish_force_terminate;
|
||||
else if (IN_SET(c, '\'', '"') && (flags & EXTRACT_QUOTES)) {
|
||||
else if (IN_SET(c, '\'', '"') && (flags & EXTRACT_UNQUOTE)) {
|
||||
quote = c;
|
||||
break;
|
||||
} else if (c == '\\' && !(flags & EXTRACT_RETAIN_ESCAPE)) {
|
||||
|
|
|
@ -7,7 +7,7 @@ typedef enum ExtractFlags {
|
|||
EXTRACT_RELAX = 1 << 0,
|
||||
EXTRACT_CUNESCAPE = 1 << 1,
|
||||
EXTRACT_CUNESCAPE_RELAX = 1 << 2,
|
||||
EXTRACT_QUOTES = 1 << 3,
|
||||
EXTRACT_UNQUOTE = 1 << 3,
|
||||
EXTRACT_DONT_COALESCE_SEPARATORS = 1 << 4,
|
||||
EXTRACT_RETAIN_ESCAPE = 1 << 5,
|
||||
} ExtractFlags;
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
#include "log.h"
|
||||
#include "macro.h"
|
||||
#include "missing.h"
|
||||
#include "mkdir.h"
|
||||
#include "parse-util.h"
|
||||
#include "path-util.h"
|
||||
#include "stdio-util.h"
|
||||
|
@ -177,6 +178,12 @@ int write_string_file_ts(
|
|||
/* We don't know how to verify whether the file contents was already on-disk. */
|
||||
assert(!((flags & WRITE_STRING_FILE_VERIFY_ON_FAILURE) && (flags & WRITE_STRING_FILE_SYNC)));
|
||||
|
||||
if (flags & WRITE_STRING_FILE_MKDIR_0755) {
|
||||
r = mkdir_parents(fn, 0755);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
if (flags & WRITE_STRING_FILE_ATOMIC) {
|
||||
assert(flags & WRITE_STRING_FILE_CREATE);
|
||||
|
||||
|
@ -589,10 +596,7 @@ static int search_and_fopen_internal(const char *path, const char *mode, const c
|
|||
_cleanup_free_ char *p = NULL;
|
||||
FILE *f;
|
||||
|
||||
if (root)
|
||||
p = strjoin(root, *i, "/", path);
|
||||
else
|
||||
p = strjoin(*i, "/", path);
|
||||
p = path_join(root, *i, path);
|
||||
if (!p)
|
||||
return -ENOMEM;
|
||||
|
||||
|
|
|
@ -21,6 +21,7 @@ typedef enum {
|
|||
WRITE_STRING_FILE_SYNC = 1 << 4,
|
||||
WRITE_STRING_FILE_DISABLE_BUFFER = 1 << 5,
|
||||
WRITE_STRING_FILE_NOFOLLOW = 1 << 6,
|
||||
WRITE_STRING_FILE_MKDIR_0755 = 1 << 7,
|
||||
|
||||
/* 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()
|
||||
|
|
72
shared/systemd/src/basic/format-util.c
Normal file
72
shared/systemd/src/basic/format-util.c
Normal file
|
@ -0,0 +1,72 @@
|
|||
/* SPDX-License-Identifier: LGPL-2.1+ */
|
||||
|
||||
#include "nm-sd-adapt-shared.h"
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include "format-util.h"
|
||||
#include "memory-util.h"
|
||||
|
||||
char *format_ifname(int ifindex, char buf[static IF_NAMESIZE + 1]) {
|
||||
/* Buffer is always cleared */
|
||||
memzero(buf, IF_NAMESIZE + 1);
|
||||
return if_indextoname(ifindex, buf);
|
||||
}
|
||||
|
||||
char *format_bytes_full(char *buf, size_t l, uint64_t t, FormatBytesFlag flag) {
|
||||
typedef struct {
|
||||
const char *suffix;
|
||||
uint64_t factor;
|
||||
} suffix_table;
|
||||
static const suffix_table table_iec[] = {
|
||||
{ "E", UINT64_C(1024)*UINT64_C(1024)*UINT64_C(1024)*UINT64_C(1024)*UINT64_C(1024)*UINT64_C(1024) },
|
||||
{ "P", UINT64_C(1024)*UINT64_C(1024)*UINT64_C(1024)*UINT64_C(1024)*UINT64_C(1024) },
|
||||
{ "T", UINT64_C(1024)*UINT64_C(1024)*UINT64_C(1024)*UINT64_C(1024) },
|
||||
{ "G", UINT64_C(1024)*UINT64_C(1024)*UINT64_C(1024) },
|
||||
{ "M", UINT64_C(1024)*UINT64_C(1024) },
|
||||
{ "K", UINT64_C(1024) },
|
||||
}, table_si[] = {
|
||||
{ "E", UINT64_C(1000)*UINT64_C(1000)*UINT64_C(1000)*UINT64_C(1000)*UINT64_C(1000)*UINT64_C(1000) },
|
||||
{ "P", UINT64_C(1000)*UINT64_C(1000)*UINT64_C(1000)*UINT64_C(1000)*UINT64_C(1000) },
|
||||
{ "T", UINT64_C(1000)*UINT64_C(1000)*UINT64_C(1000)*UINT64_C(1000) },
|
||||
{ "G", UINT64_C(1000)*UINT64_C(1000)*UINT64_C(1000) },
|
||||
{ "M", UINT64_C(1000)*UINT64_C(1000) },
|
||||
{ "K", UINT64_C(1000) },
|
||||
};
|
||||
const suffix_table *table;
|
||||
size_t n, i;
|
||||
|
||||
assert_cc(ELEMENTSOF(table_iec) == ELEMENTSOF(table_si));
|
||||
|
||||
if (t == (uint64_t) -1)
|
||||
return NULL;
|
||||
|
||||
table = flag & FORMAT_BYTES_USE_IEC ? table_iec : table_si;
|
||||
n = ELEMENTSOF(table_iec);
|
||||
|
||||
for (i = 0; i < n; i++)
|
||||
if (t >= table[i].factor) {
|
||||
if (flag & FORMAT_BYTES_BELOW_POINT) {
|
||||
snprintf(buf, l,
|
||||
"%" PRIu64 ".%" PRIu64 "%s",
|
||||
t / table[i].factor,
|
||||
i != n - 1 ?
|
||||
(t / table[i + 1].factor * UINT64_C(10) / table[n - 1].factor) % UINT64_C(10):
|
||||
(t * UINT64_C(10) / table[i].factor) % UINT64_C(10),
|
||||
table[i].suffix);
|
||||
} else
|
||||
snprintf(buf, l,
|
||||
"%" PRIu64 "%s",
|
||||
t / table[i].factor,
|
||||
table[i].suffix);
|
||||
|
||||
goto finish;
|
||||
}
|
||||
|
||||
snprintf(buf, l, "%" PRIu64 "%s", t, flag & FORMAT_BYTES_TRAILING_B ? "B" : "");
|
||||
|
||||
finish:
|
||||
buf[l-1] = 0;
|
||||
return buf;
|
||||
|
||||
}
|
83
shared/systemd/src/basic/format-util.h
Normal file
83
shared/systemd/src/basic/format-util.h
Normal file
|
@ -0,0 +1,83 @@
|
|||
/* SPDX-License-Identifier: LGPL-2.1+ */
|
||||
#pragma once
|
||||
|
||||
#include <inttypes.h>
|
||||
#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
|
||||
#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
|
||||
|
||||
#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
|
||||
|
||||
#if SIZEOF_TIME_T == 8
|
||||
# define PRI_TIME PRIi64
|
||||
#elif SIZEOF_TIME_T == 4
|
||||
# define PRI_TIME "li"
|
||||
#else
|
||||
# error Unknown time_t size
|
||||
#endif
|
||||
|
||||
#if defined __x86_64__ && defined __ILP32__
|
||||
# define PRI_TIMEX PRIi64
|
||||
#else
|
||||
# define PRI_TIMEX "li"
|
||||
#endif
|
||||
|
||||
#if SIZEOF_RLIM_T == 8
|
||||
# define RLIM_FMT "%" PRIu64
|
||||
#elif SIZEOF_RLIM_T == 4
|
||||
# define RLIM_FMT "%" PRIu32
|
||||
#else
|
||||
# error Unknown rlim_t size
|
||||
#endif
|
||||
|
||||
#if SIZEOF_DEV_T == 8
|
||||
# define DEV_FMT "%" PRIu64
|
||||
#elif SIZEOF_DEV_T == 4
|
||||
# define DEV_FMT "%" PRIu32
|
||||
#else
|
||||
# error Unknown dev_t size
|
||||
#endif
|
||||
|
||||
#if SIZEOF_INO_T == 8
|
||||
# define INO_FMT "%" PRIu64
|
||||
#elif SIZEOF_INO_T == 4
|
||||
# define INO_FMT "%" PRIu32
|
||||
#else
|
||||
# error Unknown ino_t size
|
||||
#endif
|
||||
|
||||
char *format_ifname(int ifindex, char buf[static IF_NAMESIZE + 1]);
|
||||
|
||||
typedef enum {
|
||||
FORMAT_BYTES_USE_IEC = 1 << 0,
|
||||
FORMAT_BYTES_BELOW_POINT = 1 << 1,
|
||||
FORMAT_BYTES_TRAILING_B = 1 << 2,
|
||||
} FormatBytesFlag;
|
||||
|
||||
#define FORMAT_BYTES_MAX 8
|
||||
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);
|
||||
}
|
|
@ -218,113 +218,65 @@ 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) {
|
||||
char fd_path[STRLEN("/proc/self/fd/") + DECIMAL_STR_MAX(int) + 1];
|
||||
_cleanup_close_ int fd = -1;
|
||||
bool st_valid = false;
|
||||
struct stat st;
|
||||
int r;
|
||||
|
||||
assert(path);
|
||||
|
||||
/* Under the assumption that we are running privileged we first change the access mode and only then
|
||||
* hand out ownership to avoid a window where access is too open. */
|
||||
|
||||
fd = open(path, O_PATH|O_CLOEXEC|O_NOFOLLOW); /* Let's acquire an O_PATH fd, as precaution to change
|
||||
* mode/owner on the same file */
|
||||
if (fd < 0)
|
||||
return -errno;
|
||||
|
||||
xsprintf(fd_path, "/proc/self/fd/%i", fd);
|
||||
|
||||
if (mode != MODE_INVALID) {
|
||||
if ((mode & S_IFMT) != 0) {
|
||||
|
||||
if (stat(fd_path, &st) < 0)
|
||||
return -errno;
|
||||
|
||||
if ((mode & S_IFMT) != (st.st_mode & S_IFMT))
|
||||
return -EINVAL;
|
||||
|
||||
st_valid = true;
|
||||
}
|
||||
|
||||
if (chmod(fd_path, mode & 07777) < 0) {
|
||||
r = -errno;
|
||||
|
||||
if (!st_valid && stat(fd_path, &st) < 0)
|
||||
return -errno;
|
||||
|
||||
if ((mode & 07777) != (st.st_mode & 07777))
|
||||
return r;
|
||||
|
||||
st_valid = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (uid != UID_INVALID || gid != GID_INVALID) {
|
||||
if (chown(fd_path, uid, gid) < 0) {
|
||||
r = -errno;
|
||||
|
||||
if (!st_valid && stat(fd_path, &st) < 0)
|
||||
return -errno;
|
||||
|
||||
if (uid != UID_INVALID && st.st_uid != uid)
|
||||
return r;
|
||||
if (gid != GID_INVALID && st.st_gid != gid)
|
||||
return r;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
return fchmod_and_chown(fd, mode, uid, gid);
|
||||
}
|
||||
|
||||
int fchmod_and_chown(int fd, mode_t mode, uid_t uid, gid_t gid) {
|
||||
bool st_valid = false;
|
||||
bool do_chown, do_chmod;
|
||||
struct stat st;
|
||||
int r;
|
||||
|
||||
/* Under the assumption that we are running privileged we first change the access mode and only then hand out
|
||||
* ownership to avoid a window where access is too open. */
|
||||
/* Change ownership and access mode of the specified fd. Tries to do so safely, ensuring that at no
|
||||
* point in time the access mode is above the old access mode under the old ownership or the new
|
||||
* access mode under the new ownership. Note: this call tries hard to leave the access mode
|
||||
* unaffected if the uid/gid is changed, i.e. it undoes implicit suid/sgid dropping the kernel does
|
||||
* on chown().
|
||||
*
|
||||
* This call is happy with O_PATH fds. */
|
||||
|
||||
if (mode != MODE_INVALID) {
|
||||
if ((mode & S_IFMT) != 0) {
|
||||
if (fstat(fd, &st) < 0)
|
||||
return -errno;
|
||||
|
||||
if (fstat(fd, &st) < 0)
|
||||
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 (fchmod_opath(fd, minimal & 07777) < 0)
|
||||
return -errno;
|
||||
|
||||
if ((mode & S_IFMT) != (st.st_mode & S_IFMT))
|
||||
return -EINVAL;
|
||||
|
||||
st_valid = true;
|
||||
}
|
||||
|
||||
if (fchmod(fd, mode & 07777) < 0) {
|
||||
r = -errno;
|
||||
|
||||
if (!st_valid && fstat(fd, &st) < 0)
|
||||
return -errno;
|
||||
|
||||
if ((mode & 07777) != (st.st_mode & 07777))
|
||||
return r;
|
||||
|
||||
st_valid = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (uid != UID_INVALID || gid != GID_INVALID)
|
||||
if (fchown(fd, uid, gid) < 0) {
|
||||
r = -errno;
|
||||
if (do_chown)
|
||||
if (fchownat(fd, "", uid, gid, AT_EMPTY_PATH) < 0)
|
||||
return -errno;
|
||||
|
||||
if (!st_valid && fstat(fd, &st) < 0)
|
||||
return -errno;
|
||||
if (do_chmod)
|
||||
if (fchmod_opath(fd, mode & 07777) < 0)
|
||||
return -errno;
|
||||
|
||||
if (uid != UID_INVALID && st.st_uid != uid)
|
||||
return r;
|
||||
if (gid != GID_INVALID && st.st_gid != gid)
|
||||
return r;
|
||||
}
|
||||
|
||||
return 0;
|
||||
return do_chown || do_chmod;
|
||||
}
|
||||
#endif /* NM_IGNORED */
|
||||
|
||||
|
@ -411,13 +363,7 @@ int touch_file(const char *path, bool parents, usec_t stamp, uid_t uid, gid_t gi
|
|||
* something fchown(), fchmod(), futimensat() don't allow. */
|
||||
xsprintf(fdpath, "/proc/self/fd/%i", fd);
|
||||
|
||||
if (mode != MODE_INVALID)
|
||||
if (chmod(fdpath, mode) < 0)
|
||||
ret = -errno;
|
||||
|
||||
if (uid_is_valid(uid) || gid_is_valid(gid))
|
||||
if (chown(fdpath, uid, gid) < 0 && ret >= 0)
|
||||
ret = -errno;
|
||||
ret = fchmod_and_chown(fd, mode, uid, gid);
|
||||
|
||||
if (stamp != USEC_INFINITY) {
|
||||
struct timespec ts[2];
|
||||
|
@ -1043,9 +989,9 @@ int chase_symlinks(const char *path, const char *original_root, unsigned flags,
|
|||
|
||||
/* Prefix what's left to do with what we just read, and start the loop again, but
|
||||
* remain in the current directory. */
|
||||
joined = strjoin(destination, todo);
|
||||
joined = path_join(destination, todo);
|
||||
} else
|
||||
joined = strjoin("/", destination, todo);
|
||||
joined = path_join("/", destination, todo);
|
||||
if (!joined)
|
||||
return -ENOMEM;
|
||||
|
||||
|
|
|
@ -7,12 +7,20 @@
|
|||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <sys/inotify.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "errno-util.h"
|
||||
#include "time-util.h"
|
||||
|
||||
#define MODE_INVALID ((mode_t) -1)
|
||||
|
||||
/* The following macros add 1 when converting things, since 0 is a valid mode, while the pointer
|
||||
* NULL is special */
|
||||
#define PTR_TO_MODE(p) ((mode_t) ((uintptr_t) (p)-1))
|
||||
#define MODE_TO_PTR(u) ((void *) ((uintptr_t) (u)+1))
|
||||
|
||||
int unlink_noerrno(const char *path);
|
||||
|
||||
int rmdir_parents(const char *path, const char *stop);
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
#include "macro.h"
|
||||
#include "memory-util.h"
|
||||
#include "mempool.h"
|
||||
#include "missing.h"
|
||||
#include "process-util.h"
|
||||
#include "random-util.h"
|
||||
#include "set.h"
|
||||
|
@ -287,7 +288,11 @@ _destructor_ static void cleanup_pools(void) {
|
|||
/* The pool is only allocated by the main thread, but the memory can
|
||||
* be passed to other threads. Let's clean up if we are the main thread
|
||||
* and no other threads are live. */
|
||||
if (!is_main_thread())
|
||||
/* We build our own is_main_thread() here, which doesn't use C11
|
||||
* TLS based caching of the result. That's because valgrind apparently
|
||||
* doesn't like malloc() (which C11 TLS internally uses) to be called
|
||||
* from a GCC destructors. */
|
||||
if (getpid() != gettid())
|
||||
return;
|
||||
|
||||
r = get_proc_field("/proc/self/status", "Threads", WHITESPACE, &t);
|
||||
|
|
|
@ -747,4 +747,16 @@ static int in_addr_data_compare_func(const struct in_addr_data *x, const struct
|
|||
}
|
||||
|
||||
DEFINE_HASH_OPS(in_addr_data_hash_ops, struct in_addr_data, in_addr_data_hash_func, in_addr_data_compare_func);
|
||||
|
||||
static void in6_addr_hash_func(const struct in6_addr *addr, struct siphash *state) {
|
||||
assert(addr);
|
||||
|
||||
siphash24_compress(addr, sizeof(*addr), state);
|
||||
}
|
||||
|
||||
static int in6_addr_compare_func(const struct in6_addr *a, const struct in6_addr *b) {
|
||||
return memcmp(a, b, sizeof(*a));
|
||||
}
|
||||
|
||||
DEFINE_HASH_OPS(in6_addr_hash_ops, struct in6_addr, in6_addr_hash_func, in6_addr_compare_func);
|
||||
#endif /* NM_IGNORED */
|
||||
|
|
|
@ -72,3 +72,4 @@ static inline size_t FAMILY_ADDRESS_SIZE(int family) {
|
|||
#define IN_ADDR_NULL ((union in_addr_union) { .in6 = {} })
|
||||
|
||||
extern const struct hash_ops in_addr_data_hash_ops;
|
||||
extern const struct hash_ops in6_addr_hash_ops;
|
||||
|
|
|
@ -269,4 +269,86 @@ char* set_iovec_string_field(struct iovec *iovec, size_t *n_iovec, const char *f
|
|||
iovec[(*n_iovec)++] = IOVEC_MAKE_STRING(x);
|
||||
return x;
|
||||
}
|
||||
|
||||
char* set_iovec_string_field_free(struct iovec *iovec, size_t *n_iovec, const char *field, char *value) {
|
||||
char *x;
|
||||
|
||||
x = set_iovec_string_field(iovec, n_iovec, field, value);
|
||||
free(value);
|
||||
return x;
|
||||
}
|
||||
|
||||
struct iovec_wrapper *iovw_new(void) {
|
||||
return malloc0(sizeof(struct iovec_wrapper));
|
||||
}
|
||||
|
||||
void iovw_free_contents(struct iovec_wrapper *iovw, bool free_vectors) {
|
||||
if (free_vectors)
|
||||
for (size_t i = 0; i < iovw->count; i++)
|
||||
free(iovw->iovec[i].iov_base);
|
||||
|
||||
iovw->iovec = mfree(iovw->iovec);
|
||||
iovw->count = 0;
|
||||
iovw->size_bytes = 0;
|
||||
}
|
||||
|
||||
struct iovec_wrapper *iovw_free_free(struct iovec_wrapper *iovw) {
|
||||
iovw_free_contents(iovw, true);
|
||||
|
||||
return mfree(iovw);
|
||||
}
|
||||
|
||||
struct iovec_wrapper *iovw_free(struct iovec_wrapper *iovw) {
|
||||
iovw_free_contents(iovw, false);
|
||||
|
||||
return mfree(iovw);
|
||||
}
|
||||
|
||||
int iovw_put(struct iovec_wrapper *iovw, void *data, size_t len) {
|
||||
if (iovw->count >= IOV_MAX)
|
||||
return -E2BIG;
|
||||
|
||||
if (!GREEDY_REALLOC(iovw->iovec, iovw->size_bytes, iovw->count + 1))
|
||||
return log_oom();
|
||||
|
||||
iovw->iovec[iovw->count++] = IOVEC_MAKE(data, len);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int iovw_put_string_field(struct iovec_wrapper *iovw, const char *field, const char *value) {
|
||||
_cleanup_free_ char *x = NULL;
|
||||
int r;
|
||||
|
||||
x = strappend(field, value);
|
||||
if (!x)
|
||||
return log_oom();
|
||||
|
||||
r = iovw_put(iovw, x, strlen(x));
|
||||
if (r >= 0)
|
||||
TAKE_PTR(x);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
int iovw_put_string_field_free(struct iovec_wrapper *iovw, const char *field, char *value) {
|
||||
_cleanup_free_ _unused_ char *free_ptr = value;
|
||||
|
||||
return iovw_put_string_field(iovw, field, value);
|
||||
}
|
||||
|
||||
void iovw_rebase(struct iovec_wrapper *iovw, char *old, char *new) {
|
||||
size_t i;
|
||||
|
||||
for (i = 0; i < iovw->count; i++)
|
||||
iovw->iovec[i].iov_base = (char *)iovw->iovec[i].iov_base - old + new;
|
||||
}
|
||||
|
||||
size_t iovw_size(struct iovec_wrapper *iovw) {
|
||||
size_t n = 0, i;
|
||||
|
||||
for (i = 0; i < iovw->count; i++)
|
||||
n += iovw->iovec[i].iov_len;
|
||||
|
||||
return n;
|
||||
}
|
||||
#endif /* NM_IGNORED */
|
||||
|
|
|
@ -73,3 +73,20 @@ static inline bool FILE_SIZE_VALID_OR_INFINITY(uint64_t l) {
|
|||
#define IOVEC_MAKE_STRING(string) (struct iovec) IOVEC_INIT_STRING(string)
|
||||
|
||||
char* set_iovec_string_field(struct iovec *iovec, size_t *n_iovec, const char *field, const char *value);
|
||||
char* set_iovec_string_field_free(struct iovec *iovec, size_t *n_iovec, const char *field, char *value);
|
||||
|
||||
struct iovec_wrapper {
|
||||
struct iovec *iovec;
|
||||
size_t count;
|
||||
size_t size_bytes;
|
||||
};
|
||||
|
||||
struct iovec_wrapper *iovw_new(void);
|
||||
struct iovec_wrapper *iovw_free(struct iovec_wrapper *iovw);
|
||||
struct iovec_wrapper *iovw_free_free(struct iovec_wrapper *iovw);
|
||||
void iovw_free_contents(struct iovec_wrapper *iovw, bool free_vectors);
|
||||
int iovw_put(struct iovec_wrapper *iovw, void *data, size_t len);
|
||||
int iovw_put_string_field(struct iovec_wrapper *iovw, const char *field, const char *value);
|
||||
int iovw_put_string_field_free(struct iovec_wrapper *iovw, const char *field, char *value);
|
||||
void iovw_rebase(struct iovec_wrapper *iovw, char *old, char *new);
|
||||
size_t iovw_size(struct iovec_wrapper *iovw);
|
||||
|
|
|
@ -37,8 +37,8 @@ static inline int memcmp_nn(const void *s1, size_t n1, const void *s2, size_t n2
|
|||
#define memzero(x,l) \
|
||||
({ \
|
||||
size_t _l_ = (l); \
|
||||
void *_x_ = (x); \
|
||||
_l_ == 0 ? _x_ : memset(_x_, 0, _l_); \
|
||||
if (_l_ > 0) \
|
||||
memset(x, 0, _l_); \
|
||||
})
|
||||
|
||||
#define zero(x) (memzero(&(x), sizeof(x)))
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
#include <inttypes.h>
|
||||
#include <linux/oom.h>
|
||||
#include <locale.h>
|
||||
#include <net/if.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
@ -86,6 +87,9 @@ int parse_mode(const char *s, mode_t *ret) {
|
|||
int parse_ifindex(const char *s, int *ret) {
|
||||
int ifi, r;
|
||||
|
||||
assert(s);
|
||||
assert(ret);
|
||||
|
||||
r = safe_atoi(s, &ifi);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
@ -96,6 +100,24 @@ int parse_ifindex(const char *s, int *ret) {
|
|||
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;
|
||||
}
|
||||
|
||||
int parse_mtu(int family, const char *s, uint32_t *ret) {
|
||||
uint64_t u;
|
||||
size_t m;
|
||||
|
@ -342,47 +364,6 @@ int parse_syscall_and_errno(const char *in, char **name, int *error) {
|
|||
|
||||
return 0;
|
||||
}
|
||||
|
||||
char *format_bytes(char *buf, size_t l, uint64_t t) {
|
||||
unsigned i;
|
||||
|
||||
/* This only does IEC units so far */
|
||||
|
||||
static const struct {
|
||||
const char *suffix;
|
||||
uint64_t factor;
|
||||
} table[] = {
|
||||
{ "E", UINT64_C(1024)*UINT64_C(1024)*UINT64_C(1024)*UINT64_C(1024)*UINT64_C(1024)*UINT64_C(1024) },
|
||||
{ "P", UINT64_C(1024)*UINT64_C(1024)*UINT64_C(1024)*UINT64_C(1024)*UINT64_C(1024) },
|
||||
{ "T", UINT64_C(1024)*UINT64_C(1024)*UINT64_C(1024)*UINT64_C(1024) },
|
||||
{ "G", UINT64_C(1024)*UINT64_C(1024)*UINT64_C(1024) },
|
||||
{ "M", UINT64_C(1024)*UINT64_C(1024) },
|
||||
{ "K", UINT64_C(1024) },
|
||||
};
|
||||
|
||||
if (t == (uint64_t) -1)
|
||||
return NULL;
|
||||
|
||||
for (i = 0; i < ELEMENTSOF(table); i++) {
|
||||
|
||||
if (t >= table[i].factor) {
|
||||
snprintf(buf, l,
|
||||
"%" PRIu64 ".%" PRIu64 "%s",
|
||||
t / table[i].factor,
|
||||
((t*UINT64_C(10)) / table[i].factor) % UINT64_C(10),
|
||||
table[i].suffix);
|
||||
|
||||
goto finish;
|
||||
}
|
||||
}
|
||||
|
||||
snprintf(buf, l, "%" PRIu64 "B", t);
|
||||
|
||||
finish:
|
||||
buf[l-1] = 0;
|
||||
return buf;
|
||||
|
||||
}
|
||||
#endif /* NM_IGNORED */
|
||||
|
||||
int safe_atou_full(const char *s, unsigned base, unsigned *ret_u) {
|
||||
|
|
|
@ -9,13 +9,12 @@
|
|||
|
||||
#include "macro.h"
|
||||
|
||||
#define MODE_INVALID ((mode_t) -1)
|
||||
|
||||
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_mtu(int family, const char *s, uint32_t *ret);
|
||||
|
||||
int parse_size(const char *t, uint64_t base, uint64_t *size);
|
||||
|
@ -23,9 +22,6 @@ int parse_range(const char *t, unsigned *lower, unsigned *upper);
|
|||
int parse_errno(const char *t);
|
||||
int parse_syscall_and_errno(const char *in, char **name, int *error);
|
||||
|
||||
#define FORMAT_BYTES_MAX 8
|
||||
char *format_bytes(char *buf, size_t l, uint64_t t);
|
||||
|
||||
int safe_atou_full(const char *s, unsigned base, unsigned *ret_u);
|
||||
|
||||
static inline int safe_atou(const char *s, unsigned *ret_u) {
|
||||
|
|
|
@ -71,10 +71,7 @@ char *path_make_absolute(const char *p, const char *prefix) {
|
|||
if (path_is_absolute(p) || isempty(prefix))
|
||||
return strdup(p);
|
||||
|
||||
if (endswith(prefix, "/"))
|
||||
return strjoin(prefix, p);
|
||||
else
|
||||
return strjoin(prefix, "/", p);
|
||||
return path_join(prefix, p);
|
||||
}
|
||||
|
||||
int safe_getcwd(char **ret) {
|
||||
|
@ -259,7 +256,7 @@ char **path_strv_resolve(char **l, const char *root) {
|
|||
|
||||
if (root) {
|
||||
orig = *s;
|
||||
t = prefix_root(root, orig);
|
||||
t = path_join(root, orig);
|
||||
if (!t) {
|
||||
enomem = true;
|
||||
continue;
|
||||
|
@ -586,7 +583,7 @@ int find_binary(const char *name, char **ret) {
|
|||
if (!path_is_absolute(element))
|
||||
continue;
|
||||
|
||||
j = strjoin(element, "/", name);
|
||||
j = path_join(element, name);
|
||||
if (!j)
|
||||
return -ENOMEM;
|
||||
|
||||
|
@ -691,40 +688,6 @@ int mkfs_exists(const char *fstype) {
|
|||
return binary_is_good(mkfs);
|
||||
}
|
||||
|
||||
char *prefix_root(const char *root, const char *path) {
|
||||
char *n, *p;
|
||||
size_t l;
|
||||
|
||||
/* If root is passed, prefixes path with it. Otherwise returns
|
||||
* it as is. */
|
||||
|
||||
assert(path);
|
||||
|
||||
/* First, drop duplicate prefixing slashes from the path */
|
||||
while (path[0] == '/' && path[1] == '/')
|
||||
path++;
|
||||
|
||||
if (empty_or_root(root))
|
||||
return strdup(path);
|
||||
|
||||
l = strlen(root) + 1 + strlen(path) + 1;
|
||||
|
||||
n = new(char, l);
|
||||
if (!n)
|
||||
return NULL;
|
||||
|
||||
p = stpcpy(n, root);
|
||||
|
||||
while (p > n && p[-1] == '/')
|
||||
p--;
|
||||
|
||||
if (path[0] != '/')
|
||||
*(p++) = '/';
|
||||
|
||||
strcpy(p, path);
|
||||
return n;
|
||||
}
|
||||
|
||||
int parse_path_argument_and_warn(const char *path, bool suppress_root, char **arg) {
|
||||
char *p;
|
||||
int r;
|
||||
|
@ -1034,7 +997,7 @@ int systemd_installation_has_version(const char *root, unsigned minimal_version)
|
|||
_cleanup_free_ char *path = NULL;
|
||||
char *c, **name;
|
||||
|
||||
path = prefix_root(root, pattern);
|
||||
path = path_join(root, pattern);
|
||||
if (!path)
|
||||
return -ENOMEM;
|
||||
|
||||
|
|
|
@ -118,10 +118,8 @@ int mkfs_exists(const char *fstype);
|
|||
_slash && ((*_slash = 0), true); \
|
||||
_slash = strrchr((prefix), '/'))
|
||||
|
||||
char *prefix_root(const char *root, const char *path);
|
||||
|
||||
/* Similar to prefix_root(), but returns an alloca() buffer, or
|
||||
* possibly a const pointer into the path parameter */
|
||||
/* Similar to path_join(), but only works for two components, and only the first one may be NULL and returns
|
||||
* an alloca() buffer, or possibly a const pointer into the path parameter. */
|
||||
#define prefix_roota(root, path) \
|
||||
({ \
|
||||
const char* _path = (path), *_root = (root), *_ret; \
|
||||
|
@ -129,7 +127,7 @@ char *prefix_root(const char *root, const char *path);
|
|||
size_t _l; \
|
||||
while (_path[0] == '/' && _path[1] == '/') \
|
||||
_path ++; \
|
||||
if (empty_or_root(_root)) \
|
||||
if (isempty(_root)) \
|
||||
_ret = _path; \
|
||||
else { \
|
||||
_l = strlen(_root) + 1 + strlen(_path) + 1; \
|
||||
|
|
|
@ -6,7 +6,6 @@
|
|||
#include <errno.h>
|
||||
#include <limits.h>
|
||||
#include <linux/oom.h>
|
||||
#include <sched.h>
|
||||
#include <signal.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
|
@ -29,10 +28,12 @@
|
|||
#include "alloc-util.h"
|
||||
#include "architecture.h"
|
||||
#include "escape.h"
|
||||
#include "env-util.h"
|
||||
#include "fd-util.h"
|
||||
#include "fileio.h"
|
||||
#include "fs-util.h"
|
||||
#include "ioprio.h"
|
||||
#include "locale-util.h"
|
||||
#include "log.h"
|
||||
#include "macro.h"
|
||||
#include "memory-util.h"
|
||||
|
@ -47,9 +48,16 @@
|
|||
#include "string-util.h"
|
||||
#include "terminal-util.h"
|
||||
#include "user-util.h"
|
||||
#include "utf8.h"
|
||||
|
||||
#if 0 /* NM_IGNORED */
|
||||
int get_process_state(pid_t pid) {
|
||||
|
||||
/* The kernel limits userspace processes to TASK_COMM_LEN (16 bytes), but allows higher values for its own
|
||||
* workers, e.g. "kworker/u9:3-kcryptd/253:0". Let's pick a fixed smallish limit that will work for the kernel.
|
||||
*/
|
||||
#define COMM_MAX_LEN 128
|
||||
|
||||
static int get_process_state(pid_t pid) {
|
||||
const char *p;
|
||||
char state;
|
||||
int r;
|
||||
|
@ -85,7 +93,7 @@ int get_process_comm(pid_t pid, char **ret) {
|
|||
assert(ret);
|
||||
assert(pid >= 0);
|
||||
|
||||
escaped = new(char, TASK_COMM_LEN);
|
||||
escaped = new(char, COMM_MAX_LEN);
|
||||
if (!escaped)
|
||||
return -ENOMEM;
|
||||
|
||||
|
@ -98,28 +106,31 @@ int get_process_comm(pid_t pid, char **ret) {
|
|||
return r;
|
||||
|
||||
/* Escape unprintable characters, just in case, but don't grow the string beyond the underlying size */
|
||||
cellescape(escaped, TASK_COMM_LEN, comm);
|
||||
cellescape(escaped, COMM_MAX_LEN, comm);
|
||||
|
||||
*ret = TAKE_PTR(escaped);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int get_process_cmdline(pid_t pid, size_t max_length, bool comm_fallback, char **line) {
|
||||
int get_process_cmdline(pid_t pid, size_t max_columns, ProcessCmdlineFlags flags, char **line) {
|
||||
_cleanup_fclose_ FILE *f = NULL;
|
||||
bool space = false;
|
||||
char *k;
|
||||
_cleanup_free_ char *ans = NULL;
|
||||
_cleanup_free_ char *t = NULL, *ans = NULL;
|
||||
const char *p;
|
||||
int c, r;
|
||||
int r;
|
||||
size_t k;
|
||||
|
||||
/* This is supposed to be a safety guard against runaway command lines. */
|
||||
size_t max_length = sc_arg_max();
|
||||
|
||||
assert(line);
|
||||
assert(pid >= 0);
|
||||
|
||||
/* Retrieves a process' command line. Replaces unprintable characters while doing so by whitespace (coalescing
|
||||
* multiple sequential ones into one). If max_length is != 0 will return a string of the specified size at most
|
||||
* (the trailing NUL byte does count towards the length here!), abbreviated with a "..." ellipsis. If
|
||||
* comm_fallback is true and the process has no command line set (the case for kernel threads), or has a
|
||||
* command line that resolves to the empty string will return the "comm" name of the process instead.
|
||||
/* Retrieves a process' command line. Replaces non-utf8 bytes by replacement character (<28>). If
|
||||
* max_columns is != -1 will return a string of the specified console width at most, abbreviated with
|
||||
* an ellipsis. If PROCESS_CMDLINE_COMM_FALLBACK is specified in flags and the process has no command
|
||||
* line set (the case for kernel threads), or has a command line that resolves to the empty string
|
||||
* will return the "comm" name of the process instead. This will use at most _SC_ARG_MAX bytes of
|
||||
* input data.
|
||||
*
|
||||
* Returns -ESRCH if the process doesn't exist, and -ENOENT if the process has no command line (and
|
||||
* comm_fallback is false). Returns 0 and sets *line otherwise. */
|
||||
|
@ -131,130 +142,56 @@ int get_process_cmdline(pid_t pid, size_t max_length, bool comm_fallback, char *
|
|||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (max_length == 0) {
|
||||
/* This is supposed to be a safety guard against runaway command lines. */
|
||||
long l = sysconf(_SC_ARG_MAX);
|
||||
assert(l > 0);
|
||||
max_length = l;
|
||||
}
|
||||
/* We assume that each four-byte character uses one or two columns. If we ever check for combining
|
||||
* characters, this assumption will need to be adjusted. */
|
||||
if ((size_t) 4 * max_columns + 1 < max_columns)
|
||||
max_length = MIN(max_length, (size_t) 4 * max_columns + 1);
|
||||
|
||||
if (max_length == 1) {
|
||||
|
||||
/* If there's only room for one byte, return the empty string */
|
||||
ans = new0(char, 1);
|
||||
if (!ans)
|
||||
return -ENOMEM;
|
||||
|
||||
*line = TAKE_PTR(ans);
|
||||
return 0;
|
||||
|
||||
} else {
|
||||
bool dotdotdot = false;
|
||||
size_t left;
|
||||
|
||||
ans = new(char, max_length);
|
||||
if (!ans)
|
||||
return -ENOMEM;
|
||||
|
||||
k = ans;
|
||||
left = max_length;
|
||||
while ((c = getc(f)) != EOF) {
|
||||
|
||||
if (isprint(c)) {
|
||||
|
||||
if (space) {
|
||||
if (left <= 2) {
|
||||
dotdotdot = true;
|
||||
break;
|
||||
}
|
||||
|
||||
*(k++) = ' ';
|
||||
left--;
|
||||
space = false;
|
||||
}
|
||||
|
||||
if (left <= 1) {
|
||||
dotdotdot = true;
|
||||
break;
|
||||
}
|
||||
|
||||
*(k++) = (char) c;
|
||||
left--;
|
||||
} else if (k > ans)
|
||||
space = true;
|
||||
}
|
||||
|
||||
if (dotdotdot) {
|
||||
if (max_length <= 4) {
|
||||
k = ans;
|
||||
left = max_length;
|
||||
} else {
|
||||
k = ans + max_length - 4;
|
||||
left = 4;
|
||||
|
||||
/* Eat up final spaces */
|
||||
while (k > ans && isspace(k[-1])) {
|
||||
k--;
|
||||
left++;
|
||||
}
|
||||
}
|
||||
|
||||
strncpy(k, "...", left-1);
|
||||
k[left-1] = 0;
|
||||
} else
|
||||
*k = 0;
|
||||
}
|
||||
|
||||
/* Kernel threads have no argv[] */
|
||||
if (isempty(ans)) {
|
||||
_cleanup_free_ char *t = NULL;
|
||||
int h;
|
||||
|
||||
ans = mfree(ans);
|
||||
|
||||
if (!comm_fallback)
|
||||
return -ENOENT;
|
||||
|
||||
h = get_process_comm(pid, &t);
|
||||
if (h < 0)
|
||||
return h;
|
||||
|
||||
size_t l = strlen(t);
|
||||
|
||||
if (l + 3 <= max_length) {
|
||||
ans = strjoin("[", t, "]");
|
||||
if (!ans)
|
||||
return -ENOMEM;
|
||||
|
||||
} else if (max_length <= 6) {
|
||||
ans = new(char, max_length);
|
||||
if (!ans)
|
||||
return -ENOMEM;
|
||||
|
||||
memcpy(ans, "[...]", max_length-1);
|
||||
ans[max_length-1] = 0;
|
||||
} else {
|
||||
t[max_length - 6] = 0;
|
||||
|
||||
/* Chop off final spaces */
|
||||
delete_trailing_chars(t, WHITESPACE);
|
||||
|
||||
ans = strjoin("[", t, "...]");
|
||||
if (!ans)
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
*line = TAKE_PTR(ans);
|
||||
return 0;
|
||||
}
|
||||
|
||||
k = realloc(ans, strlen(ans) + 1);
|
||||
if (!k)
|
||||
t = new(char, max_length);
|
||||
if (!t)
|
||||
return -ENOMEM;
|
||||
|
||||
ans = NULL;
|
||||
*line = k;
|
||||
k = fread(t, 1, max_length, f);
|
||||
if (k > 0) {
|
||||
/* Arguments are separated by NULs. Let's replace those with spaces. */
|
||||
for (size_t i = 0; i < k - 1; i++)
|
||||
if (t[i] == '\0')
|
||||
t[i] = ' ';
|
||||
|
||||
t[k] = '\0'; /* Normally, t[k] is already NUL, so this is just a guard in case of short read */
|
||||
} else {
|
||||
/* We only treat getting nothing as an error. We *could* also get an error after reading some
|
||||
* data, but we ignore that case, as such an error is rather unlikely and we prefer to get
|
||||
* some data rather than none. */
|
||||
if (ferror(f))
|
||||
return -errno;
|
||||
|
||||
if (!(flags & PROCESS_CMDLINE_COMM_FALLBACK))
|
||||
return -ENOENT;
|
||||
|
||||
/* Kernel threads have no argv[] */
|
||||
_cleanup_free_ char *t2 = NULL;
|
||||
|
||||
r = get_process_comm(pid, &t2);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
mfree(t);
|
||||
t = strjoin("[", t2, "]");
|
||||
if (!t)
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
delete_trailing_chars(t, WHITESPACE);
|
||||
|
||||
bool eight_bit = (flags & PROCESS_CMDLINE_USE_LOCALE) && !is_locale_utf8();
|
||||
|
||||
ans = escape_non_printable_full(t, max_columns, eight_bit);
|
||||
if (!ans)
|
||||
return -ENOMEM;
|
||||
|
||||
(void) str_realloc(&ans);
|
||||
*line = TAKE_PTR(ans);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -286,7 +223,7 @@ int rename_process(const char name[]) {
|
|||
* can use PR_SET_NAME, which sets the thread name for the calling thread. */
|
||||
if (prctl(PR_SET_NAME, name) < 0)
|
||||
log_debug_errno(errno, "PR_SET_NAME failed: %m");
|
||||
if (l >= TASK_COMM_LEN) /* Linux process names can be 15 chars at max */
|
||||
if (l >= TASK_COMM_LEN) /* Linux userspace process names can be 15 chars at max */
|
||||
truncated = true;
|
||||
|
||||
/* Second step, change glibc's ID of the process name. */
|
||||
|
@ -1543,45 +1480,11 @@ int set_oom_score_adjust(int value) {
|
|||
WRITE_STRING_FILE_VERIFY_ON_FAILURE|WRITE_STRING_FILE_DISABLE_BUFFER);
|
||||
}
|
||||
|
||||
int cpus_in_affinity_mask(void) {
|
||||
size_t n = 16;
|
||||
int r;
|
||||
|
||||
for (;;) {
|
||||
cpu_set_t *c;
|
||||
|
||||
c = CPU_ALLOC(n);
|
||||
if (!c)
|
||||
return -ENOMEM;
|
||||
|
||||
if (sched_getaffinity(0, CPU_ALLOC_SIZE(n), c) >= 0) {
|
||||
int k;
|
||||
|
||||
k = CPU_COUNT_S(CPU_ALLOC_SIZE(n), c);
|
||||
CPU_FREE(c);
|
||||
|
||||
if (k <= 0)
|
||||
return -EINVAL;
|
||||
|
||||
return k;
|
||||
}
|
||||
|
||||
r = -errno;
|
||||
CPU_FREE(c);
|
||||
|
||||
if (r != -EINVAL)
|
||||
return r;
|
||||
if (n > SIZE_MAX/2)
|
||||
return -ENOMEM;
|
||||
n *= 2;
|
||||
}
|
||||
}
|
||||
|
||||
static const char *const ioprio_class_table[] = {
|
||||
[IOPRIO_CLASS_NONE] = "none",
|
||||
[IOPRIO_CLASS_RT] = "realtime",
|
||||
[IOPRIO_CLASS_BE] = "best-effort",
|
||||
[IOPRIO_CLASS_IDLE] = "idle"
|
||||
[IOPRIO_CLASS_IDLE] = "idle",
|
||||
};
|
||||
|
||||
DEFINE_STRING_TABLE_LOOKUP_WITH_FALLBACK(ioprio_class, int, IOPRIO_N_CLASSES);
|
||||
|
@ -1602,7 +1505,7 @@ static const char* const sched_policy_table[] = {
|
|||
[SCHED_BATCH] = "batch",
|
||||
[SCHED_IDLE] = "idle",
|
||||
[SCHED_FIFO] = "fifo",
|
||||
[SCHED_RR] = "rr"
|
||||
[SCHED_RR] = "rr",
|
||||
};
|
||||
|
||||
DEFINE_STRING_TABLE_LOOKUP_WITH_FALLBACK(sched_policy, int, INT_MAX);
|
||||
|
|
|
@ -31,9 +31,13 @@
|
|||
_r_; \
|
||||
})
|
||||
|
||||
int get_process_state(pid_t pid);
|
||||
typedef enum ProcessCmdlineFlags {
|
||||
PROCESS_CMDLINE_COMM_FALLBACK = 1 << 0,
|
||||
PROCESS_CMDLINE_USE_LOCALE = 1 << 1,
|
||||
} ProcessCmdlineFlags;
|
||||
|
||||
int get_process_comm(pid_t pid, char **name);
|
||||
int get_process_cmdline(pid_t pid, size_t max_length, bool comm_fallback, char **line);
|
||||
int get_process_cmdline(pid_t pid, size_t max_columns, ProcessCmdlineFlags flags, char **line);
|
||||
int get_process_exe(pid_t pid, char **name);
|
||||
int get_process_uid(pid_t pid, uid_t *uid);
|
||||
int get_process_gid(pid_t pid, gid_t *gid);
|
||||
|
@ -196,5 +200,3 @@ assert_cc(TASKS_MAX <= (unsigned long) PID_T_MAX)
|
|||
(pid) = 0; \
|
||||
_pid_; \
|
||||
})
|
||||
|
||||
int cpus_in_affinity_mask(void);
|
||||
|
|
|
@ -35,6 +35,66 @@
|
|||
|
||||
int rdrand(unsigned long *ret) {
|
||||
|
||||
/* So, you are a "security researcher", and you wonder why we bother with using raw RDRAND here,
|
||||
* instead of sticking to /dev/urandom or getrandom()?
|
||||
*
|
||||
* Here's why: early boot. On Linux, during early boot the random pool that backs /dev/urandom and
|
||||
* getrandom() is generally not initialized yet. It is very common that initialization of the random
|
||||
* pool takes a longer time (up to many minutes), in particular on embedded devices that have no
|
||||
* explicit hardware random generator, as well as in virtualized environments such as major cloud
|
||||
* installations that do not provide virtio-rng or a similar mechanism.
|
||||
*
|
||||
* In such an environment using getrandom() synchronously means we'd block the entire system boot-up
|
||||
* until the pool is initialized, i.e. *very* long. Using getrandom() asynchronously (GRND_NONBLOCK)
|
||||
* would mean acquiring randomness during early boot would simply fail. Using /dev/urandom would mean
|
||||
* generating many kmsg log messages about our use of it before the random pool is properly
|
||||
* initialized. Neither of these outcomes is desirable.
|
||||
*
|
||||
* Thus, for very specific purposes we use RDRAND instead of either of these three options. RDRAND
|
||||
* provides us quickly and relatively reliably with random values, without having to delay boot,
|
||||
* without triggering warning messages in kmsg.
|
||||
*
|
||||
* Note that we use RDRAND only under very specific circumstances, when the requirements on the
|
||||
* quality of the returned entropy permit it. Specifically, here are some cases where we *do* use
|
||||
* RDRAND:
|
||||
*
|
||||
* • UUID generation: UUIDs are supposed to be universally unique but are not cryptographic
|
||||
* key material. The quality and trust level of RDRAND should hence be OK: UUIDs should be
|
||||
* generated in a way that is reliably unique, but they do not require ultimate trust into
|
||||
* the entropy generator. systemd generates a number of UUIDs during early boot, including
|
||||
* 'invocation IDs' for every unit spawned that identify the specific invocation of the
|
||||
* service globally, and a number of others. Other alternatives for generating these UUIDs
|
||||
* have been considered, but don't really work: for example, hashing uuids from a local
|
||||
* system identifier combined with a counter falls flat because during early boot disk
|
||||
* storage is not yet available (think: initrd) and thus a system-specific ID cannot be
|
||||
* stored or retrieved yet.
|
||||
*
|
||||
* • Hash table seed generation: systemd uses many hash tables internally. Hash tables are
|
||||
* generally assumed to have O(1) access complexity, but can deteriorate to prohibitive
|
||||
* O(n) access complexity if an attacker manages to trigger a large number of hash
|
||||
* collisions. Thus, systemd (as any software employing hash tables should) uses seeded
|
||||
* hash functions for its hash tables, with a seed generated randomly. The hash tables
|
||||
* systemd employs watch the fill level closely and reseed if necessary. This allows use of
|
||||
* a low quality RNG initially, as long as it improves should a hash table be under attack:
|
||||
* the attacker after all needs to to trigger many collisions to exploit it for the purpose
|
||||
* of DoS, but if doing so improves the seed the attack surface is reduced as the attack
|
||||
* takes place.
|
||||
*
|
||||
* Some cases where we do NOT use RDRAND are:
|
||||
*
|
||||
* • Generation of cryptographic key material 🔑
|
||||
*
|
||||
* • Generation of cryptographic salt values 🧂
|
||||
*
|
||||
* This function returns:
|
||||
*
|
||||
* -EOPNOTSUPP → RDRAND is not available on this system 😔
|
||||
* -EAGAIN → The operation failed this time, but is likely to work if you try again a few
|
||||
* times ♻
|
||||
* -EUCLEAN → We got some random value, but it looked strange, so we refused using it.
|
||||
* This failure might or might not be temporary. 😕
|
||||
*/
|
||||
|
||||
#if defined(__i386__) || defined(__x86_64__)
|
||||
static int have_rdrand = -1;
|
||||
unsigned long v;
|
||||
|
@ -92,10 +152,20 @@ int genuine_random_bytes(void *p, size_t n, RandomFlags flags) {
|
|||
bool got_some = false;
|
||||
int r;
|
||||
|
||||
/* Gathers some randomness from the kernel (or the CPU if the RANDOM_ALLOW_RDRAND flag is set). This
|
||||
* call won't block, unless the RANDOM_BLOCK flag is set. If RANDOM_MAY_FAIL is set, an error is
|
||||
* returned if the random pool is not initialized. Otherwise it will always return some data from the
|
||||
* kernel, regardless of whether the random pool is fully initialized or not. */
|
||||
/* Gathers some high-quality randomness from the kernel (or potentially mid-quality randomness from
|
||||
* the CPU if the RANDOM_ALLOW_RDRAND flag is set). This call won't block, unless the RANDOM_BLOCK
|
||||
* flag is set. If RANDOM_MAY_FAIL is set, an error is returned if the random pool is not
|
||||
* initialized. Otherwise it will always return some data from the kernel, regardless of whether the
|
||||
* random pool is fully initialized or not. If RANDOM_EXTEND_WITH_PSEUDO is set, and some but not
|
||||
* enough better quality randomness could be acquired, the rest is filled up with low quality
|
||||
* randomness.
|
||||
*
|
||||
* Of course, when creating cryptographic key material you really shouldn't use RANDOM_ALLOW_DRDRAND
|
||||
* or even RANDOM_EXTEND_WITH_PSEUDO.
|
||||
*
|
||||
* When generating UUIDs it's fine to use RANDOM_ALLOW_RDRAND but not OK to use
|
||||
* RANDOM_EXTEND_WITH_PSEUDO. In fact RANDOM_EXTEND_WITH_PSEUDO is only really fine when invoked via
|
||||
* an "all bets are off" wrapper, such as random_bytes(), see below. */
|
||||
|
||||
if (n == 0)
|
||||
return 0;
|
||||
|
@ -264,6 +334,11 @@ void initialize_srand(void) {
|
|||
void pseudo_random_bytes(void *p, size_t n) {
|
||||
uint8_t *q;
|
||||
|
||||
/* This returns pseudo-random data using libc's rand() function. You probably never want to call this
|
||||
* directly, because why would you use this if you can get better stuff cheaply? Use random_bytes()
|
||||
* instead, see below: it will fall back to this function if there's nothing better to get, but only
|
||||
* then. */
|
||||
|
||||
initialize_srand();
|
||||
|
||||
for (q = p; q < (uint8_t*) p + n; q += RAND_STEP) {
|
||||
|
@ -285,6 +360,38 @@ void pseudo_random_bytes(void *p, size_t n) {
|
|||
|
||||
void random_bytes(void *p, size_t n) {
|
||||
|
||||
/* This returns high quality randomness if we can get it cheaply. If we can't because for some reason
|
||||
* it is not available we'll try some crappy fallbacks.
|
||||
*
|
||||
* What this function will do:
|
||||
*
|
||||
* • This function will preferably use the CPU's RDRAND operation, if it is available, in
|
||||
* order to return "mid-quality" random values cheaply.
|
||||
*
|
||||
* • Use getrandom() with GRND_NONBLOCK, to return high-quality random values if they are
|
||||
* cheaply available.
|
||||
*
|
||||
* • This function will return pseudo-random data, generated via libc rand() if nothing
|
||||
* better is available.
|
||||
*
|
||||
* • This function will work fine in early boot
|
||||
*
|
||||
* • This function will always succeed
|
||||
*
|
||||
* What this function won't do:
|
||||
*
|
||||
* • This function will never fail: it will give you randomness no matter what. It might not
|
||||
* be high quality, but it will return some, possibly generated via libc's rand() call.
|
||||
*
|
||||
* • This function will never block: if the only way to get good randomness is a blocking,
|
||||
* synchronous getrandom() we'll instead provide you with pseudo-random data.
|
||||
*
|
||||
* This function is hence great for things like seeding hash tables, generating random numeric UNIX
|
||||
* user IDs (that are checked for collisions before use) and such.
|
||||
*
|
||||
* This function is hence not useful for generating UUIDs or cryptographic key material.
|
||||
*/
|
||||
|
||||
if (genuine_random_bytes(p, n, RANDOM_EXTEND_WITH_PSEUDO|RANDOM_MAY_FAIL|RANDOM_ALLOW_RDRAND) >= 0)
|
||||
return;
|
||||
|
||||
|
|
|
@ -47,6 +47,7 @@ siphash24 (const void *in, size_t inlen, const uint8_t k[16])
|
|||
|
||||
void siphash24_init(struct siphash *state, const uint8_t k[static 16]);
|
||||
void siphash24_compress(const void *in, size_t inlen, struct siphash *state);
|
||||
void siphash24_compress_boolean(bool in, struct siphash *state);
|
||||
#define siphash24_compress_byte(byte, state) siphash24_compress((const uint8_t[]) { (byte) }, 1, (state))
|
||||
|
||||
uint64_t siphash24_finalize(struct siphash *state);
|
||||
|
|
|
@ -1395,7 +1395,7 @@ int socket_bind_to_ifname(int fd, const char *ifname) {
|
|||
}
|
||||
|
||||
int socket_bind_to_ifindex(int fd, int ifindex) {
|
||||
char ifname[IFNAMSIZ] = "";
|
||||
char ifname[IF_NAMESIZE + 1];
|
||||
|
||||
assert(fd >= 0);
|
||||
|
||||
|
@ -1413,7 +1413,7 @@ int socket_bind_to_ifindex(int fd, int ifindex) {
|
|||
return -errno;
|
||||
|
||||
/* Fall back to SO_BINDTODEVICE on kernels < 5.0 which didn't have SO_BINDTOIFINDEX */
|
||||
if (!if_indextoname(ifindex, ifname))
|
||||
if (!format_ifname(ifindex, ifname))
|
||||
return -errno;
|
||||
|
||||
return socket_bind_to_ifname(fd, ifname);
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
#include <netinet/in.h>
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include <string.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/un.h>
|
||||
|
|
|
@ -257,3 +257,16 @@ static inline void *memory_startswith_no_case(const void *p, size_t sz, const ch
|
|||
|
||||
return (uint8_t*) p + n;
|
||||
}
|
||||
|
||||
static inline char* str_realloc(char **p) {
|
||||
/* Reallocate *p to actual size */
|
||||
|
||||
if (!*p)
|
||||
return NULL;
|
||||
|
||||
char *t = realloc(*p, strlen(*p) + 1);
|
||||
if (!t)
|
||||
return NULL;
|
||||
|
||||
return (*p = t);
|
||||
}
|
||||
|
|
|
@ -580,7 +580,6 @@ static int parse_timestamp_impl(const char *t, usec_t *usec, bool with_tz) {
|
|||
*/
|
||||
|
||||
assert(t);
|
||||
assert(usec);
|
||||
|
||||
if (t[0] == '@' && !with_tz)
|
||||
return parse_sec(t + 1, usec);
|
||||
|
@ -808,8 +807,8 @@ finish:
|
|||
else
|
||||
return -EINVAL;
|
||||
|
||||
*usec = ret;
|
||||
|
||||
if (usec)
|
||||
*usec = ret;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -866,7 +865,7 @@ int parse_timestamp(const char *t, usec_t *usec) {
|
|||
if (munmap(shared, sizeof *shared) != 0)
|
||||
return negative_errno();
|
||||
|
||||
if (tmp.return_value == 0)
|
||||
if (tmp.return_value == 0 && usec)
|
||||
*usec = tmp.usec;
|
||||
|
||||
return tmp.return_value;
|
||||
|
@ -928,7 +927,6 @@ int parse_time(const char *t, usec_t *usec, usec_t default_unit) {
|
|||
bool something = false;
|
||||
|
||||
assert(t);
|
||||
assert(usec);
|
||||
assert(default_unit > 0);
|
||||
|
||||
p = t;
|
||||
|
@ -940,7 +938,8 @@ int parse_time(const char *t, usec_t *usec, usec_t default_unit) {
|
|||
if (*s != 0)
|
||||
return -EINVAL;
|
||||
|
||||
*usec = USEC_INFINITY;
|
||||
if (usec)
|
||||
*usec = USEC_INFINITY;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -1012,8 +1011,8 @@ int parse_time(const char *t, usec_t *usec, usec_t default_unit) {
|
|||
}
|
||||
}
|
||||
|
||||
*usec = r;
|
||||
|
||||
if (usec)
|
||||
*usec = r;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -59,13 +59,11 @@ int fopen_temporary(const char *path, FILE **_f, char **_temp_path) {
|
|||
|
||||
/* This is much like mkostemp() but is subject to umask(). */
|
||||
int mkostemp_safe(char *pattern) {
|
||||
_cleanup_umask_ mode_t u = 0;
|
||||
_unused_ _cleanup_umask_ mode_t u = umask(0077);
|
||||
int fd;
|
||||
|
||||
assert(pattern);
|
||||
|
||||
u = umask(077);
|
||||
|
||||
fd = mkostemp(pattern, O_CLOEXEC);
|
||||
if (fd < 0)
|
||||
return -errno;
|
||||
|
@ -326,7 +324,7 @@ int mkdtemp_malloc(const char *template, char **ret) {
|
|||
if (r < 0)
|
||||
return r;
|
||||
|
||||
p = strjoin(tmp, "/XXXXXX");
|
||||
p = path_join(tmp, "XXXXXX");
|
||||
}
|
||||
if (!p)
|
||||
return -ENOMEM;
|
||||
|
|
|
@ -34,6 +34,7 @@
|
|||
#include "gunicode.h"
|
||||
#include "hexdecoct.h"
|
||||
#include "macro.h"
|
||||
#include "string-util.h"
|
||||
#include "utf8.h"
|
||||
|
||||
bool unichar_is_valid(char32_t ch) {
|
||||
|
@ -198,47 +199,94 @@ char *utf8_escape_invalid(const char *str) {
|
|||
}
|
||||
|
||||
*s = '\0';
|
||||
|
||||
(void) str_realloc(&p);
|
||||
return p;
|
||||
}
|
||||
|
||||
#if 0 /* NM_IGNORED */
|
||||
char *utf8_escape_non_printable(const char *str) {
|
||||
char *p, *s;
|
||||
static int utf8_char_console_width(const char *str) {
|
||||
char32_t c;
|
||||
int r;
|
||||
|
||||
r = utf8_encoded_to_unichar(str, &c);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
/* TODO: we should detect combining characters */
|
||||
|
||||
return unichar_iswide(c) ? 2 : 1;
|
||||
}
|
||||
|
||||
char *utf8_escape_non_printable_full(const char *str, size_t console_width) {
|
||||
char *p, *s, *prev_s;
|
||||
size_t n = 0; /* estimated print width */
|
||||
|
||||
assert(str);
|
||||
|
||||
p = s = malloc(strlen(str) * 4 + 1);
|
||||
if (console_width == 0)
|
||||
return strdup("");
|
||||
|
||||
p = s = prev_s = malloc(strlen(str) * 4 + 1);
|
||||
if (!p)
|
||||
return NULL;
|
||||
|
||||
while (*str) {
|
||||
for (;;) {
|
||||
int len;
|
||||
char *saved_s = s;
|
||||
|
||||
if (!*str) /* done! */
|
||||
goto finish;
|
||||
|
||||
len = utf8_encoded_valid_unichar(str, (size_t) -1);
|
||||
if (len > 0) {
|
||||
if (utf8_is_printable(str, len)) {
|
||||
int w;
|
||||
|
||||
w = utf8_char_console_width(str);
|
||||
assert(w >= 0);
|
||||
if (n + w > console_width)
|
||||
goto truncation;
|
||||
|
||||
s = mempcpy(s, str, len);
|
||||
str += len;
|
||||
n += w;
|
||||
|
||||
} else {
|
||||
while (len > 0) {
|
||||
for (; len > 0; len--) {
|
||||
if (n + 4 > console_width)
|
||||
goto truncation;
|
||||
|
||||
*(s++) = '\\';
|
||||
*(s++) = 'x';
|
||||
*(s++) = hexchar((int) *str >> 4);
|
||||
*(s++) = hexchar((int) *str);
|
||||
|
||||
str += 1;
|
||||
len--;
|
||||
n += 4;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
s = stpcpy(s, UTF8_REPLACEMENT_CHARACTER);
|
||||
if (n + 1 > console_width)
|
||||
goto truncation;
|
||||
|
||||
s = mempcpy(s, UTF8_REPLACEMENT_CHARACTER, strlen(UTF8_REPLACEMENT_CHARACTER));
|
||||
str += 1;
|
||||
n += 1;
|
||||
}
|
||||
|
||||
prev_s = saved_s;
|
||||
}
|
||||
|
||||
*s = '\0';
|
||||
truncation:
|
||||
/* Try to go back one if we don't have enough space for the ellipsis */
|
||||
if (n + 1 >= console_width)
|
||||
s = prev_s;
|
||||
|
||||
s = mempcpy(s, "…", strlen("…"));
|
||||
|
||||
finish:
|
||||
*s = '\0';
|
||||
(void) str_realloc(&p);
|
||||
return p;
|
||||
}
|
||||
#endif /* NM_IGNORED */
|
||||
|
@ -532,15 +580,15 @@ size_t utf8_console_width(const char *str) {
|
|||
/* Returns the approximate width a string will take on screen when printed on a character cell
|
||||
* terminal/console. */
|
||||
|
||||
while (*str != 0) {
|
||||
char32_t c;
|
||||
while (*str) {
|
||||
int w;
|
||||
|
||||
if (utf8_encoded_to_unichar(str, &c) < 0)
|
||||
w = utf8_char_console_width(str);
|
||||
if (w < 0)
|
||||
return (size_t) -1;
|
||||
|
||||
n += w;
|
||||
str = utf8_next_char(str);
|
||||
|
||||
n += unichar_iswide(c) ? 2 : 1;
|
||||
}
|
||||
|
||||
return n;
|
||||
|
|
|
@ -22,7 +22,10 @@ bool utf8_is_printable_newline(const char* str, size_t length, bool newline) _pu
|
|||
#define utf8_is_printable(str, length) utf8_is_printable_newline(str, length, true)
|
||||
|
||||
char *utf8_escape_invalid(const char *s);
|
||||
char *utf8_escape_non_printable(const char *str);
|
||||
char *utf8_escape_non_printable_full(const char *str, size_t console_width);
|
||||
static inline char *utf8_escape_non_printable(const char *str) {
|
||||
return utf8_escape_non_printable_full(str, (size_t) -1);
|
||||
}
|
||||
|
||||
size_t utf8_encode_unichar(char *out_utf8, char32_t g);
|
||||
size_t utf16_encode_unichar(char16_t *out, char32_t c);
|
||||
|
|
|
@ -197,7 +197,7 @@ int dhcp_identifier_set_iaid(
|
|||
/* device is under renaming */
|
||||
return -EBUSY;
|
||||
|
||||
name = net_get_name(device);
|
||||
name = net_get_name_persistent(device);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -199,7 +199,7 @@ static int parse_options(const uint8_t options[], size_t buflen, uint8_t *overlo
|
|||
if (memchr(option, 0, len - 1))
|
||||
return -EINVAL;
|
||||
|
||||
string = strndup((const char *) option, len);
|
||||
string = memdup_suffix0((const char *) option, len);
|
||||
if (!string)
|
||||
return -ENOMEM;
|
||||
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
#include "conf-parser.h"
|
||||
#include "device-util.h"
|
||||
#include "dhcp-lease-internal.h"
|
||||
#include "env-util.h"
|
||||
#include "ether-addr-util.h"
|
||||
#include "hexdecoct.h"
|
||||
#include "log.h"
|
||||
|
@ -27,7 +28,7 @@
|
|||
#include "util.h"
|
||||
|
||||
#if 0 /* NM_IGNORED */
|
||||
const char *net_get_name(sd_device *device) {
|
||||
const char *net_get_name_persistent(sd_device *device) {
|
||||
const char *name, *field;
|
||||
|
||||
assert(device);
|
||||
|
@ -42,7 +43,7 @@ const char *net_get_name(sd_device *device) {
|
|||
|
||||
#define HASH_KEY SD_ID128_MAKE(d3,1e,48,fa,90,fe,4b,4c,9d,af,d5,d7,a1,b1,2e,8a)
|
||||
|
||||
int net_get_unique_predictable_data(sd_device *device, uint64_t *result) {
|
||||
int net_get_unique_predictable_data(sd_device *device, bool use_sysname, uint64_t *result) {
|
||||
size_t l, sz = 0;
|
||||
const char *name;
|
||||
int r;
|
||||
|
@ -50,10 +51,10 @@ int net_get_unique_predictable_data(sd_device *device, uint64_t *result) {
|
|||
|
||||
assert(device);
|
||||
|
||||
/* net_get_name() will return one of the device names based on stable information about the
|
||||
* device. If this is not available, we fall back to using the device name. */
|
||||
name = net_get_name(device);
|
||||
if (!name)
|
||||
/* net_get_name_persistent() will return one of the device names based on stable information about
|
||||
* the device. If this is not available, we fall back to using the actual device name. */
|
||||
name = net_get_name_persistent(device);
|
||||
if (!name && use_sysname)
|
||||
(void) sd_device_get_sysname(device, &name);
|
||||
if (!name)
|
||||
return log_device_debug_errno(device, SYNTHETIC_ERRNO(ENODATA),
|
||||
|
@ -76,26 +77,66 @@ int net_get_unique_predictable_data(sd_device *device, uint64_t *result) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
static bool net_condition_test_strv(char * const *raw_patterns,
|
||||
const char *string) {
|
||||
if (strv_isempty(raw_patterns))
|
||||
static bool net_condition_test_strv(char * const *patterns, const char *string) {
|
||||
char * const *p;
|
||||
bool match = false, has_positive_rule = false;
|
||||
|
||||
if (strv_isempty(patterns))
|
||||
return true;
|
||||
|
||||
/* If the patterns begin with "!", edit it out and negate the test. */
|
||||
if (raw_patterns[0][0] == '!') {
|
||||
char **patterns;
|
||||
size_t i, length;
|
||||
STRV_FOREACH(p, patterns) {
|
||||
const char *q = *p;
|
||||
bool invert;
|
||||
|
||||
length = strv_length(raw_patterns) + 1; /* Include the NULL. */
|
||||
patterns = newa(char*, length);
|
||||
patterns[0] = raw_patterns[0] + 1; /* Skip the "!". */
|
||||
for (i = 1; i < length; i++)
|
||||
patterns[i] = raw_patterns[i];
|
||||
invert = *q == '!';
|
||||
q += invert;
|
||||
|
||||
return !string || !strv_fnmatch(patterns, string, 0);
|
||||
if (!invert)
|
||||
has_positive_rule = true;
|
||||
|
||||
if (string && fnmatch(q, string, 0) == 0) {
|
||||
if (invert)
|
||||
return false;
|
||||
else
|
||||
match = true;
|
||||
}
|
||||
}
|
||||
|
||||
return string && strv_fnmatch(raw_patterns, string, 0);
|
||||
return has_positive_rule ? match : true;
|
||||
}
|
||||
|
||||
static int net_condition_test_property(char * const *match_property, sd_device *device) {
|
||||
char * const *p;
|
||||
|
||||
if (strv_isempty(match_property))
|
||||
return true;
|
||||
|
||||
STRV_FOREACH(p, match_property) {
|
||||
_cleanup_free_ char *key = NULL;
|
||||
const char *val, *dev_val;
|
||||
bool invert, v;
|
||||
|
||||
invert = **p == '!';
|
||||
|
||||
val = strchr(*p + invert, '=');
|
||||
if (!val)
|
||||
return -EINVAL;
|
||||
|
||||
key = strndup(*p + invert, val - *p - invert);
|
||||
if (!key)
|
||||
return -ENOMEM;
|
||||
|
||||
val++;
|
||||
|
||||
v = device &&
|
||||
sd_device_get_property_value(device, key, &dev_val) >= 0 &&
|
||||
fnmatch(val, dev_val, 0) == 0;
|
||||
|
||||
if (invert ? v : !v)
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool net_match_config(Set *match_mac,
|
||||
|
@ -103,12 +144,25 @@ bool net_match_config(Set *match_mac,
|
|||
char * const *match_drivers,
|
||||
char * const *match_types,
|
||||
char * const *match_names,
|
||||
char * const *match_property,
|
||||
sd_device *device,
|
||||
const struct ether_addr *dev_mac,
|
||||
const char *dev_path,
|
||||
const char *dev_driver,
|
||||
const char *dev_type,
|
||||
const char *dev_name) {
|
||||
|
||||
const char *dev_path = NULL, *dev_driver = NULL, *dev_type = NULL, *mac_str;
|
||||
|
||||
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 &&
|
||||
sd_device_get_sysattr_value(device, "address", &mac_str) >= 0)
|
||||
dev_mac = ether_aton(mac_str);
|
||||
}
|
||||
|
||||
if (match_mac && (!dev_mac || !set_contains(match_mac, dev_mac)))
|
||||
return false;
|
||||
|
||||
|
@ -124,6 +178,9 @@ bool net_match_config(Set *match_mac,
|
|||
if (!net_condition_test_strv(match_names, dev_name))
|
||||
return false;
|
||||
|
||||
if (!net_condition_test_property(match_property, device))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -167,7 +224,7 @@ int config_parse_net_condition(const char *unit,
|
|||
return 0;
|
||||
}
|
||||
|
||||
int config_parse_ifnames(
|
||||
int config_parse_match_strv(
|
||||
const char *unit,
|
||||
const char *filename,
|
||||
unsigned line,
|
||||
|
@ -179,7 +236,9 @@ int config_parse_ifnames(
|
|||
void *data,
|
||||
void *userdata) {
|
||||
|
||||
const char *p = rvalue;
|
||||
char ***sv = data;
|
||||
bool invert;
|
||||
int r;
|
||||
|
||||
assert(filename);
|
||||
|
@ -187,30 +246,154 @@ int config_parse_ifnames(
|
|||
assert(rvalue);
|
||||
assert(data);
|
||||
|
||||
for (;;) {
|
||||
_cleanup_free_ char *word = NULL;
|
||||
|
||||
r = extract_first_word(&rvalue, &word, NULL, 0);
|
||||
if (r < 0) {
|
||||
log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse interface name list: %s", rvalue);
|
||||
return 0;
|
||||
}
|
||||
if (r == 0)
|
||||
break;
|
||||
|
||||
if (!ifname_valid(word)) {
|
||||
log_syntax(unit, LOG_ERR, filename, line, 0, "Interface name is not valid or too long, ignoring assignment: %s", rvalue);
|
||||
return 0;
|
||||
}
|
||||
|
||||
r = strv_push(sv, word);
|
||||
if (r < 0)
|
||||
return log_oom();
|
||||
|
||||
word = NULL;
|
||||
if (isempty(rvalue)) {
|
||||
*sv = strv_free(*sv);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
invert = *p == '!';
|
||||
p += invert;
|
||||
|
||||
for (;;) {
|
||||
_cleanup_free_ char *word = NULL, *k = NULL;
|
||||
|
||||
r = extract_first_word(&p, &word, NULL, EXTRACT_UNQUOTE|EXTRACT_RETAIN_ESCAPE);
|
||||
if (r == 0)
|
||||
return 0;
|
||||
if (r == -ENOMEM)
|
||||
return log_oom();
|
||||
if (r < 0) {
|
||||
log_syntax(unit, LOG_ERR, filename, line, r, "Invalid syntax, ignoring: %s", rvalue);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (invert) {
|
||||
k = strjoin("!", word);
|
||||
if (!k)
|
||||
return log_oom();
|
||||
} else
|
||||
k = TAKE_PTR(word);
|
||||
|
||||
r = strv_consume(sv, TAKE_PTR(k));
|
||||
if (r < 0)
|
||||
return log_oom();
|
||||
}
|
||||
}
|
||||
|
||||
int config_parse_match_ifnames(
|
||||
const char *unit,
|
||||
const char *filename,
|
||||
unsigned line,
|
||||
const char *section,
|
||||
unsigned section_line,
|
||||
const char *lvalue,
|
||||
int ltype,
|
||||
const char *rvalue,
|
||||
void *data,
|
||||
void *userdata) {
|
||||
|
||||
const char *p = rvalue;
|
||||
char ***sv = data;
|
||||
bool invert;
|
||||
int r;
|
||||
|
||||
assert(filename);
|
||||
assert(lvalue);
|
||||
assert(rvalue);
|
||||
assert(data);
|
||||
|
||||
invert = *p == '!';
|
||||
p += invert;
|
||||
|
||||
for (;;) {
|
||||
_cleanup_free_ char *word = NULL, *k = NULL;
|
||||
|
||||
r = extract_first_word(&p, &word, NULL, 0);
|
||||
if (r == 0)
|
||||
return 0;
|
||||
if (r == -ENOMEM)
|
||||
return log_oom();
|
||||
if (r < 0) {
|
||||
log_syntax(unit, LOG_ERR, filename, line, 0,
|
||||
"Failed to parse interface name list: %s", rvalue);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!ifname_valid(word)) {
|
||||
log_syntax(unit, LOG_ERR, filename, line, 0,
|
||||
"Interface name is not valid or too long, ignoring assignment: %s", word);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (invert) {
|
||||
k = strjoin("!", word);
|
||||
if (!k)
|
||||
return log_oom();
|
||||
} else
|
||||
k = TAKE_PTR(word);
|
||||
|
||||
r = strv_consume(sv, TAKE_PTR(k));
|
||||
if (r < 0)
|
||||
return log_oom();
|
||||
}
|
||||
}
|
||||
|
||||
int config_parse_match_property(
|
||||
const char *unit,
|
||||
const char *filename,
|
||||
unsigned line,
|
||||
const char *section,
|
||||
unsigned section_line,
|
||||
const char *lvalue,
|
||||
int ltype,
|
||||
const char *rvalue,
|
||||
void *data,
|
||||
void *userdata) {
|
||||
|
||||
const char *p = rvalue;
|
||||
char ***sv = data;
|
||||
bool invert;
|
||||
int r;
|
||||
|
||||
assert(filename);
|
||||
assert(lvalue);
|
||||
assert(rvalue);
|
||||
assert(data);
|
||||
|
||||
invert = *p == '!';
|
||||
p += invert;
|
||||
|
||||
for (;;) {
|
||||
_cleanup_free_ char *word = NULL, *k = NULL;
|
||||
|
||||
r = extract_first_word(&p, &word, NULL, EXTRACT_CUNESCAPE|EXTRACT_UNQUOTE);
|
||||
if (r == 0)
|
||||
return 0;
|
||||
if (r == -ENOMEM)
|
||||
return log_oom();
|
||||
if (r < 0) {
|
||||
log_syntax(unit, LOG_ERR, filename, line, 0,
|
||||
"Invalid syntax, ignoring: %s", rvalue);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!env_assignment_is_valid(word)) {
|
||||
log_syntax(unit, LOG_ERR, filename, line, 0,
|
||||
"Invalid property or value, ignoring assignment: %s", word);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (invert) {
|
||||
k = strjoin("!", word);
|
||||
if (!k)
|
||||
return log_oom();
|
||||
} else
|
||||
k = TAKE_PTR(word);
|
||||
|
||||
r = strv_consume(sv, TAKE_PTR(k));
|
||||
if (r < 0)
|
||||
return log_oom();
|
||||
}
|
||||
}
|
||||
|
||||
int config_parse_ifalias(const char *unit,
|
||||
|
|
|
@ -14,27 +14,28 @@
|
|||
#define LINK_BRIDGE_PORT_PRIORITY_INVALID 128
|
||||
#define LINK_BRIDGE_PORT_PRIORITY_MAX 63
|
||||
|
||||
#if 0 /* NM_IGNORED */
|
||||
bool net_match_config(Set *match_mac,
|
||||
char * const *match_path,
|
||||
char * const *match_driver,
|
||||
char * const *match_type,
|
||||
char * const *match_name,
|
||||
char * const *match_property,
|
||||
sd_device *device,
|
||||
const struct ether_addr *dev_mac,
|
||||
const char *dev_path,
|
||||
const char *dev_driver,
|
||||
const char *dev_type,
|
||||
const char *dev_name);
|
||||
|
||||
#if 0 /* NM_IGNORED */
|
||||
CONFIG_PARSER_PROTOTYPE(config_parse_net_condition);
|
||||
CONFIG_PARSER_PROTOTYPE(config_parse_hwaddr);
|
||||
CONFIG_PARSER_PROTOTYPE(config_parse_hwaddrs);
|
||||
CONFIG_PARSER_PROTOTYPE(config_parse_ifnames);
|
||||
CONFIG_PARSER_PROTOTYPE(config_parse_match_strv);
|
||||
CONFIG_PARSER_PROTOTYPE(config_parse_match_ifnames);
|
||||
CONFIG_PARSER_PROTOTYPE(config_parse_match_property);
|
||||
CONFIG_PARSER_PROTOTYPE(config_parse_ifalias);
|
||||
CONFIG_PARSER_PROTOTYPE(config_parse_bridge_port_priority);
|
||||
|
||||
int net_get_unique_predictable_data(sd_device *device, uint64_t *result);
|
||||
const char *net_get_name(sd_device *device);
|
||||
int net_get_unique_predictable_data(sd_device *device, bool use_sysname, uint64_t *result);
|
||||
const char *net_get_name_persistent(sd_device *device);
|
||||
#endif /* NM_IGNORED */
|
||||
|
||||
size_t serialize_in_addrs(FILE *f,
|
||||
|
|
|
@ -1389,6 +1389,23 @@ static int client_handle_forcerenew(sd_dhcp_client *client, DHCPMessage *force,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static bool lease_equal(const sd_dhcp_lease *a, const sd_dhcp_lease *b) {
|
||||
if (a->address != b->address)
|
||||
return false;
|
||||
|
||||
if (a->subnet_mask != b->subnet_mask)
|
||||
return false;
|
||||
|
||||
if (a->router_size != b->router_size)
|
||||
return false;
|
||||
|
||||
for (size_t i = 0; i < a->router_size; i++)
|
||||
if (a->router[i].s_addr != b->router[i].s_addr)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static int client_handle_ack(sd_dhcp_client *client, DHCPMessage *ack, size_t len) {
|
||||
_cleanup_(sd_dhcp_lease_unrefp) sd_dhcp_lease *lease = NULL;
|
||||
_cleanup_free_ char *error_message = NULL;
|
||||
|
@ -1441,12 +1458,10 @@ static int client_handle_ack(sd_dhcp_client *client, DHCPMessage *ack, size_t le
|
|||
|
||||
r = SD_DHCP_CLIENT_EVENT_IP_ACQUIRE;
|
||||
if (client->lease) {
|
||||
if (client->lease->address != lease->address ||
|
||||
client->lease->subnet_mask != lease->subnet_mask ||
|
||||
client->lease->router != lease->router) {
|
||||
r = SD_DHCP_CLIENT_EVENT_IP_CHANGE;
|
||||
} else
|
||||
if (lease_equal(client->lease, lease))
|
||||
r = SD_DHCP_CLIENT_EVENT_RENEW;
|
||||
else
|
||||
r = SD_DHCP_CLIENT_EVENT_IP_CHANGE;
|
||||
|
||||
client->lease = sd_dhcp_lease_unref(client->lease);
|
||||
}
|
||||
|
|
|
@ -334,7 +334,7 @@ static int lease_parse_string(const uint8_t *option, size_t len, char **ret) {
|
|||
if (memchr(option, 0, len - 1))
|
||||
return -EINVAL;
|
||||
|
||||
string = strndup((const char *) option, len);
|
||||
string = memdup_suffix0((const char *) option, len);
|
||||
if (!string)
|
||||
return -ENOMEM;
|
||||
|
||||
|
|
Loading…
Reference in a new issue