systemd: merge branch systemd into master

This commit is contained in:
Thomas Haller
2016-10-24 17:37:31 +02:00
27 changed files with 374 additions and 51 deletions

View File

@@ -0,0 +1,3 @@
#pragma once
/* dummy header */

View File

@@ -43,6 +43,14 @@ static inline void *mfree(void *memory) {
return NULL; return NULL;
} }
#define free_and_replace(a, b) \
({ \
free(a); \
(a) = (b); \
(b) = NULL; \
0; \
})
void* memdup(const void *p, size_t l) _alloc_(2); void* memdup(const void *p, size_t l) _alloc_(2);
static inline void freep(void *p) { static inline void freep(void *p) {

View File

@@ -335,7 +335,7 @@ int cunescape_length_with_prefix(const char *s, size_t length, const char *prefi
assert(remaining > 0); assert(remaining > 0);
if (*f != '\\') { if (*f != '\\') {
/* A literal literal, copy verbatim */ /* A literal, copy verbatim */
*(t++) = *f; *(t++) = *f;
continue; continue;
} }

View File

@@ -604,4 +604,187 @@ int inotify_add_watch_fd(int fd, int what, uint32_t mask) {
return r; return r;
} }
int chase_symlinks(const char *path, const char *_root, char **ret) {
_cleanup_free_ char *buffer = NULL, *done = NULL, *root = NULL;
_cleanup_close_ int fd = -1;
unsigned max_follow = 32; /* how many symlinks to follow before giving up and returning ELOOP */
char *todo;
int r;
assert(path);
/* This is a lot like canonicalize_file_name(), but takes an additional "root" parameter, that allows following
* symlinks relative to a root directory, instead of the root of the host.
*
* Note that "root" matters only if we encounter an absolute symlink, it's unused otherwise. Most importantly
* this means the path parameter passed in is not prefixed by it.
*
* Algorithmically this operates on two path buffers: "done" are the components of the path we already
* processed and resolved symlinks, "." and ".." of. "todo" are the components of the path we still need to
* process. On each iteration, we move one component from "todo" to "done", processing it's special meaning
* each time. The "todo" path always starts with at least one slash, the "done" path always ends in no
* slash. We always keep an O_PATH fd to the component we are currently processing, thus keeping lookup races
* at a minimum. */
r = path_make_absolute_cwd(path, &buffer);
if (r < 0)
return r;
if (_root) {
r = path_make_absolute_cwd(_root, &root);
if (r < 0)
return r;
}
fd = open("/", O_CLOEXEC|O_NOFOLLOW|O_PATH);
if (fd < 0)
return -errno;
todo = buffer;
for (;;) {
_cleanup_free_ char *first = NULL;
_cleanup_close_ int child = -1;
struct stat st;
size_t n, m;
/* Determine length of first component in the path */
n = strspn(todo, "/"); /* The slashes */
m = n + strcspn(todo + n, "/"); /* The entire length of the component */
/* Extract the first component. */
first = strndup(todo, m);
if (!first)
return -ENOMEM;
todo += m;
/* Just a single slash? Then we reached the end. */
if (isempty(first) || path_equal(first, "/"))
break;
/* Just a dot? Then let's eat this up. */
if (path_equal(first, "/."))
continue;
/* Two dots? Then chop off the last bit of what we already found out. */
if (path_equal(first, "/..")) {
_cleanup_free_ char *parent = NULL;
int fd_parent = -1;
if (isempty(done) || path_equal(done, "/"))
return -EINVAL;
parent = dirname_malloc(done);
if (!parent)
return -ENOMEM;
/* Don't allow this to leave the root dir */
if (root &&
path_startswith(done, root) &&
!path_startswith(parent, root))
return -EINVAL;
free_and_replace(done, parent);
fd_parent = openat(fd, "..", O_CLOEXEC|O_NOFOLLOW|O_PATH);
if (fd_parent < 0)
return -errno;
safe_close(fd);
fd = fd_parent;
continue;
}
/* Otherwise let's see what this is. */
child = openat(fd, first + n, O_CLOEXEC|O_NOFOLLOW|O_PATH);
if (child < 0)
return -errno;
if (fstat(child, &st) < 0)
return -errno;
if (S_ISLNK(st.st_mode)) {
_cleanup_free_ char *destination = NULL;
/* This is a symlink, in this case read the destination. But let's make sure we don't follow
* symlinks without bounds. */
if (--max_follow <= 0)
return -ELOOP;
r = readlinkat_malloc(fd, first + n, &destination);
if (r < 0)
return r;
if (isempty(destination))
return -EINVAL;
if (path_is_absolute(destination)) {
/* An absolute destination. Start the loop from the beginning, but use the root
* directory as base. */
safe_close(fd);
fd = open(root ?: "/", O_CLOEXEC|O_NOFOLLOW|O_PATH);
if (fd < 0)
return -errno;
free_and_replace(buffer, destination);
todo = buffer;
free(done);
/* Note that we do not revalidate the root, we take it as is. */
if (isempty(root))
done = NULL;
else {
done = strdup(root);
if (!done)
return -ENOMEM;
}
} else {
char *joined;
/* A relative destination. If so, this is what we'll 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, NULL);
if (!joined)
return -ENOMEM;
free(buffer);
todo = buffer = joined;
}
continue;
}
/* If this is not a symlink, then let's just add the name we read to what we already verified. */
if (!done) {
done = first;
first = NULL;
} else {
if (!strextend(&done, first, NULL))
return -ENOMEM;
}
/* And iterate again, but go one directory further down. */
safe_close(fd);
fd = child;
child = -1;
}
if (!done) {
/* Special case, turn the empty string into "/", to indicate the root directory. */
done = strdup("/");
if (!done)
return -ENOMEM;
}
*ret = done;
done = NULL;
return 0;
}
#endif /* NM_IGNORED */ #endif /* NM_IGNORED */

View File

@@ -77,3 +77,5 @@ union inotify_event_buffer {
}; };
int inotify_add_watch_fd(int fd, int what, uint32_t mask); int inotify_add_watch_fd(int fd, int what, uint32_t mask);
int chase_symlinks(const char *path, const char *_root, char **ret);

View File

@@ -142,6 +142,8 @@
} else { \ } else { \
if ((_b->name##_prev = _a->name##_prev)) \ if ((_b->name##_prev = _a->name##_prev)) \
_b->name##_prev->name##_next = _b; \ _b->name##_prev->name##_next = _b; \
else \
*_head = _b; \
_b->name##_next = _a; \ _b->name##_next = _a; \
_a->name##_prev = _b; \ _a->name##_prev = _b; \
} \ } \

View File

@@ -101,18 +101,22 @@ int log_object_internal(
const char *func, const char *func,
const char *object_field, const char *object_field,
const char *object, const char *object,
const char *format, ...) _printf_(8,9); const char *extra_field,
const char *extra,
const char *format, ...) _printf_(10,11);
int log_object_internalv( int log_object_internalv(
int level, int level,
int error, int error,
const char*file, const char *file,
int line, int line,
const char *func, const char *func,
const char *object_field, const char *object_field,
const char *object, const char *object,
const char *extra_field,
const char *extra,
const char *format, const char *format,
va_list ap) _printf_(8,0); va_list ap) _printf_(9,0);
int log_struct_internal( int log_struct_internal(
int level, int level,

View File

@@ -36,9 +36,11 @@
#include "alloc-util.h" #include "alloc-util.h"
#include "extract-word.h" #include "extract-word.h"
#include "fs-util.h" #include "fs-util.h"
#include "glob-util.h"
#include "log.h" #include "log.h"
#include "macro.h" #include "macro.h"
#include "missing.h" #include "missing.h"
#include "parse-util.h"
#include "path-util.h" #include "path-util.h"
#include "stat-util.h" #include "stat-util.h"
#include "string-util.h" #include "string-util.h"
@@ -289,9 +291,7 @@ char **path_strv_resolve(char **l, const char *prefix) {
} else { } else {
/* canonicalized path goes outside of /* canonicalized path goes outside of
* prefix, keep the original path instead */ * prefix, keep the original path instead */
free(u); free_and_replace(u, orig);
u = orig;
orig = NULL;
} }
} else } else
free(t); free(t);
@@ -817,8 +817,79 @@ bool is_device_path(const char *path) {
/* Returns true on paths that refer to a device, either in /* Returns true on paths that refer to a device, either in
* sysfs or in /dev */ * sysfs or in /dev */
return return path_startswith(path, "/dev/") ||
path_startswith(path, "/dev/") || path_startswith(path, "/sys/");
path_startswith(path, "/sys/"); }
bool is_deviceallow_pattern(const char *path) {
return path_startswith(path, "/dev/") ||
startswith(path, "block-") ||
startswith(path, "char-");
}
int systemd_installation_has_version(const char *root, unsigned minimal_version) {
const char *pattern;
int r;
/* Try to guess if systemd installation is later than the specified version. This
* is hacky and likely to yield false negatives, particularly if the installation
* is non-standard. False positives should be relatively rare.
*/
NULSTR_FOREACH(pattern,
/* /lib works for systems without usr-merge, and for systems with a sane
* usr-merge, where /lib is a symlink to /usr/lib. /usr/lib is necessary
* for Gentoo which does a merge without making /lib a symlink.
*/
"lib/systemd/libsystemd-shared-*.so\0"
"usr/lib/systemd/libsystemd-shared-*.so\0") {
_cleanup_strv_free_ char **names = NULL;
_cleanup_free_ char *path = NULL;
char *c, **name;
path = prefix_root(root, pattern);
if (!path)
return -ENOMEM;
r = glob_extend(&names, path);
if (r == -ENOENT)
continue;
if (r < 0)
return r;
assert_se((c = endswith(path, "*.so")));
*c = '\0'; /* truncate the glob part */
STRV_FOREACH(name, names) {
/* This is most likely to run only once, hence let's not optimize anything. */
char *t, *t2;
unsigned version;
t = startswith(*name, path);
if (!t)
continue;
t2 = endswith(t, ".so");
if (!t2)
continue;
t2[0] = '\0'; /* truncate the suffix */
r = safe_atou(t, &version);
if (r < 0) {
log_debug_errno(r, "Found libsystemd shared at \"%s.so\", but failed to parse version: %m", *name);
continue;
}
log_debug("Found libsystemd shared at \"%s.so\", version %u (%s).",
*name, version,
version >= minimal_version ? "OK" : "too old");
if (version >= minimal_version)
return true;
}
}
return false;
} }
#endif /* NM_IGNORED */ #endif /* NM_IGNORED */

