systemd: merge branch systemd into master

This commit is contained in:
Thomas Haller 2018-05-18 16:44:44 +02:00
commit d577888d8f
42 changed files with 858 additions and 196 deletions

View file

@ -1355,6 +1355,8 @@ src_libsystemd_nm_la_SOURCES = \
src/systemd/src/basic/socket-util.c \
src/systemd/src/basic/socket-util.h \
src/systemd/src/basic/sparse-endian.h \
src/systemd/src/basic/stat-util.c \
src/systemd/src/basic/stat-util.h \
src/systemd/src/basic/stdio-util.h \
src/systemd/src/basic/string-table.c \
src/systemd/src/basic/string-table.h \

View file

@ -142,6 +142,8 @@ G_STMT_START { \
# endif
#endif
#define VALGRIND 0
static inline pid_t
raw_getpid (void) {
#if defined(__alpha__)

View file

@ -18,9 +18,17 @@
#define new0(t, n) ((t*) calloc((n), sizeof(t)))
#define newa(t, n) ((t*) alloca(sizeof(t)*(n)))
#define newa(t, n) \
({ \
assert(!size_multiply_overflow(sizeof(t), n)); \
(t*) alloca(sizeof(t)*(n)); \
})
#define newa0(t, n) ((t*) alloca0(sizeof(t)*(n)))
#define newa0(t, n) \
({ \
assert(!size_multiply_overflow(sizeof(t), n)); \
(t*) alloca0(sizeof(t)*(n)); \
})
#define newdup(t, p, n) ((t*) memdup_multiply(p, sizeof(t), (n)))

View file

@ -190,7 +190,7 @@ int cunescape_one(const char *p, size_t length, char32_t *ret, bool *eight_bit)
/* C++11 style 16bit unicode */
int a[4];
unsigned i;
size_t i;
uint32_t c;
if (length != (size_t) -1 && length < 5)
@ -217,7 +217,7 @@ int cunescape_one(const char *p, size_t length, char32_t *ret, bool *eight_bit)
/* C++11 style 32bit unicode */
int a[8];
unsigned i;
size_t i;
char32_t c;
if (length != (size_t) -1 && length < 9)

View file

@ -35,19 +35,23 @@ char* ether_addr_to_string(const struct ether_addr *addr, char buffer[ETHER_ADDR
return buffer;
}
bool ether_addr_equal(const struct ether_addr *a, const struct ether_addr *b) {
int ether_addr_compare(const void *a, const void *b) {
assert(a);
assert(b);
return a->ether_addr_octet[0] == b->ether_addr_octet[0] &&
a->ether_addr_octet[1] == b->ether_addr_octet[1] &&
a->ether_addr_octet[2] == b->ether_addr_octet[2] &&
a->ether_addr_octet[3] == b->ether_addr_octet[3] &&
a->ether_addr_octet[4] == b->ether_addr_octet[4] &&
a->ether_addr_octet[5] == b->ether_addr_octet[5];
return memcmp(a, b, ETH_ALEN);
}
int ether_addr_from_string(const char *s, struct ether_addr *ret, size_t *offset) {
static void ether_addr_hash_func(const void *p, struct siphash *state) {
siphash24_compress(p, sizeof(struct ether_addr), state);
}
const struct hash_ops ether_addr_hash_ops = {
.hash = ether_addr_hash_func,
.compare = ether_addr_compare
};
int ether_addr_from_string(const char *s, struct ether_addr *ret) {
size_t pos = 0, n, field;
char sep = '\0';
const char *hex = HEXDIGITS, *hexoff;
@ -86,31 +90,35 @@ int ether_addr_from_string(const char *s, struct ether_addr *ret, size_t *offset
assert(s);
assert(ret);
s += strspn(s, WHITESPACE);
sep = s[strspn(s, hex)];
if (sep == '\n')
return -EINVAL;
if (!strchr(":.-", sep))
return -EINVAL;
if (sep == '.') {
uint16_t shorts[3] = { 0 };
parse_fields(shorts);
if (s[pos] != '\0')
return -EINVAL;
for (n = 0; n < ELEMENTSOF(shorts); n++) {
ret->ether_addr_octet[2*n] = ((shorts[n] & (uint16_t)0xff00) >> 8);
ret->ether_addr_octet[2*n + 1] = (shorts[n] & (uint16_t)0x00ff);
}
} else {
struct ether_addr out = { .ether_addr_octet = { 0 } };
} else if (IN_SET(sep, ':', '-')) {
struct ether_addr out = ETHER_ADDR_NULL;
parse_fields(out.ether_addr_octet);
if (s[pos] != '\0')
return -EINVAL;
for (n = 0; n < ELEMENTSOF(out.ether_addr_octet); n++)
ret->ether_addr_octet[n] = out.ether_addr_octet[n];
}
if (offset)
*offset = pos;
} else
return -EINVAL;
return 0;
}

View file

@ -10,13 +10,18 @@
#include <net/ethernet.h>
#include <stdbool.h>
#include "hash-funcs.h"
#define ETHER_ADDR_FORMAT_STR "%02X%02X%02X%02X%02X%02X"
#define ETHER_ADDR_FORMAT_VAL(x) (x).ether_addr_octet[0], (x).ether_addr_octet[1], (x).ether_addr_octet[2], (x).ether_addr_octet[3], (x).ether_addr_octet[4], (x).ether_addr_octet[5]
#define ETHER_ADDR_TO_STRING_MAX (3*6)
char* ether_addr_to_string(const struct ether_addr *addr, char buffer[ETHER_ADDR_TO_STRING_MAX]);
bool ether_addr_equal(const struct ether_addr *a, const struct ether_addr *b);
int ether_addr_compare(const void *a, const void *b);
static inline bool ether_addr_equal(const struct ether_addr *a, const struct ether_addr *b) {
return ether_addr_compare(a, b) == 0;
}
#define ETHER_ADDR_NULL ((const struct ether_addr){})
@ -24,4 +29,6 @@ static inline bool ether_addr_is_null(const struct ether_addr *addr) {
return ether_addr_equal(addr, &ETHER_ADDR_NULL);
}
int ether_addr_from_string(const char *s, struct ether_addr *ret, size_t *offset);
int ether_addr_from_string(const char *s, struct ether_addr *ret);
extern const struct hash_ops ether_addr_hash_ops;

View file

@ -87,8 +87,8 @@ void safe_close_pair(int p[]) {
p[1] = safe_close(p[1]);
}
void close_many(const int fds[], unsigned n_fd) {
unsigned i;
void close_many(const int fds[], size_t n_fd) {
size_t i;
assert(fds || n_fd <= 0);
@ -181,8 +181,8 @@ int fd_cloexec(int fd, bool cloexec) {
}
#if 0 /* NM_IGNORED */
_pure_ static bool fd_in_set(int fd, const int fdset[], unsigned n_fdset) {
unsigned i;
_pure_ static bool fd_in_set(int fd, const int fdset[], size_t n_fdset) {
size_t i;
assert(n_fdset == 0 || fdset);
@ -193,7 +193,7 @@ _pure_ static bool fd_in_set(int fd, const int fdset[], unsigned n_fdset) {
return false;
}
int close_all_fds(const int except[], unsigned n_except) {
int close_all_fds(const int except[], size_t n_except) {
_cleanup_closedir_ DIR *d = NULL;
struct dirent *de;
int r = 0;
@ -202,15 +202,22 @@ int close_all_fds(const int except[], unsigned n_except) {
d = opendir("/proc/self/fd");
if (!d) {
int fd;
struct rlimit rl;
int fd, max_fd;
/* When /proc isn't available (for example in chroots)
* the fallback is brute forcing through the fd
/* When /proc isn't available (for example in chroots) the fallback is brute forcing through the fd
* table */
assert_se(getrlimit(RLIMIT_NOFILE, &rl) >= 0);
for (fd = 3; fd < (int) rl.rlim_max; fd ++) {
if (rl.rlim_max == 0)
return -EINVAL;
/* Let's take special care if the resource limit is set to unlimited, or actually larger than the range
* of 'int'. Let's avoid implicit overflows. */
max_fd = (rl.rlim_max == RLIM_INFINITY || rl.rlim_max > INT_MAX) ? INT_MAX : (int) (rl.rlim_max - 1);
for (fd = 3; fd >= 0; fd = fd < max_fd ? fd + 1 : -1) {
int q;
if (fd_in_set(fd, except, n_except))

View file

@ -29,7 +29,7 @@ static inline int safe_close_above_stdio(int fd) {
return safe_close(fd);
}
void close_many(const int fds[], unsigned n_fd);
void close_many(const int fds[], size_t n_fd);
int fclose_nointr(FILE *f);
FILE* safe_fclose(FILE *f);
@ -59,7 +59,7 @@ DEFINE_TRIVIAL_CLEANUP_FUNC(DIR*, closedir);
int fd_nonblock(int fd, bool nonblock);
int fd_cloexec(int fd, bool cloexec);
int close_all_fds(const int except[], unsigned n_except);
int close_all_fds(const int except[], size_t n_except);
int same_fd(int a, int b);

View file

@ -53,6 +53,7 @@ int write_string_stream_ts(
struct timespec *ts) {
bool needs_nl;
int r;
assert(f);
assert(line);
@ -77,6 +78,13 @@ int write_string_stream_ts(
if (fputc('\n', f) == EOF)
return -errno;
if (flags & WRITE_STRING_FILE_SYNC)
r = fflush_sync_and_check(f);
else
r = fflush_and_check(f);
if (r < 0)
return r;
if (ts) {
struct timespec twice[2] = {*ts, *ts};
@ -84,10 +92,7 @@ int write_string_stream_ts(
return -errno;
}
if (flags & WRITE_STRING_FILE_SYNC)
return fflush_sync_and_check(f);
else
return fflush_and_check(f);
return 0;
}
static int write_string_file_atomic(

View file

@ -248,6 +248,21 @@ int fchmod_umask(int fd, mode_t m) {
}
#if 0 /* NM_IGNORED */
int fchmod_opath(int fd, mode_t m) {
char procfs_path[strlen("/proc/self/fd/") + DECIMAL_STR_MAX(int)];
/* This function operates also on fd that might have been opened with
* O_PATH. Indeed fchmodat() doesn't have the AT_EMPTY_PATH flag like
* fchownat() does. */
xsprintf(procfs_path, "/proc/self/fd/%i", fd);
if (chmod(procfs_path, m) < 0)
return -errno;
return 0;
}
int fd_warn_permissions(const char *path, int fd) {
struct stat st;
@ -911,25 +926,12 @@ int chase_symlinks(const char *path, const char *original_root, unsigned flags,
return exists;
chased_one:
if (ret) {
char *c;
if (done) {
if (todo) {
c = strjoin(done, todo);
if (!c)
return -ENOMEM;
} else
c = TAKE_PTR(done);
} else {
if (todo)
c = strdup(todo);
else
c = strdup("/");
if (!c)
return -ENOMEM;
}
c = strjoin(strempty(done), todo);
if (!c)
return -ENOMEM;
*ret = c;
}

View file

@ -33,6 +33,7 @@ int readlink_and_make_absolute(const char *p, char **r);
int chmod_and_chown(const char *path, mode_t mode, uid_t uid, gid_t gid);
int fchmod_umask(int fd, mode_t mode);
int fchmod_opath(int fd, mode_t m);
int fd_warn_permissions(const char *path, int fd);

View file

@ -283,7 +283,7 @@ static const struct hashmap_type_info hashmap_type_info[_HASHMAP_TYPE_MAX] = {
},
};
#ifdef VALGRIND
#if VALGRIND
__attribute__((destructor)) static void cleanup_pools(void) {
_cleanup_free_ char *t = NULL;
int r;

View file

@ -79,33 +79,69 @@ char *hexmem(const void *p, size_t l) {
return r;
}
int unhexmem(const char *p, size_t l, void **mem, size_t *len) {
_cleanup_free_ uint8_t *r = NULL;
uint8_t *z;
const char *x;
static int unhex_next(const char **p, size_t *l) {
int r;
assert(mem);
assert(len);
assert(p);
assert(l);
/* Find the next non-whitespace character, and decode it. We
* greedily skip all preceeding and all following whitespace. */
for (;;) {
if (*l == 0)
return -EPIPE;
if (!strchr(WHITESPACE, **p))
break;
/* Skip leading whitespace */
(*p)++, (*l)--;
}
r = unhexchar(**p);
if (r < 0)
return r;
for (;;) {
(*p)++, (*l)--;
if (*l == 0 || !strchr(WHITESPACE, **p))
break;
/* Skip following whitespace */
}
return r;
}
int unhexmem(const char *p, size_t l, void **ret, size_t *ret_len) {
_cleanup_free_ uint8_t *buf = NULL;
const char *x;
uint8_t *z;
assert(ret);
assert(ret_len);
assert(p || l == 0);
if (l == (size_t) -1)
l = strlen(p);
if (l % 2 != 0)
return -EINVAL;
z = r = malloc((l + 1) / 2 + 1);
if (!r)
/* Note that the calculation of memory size is an upper boundary, as we ignore whitespace while decoding */
buf = malloc((l + 1) / 2 + 1);
if (!buf)
return -ENOMEM;
for (x = p; x < p + l; x += 2) {
for (x = p, z = buf;;) {
int a, b;
a = unhexchar(x[0]);
a = unhex_next(&x, &l);
if (a == -EPIPE) /* End of string */
break;
if (a < 0)
return a;
b = unhexchar(x[1]);
b = unhex_next(&x, &l);
if (b < 0)
return b;
@ -114,8 +150,8 @@ int unhexmem(const char *p, size_t l, void **mem, size_t *len) {
*z = 0;
*mem = TAKE_PTR(r);
*len = (l + 1) / 2;
*ret_len = (size_t) (z - buf);
*ret = TAKE_PTR(buf);
return 0;
}
@ -184,7 +220,7 @@ char *base32hexmem(const void *p, size_t l, bool padding) {
for (x = p; x < (const uint8_t*) p + (l / 5) * 5; x += 5) {
/* x[0] == XXXXXXXX; x[1] == YYYYYYYY; x[2] == ZZZZZZZZ
x[3] == QQQQQQQQ; x[4] == WWWWWWWW */
* x[3] == QQQQQQQQ; x[4] == WWWWWWWW */
*(z++) = base32hexchar(x[0] >> 3); /* 000XXXXX */
*(z++) = base32hexchar((x[0] & 7) << 2 | x[1] >> 6); /* 000XXXYY */
*(z++) = base32hexchar((x[1] & 63) >> 1); /* 000YYYYY */
@ -284,7 +320,7 @@ int unbase32hexmem(const char *p, size_t l, bool padding, void **mem, size_t *_l
}
/* a group of eight input bytes needs five output bytes, in case of
padding we need to add some extra bytes */
* padding we need to add some extra bytes */
len = (l / 8) * 5;
switch (l % 8) {
@ -312,7 +348,7 @@ int unbase32hexmem(const char *p, size_t l, bool padding, void **mem, size_t *_l
for (x = p; x < p + (l / 8) * 8; x += 8) {
/* a == 000XXXXX; b == 000YYYYY; c == 000ZZZZZ; d == 000WWWWW
e == 000SSSSS; f == 000QQQQQ; g == 000VVVVV; h == 000RRRRR */
* e == 000SSSSS; f == 000QQQQQ; g == 000VVVVV; h == 000RRRRR */
a = unbase32hexchar(x[0]);
if (a < 0)
return -EINVAL;
@ -668,7 +704,7 @@ int unbase64mem(const char *p, size_t l, void **ret, size_t *ret_size) {
l = strlen(p);
/* A group of four input bytes needs three output bytes, in case of padding we need to add two or three extra
bytes. Note that this calculation is an upper boundary, as we ignore whitespace while decoding */
* bytes. Note that this calculation is an upper boundary, as we ignore whitespace while decoding */
len = (l / 4) * 3 + (l % 4 != 0 ? (l % 4) - 1 : 0);
buf = malloc(len + 1);
@ -736,9 +772,7 @@ int unbase64mem(const char *p, size_t l, void **ret, size_t *ret_size) {
*z = 0;
if (ret_size)
*ret_size = (size_t) (z - buf);
*ret_size = (size_t) (z - buf);
*ret = TAKE_PTR(buf);
return 0;

View file

@ -28,9 +28,8 @@ int fd_wait_for_event(int fd, int event, usec_t timeout);
ssize_t sparse_write(int fd, const void *p, size_t sz, size_t run_length);
static inline size_t IOVEC_TOTAL_SIZE(const struct iovec *i, unsigned n) {
unsigned j;
size_t r = 0;
static inline size_t IOVEC_TOTAL_SIZE(const struct iovec *i, size_t n) {
size_t j, r = 0;
for (j = 0; j < n; j++)
r += i[j].iov_len;
@ -38,8 +37,8 @@ static inline size_t IOVEC_TOTAL_SIZE(const struct iovec *i, unsigned n) {
return r;
}
static inline size_t IOVEC_INCREMENT(struct iovec *i, unsigned n, size_t k) {
unsigned j;
static inline size_t IOVEC_INCREMENT(struct iovec *i, size_t n, size_t k) {
size_t j;
for (j = 0; j < n; j++) {
size_t sub;

View file

@ -17,12 +17,12 @@
struct pool {
struct pool *next;
unsigned n_tiles;
unsigned n_used;
size_t n_tiles;
size_t n_used;
};
void* mempool_alloc_tile(struct mempool *mp) {
unsigned i;
size_t i;
/* When a tile is released we add it to the list and simply
* place the next pointer at its offset 0. */
@ -40,8 +40,7 @@ void* mempool_alloc_tile(struct mempool *mp) {
if (_unlikely_(!mp->first_pool) ||
_unlikely_(mp->first_pool->n_used >= mp->first_pool->n_tiles)) {
unsigned n;
size_t size;
size_t size, n;
struct pool *p;
n = mp->first_pool ? mp->first_pool->n_tiles : 0;
@ -79,7 +78,7 @@ void mempool_free_tile(struct mempool *mp, void *p) {
mp->freelist = p;
}
#ifdef VALGRIND
#if VALGRIND
void mempool_drop(struct mempool *mp) {
struct pool *p = mp->first_pool;

View file

@ -30,6 +30,6 @@ static struct mempool pool_name = { \
}
#ifdef VALGRIND
#if VALGRIND
void mempool_drop(struct mempool *mp);
#endif

View file

@ -13,12 +13,14 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include "alloc-util.h"
#include "errno-list.h"
#include "extract-word.h"
#include "locale-util.h"
#include "macro.h"
#include "missing.h"
#include "parse-util.h"
#include "process-util.h"
#include "string-util.h"
@ -96,6 +98,30 @@ int parse_ifindex(const char *s, int *ret) {
return 0;
}
int parse_mtu(int family, const char *s, uint32_t *ret) {
uint64_t u;
size_t m;
int r;
r = parse_size(s, 1024, &u);
if (r < 0)
return r;
if (u > UINT32_MAX)
return -ERANGE;
if (family == AF_INET6)
m = IPV6_MIN_MTU; /* This is 1280 */
else
m = IPV4_MIN_MTU; /* For all other protocols, including 'unspecified' we assume the IPv4 minimal MTU */
if (u < m)
return -ERANGE;
*ret = (uint32_t) u;
return 0;
}
int parse_size(const char *t, uint64_t base, uint64_t *size) {
/* Soo, sometimes we want to parse IEC binary suffixes, and
@ -655,4 +681,21 @@ int parse_dev(const char *s, dev_t *ret) {
*ret = d;
return 0;
}
int parse_oom_score_adjust(const char *s, int *ret) {
int r, v;
assert(s);
assert(ret);
r = safe_atoi(s, &v);
if (r < 0)
return r;
if (v < OOM_SCORE_ADJ_MIN || v > OOM_SCORE_ADJ_MAX)
return -ERANGE;
*ret = v;
return 0;
}
#endif /* NM_IGNORED */

View file

@ -22,6 +22,7 @@ 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_mtu(int family, const char *s, uint32_t *ret);
int parse_size(const char *t, uint64_t base, uint64_t *size);
int parse_range(const char *t, unsigned *lower, unsigned *upper);
@ -117,3 +118,5 @@ int parse_percent(const char *p);
int parse_nice(const char *p, int *ret);
int parse_ip_port(const char *s, uint16_t *ret);
int parse_oom_score_adjust(const char *s, int *ret);

View file

@ -690,11 +690,12 @@ int parse_path_argument_and_warn(const char *path, bool suppress_root, char **ar
return log_error_errno(r, "Failed to parse path \"%s\" and make it absolute: %m", path);
path_kill_slashes(p);
if (suppress_root && path_equal(p, "/"))
if (suppress_root && empty_or_root(p))
p = mfree(p);
free(*arg);
*arg = p;
return 0;
}

View file

@ -166,3 +166,6 @@ static inline const char *skip_dev_prefix(const char *p) {
}
bool empty_or_root(const char *root);
static inline const char *empty_to_root(const char *path) {
return isempty(path) ? "/" : path;
}

View file

@ -885,7 +885,7 @@ int getenv_for_pid(pid_t pid, const char *field, char **ret) {
do {
char line[LINE_MAX];
unsigned i;
size_t i;
for (i = 0; i < sizeof(line)-1; i++) {
int c;
@ -1384,9 +1384,9 @@ int safe_fork_full(
return 0;
}
int fork_agent(const char *name, const int except[], unsigned n_except, pid_t *ret_pid, const char *path, ...) {
int fork_agent(const char *name, const int except[], size_t n_except, pid_t *ret_pid, const char *path, ...) {
bool stdout_is_tty, stderr_is_tty;
unsigned n, i;
size_t n, i;
va_list ap;
char **l;
int r;
@ -1442,7 +1442,7 @@ int fork_agent(const char *name, const int except[], unsigned n_except, pid_t *r
va_end(ap);
/* Allocate strv */
l = alloca(sizeof(char *) * (n + 1));
l = newa(char*, n + 1);
/* Fill in arguments */
va_start(ap, path);
@ -1454,6 +1454,15 @@ int fork_agent(const char *name, const int except[], unsigned n_except, pid_t *r
_exit(EXIT_FAILURE);
}
int set_oom_score_adjust(int value) {
char t[DECIMAL_STR_MAX(int)];
sprintf(t, "%i", value);
return write_string_file("/proc/self/oom_score_adj", t,
WRITE_STRING_FILE_VERIFY_ON_FAILURE|WRITE_STRING_FILE_DISABLE_BUFFER);
}
static const char *const ioprio_class_table[] = {
[IOPRIO_CLASS_NONE] = "none",
[IOPRIO_CLASS_RT] = "realtime",

View file

@ -173,7 +173,9 @@ static inline int safe_fork(const char *name, ForkFlags flags, pid_t *ret_pid) {
return safe_fork_full(name, NULL, 0, flags, ret_pid);
}
int fork_agent(const char *name, const int except[], unsigned n_except, pid_t *pid, const char *path, ...);
int fork_agent(const char *name, const int except[], size_t n_except, pid_t *pid, const char *path, ...);
int set_oom_score_adjust(int value);
#if SIZEOF_PID_T == 4
/* The highest possibly (theoretic) pid_t value on this architecture. */

View file

@ -37,7 +37,7 @@ int acquire_random_bytes(void *p, size_t n, bool high_quality_required) {
static int have_syscall = -1;
_cleanup_close_ int fd = -1;
unsigned already_done = 0;
size_t already_done = 0;
int r;
/* Gathers some randomness from the kernel. This call will never block. If

View file

@ -136,5 +136,3 @@ DEFINE_TRIVIAL_CLEANUP_FUNC(Set*, set_free_free);
#define _cleanup_set_free_ _cleanup_(set_freep)
#define _cleanup_set_free_free_ _cleanup_(set_free_freep)
int set_make(Set **ret, const struct hash_ops *hash_ops HASHMAP_DEBUG_PARAMS, void *add, ...);

View file

@ -24,8 +24,6 @@ int sigprocmask_many(int how, sigset_t *old, ...);
const char *signal_to_string(int i) _const_;
int signal_from_string(const char *s) _pure_;
int signal_from_string_try_harder(const char *s);
void nop_signal_handler(int sig);
static inline void block_signals_reset(sigset_t *ss) {

View file

@ -0,0 +1,292 @@
/* SPDX-License-Identifier: LGPL-2.1+ */
/***
This file is part of systemd.
Copyright 2010-2012 Lennart Poettering
***/
#include "nm-sd-adapt.h"
#include <dirent.h>
#include <errno.h>
#include <fcntl.h>
#include <linux/magic.h>
#include <sched.h>
#include <sys/stat.h>
#include <sys/statvfs.h>
#include <sys/types.h>
#include <unistd.h>
#include "dirent-util.h"
#include "fd-util.h"
#include "fs-util.h"
#include "macro.h"
#include "missing.h"
#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);
}
int is_dir(const char* path, bool follow) {
struct stat st;
int r;
assert(path);
if (follow)
r = stat(path, &st);
else
r = lstat(path, &st);
if (r < 0)
return -errno;
return !!S_ISDIR(st.st_mode);
}
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));
}
int dir_is_empty(const char *path) {
_cleanup_closedir_ DIR *d;
struct dirent *de;
d = opendir(path);
if (!d)
return -errno;
FOREACH_DIRENT(de, d, return -errno)
return 0;
return 1;
}
bool null_or_empty(struct stat *st) {
assert(st);
if (S_ISREG(st->st_mode) && st->st_size <= 0)
return true;
/* We don't want to hardcode the major/minor of /dev/null,
* hence we do a simpler "is this a device node?" check. */
if (S_ISCHR(st->st_mode) || S_ISBLK(st->st_mode))
return true;
return false;
}
int null_or_empty_path(const char *fn) {
struct stat st;
assert(fn);
if (stat(fn, &st) < 0)
return -errno;
return null_or_empty(&st);
}
int null_or_empty_fd(int fd) {
struct stat st;
assert(fd >= 0);
if (fstat(fd, &st) < 0)
return -errno;
return null_or_empty(&st);
}
int path_is_read_only_fs(const char *path) {
struct statvfs st;
assert(path);
if (statvfs(path, &st) < 0)
return -errno;
if (st.f_flag & ST_RDONLY)
return true;
/* On NFS, statvfs() might not reflect whether we can actually
* write to the remote share. Let's try again with
* access(W_OK) which is more reliable, at least sometimes. */
if (access(path, W_OK) < 0 && errno == EROFS)
return true;
return false;
}
int path_is_os_tree(const char *path) {
int r;
assert(path);
/* Does the path exist at all? If not, generate an error immediately. This is useful so that a missing root dir
* always results in -ENOENT, and we can properly distuingish the case where the whole root doesn't exist from
* the case where just the os-release file is missing. */
if (laccess(path, F_OK) < 0)
return -errno;
/* We use /usr/lib/os-release as flag file if something is an OS */
r = chase_symlinks("/usr/lib/os-release", path, CHASE_PREFIX_ROOT, NULL);
if (r == -ENOENT) {
/* Also check for the old location in /etc, just in case. */
r = chase_symlinks("/etc/os-release", path, CHASE_PREFIX_ROOT, NULL);
if (r == -ENOENT)
return 0; /* We got nothing */
}
if (r < 0)
return r;
return 1;
}
int files_same(const char *filea, const char *fileb, int flags) {
struct stat a, b;
assert(filea);
assert(fileb);
if (fstatat(AT_FDCWD, filea, &a, flags) < 0)
return -errno;
if (fstatat(AT_FDCWD, fileb, &b, flags) < 0)
return -errno;
return a.st_dev == b.st_dev &&
a.st_ino == b.st_ino;
}
bool is_fs_type(const struct statfs *s, statfs_f_type_t magic_value) {
assert(s);
assert_cc(sizeof(statfs_f_type_t) >= sizeof(s->f_type));
return F_TYPE_EQUAL(s->f_type, magic_value);
}
int fd_is_fs_type(int fd, statfs_f_type_t magic_value) {
struct statfs s;
if (fstatfs(fd, &s) < 0)
return -errno;
return is_fs_type(&s, magic_value);
}
int path_is_fs_type(const char *path, statfs_f_type_t magic_value) {
_cleanup_close_ int fd = -1;
fd = open(path, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_PATH);
if (fd < 0)
return -errno;
return fd_is_fs_type(fd, magic_value);
}
bool is_temporary_fs(const struct statfs *s) {
return is_fs_type(s, TMPFS_MAGIC) ||
is_fs_type(s, RAMFS_MAGIC);
}
bool is_network_fs(const struct statfs *s) {
return is_fs_type(s, CIFS_MAGIC_NUMBER) ||
is_fs_type(s, CODA_SUPER_MAGIC) ||
is_fs_type(s, NCP_SUPER_MAGIC) ||
is_fs_type(s, NFS_SUPER_MAGIC) ||
is_fs_type(s, SMB_SUPER_MAGIC) ||
is_fs_type(s, V9FS_MAGIC) ||
is_fs_type(s, AFS_SUPER_MAGIC) ||
is_fs_type(s, OCFS2_SUPER_MAGIC);
}
int fd_is_temporary_fs(int fd) {
struct statfs s;
if (fstatfs(fd, &s) < 0)
return -errno;
return is_temporary_fs(&s);
}
int fd_is_network_fs(int fd) {
struct statfs s;
if (fstatfs(fd, &s) < 0)
return -errno;
return is_network_fs(&s);
}
int fd_is_network_ns(int fd) {
int r;
r = fd_is_fs_type(fd, NSFS_MAGIC);
if (r <= 0)
return r;
r = ioctl(fd, NS_GET_NSTYPE);
if (r < 0)
return -errno;
return r == CLONE_NEWNET;
}
int path_is_temporary_fs(const char *path) {
_cleanup_close_ int fd = -1;
fd = open(path, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_PATH);
if (fd < 0)
return -errno;
return fd_is_temporary_fs(fd);
}
#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);
}

View file

@ -0,0 +1,67 @@
/* SPDX-License-Identifier: LGPL-2.1+ */
#pragma once
/***
This file is part of systemd.
Copyright 2010-2012 Lennart Poettering
***/
#include <stdbool.h>
#include <stddef.h>
#include <sys/stat.h>
#include <sys/statfs.h>
#include <sys/types.h>
#include <sys/vfs.h>
#include "macro.h"
int is_symlink(const char *path);
int is_dir(const char *path, bool follow);
int is_device_node(const char *path);
int dir_is_empty(const char *path);
static inline int dir_is_populated(const char *path) {
int r;
r = dir_is_empty(path);
if (r < 0)
return r;
return !r;
}
bool null_or_empty(struct stat *st) _pure_;
int null_or_empty_path(const char *fn);
int null_or_empty_fd(int fd);
int path_is_read_only_fs(const char *path);
int path_is_os_tree(const char *path);
int files_same(const char *filea, const char *fileb, int flags);
/* The .f_type field of struct statfs is really weird defined on
* different archs. Let's give its type a name. */
typedef typeof(((struct statfs*)NULL)->f_type) statfs_f_type_t;
bool is_fs_type(const struct statfs *s, statfs_f_type_t magic_value) _pure_;
int fd_is_fs_type(int fd, statfs_f_type_t magic_value);
int path_is_fs_type(const char *path, statfs_f_type_t magic_value);
bool is_temporary_fs(const struct statfs *s) _pure_;
bool is_network_fs(const struct statfs *s) _pure_;
int fd_is_temporary_fs(int fd);
int fd_is_network_fs(int fd);
int fd_is_network_ns(int fd);
int path_is_temporary_fs(const char *path);
/* Because statfs.t_type can be int on some architectures, we have to cast
* the const magic to the type, otherwise the compiler warns about
* signed/unsigned comparison, because the magic can be 32 bit unsigned.
*/
#define F_TYPE_EQUAL(a, b) (a == (typeof(a)) b)
int stat_verify_regular(const struct stat *st);
int fd_verify_regular(int fd);

View file

@ -23,6 +23,7 @@
#include "terminal-util.h"
#include "utf8.h"
#include "util.h"
#include "fileio.h"
int strcmp_ptr(const char *a, const char *b) {
@ -700,7 +701,8 @@ char *strip_tab_ansi(char **ibuf, size_t *_isz, size_t highlight[2]) {
enum {
STATE_OTHER,
STATE_ESCAPE,
STATE_BRACKET
STATE_CSI,
STATE_CSO,
} state = STATE_OTHER;
char *obuf = NULL;
size_t osz = 0, isz, shift[2] = {};
@ -709,7 +711,17 @@ char *strip_tab_ansi(char **ibuf, size_t *_isz, size_t highlight[2]) {
assert(ibuf);
assert(*ibuf);
/* Strips ANSI color and replaces TABs by 8 spaces */
/* This does three things:
*
* 1. Replaces TABs by 8 spaces
* 2. Strips ANSI color sequences (a subset of CSI), i.e. ESC '[' 'm' sequences
* 3. Strips ANSI operating system sequences (CSO), i.e. ESC ']' BEL sequences
*
* Everything else will be left as it is. In particular other ANSI sequences are left as they are, as are any
* other special characters. Truncated ANSI sequences are left-as is too. This call is supposed to suppress the
* most basic formatting noise, but nothing else.
*
* Why care for CSO sequences? Well, to undo what terminal_urlify() and friends generate. */
isz = _isz ? *_isz : strlen(*ibuf);
@ -744,8 +756,11 @@ char *strip_tab_ansi(char **ibuf, size_t *_isz, size_t highlight[2]) {
fputc('\x1B', f);
advance_offsets(i - *ibuf, highlight, shift, 1);
break;
} else if (*i == '[') {
state = STATE_BRACKET;
} else if (*i == '[') { /* ANSI CSI */
state = STATE_CSI;
begin = i + 1;
} else if (*i == ']') { /* ANSI CSO */
state = STATE_CSO;
begin = i + 1;
} else {
fputc('\x1B', f);
@ -756,10 +771,10 @@ char *strip_tab_ansi(char **ibuf, size_t *_isz, size_t highlight[2]) {
break;
case STATE_BRACKET:
case STATE_CSI:
if (i >= *ibuf + isz || /* EOT */
(!(*i >= '0' && *i <= '9') && !IN_SET(*i, ';', 'm'))) {
if (i >= *ibuf + isz || /* EOT */
!strchr("01234567890;m", *i)) { /* … or invalid chars in sequence */
fputc('\x1B', f);
fputc('[', f);
advance_offsets(i - *ibuf, highlight, shift, 2);
@ -767,11 +782,26 @@ char *strip_tab_ansi(char **ibuf, size_t *_isz, size_t highlight[2]) {
i = begin-1;
} else if (*i == 'm')
state = STATE_OTHER;
break;
case STATE_CSO:
if (i >= *ibuf + isz || /* EOT … */
(*i != '\a' && (uint8_t) *i < 32U) || (uint8_t) *i > 126U) { /* … or invalid chars in sequence */
fputc('\x1B', f);
fputc(']', f);
advance_offsets(i - *ibuf, highlight, shift, 2);
state = STATE_OTHER;
i = begin-1;
} else if (*i == '\a')
state = STATE_OTHER;
break;
}
}
if (ferror(f)) {
if (fflush_and_check(f) < 0) {
fclose(f);
return mfree(obuf);
}

View file

@ -58,7 +58,7 @@ static inline const char *empty_to_null(const char *p) {
return isempty(p) ? NULL : p;
}
static inline const char *strdash_if_empty(const char *str) {
static inline const char *empty_to_dash(const char *str) {
return isempty(str) ? "-" : str;
}
@ -109,7 +109,7 @@ char *strjoin_real(const char *x, ...) _sentinel_;
const char *_appendees_[] = { a, __VA_ARGS__ }; \
char *_d_, *_p_; \
size_t _len_ = 0; \
unsigned _i_; \
size_t _i_; \
for (_i_ = 0; _i_ < ELEMENTSOF(_appendees_) && _appendees_[_i_]; _i_++) \
_len_ += strlen(_appendees_[_i_]); \
_p_ = _d_ = alloca(_len_ + 1); \

View file

@ -109,8 +109,8 @@ char **strv_copy(char * const *l) {
return r;
}
unsigned strv_length(char * const *l) {
unsigned n = 0;
size_t strv_length(char * const *l) {
size_t n = 0;
if (!l)
return 0;
@ -123,8 +123,8 @@ unsigned strv_length(char * const *l) {
char **strv_new_ap(const char *x, va_list ap) {
const char *s;
char **a;
unsigned n = 0, i = 0;
_cleanup_strv_free_ char **a = NULL;
size_t n = 0, i = 0;
va_list aq;
/* As a special trick we ignore all listed strings that equal
@ -154,7 +154,7 @@ char **strv_new_ap(const char *x, va_list ap) {
if (x != STRV_IGNORE) {
a[i] = strdup(x);
if (!a[i])
goto fail;
return NULL;
i++;
}
@ -165,7 +165,7 @@ char **strv_new_ap(const char *x, va_list ap) {
a[i] = strdup(s);
if (!a[i])
goto fail;
return NULL;
i++;
}
@ -173,11 +173,7 @@ char **strv_new_ap(const char *x, va_list ap) {
a[i] = NULL;
return a;
fail:
strv_free(a);
return NULL;
return TAKE_PTR(a);
}
char **strv_new(const char *x, ...) {
@ -259,7 +255,7 @@ int strv_extend_strv_concat(char ***a, char **b, const char *suffix) {
char **strv_split(const char *s, const char *separator) {
const char *word, *state;
size_t l;
unsigned n, i;
size_t n, i;
char **r;
assert(s);
@ -289,7 +285,7 @@ char **strv_split(const char *s, const char *separator) {
char **strv_split_newlines(const char *s) {
char **l;
unsigned n;
size_t n;
assert(s);
@ -384,7 +380,7 @@ char *strv_join(char **l, const char *separator) {
int strv_push(char ***l, char *value) {
char **c;
unsigned n, m;
size_t n, m;
if (!value)
return 0;
@ -409,7 +405,7 @@ int strv_push(char ***l, char *value) {
int strv_push_pair(char ***l, char *a, char *b) {
char **c;
unsigned n, m;
size_t n, m;
if (!a && !b)
return 0;
@ -435,9 +431,9 @@ int strv_push_pair(char ***l, char *a, char *b) {
return 0;
}
int strv_insert(char ***l, unsigned position, char *value) {
int strv_insert(char ***l, size_t position, char *value) {
char **c;
unsigned n, m, i;
size_t n, m, i;
if (!value)
return 0;
@ -605,7 +601,7 @@ char **strv_parse_nulstr(const char *s, size_t l) {
*/
const char *p;
unsigned c = 0, i = 0;
size_t c = 0, i = 0;
char **v;
assert(s || l <= 0);
@ -769,7 +765,7 @@ int strv_extendf(char ***l, const char *format, ...) {
}
char **strv_reverse(char **l) {
unsigned n, i;
size_t n, i;
n = strv_length(l);
if (n <= 1)

View file

@ -32,7 +32,7 @@ DEFINE_TRIVIAL_CLEANUP_FUNC(char**, strv_free_erase);
void strv_clear(char **l);
char **strv_copy(char * const *l);
unsigned strv_length(char * const *l) _pure_;
size_t strv_length(char * const *l) _pure_;
int strv_extend_strv(char ***a, char **b, bool filter_duplicates);
int strv_extend_strv_concat(char ***a, char **b, const char *suffix);
@ -41,7 +41,7 @@ int strv_extendf(char ***l, const char *format, ...) _printf_(2,0);
int strv_extend_front(char ***l, const char *value);
int strv_push(char ***l, char *value);
int strv_push_pair(char ***l, char *a, char *b);
int strv_insert(char ***l, unsigned position, char *value);
int strv_insert(char ***l, size_t position, char *value);
static inline int strv_push_prepend(char ***l, char *value) {
return strv_insert(l, 0, value);
@ -113,7 +113,7 @@ void strv_print(char **l);
if (!first) \
_l = (char**) &first; \
else { \
unsigned _n; \
size_t _n; \
va_list _ap; \
\
_n = 1; \

View file

@ -23,11 +23,13 @@
#include "fd-util.h"
#include "fileio.h"
#include "fs-util.h"
#include "io-util.h"
#include "log.h"
#include "macro.h"
#include "parse-util.h"
#include "path-util.h"
#include "process-util.h"
#include "stat-util.h"
#include "string-util.h"
#include "strv.h"
#include "time-util.h"
@ -438,7 +440,7 @@ char *format_timespan(char *buf, size_t l, usec_t t, usec_t accuracy) {
{ "us", 1 },
};
unsigned i;
size_t i;
char *p = buf;
bool something = false;
@ -617,10 +619,9 @@ static int parse_timestamp_impl(const char *t, usec_t *usec, bool with_tz) {
time_t x;
usec_t x_usec, plus = 0, minus = 0, ret;
int r, weekday = -1, dst = -1;
unsigned i;
size_t i;
/*
* Allowed syntaxes:
/* Allowed syntaxes:
*
* 2012-09-22 16:34:22
* 2012-09-22 16:34 (seconds will be set to 0)
@ -634,7 +635,6 @@ static int parse_timestamp_impl(const char *t, usec_t *usec, bool with_tz) {
* +5min
* -5days
* @2147483647 (seconds since epoch)
*
*/
assert(t);
@ -693,10 +693,10 @@ static int parse_timestamp_impl(const char *t, usec_t *usec, bool with_tz) {
tzset();
/* See if the timestamp is suffixed by either the DST or non-DST local timezone. Note that we only
* support the local timezones here, nothing else. Not because we wouldn't want to, but simply because
* there are no nice APIs available to cover this. By accepting the local time zone strings, we make
* sure that all timestamps written by format_timestamp() can be parsed correctly, even though we don't
* support arbitrary timezone specifications. */
* support the local timezones here, nothing else. Not because we wouldn't want to, but simply because
* there are no nice APIs available to cover this. By accepting the local time zone strings, we make
* sure that all timestamps written by format_timestamp() can be parsed correctly, even though we don't
* support arbitrary timezone specifications. */
for (j = 0; j <= 1; j++) {
@ -882,7 +882,7 @@ int parse_timestamp(const char *t, usec_t *usec) {
int r;
last_space = strrchr(t, ' ');
if (last_space != NULL && timezone_is_valid(last_space + 1))
if (last_space != NULL && timezone_is_valid(last_space + 1, LOG_DEBUG))
tz = last_space + 1;
if (!tz || endswith_no_case(t, " UTC"))
@ -908,10 +908,10 @@ int parse_timestamp(const char *t, usec_t *usec) {
tzset();
/* If there is a timezone that matches the tzname fields, leave the parsing to the implementation.
* Otherwise just cut it off */
* Otherwise just cut it off. */
with_tz = !STR_IN_SET(tz, tzname[0], tzname[1]);
/*cut off the timezone if we dont need it*/
/* Cut off the timezone if we dont need it. */
if (with_tz)
t = strndupa(t, last_space - t);
@ -965,7 +965,7 @@ static char* extract_multiplier(char *p, usec_t *multiplier) {
{ "us", 1ULL },
{ "µs", 1ULL },
};
unsigned i;
size_t i;
for (i = 0; i < ELEMENTSOF(table); i++) {
char *e;
@ -1139,8 +1139,8 @@ int parse_nsec(const char *t, nsec_t *nsec) {
for (;;) {
long long l, z = 0;
size_t n = 0, i;
char *e;
unsigned i, n = 0;
p += strspn(p, WHITESPACE);
@ -1281,10 +1281,12 @@ int get_timezones(char ***ret) {
}
#endif /* NM_IGNORED */
bool timezone_is_valid(const char *name) {
bool timezone_is_valid(const char *name, int log_level) {
bool slash = false;
const char *p, *t;
struct stat st;
_cleanup_close_ int fd = -1;
char buf[4];
int r;
if (isempty(name))
return false;
@ -1313,11 +1315,30 @@ bool timezone_is_valid(const char *name) {
return false;
t = strjoina("/usr/share/zoneinfo/", name);
if (stat(t, &st) < 0)
return false;
if (!S_ISREG(st.st_mode))
fd = open(t, O_RDONLY|O_CLOEXEC);
if (fd < 0) {
log_full_errno(log_level, errno, "Failed to open timezone file '%s': %m", t);
return false;
}
r = fd_verify_regular(fd);
if (r < 0) {
log_full_errno(log_level, r, "Timezone file '%s' is not a regular file: %m", t);
return false;
}
r = loop_read_exact(fd, buf, 4, false);
if (r < 0) {
log_full_errno(log_level, r, "Failed to read from timezone file '%s': %m", t);
return false;
}
/* Magic from tzfile(5) */
if (memcmp(buf, "TZif", 4) != 0) {
log_full(log_level, "Timezone file '%s' has wrong magic bytes", t);
return false;
}
return true;
}
@ -1389,7 +1410,7 @@ int get_timezone(char **tz) {
if (!e)
return -EINVAL;
if (!timezone_is_valid(e))
if (!timezone_is_valid(e, LOG_DEBUG))
return -EINVAL;
z = strdup(e);

View file

@ -128,7 +128,7 @@ int parse_nsec(const char *t, nsec_t *nsec);
bool ntp_synced(void);
int get_timezones(char ***l);
bool timezone_is_valid(const char *name);
bool timezone_is_valid(const char *name, int log_level);
bool clock_boottime_supported(void);
bool clock_supported(clockid_t clock);

View file

@ -86,7 +86,7 @@ int dhcp_identifier_set_iaid(int ifindex, uint8_t *mac, size_t mac_len, void *_i
#if 0 /* NM_IGNORED */
/* name is a pointer to memory in the udev_device struct, so must
have the same scope */
_cleanup_udev_device_unref_ struct udev_device *device = NULL;
_cleanup_(udev_device_unrefp) struct udev_device *device = NULL;
#else /* NM_IGNORED */
char name_buf[IF_NAMESIZE];
#endif /* NM_IGNORED */
@ -96,7 +96,7 @@ int dhcp_identifier_set_iaid(int ifindex, uint8_t *mac, size_t mac_len, void *_i
#if 0 /* NM_IGNORED */
if (detect_container() <= 0) {
/* not in a container, udev will be around */
_cleanup_udev_unref_ struct udev *udev;
_cleanup_(udev_unrefp) struct udev *udev;
char ifindex_str[2 + DECIMAL_STR_MAX(int)];
udev = udev_new();

View file

@ -14,6 +14,7 @@
#include "alloc-util.h"
#include "utf8.h"
#include "strv.h"
#include "dhcp-internal.h"
@ -37,6 +38,34 @@ static int option_append(uint8_t options[], size_t size, size_t *offset,
*offset += 1;
break;
case SD_DHCP_OPTION_USER_CLASS: {
size_t len = 0;
char **s;
STRV_FOREACH(s, (char **) optval)
len += strlen(*s) + 1;
if (size < *offset + len + 2)
return -ENOBUFS;
options[*offset] = code;
options[*offset + 1] = len;
*offset += 2;
STRV_FOREACH(s, (char **) optval) {
len = strlen(*s);
if (len > 255)
return -ENAMETOOLONG;
options[*offset] = len;
memcpy_safe(&options[*offset + 1], *s, len);
*offset += len + 1;
}
break;
}
default:
if (size < *offset + optlen + 2)
return -ENOBUFS;

View file

@ -86,7 +86,7 @@ static bool net_condition_test_strv(char * const *raw_patterns,
/* If the patterns begin with "!", edit it out and negate the test. */
if (raw_patterns[0][0] == '!') {
char **patterns;
unsigned i, length;
size_t i, length;
length = strv_length(raw_patterns) + 1; /* Include the NULL. */
patterns = newa(char*, length);
@ -100,7 +100,7 @@ static bool net_condition_test_strv(char * const *raw_patterns,
return string && strv_fnmatch(raw_patterns, string, 0);
}
bool net_match_config(const struct ether_addr *match_mac,
bool net_match_config(Set *match_mac,
char * const *match_paths,
char * const *match_drivers,
char * const *match_types,
@ -132,7 +132,7 @@ bool net_match_config(const struct ether_addr *match_mac,
if (match_arch && condition_test(match_arch) <= 0)
return false;
if (match_mac && (!dev_mac || memcmp(match_mac, dev_mac, ETH_ALEN)))
if (match_mac && dev_mac && !set_contains(match_mac, dev_mac))
return false;
if (!net_condition_test_strv(match_paths, dev_path))
@ -284,10 +284,9 @@ int config_parse_hwaddr(const char *unit,
const char *rvalue,
void *data,
void *userdata) {
_cleanup_free_ struct ether_addr *n = NULL;
struct ether_addr **hwaddr = data;
struct ether_addr *n;
const char *start;
size_t offset;
int r;
assert(filename);
@ -299,17 +298,86 @@ int config_parse_hwaddr(const char *unit,
if (!n)
return log_oom();
start = rvalue + strspn(rvalue, WHITESPACE);
r = ether_addr_from_string(start, n, &offset);
if (r || (start[offset + strspn(start + offset, WHITESPACE)] != '\0')) {
log_syntax(unit, LOG_ERR, filename, line, 0, "Not a valid MAC address, ignoring assignment: %s", rvalue);
free(n);
r = ether_addr_from_string(rvalue, n);
if (r < 0) {
log_syntax(unit, LOG_ERR, filename, line, r, "Not a valid MAC address, ignoring assignment: %s", rvalue);
return 0;
}
free(*hwaddr);
*hwaddr = n;
*hwaddr = TAKE_PTR(n);
return 0;
}
int config_parse_hwaddrs(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) {
_cleanup_set_free_free_ Set *s = NULL;
const char *p = rvalue;
Set **hwaddrs = data;
int r;
assert(filename);
assert(lvalue);
assert(rvalue);
assert(data);
if (isempty(rvalue)) {
/* Empty assignment resets the list */
*hwaddrs = set_free_free(*hwaddrs);
return 0;
}
s = set_new(&ether_addr_hash_ops);
if (!s)
return log_oom();
for (;;) {
_cleanup_free_ char *word = NULL;
_cleanup_free_ struct ether_addr *n = NULL;
r = extract_first_word(&p, &word, NULL, 0);
if (r == 0)
break;
if (r == -ENOMEM)
return log_oom();
if (r < 0) {
log_syntax(unit, LOG_WARNING, filename, line, r, "Invalid syntax, ignoring: %s", rvalue);
return 0;
}
n = new(struct ether_addr, 1);
if (!n)
return log_oom();
r = ether_addr_from_string(word, n);
if (r < 0) {
log_syntax(unit, LOG_ERR, filename, line, 0, "Not a valid MAC address, ignoring: %s", word);
continue;
}
r = set_put(s, n);
if (r < 0)
return log_oom();
if (r > 0)
n = NULL; /* avoid cleanup */
}
r = set_ensure_allocated(hwaddrs, &ether_addr_hash_ops);
if (r < 0)
return log_oom();
r = set_move(*hwaddrs, s);
if (r < 0)
return log_oom();
return 0;
}
@ -592,14 +660,3 @@ int serialize_dhcp_option(FILE *f, const char *key, const void *data, size_t siz
return 0;
}
int deserialize_dhcp_option(void **data, size_t *data_len, const char *string) {
assert(data);
assert(data_len);
assert(string);
if (strlen(string) % 2)
return -EINVAL;
return unhexmem(string, strlen(string), (void **)data, data_len);
}

View file

@ -12,12 +12,13 @@
#include "sd-dhcp-lease.h"
#include "condition.h"
#include "set.h"
#include "udev.h"
#define LINK_BRIDGE_PORT_PRIORITY_INVALID 128
#define LINK_BRIDGE_PORT_PRIORITY_MAX 63
bool net_match_config(const struct ether_addr *match_mac,
bool net_match_config(Set *match_mac,
char * const *match_path,
char * const *match_driver,
char * const *match_type,
@ -42,6 +43,10 @@ int config_parse_hwaddr(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);
int config_parse_hwaddrs(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);
int config_parse_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);
@ -73,5 +78,5 @@ struct sd_dhcp_route;
void serialize_dhcp_routes(FILE *f, const char *key, sd_dhcp_route **routes, size_t size);
int deserialize_dhcp_routes(struct sd_dhcp_route **ret, size_t *ret_size, size_t *ret_allocated, const char *string);
/* It is not necessary to add deserialize_dhcp_option(). Use unhexmem() instead. */
int serialize_dhcp_option(FILE *f, const char *key, const void *data, size_t size);
int deserialize_dhcp_option(void **data, size_t *data_len, const char *string);

View file

@ -29,6 +29,7 @@
#include "random-util.h"
#include "string-util.h"
#include "util.h"
#include "strv.h"
#define MAX_CLIENT_ID_LEN (sizeof(uint32_t) + MAX_DUID_LEN) /* Arbitrary limit */
#define MAX_MAC_ADDR_LEN CONST_MAX(INFINIBAND_ALEN, ETH_ALEN)
@ -85,6 +86,7 @@ struct sd_dhcp_client {
size_t client_id_len;
char *hostname;
char *vendor_class_identifier;
char **user_class;
uint32_t mtu;
uint32_t xid;
usec_t start_time;
@ -445,6 +447,26 @@ int sd_dhcp_client_set_vendor_class_identifier(
return free_and_strdup(&client->vendor_class_identifier, vci);
}
int sd_dhcp_client_set_user_class(
sd_dhcp_client *client,
const char* const* user_class) {
_cleanup_strv_free_ char **s = NULL;
char **p;
STRV_FOREACH(p, (char **) user_class)
if (strlen(*p) > 255)
return -ENAMETOOLONG;
s = strv_copy((char **) user_class);
if (!s)
return -ENOMEM;
client->user_class = TAKE_PTR(s);
return 0;
}
int sd_dhcp_client_set_client_port(
sd_dhcp_client *client,
uint16_t port) {
@ -768,6 +790,15 @@ static int client_send_discover(sd_dhcp_client *client) {
return r;
}
if (client->user_class) {
r = dhcp_option_append(&discover->dhcp, optlen, &optoffset, 0,
SD_DHCP_OPTION_USER_CLASS,
strv_length(client->user_class),
client->user_class);
if (r < 0)
return r;
}
r = dhcp_option_append(&discover->dhcp, optlen, &optoffset, 0,
SD_DHCP_OPTION_END, 0, NULL);
if (r < 0)
@ -1923,6 +1954,7 @@ sd_dhcp_client *sd_dhcp_client_unref(sd_dhcp_client *client) {
free(client->req_opts);
free(client->hostname);
free(client->vendor_class_identifier);
client->user_class = strv_free(client->user_class);
return mfree(client);
}

View file

@ -223,7 +223,7 @@ int sd_dhcp_lease_get_routes(sd_dhcp_lease *lease, sd_dhcp_route ***routes) {
}
int sd_dhcp_lease_get_search_domains(sd_dhcp_lease *lease, char ***domains) {
unsigned r;
size_t r;
assert_return(lease, -EINVAL);
assert_return(domains, -EINVAL);
@ -669,7 +669,7 @@ int dhcp_lease_parse_options(uint8_t code, uint8_t len, const void *option, void
return 0;
}
if (!timezone_is_valid(tz)) {
if (!timezone_is_valid(tz, LOG_DEBUG)) {
log_debug_errno(r, "Timezone is not valid, ignoring: %m");
return 0;
}
@ -1195,13 +1195,13 @@ int dhcp_lease_load(sd_dhcp_lease **ret, const char *lease_file) {
}
if (client_id_hex) {
r = deserialize_dhcp_option(&lease->client_id, &lease->client_id_len, client_id_hex);
r = unhexmem(client_id_hex, (size_t) -1, &lease->client_id, &lease->client_id_len);
if (r < 0)
log_debug_errno(r, "Failed to parse client ID %s, ignoring: %m", client_id_hex);
}
if (vendor_specific_hex) {
r = deserialize_dhcp_option(&lease->vendor_specific, &lease->vendor_specific_len, vendor_specific_hex);
r = unhexmem(vendor_specific_hex, (size_t) -1, &lease->vendor_specific, &lease->vendor_specific_len);
if (r < 0)
log_debug_errno(r, "Failed to parse vendor specific data %s, ignoring: %m", vendor_specific_hex);
}
@ -1213,7 +1213,7 @@ int dhcp_lease_load(sd_dhcp_lease **ret, const char *lease_file) {
if (!options[i])
continue;
r = deserialize_dhcp_option(&data, &len, options[i]);
r = unhexmem(options[i], (size_t) -1, &data, &len);
if (r < 0) {
log_debug_errno(r, "Failed to parse private DHCP option %s, ignoring: %m", options[i]);
continue;

View file

@ -250,8 +250,7 @@ int dhcp6_lease_set_domains(sd_dhcp6_lease *lease, uint8_t *optval,
if (r < 0)
return 0;
strv_free(lease->domains);
lease->domains = domains;
strv_free_and_replace(lease->domains, domains);
lease->domains_count = r;
return r;
@ -310,8 +309,7 @@ int dhcp6_lease_set_ntp(sd_dhcp6_lease *lease, uint8_t *optval, size_t optlen) {
if (r < 0)
return 0;
lease->ntp_fqdn = strv_free(lease->ntp_fqdn);
lease->ntp_fqdn = servers;
strv_free_and_replace(lease->ntp_fqdn, servers);
lease->ntp_fqdn_count = r;
break;

View file

@ -404,15 +404,15 @@ static int neighbor_compare_func(const void *a, const void *b) {
static int on_timer_event(sd_event_source *s, uint64_t usec, void *userdata) {
sd_lldp *lldp = userdata;
int r, q;
int r;
r = lldp_make_space(lldp, 0);
if (r < 0)
return log_lldp_errno(r, "Failed to make space: %m");
q = lldp_start_timer(lldp, NULL);
if (q < 0)
return log_lldp_errno(q, "Failed to restart timer: %m");
r = lldp_start_timer(lldp, NULL);
if (r < 0)
return log_lldp_errno(r, "Failed to restart timer: %m");
return 0;
}

View file

@ -82,6 +82,7 @@ enum {
SD_DHCP_OPTION_REBINDING_T2_TIME = 59,
SD_DHCP_OPTION_VENDOR_CLASS_IDENTIFIER = 60,
SD_DHCP_OPTION_CLIENT_IDENTIFIER = 61,
SD_DHCP_OPTION_USER_CLASS = 77,
SD_DHCP_OPTION_FQDN = 81,
SD_DHCP_OPTION_NEW_POSIX_TIMEZONE = 100,
SD_DHCP_OPTION_NEW_TZDB_TIMEZONE = 101,
@ -154,6 +155,9 @@ int sd_dhcp_client_set_hostname(
int sd_dhcp_client_set_vendor_class_identifier(
sd_dhcp_client *client,
const char *vci);
int sd_dhcp_client_set_user_class(
sd_dhcp_client *client,
const char* const *user_class);
int sd_dhcp_client_get_lease(
sd_dhcp_client *client,
sd_dhcp_lease **ret);