View File

@@ -125,3 +125,6 @@ char *file_in_same_dir(const char *path, const char *filename);
bool hidden_or_backup_file(const char *filename) _pure_; bool hidden_or_backup_file(const char *filename) _pure_;
bool is_device_path(const char *path); bool is_device_path(const char *path);
bool is_deviceallow_pattern(const char *path);
int systemd_installation_has_version(const char *root, unsigned minimal_version);

View File

@@ -64,9 +64,7 @@ Prioq* prioq_free(Prioq *q) {
return NULL; return NULL;
free(q->items); free(q->items);
free(q); return mfree(q);
return NULL;
} }
int prioq_ensure_allocated(Prioq **q, compare_func_t compare_func) { int prioq_ensure_allocated(Prioq **q, compare_func_t compare_func) {

View File

@@ -444,7 +444,7 @@ const char* socket_address_get_path(const SocketAddress *a) {
} }
bool socket_ipv6_is_supported(void) { bool socket_ipv6_is_supported(void) {
if (access("/proc/net/sockstat6", F_OK) != 0) if (access("/proc/net/if_inet6", F_OK) != 0)
return false; return false;
return true; return true;
@@ -1064,3 +1064,20 @@ struct cmsghdr* cmsg_find(struct msghdr *mh, int level, int type, socklen_t leng
return NULL; return NULL;
} }
int socket_ioctl_fd(void) {
int fd;
/* Create a socket to invoke the various network interface ioctl()s on. Traditionally only AF_INET was good for
* that. Since kernel 4.6 AF_NETLINK works for this too. We first try to use AF_INET hence, but if that's not
* available (for example, because it is made unavailable via SECCOMP or such), we'll fall back to the more
* generic AF_NETLINK. */
fd = socket(AF_INET, SOCK_DGRAM|SOCK_CLOEXEC, 0);
if (fd < 0)
fd = socket(AF_NETLINK, SOCK_RAW|SOCK_CLOEXEC, NETLINK_GENERIC);
if (fd < 0)
return -errno;
return fd;
}

View File

@@ -154,3 +154,5 @@ struct cmsghdr* cmsg_find(struct msghdr *mh, int level, int type, socklen_t leng
1 + strnlen(_sa->sun_path+1, sizeof(_sa->sun_path)-1) : \ 1 + strnlen(_sa->sun_path+1, sizeof(_sa->sun_path)-1) : \
strnlen(_sa->sun_path, sizeof(_sa->sun_path))); \ strnlen(_sa->sun_path, sizeof(_sa->sun_path))); \
}) })
int socket_ioctl_fd(void);

View File

@@ -614,8 +614,7 @@ char *strreplace(const char *text, const char *old_string, const char *new_strin
return r; return r;
oom: oom:
free(r); return mfree(r);
return NULL;
} }
char *strip_tab_ansi(char **ibuf, size_t *_isz) { char *strip_tab_ansi(char **ibuf, size_t *_isz) {
@@ -686,8 +685,7 @@ char *strip_tab_ansi(char **ibuf, size_t *_isz) {
if (ferror(f)) { if (ferror(f)) {
fclose(f); fclose(f);
free(obuf); return mfree(obuf);
return NULL;
} }
fclose(f); fclose(f);

View File

@@ -89,8 +89,7 @@ void strv_clear(char **l) {
char **strv_free(char **l) { char **strv_free(char **l) {
strv_clear(l); strv_clear(l);
free(l); return mfree(l);
return NULL;
} }
char **strv_free_erase(char **l) { char **strv_free_erase(char **l) {
@@ -430,8 +429,7 @@ char *strv_join_quoted(char **l) {
return buf; return buf;
oom: oom:
free(buf); return mfree(buf);
return NULL;
} }
int strv_push(char ***l, char *value) { int strv_push(char ***l, char *value) {
@@ -873,8 +871,7 @@ char ***strv_free_free(char ***l) {
for (i = l; *i; i++) for (i = l; *i; i++)
strv_free(*i); strv_free(*i);
free(l); return mfree(l);
return NULL;
} }
char **strv_skip(char **l, size_t n) { char **strv_skip(char **l, size_t n) {

View File

@@ -96,10 +96,13 @@ bool strv_overlap(char **a, char **b) _pure_;
#define STRV_FOREACH(s, l) \ #define STRV_FOREACH(s, l) \
for ((s) = (l); (s) && *(s); (s)++) for ((s) = (l); (s) && *(s); (s)++)
#define STRV_FOREACH_BACKWARDS(s, l) \ #define STRV_FOREACH_BACKWARDS(s, l) \
STRV_FOREACH(s, l) \ for (s = ({ \
; \ char **_l = l; \
for ((s)--; (l) && ((s) >= (l)); (s)--) _l ? _l + strv_length(_l) - 1U : NULL; \
}); \
(l) && ((s) >= (l)); \
(s)--)
#define STRV_FOREACH_PAIR(x, y, l) \ #define STRV_FOREACH_PAIR(x, y, l) \
for ((x) = (l), (y) = (x+1); (x) && *(x) && *(y); (x) += 2, (y) = (x + 1)) for ((x) = (l), (y) = (x+1); (x) && *(x) && *(y); (x) += 2, (y) = (x + 1))
@@ -141,6 +144,11 @@ void strv_print(char **l);
}) })
#define STR_IN_SET(x, ...) strv_contains(STRV_MAKE(__VA_ARGS__), x) #define STR_IN_SET(x, ...) strv_contains(STRV_MAKE(__VA_ARGS__), x)
#define STRPTR_IN_SET(x, ...) \
({ \
const char* _x = (x); \
_x && strv_contains(STRV_MAKE(__VA_ARGS__), _x); \
})
#define FOREACH_STRING(x, ...) \ #define FOREACH_STRING(x, ...) \
for (char **_l = ({ \ for (char **_l = ({ \

View File

@@ -472,7 +472,7 @@ bool in_initrd(void) {
* 2. the root file system must be a memory file system * 2. the root file system must be a memory file system
* *
* The second check is extra paranoia, since misdetecting an * The second check is extra paranoia, since misdetecting an
* initrd can have bad bad consequences due the initrd * initrd can have bad consequences due the initrd
* emptying when transititioning to the main systemd. * emptying when transititioning to the main systemd.
*/ */

View File

@@ -1877,9 +1877,7 @@ sd_dhcp_client *sd_dhcp_client_unref(sd_dhcp_client *client) {
free(client->req_opts); free(client->req_opts);
free(client->hostname); free(client->hostname);
free(client->vendor_class_identifier); free(client->vendor_class_identifier);
free(client); return mfree(client);
return NULL;
} }
int sd_dhcp_client_new(sd_dhcp_client **ret) { int sd_dhcp_client_new(sd_dhcp_client **ret) {

View File

@@ -284,9 +284,7 @@ sd_dhcp_lease *sd_dhcp_lease_unref(sd_dhcp_lease *lease) {
free(lease->static_route); free(lease->static_route);
free(lease->client_id); free(lease->client_id);
free(lease->vendor_specific); free(lease->vendor_specific);
free(lease); return mfree(lease);
return NULL;
} }
static int lease_parse_u32(const uint8_t *option, size_t len, uint32_t *ret, uint32_t min) { static int lease_parse_u32(const uint8_t *option, size_t len, uint32_t *ret, uint32_t min) {

View File

@@ -1304,9 +1304,7 @@ sd_dhcp6_client *sd_dhcp6_client_unref(sd_dhcp6_client *client) {
sd_dhcp6_client_detach_event(client); sd_dhcp6_client_detach_event(client);
free(client->req_opts); free(client->req_opts);
free(client); return mfree(client);
return NULL;
} }
int sd_dhcp6_client_new(sd_dhcp6_client **ret) { int sd_dhcp6_client_new(sd_dhcp6_client **ret) {

View File

@@ -391,9 +391,7 @@ sd_dhcp6_lease *sd_dhcp6_lease_unref(sd_dhcp6_lease *lease) {
free(lease->ntp); free(lease->ntp);
lease->ntp_fqdn = strv_free(lease->ntp_fqdn); lease->ntp_fqdn = strv_free(lease->ntp_fqdn);
free(lease); return mfree(lease);
return NULL;
} }
int dhcp6_lease_new(sd_dhcp6_lease **ret) { int dhcp6_lease_new(sd_dhcp6_lease **ret) {

View File

@@ -137,9 +137,7 @@ sd_ipv4acd *sd_ipv4acd_unref(sd_ipv4acd *acd) {
ipv4acd_reset(acd); ipv4acd_reset(acd);
sd_ipv4acd_detach_event(acd); sd_ipv4acd_detach_event(acd);
free(acd); return mfree(acd);
return NULL;
} }
int sd_ipv4acd_new(sd_ipv4acd **ret) { int sd_ipv4acd_new(sd_ipv4acd **ret) {

View File

@@ -92,9 +92,7 @@ sd_ipv4ll *sd_ipv4ll_unref(sd_ipv4ll *ll) {
return NULL; return NULL;
sd_ipv4acd_unref(ll->acd); sd_ipv4acd_unref(ll->acd);
free(ll); return mfree(ll);
return NULL;
} }
int sd_ipv4ll_new(sd_ipv4ll **ret) { int sd_ipv4ll_new(sd_ipv4ll **ret) {

View File

@@ -376,9 +376,7 @@ _public_ sd_lldp* sd_lldp_unref(sd_lldp *lldp) {
hashmap_free(lldp->neighbor_by_id); hashmap_free(lldp->neighbor_by_id);
prioq_free(lldp->neighbor_by_expiry); prioq_free(lldp->neighbor_by_expiry);
free(lldp); return mfree(lldp);
return NULL;
} }
_public_ int sd_lldp_new(sd_lldp **ret) { _public_ int sd_lldp_new(sd_lldp **ret) {

View File

@@ -197,4 +197,17 @@ int id128_write(const char *p, Id128Format f, sd_id128_t id, bool do_sync) {
return id128_write_fd(fd, f, id, do_sync); return id128_write_fd(fd, f, id, do_sync);
} }
void id128_hash_func(const void *p, struct siphash *state) {
siphash24_compress(p, 16, state);
}
int id128_compare_func(const void *a, const void *b) {
return memcmp(a, b, 16);
}
const struct hash_ops id128_hash_ops = {
.hash = id128_hash_func,
.compare = id128_compare_func,
};
#endif /* NM_IGNORED */ #endif /* NM_IGNORED */

View File

@@ -22,6 +22,8 @@
#include <stdbool.h> #include <stdbool.h>
#include "sd-id128.h" #include "sd-id128.h"
#include "hash-funcs.h"
#include "macro.h" #include "macro.h"
char *id128_to_uuid_string(sd_id128_t id, char s[37]); char *id128_to_uuid_string(sd_id128_t id, char s[37]);
@@ -43,3 +45,7 @@ int id128_read(const char *p, Id128Format f, sd_id128_t *ret);
int id128_write_fd(int fd, Id128Format f, sd_id128_t id, bool do_sync); int id128_write_fd(int fd, Id128Format f, sd_id128_t id, bool do_sync);
int id128_write(const char *p, Id128Format f, sd_id128_t id, bool do_sync); int id128_write(const char *p, Id128Format f, sd_id128_t id, bool do_sync);
void id128_hash_func(const void *p, struct siphash *state);
int id128_compare_func(const void *a, const void *b) _pure_;
extern const struct hash_ops id128_hash_ops;

View File

@@ -134,6 +134,28 @@ _public_ int sd_id128_get_boot(sd_id128_t *ret) {
} }
#if 0 /* NM_IGNORED */ #if 0 /* NM_IGNORED */
_public_ int sd_id128_get_invocation(sd_id128_t *ret) {
static thread_local sd_id128_t saved_invocation_id = {};
int r;
assert_return(ret, -EINVAL);
if (sd_id128_is_null(saved_invocation_id)) {
const char *e;
e = secure_getenv("INVOCATION_ID");
if (!e)
return -ENXIO;
r = sd_id128_from_string(e, &saved_invocation_id);
if (r < 0)
return r;
}
*ret = saved_invocation_id;
return 0;
}
static sd_id128_t make_v4_uuid(sd_id128_t id) { static sd_id128_t make_v4_uuid(sd_id128_t id) {
/* Stolen from generate_random_uuid() of drivers/char/random.c /* Stolen from generate_random_uuid() of drivers/char/random.c
* in the kernel sources */ * in the kernel sources */

View File

@@ -45,8 +45,8 @@ int sd_id128_from_string(const char *s, sd_id128_t *ret);
int sd_id128_randomize(sd_id128_t *ret); int sd_id128_randomize(sd_id128_t *ret);
int sd_id128_get_machine(sd_id128_t *ret); int sd_id128_get_machine(sd_id128_t *ret);
int sd_id128_get_boot(sd_id128_t *ret); int sd_id128_get_boot(sd_id128_t *ret);
int sd_id128_get_invocation(sd_id128_t *ret);
#define SD_ID128_MAKE(v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15) \ #define SD_ID128_MAKE(v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15) \
((const sd_id128_t) { .bytes = { 0x##v0, 0x##v1, 0x##v2, 0x##v3, 0x##v4, 0x##v5, 0x##v6, 0x##v7, \ ((const sd_id128_t) { .bytes = { 0x##v0, 0x##v1, 0x##v2, 0x##v3, 0x##v4, 0x##v5, 0x##v6, 0x##v7, \