systemd: update code from upstream

This is a direct dump from systemd git on 2016-08-11, git commit
9c5077fed42dc3cd2517a7ab816babef549dd079.

======

SYSTEMD_DIR=../systemd
COMMIT=9c5077fed42dc3cd2517a7ab816babef549dd079

(
  cd "$SYSTEMD_DIR"
  git checkout "$COMMIT"
  git reset --hard
  git clean -fdx
)

git ls-files :/src/systemd/src/ | xargs -d '\n' rm -f

nm_copy_sd() {
    mkdir -p "./src/systemd/$(dirname "$1")"
    cp "$SYSTEMD_DIR/$1" "./src/systemd/$1"
}

nm_copy_sd "src/basic/alloc-util.c"
nm_copy_sd "src/basic/alloc-util.h"
nm_copy_sd "src/basic/async.h"
nm_copy_sd "src/basic/escape.c"
nm_copy_sd "src/basic/escape.h"
nm_copy_sd "src/basic/ether-addr-util.c"
nm_copy_sd "src/basic/ether-addr-util.h"
nm_copy_sd "src/basic/extract-word.c"
nm_copy_sd "src/basic/extract-word.h"
nm_copy_sd "src/basic/fileio.c"
nm_copy_sd "src/basic/fileio.h"
nm_copy_sd "src/basic/fd-util.c"
nm_copy_sd "src/basic/fd-util.h"
nm_copy_sd "src/basic/fs-util.c"
nm_copy_sd "src/basic/fs-util.h"
nm_copy_sd "src/basic/hash-funcs.c"
nm_copy_sd "src/basic/hash-funcs.h"
nm_copy_sd "src/basic/hashmap.c"
nm_copy_sd "src/basic/hashmap.h"
nm_copy_sd "src/basic/hexdecoct.c"
nm_copy_sd "src/basic/hexdecoct.h"
nm_copy_sd "src/basic/hostname-util.c"
nm_copy_sd "src/basic/hostname-util.h"
nm_copy_sd "src/basic/in-addr-util.c"
nm_copy_sd "src/basic/in-addr-util.h"
nm_copy_sd "src/basic/io-util.c"
nm_copy_sd "src/basic/io-util.h"
nm_copy_sd "src/basic/list.h"
nm_copy_sd "src/basic/log.h"
nm_copy_sd "src/basic/macro.h"
nm_copy_sd "src/basic/mempool.h"
nm_copy_sd "src/basic/mempool.c"
nm_copy_sd "src/basic/parse-util.c"
nm_copy_sd "src/basic/parse-util.h"
nm_copy_sd "src/basic/path-util.c"
nm_copy_sd "src/basic/path-util.h"
nm_copy_sd "src/basic/prioq.h"
nm_copy_sd "src/basic/prioq.c"
nm_copy_sd "src/basic/random-util.c"
nm_copy_sd "src/basic/random-util.h"
nm_copy_sd "src/basic/refcnt.h"
nm_copy_sd "src/basic/set.h"
nm_copy_sd "src/basic/signal-util.h"
nm_copy_sd "src/basic/siphash24.c"
nm_copy_sd "src/basic/siphash24.h"
nm_copy_sd "src/basic/socket-util.c"
nm_copy_sd "src/basic/socket-util.h"
nm_copy_sd "src/basic/sparse-endian.h"
nm_copy_sd "src/basic/stdio-util.h"
nm_copy_sd "src/basic/string-table.c"
nm_copy_sd "src/basic/string-table.h"
nm_copy_sd "src/basic/string-util.c"
nm_copy_sd "src/basic/string-util.h"
nm_copy_sd "src/basic/strv.c"
nm_copy_sd "src/basic/strv.h"
nm_copy_sd "src/basic/time-util.c"
nm_copy_sd "src/basic/time-util.h"
nm_copy_sd "src/basic/umask-util.h"
nm_copy_sd "src/basic/unaligned.h"
nm_copy_sd "src/basic/utf8.c"
nm_copy_sd "src/basic/utf8.h"
nm_copy_sd "src/basic/util.c"
nm_copy_sd "src/basic/util.h"
nm_copy_sd "src/libsystemd-network/arp-util.c"
nm_copy_sd "src/libsystemd-network/arp-util.h"
nm_copy_sd "src/libsystemd-network/dhcp6-internal.h"
nm_copy_sd "src/libsystemd-network/dhcp6-lease-internal.h"
nm_copy_sd "src/libsystemd-network/dhcp6-network.c"
nm_copy_sd "src/libsystemd-network/dhcp6-option.c"
nm_copy_sd "src/libsystemd-network/dhcp6-protocol.h"
nm_copy_sd "src/libsystemd-network/dhcp-identifier.c"
nm_copy_sd "src/libsystemd-network/dhcp-identifier.h"
nm_copy_sd "src/libsystemd-network/dhcp-internal.h"
nm_copy_sd "src/libsystemd-network/dhcp-lease-internal.h"
nm_copy_sd "src/libsystemd-network/dhcp-network.c"
nm_copy_sd "src/libsystemd-network/dhcp-option.c"
nm_copy_sd "src/libsystemd-network/dhcp-packet.c"
nm_copy_sd "src/libsystemd-network/dhcp-protocol.h"
nm_copy_sd "src/libsystemd-network/lldp-internal.h"
nm_copy_sd "src/libsystemd-network/lldp-neighbor.c"
nm_copy_sd "src/libsystemd-network/lldp-neighbor.h"
nm_copy_sd "src/libsystemd-network/lldp-network.c"
nm_copy_sd "src/libsystemd-network/lldp-network.h"
nm_copy_sd "src/libsystemd-network/network-internal.c"
nm_copy_sd "src/libsystemd-network/network-internal.h"
nm_copy_sd "src/libsystemd-network/sd-dhcp6-client.c"
nm_copy_sd "src/libsystemd-network/sd-dhcp6-lease.c"
nm_copy_sd "src/libsystemd-network/sd-dhcp-client.c"
nm_copy_sd "src/libsystemd-network/sd-dhcp-lease.c"
nm_copy_sd "src/libsystemd-network/sd-ipv4ll.c"
nm_copy_sd "src/libsystemd-network/sd-ipv4acd.c"
nm_copy_sd "src/libsystemd-network/sd-lldp.c"
nm_copy_sd "src/libsystemd/sd-event/sd-event.c"
nm_copy_sd "src/libsystemd/sd-id128/id128-util.c"
nm_copy_sd "src/libsystemd/sd-id128/id128-util.h"
nm_copy_sd "src/libsystemd/sd-id128/sd-id128.c"
nm_copy_sd "src/shared/dns-domain.c"
nm_copy_sd "src/shared/dns-domain.h"
nm_copy_sd "src/systemd/_sd-common.h"
nm_copy_sd "src/systemd/sd-dhcp6-client.h"
nm_copy_sd "src/systemd/sd-dhcp6-lease.h"
nm_copy_sd "src/systemd/sd-dhcp-client.h"
nm_copy_sd "src/systemd/sd-dhcp-lease.h"
nm_copy_sd "src/systemd/sd-event.h"
nm_copy_sd "src/systemd/sd-ndisc.h"
nm_copy_sd "src/systemd/sd-id128.h"
nm_copy_sd "src/systemd/sd-ipv4acd.h"
nm_copy_sd "src/systemd/sd-ipv4ll.h"
nm_copy_sd "src/systemd/sd-lldp.h"
This commit is contained in:
Thomas Haller 2016-08-11 21:39:15 +02:00
parent 21e3aa91d8
commit 5507dd68ca
25 changed files with 763 additions and 219 deletions

View file

@ -186,6 +186,12 @@ int fd_cloexec(int fd, bool cloexec) {
return 0;
}
void stdio_unset_cloexec(void) {
fd_cloexec(STDIN_FILENO, false);
fd_cloexec(STDOUT_FILENO, false);
fd_cloexec(STDERR_FILENO, false);
}
_pure_ static bool fd_in_set(int fd, const int fdset[], unsigned n_fdset) {
unsigned i;

View file

@ -63,6 +63,7 @@ DEFINE_TRIVIAL_CLEANUP_FUNC(DIR*, closedir);
int fd_nonblock(int fd, bool nonblock);
int fd_cloexec(int fd, bool cloexec);
void stdio_unset_cloexec(void);
int close_all_fds(const int except[], unsigned n_except);

View file

@ -47,6 +47,8 @@
#include "umask-util.h"
#include "utf8.h"
#define READ_FULL_BYTES_MAX (4U*1024U*1024U)
int write_string_stream(FILE *f, const char *line, bool enforce_newline) {
assert(f);
@ -230,7 +232,7 @@ int read_full_stream(FILE *f, char **contents, size_t *size) {
if (S_ISREG(st.st_mode)) {
/* Safety check */
if (st.st_size > 4*1024*1024)
if (st.st_size > READ_FULL_BYTES_MAX)
return -E2BIG;
/* Start with the right file size, but be prepared for
@ -245,26 +247,31 @@ int read_full_stream(FILE *f, char **contents, size_t *size) {
char *t;
size_t k;
t = realloc(buf, n+1);
t = realloc(buf, n + 1);
if (!t)
return -ENOMEM;
buf = t;
k = fread(buf + l, 1, n - l, f);
if (k > 0)
l += k;
if (k <= 0) {
if (ferror(f))
return -errno;
if (ferror(f))
return -errno;
if (feof(f))
break;
}
l += k;
n *= 2;
/* We aren't expecting fread() to return a short read outside
* of (error && eof), assert buffer is full and enlarge buffer.
*/
assert(l == n);
/* Safety check */
if (n > 4*1024*1024)
if (n >= READ_FULL_BYTES_MAX)
return -E2BIG;
n = MIN(n * 2, READ_FULL_BYTES_MAX);
}
buf[l] = 0;
@ -1067,7 +1074,7 @@ int fflush_and_check(FILE *f) {
return 0;
}
/* This is much like like mkostemp() but is subject to umask(). */
/* This is much like mkostemp() but is subject to umask(). */
int mkostemp_safe(char *pattern, int flags) {
_cleanup_umask_ mode_t u = 0;
int fd;
@ -1161,8 +1168,8 @@ int tempfn_random_child(const char *p, const char *extra, char **ret) {
char *t, *x;
uint64_t u;
unsigned i;
int r;
assert(p);
assert(ret);
/* Turns this:
@ -1171,6 +1178,12 @@ int tempfn_random_child(const char *p, const char *extra, char **ret) {
* /foo/bar/waldo/.#<extra>3c2b6219aa75d7d0
*/
if (!p) {
r = tmp_dir(&p);
if (r < 0)
return r;
}
if (!extra)
extra = "";
@ -1257,9 +1270,13 @@ int fputs_with_space(FILE *f, const char *s, const char *separator, bool *space)
int open_tmpfile_unlinkable(const char *directory, int flags) {
char *p;
int fd;
int fd, r;
assert(directory);
if (!directory) {
r = tmp_dir(&directory);
if (r < 0)
return r;
}
/* Returns an unlinked temporary file that cannot be linked into the file system anymore */
@ -1354,3 +1371,44 @@ int link_tmpfile(int fd, const char *path, const char *target) {
return 0;
}
int read_nul_string(FILE *f, char **ret) {
_cleanup_free_ char *x = NULL;
size_t allocated = 0, n = 0;
assert(f);
assert(ret);
/* Reads a NUL-terminated string from the specified file. */
for (;;) {
int c;
if (!GREEDY_REALLOC(x, allocated, n+2))
return -ENOMEM;
c = fgetc(f);
if (c == 0) /* Terminate at NUL byte */
break;
if (c == EOF) {
if (ferror(f))
return -errno;
break; /* Terminate at EOF */
}
x[n++] = (char) c;
}
if (x)
x[n] = 0;
else {
x = new0(char, 1);
if (!x)
return -ENOMEM;
}
*ret = x;
x = NULL;
return 0;
}

View file

@ -86,3 +86,5 @@ int open_tmpfile_unlinkable(const char *directory, int flags);
int open_tmpfile_linkable(const char *target, int flags, char **ret_path);
int link_tmpfile(int fd, const char *path, const char *target);
int read_nul_string(FILE *f, char **ret);

View file

@ -38,6 +38,7 @@
#include "mkdir.h"
#include "parse-util.h"
#include "path-util.h"
#include "stat-util.h"
#include "stdio-util.h"
#include "string-util.h"
#include "strv.h"
@ -495,6 +496,94 @@ int get_files_in_directory(const char *path, char ***list) {
return n;
}
static int getenv_tmp_dir(const char **ret_path) {
const char *n;
int r, ret = 0;
assert(ret_path);
/* We use the same order of environment variables python uses in tempfile.gettempdir():
* https://docs.python.org/3/library/tempfile.html#tempfile.gettempdir */
FOREACH_STRING(n, "TMPDIR", "TEMP", "TMP") {
const char *e;
e = secure_getenv(n);
if (!e)
continue;
if (!path_is_absolute(e)) {
r = -ENOTDIR;
goto next;
}
if (!path_is_safe(e)) {
r = -EPERM;
goto next;
}
r = is_dir(e, true);
if (r < 0)
goto next;
if (r == 0) {
r = -ENOTDIR;
goto next;
}
*ret_path = e;
return 1;
next:
/* Remember first error, to make this more debuggable */
if (ret >= 0)
ret = r;
}
if (ret < 0)
return ret;
*ret_path = NULL;
return ret;
}
static int tmp_dir_internal(const char *def, const char **ret) {
const char *e;
int r, k;
assert(def);
assert(ret);
r = getenv_tmp_dir(&e);
if (r > 0) {
*ret = e;
return 0;
}
k = is_dir(def, true);
if (k == 0)
k = -ENOTDIR;
if (k < 0)
return r < 0 ? r : k;
*ret = def;
return 0;
}
int var_tmp_dir(const char **ret) {
/* Returns the location for "larger" temporary files, that is backed by physical storage if available, and thus
* even might survive a boot: /var/tmp. If $TMPDIR (or related environment variables) are set, its value is
* returned preferably however. Note that both this function and tmp_dir() below are affected by $TMPDIR,
* making it a variable that overrides all temporary file storage locations. */
return tmp_dir_internal("/var/tmp", ret);
}
int tmp_dir(const char **ret) {
/* Similar to var_tmp_dir() above, but returns the location for "smaller" temporary files, which is usually
* backed by an in-memory file system: /tmp. */
return tmp_dir_internal("/tmp", ret);
}
int inotify_add_watch_fd(int fd, int what, uint32_t mask) {
char path[strlen("/proc/self/fd/") + DECIMAL_STR_MAX(int) + 1];
int r;

View file

@ -61,6 +61,9 @@ int mkfifo_atomic(const char *path, mode_t mode);
int get_files_in_directory(const char *path, char ***list);
int tmp_dir(const char **ret);
int var_tmp_dir(const char **ret);
#define INOTIFY_EVENT_MAX (sizeof(struct inotify_event) + NAME_MAX + 1)
#define FOREACH_INOTIFY_EVENT(e, buffer, sz) \

View file

@ -29,6 +29,7 @@
#include "extract-word.h"
#include "macro.h"
#include "parse-util.h"
#include "process-util.h"
#include "string-util.h"
int parse_boolean(const char *v) {
@ -533,7 +534,7 @@ int parse_fractional_part_u(const char **p, size_t digits, unsigned *res) {
return 0;
}
int parse_percent(const char *p) {
int parse_percent_unbounded(const char *p) {
const char *pc, *n;
unsigned v;
int r;
@ -546,8 +547,30 @@ int parse_percent(const char *p) {
r = safe_atou(n, &v);
if (r < 0)
return r;
if (v > 100)
return -ERANGE;
return (int) v;
}
int parse_percent(const char *p) {
int v;
v = parse_percent_unbounded(p);
if (v > 100)
return -ERANGE;
return v;
}
int parse_nice(const char *p, int *ret) {
int n, r;
r = safe_atoi(p, &n);
if (r < 0)
return r;
if (!nice_is_valid(n))
return -ERANGE;
*ret = n;
return 0;
}

View file

@ -106,4 +106,7 @@ int safe_atod(const char *s, double *ret_d);
int parse_fractional_part_u(const char **s, size_t digits, unsigned *res);
int parse_percent_unbounded(const char *p);
int parse_percent(const char *p);
int parse_nice(const char *p, int *ret);

View file

@ -23,8 +23,8 @@
#include "hashmap.h"
#include "macro.h"
Set *internal_set_new(const struct hash_ops *hash_ops HASHMAP_DEBUG_PARAMS);
#define set_new(ops) internal_set_new(ops HASHMAP_DEBUG_SRC_ARGS)
Set *internal_set_new(const struct hash_ops *hash_ops HASHMAP_DEBUG_PARAMS);
#define set_new(ops) internal_set_new(ops HASHMAP_DEBUG_SRC_ARGS)
static inline Set *set_free(Set *s) {
internal_hashmap_free(HASHMAP_BASE(s));
@ -42,8 +42,8 @@ static inline Set *set_copy(Set *s) {
return (Set*) internal_hashmap_copy(HASHMAP_BASE(s));
}
int internal_set_ensure_allocated(Set **s, const struct hash_ops *hash_ops HASHMAP_DEBUG_PARAMS);
#define set_ensure_allocated(h, ops) internal_set_ensure_allocated(h, ops HASHMAP_DEBUG_SRC_ARGS)
int internal_set_ensure_allocated(Set **s, const struct hash_ops *hash_ops HASHMAP_DEBUG_PARAMS);
#define set_ensure_allocated(h, ops) internal_set_ensure_allocated(h, ops HASHMAP_DEBUG_SRC_ARGS)
int set_put(Set *s, const void *key);
/* no set_update */

View file

@ -1046,3 +1046,17 @@ int flush_accept(int fd) {
close(cfd);
}
}
struct cmsghdr* cmsg_find(struct msghdr *mh, int level, int type, socklen_t length) {
struct cmsghdr *cmsg;
assert(mh);
CMSG_FOREACH(cmsg, mh)
if (cmsg->cmsg_level == level &&
cmsg->cmsg_type == type &&
(length == (socklen_t) -1 || length == cmsg->cmsg_len))
return cmsg;
return NULL;
}

View file

@ -142,6 +142,8 @@ int flush_accept(int fd);
#define CMSG_FOREACH(cmsg, mh) \
for ((cmsg) = CMSG_FIRSTHDR(mh); (cmsg); (cmsg) = CMSG_NXTHDR((mh), (cmsg)))
struct cmsghdr* cmsg_find(struct msghdr *mh, int level, int type, socklen_t length);
/* Covers only file system and abstract AF_UNIX socket addresses, but not unnamed socket addresses. */
#define SOCKADDR_UN_LEN(sa) \
({ \

View file

@ -22,6 +22,7 @@
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "alloc-util.h"
#include "gunicode.h"
@ -323,6 +324,14 @@ char ascii_tolower(char x) {
return x;
}
char ascii_toupper(char x) {
if (x >= 'a' && x <= 'z')
return x - 'a' + 'A';
return x;
}
char *ascii_strlower(char *t) {
char *p;
@ -334,6 +343,17 @@ char *ascii_strlower(char *t) {
return t;
}
char *ascii_strupper(char *t) {
char *p;
assert(t);
for (p = t; *p; p++)
*p = ascii_toupper(*p);
return t;
}
char *ascii_strlower_n(char *t, size_t n) {
size_t i;
@ -803,25 +823,20 @@ int free_and_strdup(char **p, const char *s) {
return 1;
}
#pragma GCC push_options
#pragma GCC optimize("O0")
/*
* Pointer to memset is volatile so that compiler must de-reference
* the pointer and can't assume that it points to any function in
* particular (such as memset, which it then might further "optimize")
* This approach is inspired by openssl's crypto/mem_clr.c.
*/
typedef void *(*memset_t)(void *,int,size_t);
static volatile memset_t memset_func = memset;
void* memory_erase(void *p, size_t l) {
volatile uint8_t* x = (volatile uint8_t*) p;
/* This basically does what memset() does, but hopefully isn't
* optimized away by the compiler. One of those days, when
* glibc learns memset_s() we should replace this call by
* memset_s(), but until then this has to do. */
for (; l > 0; l--)
*(x++) = 'x';
return p;
return memset_func(p, 'x', l);
}
#pragma GCC pop_options
char* string_erase(char *x) {
if (!x)

View file

@ -137,6 +137,9 @@ char ascii_tolower(char x);
char *ascii_strlower(char *s);
char *ascii_strlower_n(char *s, size_t n);
char ascii_toupper(char x);
char *ascii_strupper(char *s);
int ascii_strcasecmp_n(const char *a, const char *b, size_t n);
int ascii_strcasecmp_nn(const char *a, size_t n, const char *b, size_t m);

View file

@ -638,6 +638,17 @@ char **strv_remove(char **l, const char *s) {
}
char **strv_parse_nulstr(const char *s, size_t l) {
/* l is the length of the input data, which will be split at NULs into
* elements of the resulting strv. Hence, the number of items in the resulting strv
* will be equal to one plus the number of NUL bytes in the l bytes starting at s,
* unless s[l-1] is NUL, in which case the final empty string is not stored in
* the resulting strv, and length is equal to the number of NUL bytes.
*
* Note that contrary to a normal nulstr which cannot contain empty strings, because
* the input data is terminated by any two consequent NUL bytes, this parser accepts
* empty strings in s.
*/
const char *p;
unsigned c = 0, i = 0;
char **v;
@ -700,6 +711,13 @@ char **strv_split_nulstr(const char *s) {
}
int strv_make_nulstr(char **l, char **p, size_t *q) {
/* A valid nulstr with two NULs at the end will be created, but
* q will be the length without the two trailing NULs. Thus the output
* string is a valid nulstr and can be iterated over using NULSTR_FOREACH,
* and can also be parsed by strv_parse_nulstr as long as the length
* is provided separately.
*/
size_t n_allocated = 0, n = 0;
_cleanup_free_ char *m = NULL;
char **i;
@ -712,7 +730,7 @@ int strv_make_nulstr(char **l, char **p, size_t *q) {
z = strlen(*i);
if (!GREEDY_REALLOC(m, n_allocated, n + z + 1))
if (!GREEDY_REALLOC(m, n_allocated, n + z + 2))
return -ENOMEM;
memcpy(m + n, *i, z + 1);
@ -723,11 +741,14 @@ int strv_make_nulstr(char **l, char **p, size_t *q) {
m = new0(char, 1);
if (!m)
return -ENOMEM;
n = 0;
}
n = 1;
} else
/* make sure there is a second extra NUL at the end of resulting nulstr */
m[n] = '\0';
assert(n > 0);
*p = m;
*q = n;
*q = n - 1;
m = NULL;
@ -803,9 +824,8 @@ char **strv_reverse(char **l) {
if (n <= 1)
return l;
for (i = 0; i < n / 2; i++) {
for (i = 0; i < n / 2; i++)
SWAP_TWO(l[i], l[n-1-i]);
}
return l;
}
@ -876,7 +896,7 @@ int strv_extend_n(char ***l, const char *value, size_t n) {
if (n == 0)
return 0;
/* Adds the value value n times to l */
/* Adds the value n times to l */
k = strv_length(*l);

View file

@ -254,32 +254,95 @@ struct timeval *timeval_store(struct timeval *tv, usec_t u) {
return tv;
}
static char *format_timestamp_internal(char *buf, size_t l, usec_t t,
bool utc, bool us) {
static char *format_timestamp_internal(
char *buf,
size_t l,
usec_t t,
bool utc,
bool us) {
/* The weekdays in non-localized (English) form. We use this instead of the localized form, so that our
* generated timestamps may be parsed with parse_timestamp(), and always read the same. */
static const char * const weekdays[] = {
[0] = "Sun",
[1] = "Mon",
[2] = "Tue",
[3] = "Wed",
[4] = "Thu",
[5] = "Fri",
[6] = "Sat",
};
struct tm tm;
time_t sec;
int k;
size_t n;
assert(buf);
assert(l > 0);
if (l <
3 + /* week day */
1 + 10 + /* space and date */
1 + 8 + /* space and time */
(us ? 1 + 6 : 0) + /* "." and microsecond part */
1 + 1 + /* space and shortest possible zone */
1)
return NULL; /* Not enough space even for the shortest form. */
if (t <= 0 || t == USEC_INFINITY)
return NULL; /* Timestamp is unset */
sec = (time_t) (t / USEC_PER_SEC); /* Round down */
if ((usec_t) sec != (t / USEC_PER_SEC))
return NULL; /* overflow? */
if (!localtime_or_gmtime_r(&sec, &tm, utc))
return NULL;
sec = (time_t) (t / USEC_PER_SEC);
localtime_or_gmtime_r(&sec, &tm, utc);
/* Start with the week day */
assert((size_t) tm.tm_wday < ELEMENTSOF(weekdays));
memcpy(buf, weekdays[tm.tm_wday], 4);
if (us)
k = strftime(buf, l, "%a %Y-%m-%d %H:%M:%S", &tm);
else
k = strftime(buf, l, "%a %Y-%m-%d %H:%M:%S %Z", &tm);
/* Add the main components */
if (strftime(buf + 3, l - 3, " %Y-%m-%d %H:%M:%S", &tm) <= 0)
return NULL; /* Doesn't fit */
if (k <= 0)
return NULL;
/* Append the microseconds part, if that's requested */
if (us) {
snprintf(buf + strlen(buf), l - strlen(buf), ".%06llu", (unsigned long long) (t % USEC_PER_SEC));
if (strftime(buf + strlen(buf), l - strlen(buf), " %Z", &tm) <= 0)
return NULL;
n = strlen(buf);
if (n + 8 > l)
return NULL; /* Microseconds part doesn't fit. */
sprintf(buf + n, ".%06llu", (unsigned long long) (t % USEC_PER_SEC));
}
/* Append the timezone */
n = strlen(buf);
if (utc) {
/* If this is UTC then let's explicitly use the "UTC" string here, because gmtime_r() normally uses the
* obsolete "GMT" instead. */
if (n + 5 > l)
return NULL; /* "UTC" doesn't fit. */
strcpy(buf + n, " UTC");
} else if (!isempty(tm.tm_zone)) {
size_t tn;
/* An explicit timezone is specified, let's use it, if it fits */
tn = strlen(tm.tm_zone);
if (n + 1 + tn + 1 > l) {
/* The full time zone does not fit in. Yuck. */
if (n + 1 + _POSIX_TZNAME_MAX + 1 > l)
return NULL; /* Not even enough space for the POSIX minimum (of 6)? In that case, complain that it doesn't fit */
/* So the time zone doesn't fit in fully, but the caller passed enough space for the POSIX
* minimum time zone length. In this case suppress the timezone entirely, in order not to dump
* an overly long, hard to read string on the user. This should be safe, because the user will
* assume the local timezone anyway if none is shown. And so does parse_timestamp(). */
} else {
buf[n++] = ' ';
strcpy(buf + n, tm.tm_zone);
}
}
return buf;
@ -539,12 +602,11 @@ int parse_timestamp(const char *t, usec_t *usec) {
{ "Sat", 6 },
};
const char *k;
const char *utc;
const char *k, *utc, *tzn = NULL;
struct tm tm, copy;
time_t x;
usec_t x_usec, plus = 0, minus = 0, ret;
int r, weekday = -1;
int r, weekday = -1, dst = -1;
unsigned i;
/*
@ -609,15 +671,55 @@ int parse_timestamp(const char *t, usec_t *usec) {
goto finish;
}
/* See if the timestamp is suffixed with UTC */
utc = endswith_no_case(t, " UTC");
if (utc)
t = strndupa(t, utc - t);
else {
const char *e = NULL;
int j;
x = ret / USEC_PER_SEC;
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. */
for (j = 0; j <= 1; j++) {
if (isempty(tzname[j]))
continue;
e = endswith_no_case(t, tzname[j]);
if (!e)
continue;
if (e == t)
continue;
if (e[-1] != ' ')
continue;
break;
}
if (IN_SET(j, 0, 1)) {
/* Found one of the two timezones specified. */
t = strndupa(t, e - t - 1);
dst = j;
tzn = tzname[j];
}
}
x = (time_t) (ret / USEC_PER_SEC);
x_usec = 0;
assert_se(localtime_or_gmtime_r(&x, &tm, utc));
tm.tm_isdst = -1;
if (!localtime_or_gmtime_r(&x, &tm, utc))
return -EINVAL;
tm.tm_isdst = dst;
if (tzn)
tm.tm_zone = tzn;
if (streq(t, "today")) {
tm.tm_sec = tm.tm_min = tm.tm_hour = 0;
@ -634,7 +736,6 @@ int parse_timestamp(const char *t, usec_t *usec) {
goto from_tm;
}
for (i = 0; i < ELEMENTSOF(day_nr); i++) {
size_t skip;
@ -727,7 +828,6 @@ parse_usec:
return -EINVAL;
x_usec = add;
}
from_tm:

View file

@ -68,7 +68,9 @@ typedef struct triple_timestamp {
#define USEC_PER_YEAR ((usec_t) (31557600ULL*USEC_PER_SEC))
#define NSEC_PER_YEAR ((nsec_t) (31557600ULL*NSEC_PER_SEC))
#define FORMAT_TIMESTAMP_MAX ((4*4+1)+11+9+4+1) /* weekdays can be unicode */
/* We assume a maximum timezone length of 6. TZNAME_MAX is not defined on Linux, but glibc internally initializes this
* to 6. Let's rely on that. */
#define FORMAT_TIMESTAMP_MAX (3+1+10+1+8+1+6+1+6+1)
#define FORMAT_TIMESTAMP_WIDTH 28 /* when outputting, assume this width */
#define FORMAT_TIMESTAMP_RELATIVE_MAX 256
#define FORMAT_TIMESPAN_MAX 64

View file

@ -581,47 +581,6 @@ int on_ac_power(void) {
return found_online || !found_offline;
}
bool id128_is_valid(const char *s) {
size_t i, l;
l = strlen(s);
if (l == 32) {
/* Simple formatted 128bit hex string */
for (i = 0; i < l; i++) {
char c = s[i];
if (!(c >= '0' && c <= '9') &&
!(c >= 'a' && c <= 'z') &&
!(c >= 'A' && c <= 'Z'))
return false;
}
} else if (l == 36) {
/* Formatted UUID */
for (i = 0; i < l; i++) {
char c = s[i];
if ((i == 8 || i == 13 || i == 18 || i == 23)) {
if (c != '-')
return false;
} else {
if (!(c >= '0' && c <= '9') &&
!(c >= 'a' && c <= 'z') &&
!(c >= 'A' && c <= 'Z'))
return false;
}
}
} else
return false;
return true;
}
int container_get_leader(const char *machine, pid_t *pid) {
_cleanup_free_ char *s = NULL, *class = NULL;
const char *p;
@ -832,6 +791,61 @@ uint64_t physical_memory_scale(uint64_t v, uint64_t max) {
return r;
}
uint64_t system_tasks_max(void) {
#if SIZEOF_PID_T == 4
#define TASKS_MAX ((uint64_t) (INT32_MAX-1))
#elif SIZEOF_PID_T == 2
#define TASKS_MAX ((uint64_t) (INT16_MAX-1))
#else
#error "Unknown pid_t size"
#endif
_cleanup_free_ char *value = NULL, *root = NULL;
uint64_t a = TASKS_MAX, b = TASKS_MAX;
/* Determine the maximum number of tasks that may run on this system. We check three sources to determine this
* limit:
*
* a) the maximum value for the pid_t type
* b) the cgroups pids_max attribute for the system
* c) the kernel's configure maximum PID value
*
* And then pick the smallest of the three */
if (read_one_line_file("/proc/sys/kernel/pid_max", &value) >= 0)
(void) safe_atou64(value, &a);
if (cg_get_root_path(&root) >= 0) {
value = mfree(value);
if (cg_get_attribute("pids", root, "pids.max", &value) >= 0)
(void) safe_atou64(value, &b);
}
return MIN3(TASKS_MAX,
a <= 0 ? TASKS_MAX : a,
b <= 0 ? TASKS_MAX : b);
}
uint64_t system_tasks_max_scale(uint64_t v, uint64_t max) {
uint64_t t, m;
assert(max > 0);
/* Multiply the system's task value by the fraction v/max. Hence, if max==100 this calculates percentages
* relative to the system's maximum number of tasks. Returns UINT64_MAX on overflow. */
t = system_tasks_max();
assert(t > 0);
m = t * v;
if (m / t != v) /* overflow? */
return UINT64_MAX;
return m / max;
}
int update_reboot_parameter_and_warn(const char *param) {
int r;

View file

@ -61,6 +61,10 @@ static inline const char* one_zero(bool b) {
return b ? "1" : "0";
}
static inline const char* enable_disable(bool b) {
return b ? "enable" : "disable";
}
void execute_directories(const char* const* directories, usec_t timeout, char *argv[]);
bool plymouth_running(void);
@ -176,8 +180,6 @@ static inline unsigned log2u_round_up(unsigned x) {
return log2u(x - 1) + 1;
}
bool id128_is_valid(const char *s) _pure_;
int container_get_leader(const char *machine, pid_t *pid);
int namespace_open(pid_t pid, int *pidns_fd, int *mntns_fd, int *netns_fd, int *userns_fd, int *root_fd);
@ -186,6 +188,9 @@ int namespace_enter(int pidns_fd, int mntns_fd, int netns_fd, int userns_fd, int
uint64_t physical_memory(void);
uint64_t physical_memory_scale(uint64_t v, uint64_t max);
uint64_t system_tasks_max(void);
uint64_t system_tasks_max_scale(uint64_t v, uint64_t max);
int update_reboot_parameter_and_warn(const char *param);
int version(void);

View file

@ -197,7 +197,7 @@ int lldp_neighbor_parse(sd_lldp_neighbor *n) {
assert(n);
if (n->raw_size < sizeof(struct ether_header)) {
log_lldp("Recieved truncated packet, ignoring.");
log_lldp("Received truncated packet, ignoring.");
return -EBADMSG;
}

View file

@ -102,16 +102,16 @@ bool net_match_config(const struct ether_addr *match_mac,
const char *dev_type,
const char *dev_name) {
if (match_host && !condition_test(match_host))
if (match_host && condition_test(match_host) <= 0)
return false;
if (match_virt && !condition_test(match_virt))
if (match_virt && condition_test(match_virt) <= 0)
return false;
if (match_kernel && !condition_test(match_kernel))
if (match_kernel && condition_test(match_kernel) <= 0)
return false;
if (match_arch && !condition_test(match_arch))
if (match_arch && condition_test(match_arch) <= 0)
return false;
if (match_mac && (!dev_mac || memcmp(match_mac, dev_mac, ETH_ALEN)))

View file

@ -109,8 +109,8 @@ struct sd_event_source {
int64_t priority;
unsigned pending_index;
unsigned prepare_index;
unsigned pending_iteration;
unsigned prepare_iteration;
uint64_t pending_iteration;
uint64_t prepare_iteration;
LIST_FIELDS(sd_event_source, sources);
@ -215,7 +215,7 @@ struct sd_event {
pid_t original_pid;
unsigned iteration;
uint64_t iteration;
triple_timestamp timestamp;
int state;
@ -2874,3 +2874,11 @@ _public_ int sd_event_get_watchdog(sd_event *e) {
return e->watchdog;
}
_public_ int sd_event_get_iteration(sd_event *e, uint64_t *ret) {
assert_return(e, -EINVAL);
assert_return(!event_pid_changed(e), -ECHILD);
*ret = e->iteration;
return 0;
}

View file

@ -0,0 +1,194 @@
/***
This file is part of systemd.
Copyright 2016 Lennart Poettering
systemd is free software; you can redistribute it and/or modify it
under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 2.1 of the License, or
(at your option) any later version.
systemd is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
#include <fcntl.h>
#include <unistd.h>
#include "fd-util.h"
#include "hexdecoct.h"
#include "id128-util.h"
#include "io-util.h"
#include "stdio-util.h"
char *id128_to_uuid_string(sd_id128_t id, char s[37]) {
unsigned n, k = 0;
assert(s);
/* Similar to sd_id128_to_string() but formats the result as UUID instead of plain hex chars */
for (n = 0; n < 16; n++) {
if (IN_SET(n, 4, 6, 8, 10))
s[k++] = '-';
s[k++] = hexchar(id.bytes[n] >> 4);
s[k++] = hexchar(id.bytes[n] & 0xF);
}
assert(k == 36);
s[k] = 0;
return s;
}
bool id128_is_valid(const char *s) {
size_t i, l;
assert(s);
l = strlen(s);
if (l == 32) {
/* Plain formatted 128bit hex string */
for (i = 0; i < l; i++) {
char c = s[i];
if (!(c >= '0' && c <= '9') &&
!(c >= 'a' && c <= 'z') &&
!(c >= 'A' && c <= 'Z'))
return false;
}
} else if (l == 36) {
/* Formatted UUID */
for (i = 0; i < l; i++) {
char c = s[i];
if ((i == 8 || i == 13 || i == 18 || i == 23)) {
if (c != '-')
return false;
} else {
if (!(c >= '0' && c <= '9') &&
!(c >= 'a' && c <= 'z') &&
!(c >= 'A' && c <= 'Z'))
return false;
}
}
} else
return false;
return true;
}
int id128_read_fd(int fd, Id128Format f, sd_id128_t *ret) {
char buffer[36 + 2];
ssize_t l;
assert(fd >= 0);
assert(f < _ID128_FORMAT_MAX);
/* Reads an 128bit ID from a file, which may either be in plain format (32 hex digits), or in UUID format, both
* optionally followed by a newline and nothing else. ID files should really be newline terminated, but if they
* aren't that's OK too, following the rule of "Be conservative in what you send, be liberal in what you
* accept". */
l = loop_read(fd, buffer, sizeof(buffer), false); /* we expect a short read of either 32/33 or 36/37 chars */
if (l < 0)
return (int) l;
if (l == 0) /* empty? */
return -ENOMEDIUM;
switch (l) {
case 33: /* plain UUID with trailing newline */
if (buffer[32] != '\n')
return -EINVAL;
/* fall through */
case 32: /* plain UUID without trailing newline */
if (f == ID128_UUID)
return -EINVAL;
buffer[32] = 0;
break;
case 37: /* RFC UUID with trailing newline */
if (buffer[36] != '\n')
return -EINVAL;
/* fall through */
case 36: /* RFC UUID without trailing newline */
if (f == ID128_PLAIN)
return -EINVAL;
buffer[36] = 0;
break;
default:
return -EINVAL;
}
return sd_id128_from_string(buffer, ret);
}
int id128_read(const char *p, Id128Format f, sd_id128_t *ret) {
_cleanup_close_ int fd = -1;
fd = open(p, O_RDONLY|O_CLOEXEC|O_NOCTTY);
if (fd < 0)
return -errno;
return id128_read_fd(fd, f, ret);
}
int id128_write_fd(int fd, Id128Format f, sd_id128_t id, bool do_sync) {
char buffer[36 + 2];
size_t sz;
int r;
assert(fd >= 0);
assert(f < _ID128_FORMAT_MAX);
if (f != ID128_UUID) {
sd_id128_to_string(id, buffer);
buffer[32] = '\n';
sz = 33;
} else {
id128_to_uuid_string(id, buffer);
buffer[36] = '\n';
sz = 37;
}
r = loop_write(fd, buffer, sz, false);
if (r < 0)
return r;
if (do_sync) {
if (fsync(fd) < 0)
return -errno;
}
return r;
}
int id128_write(const char *p, Id128Format f, sd_id128_t id, bool do_sync) {
_cleanup_close_ int fd = -1;
fd = open(p, O_WRONLY|O_CREAT|O_CLOEXEC|O_NOCTTY, 0444);
if (fd < 0)
return -errno;
return id128_write_fd(fd, f, id, do_sync);
}

View file

@ -0,0 +1,45 @@
#pragma once
/***
This file is part of systemd.
Copyright 2016 Lennart Poettering
systemd is free software; you can redistribute it and/or modify it
under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 2.1 of the License, or
(at your option) any later version.
systemd is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
#include <stdbool.h>
#include "sd-id128.h"
#include "macro.h"
char *id128_to_uuid_string(sd_id128_t id, char s[37]);
/* Like SD_ID128_FORMAT_STR, but formats as UUID, not in plain format */
#define ID128_UUID_FORMAT_STR "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x"
bool id128_is_valid(const char *s) _pure_;
typedef enum Id128Format {
ID128_ANY,
ID128_PLAIN, /* formatted as 32 hex chars as-is */
ID128_UUID, /* formatted as 36 character uuid string */
_ID128_FORMAT_MAX,
} Id128Format;
int id128_read_fd(int fd, Id128Format f, sd_id128_t *ret);
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(const char *p, Id128Format f, sd_id128_t id, bool do_sync);

View file

@ -25,6 +25,7 @@
#include "fd-util.h"
#include "hexdecoct.h"
#include "id128-util.h"
#include "io-util.h"
#include "macro.h"
#include "random-util.h"
@ -51,7 +52,6 @@ _public_ int sd_id128_from_string(const char s[], sd_id128_t *ret) {
bool is_guid = false;
assert_return(s, -EINVAL);
assert_return(ret, -EINVAL);
for (n = 0, i = 0; n < 16;) {
int a, b;
@ -89,7 +89,43 @@ _public_ int sd_id128_from_string(const char s[], sd_id128_t *ret) {
if (s[i] != 0)
return -EINVAL;
*ret = t;
if (ret)
*ret = t;
return 0;
}
_public_ int sd_id128_get_machine(sd_id128_t *ret) {
static thread_local sd_id128_t saved_machine_id = {};
int r;
assert_return(ret, -EINVAL);
if (sd_id128_is_null(saved_machine_id)) {
r = id128_read("/etc/machine-id", ID128_PLAIN, &saved_machine_id);
if (r < 0)
return r;
if (sd_id128_is_null(saved_machine_id))
return -EINVAL;
}
*ret = saved_machine_id;
return 0;
}
_public_ int sd_id128_get_boot(sd_id128_t *ret) {
static thread_local sd_id128_t saved_boot_id = {};
int r;
assert_return(ret, -EINVAL);
if (sd_id128_is_null(saved_boot_id)) {
r = id128_read("/proc/sys/kernel/random/boot_id", ID128_UUID, &saved_boot_id);
if (r < 0)
return r;
}
*ret = saved_boot_id;
return 0;
}
@ -106,106 +142,6 @@ static sd_id128_t make_v4_uuid(sd_id128_t id) {
return id;
}
_public_ int sd_id128_get_machine(sd_id128_t *ret) {
static thread_local sd_id128_t saved_machine_id;
static thread_local bool saved_machine_id_valid = false;
_cleanup_close_ int fd = -1;
char buf[33];
unsigned j;
sd_id128_t t;
int r;
assert_return(ret, -EINVAL);
if (saved_machine_id_valid) {
*ret = saved_machine_id;
return 0;
}
fd = open("/etc/machine-id", O_RDONLY|O_CLOEXEC|O_NOCTTY);
if (fd < 0)
return -errno;
r = loop_read_exact(fd, buf, 33, false);
if (r < 0)
return r;
if (buf[32] !='\n')
return -EIO;
for (j = 0; j < 16; j++) {
int a, b;
a = unhexchar(buf[j*2]);
b = unhexchar(buf[j*2+1]);
if (a < 0 || b < 0)
return -EIO;
t.bytes[j] = a << 4 | b;
}
saved_machine_id = t;
saved_machine_id_valid = true;
*ret = t;
return 0;
}
_public_ int sd_id128_get_boot(sd_id128_t *ret) {
static thread_local sd_id128_t saved_boot_id;
static thread_local bool saved_boot_id_valid = false;
_cleanup_close_ int fd = -1;
char buf[36];
unsigned j;
sd_id128_t t;
char *p;
int r;
assert_return(ret, -EINVAL);
if (saved_boot_id_valid) {
*ret = saved_boot_id;
return 0;
}
fd = open("/proc/sys/kernel/random/boot_id", O_RDONLY|O_CLOEXEC|O_NOCTTY);
if (fd < 0)
return -errno;
r = loop_read_exact(fd, buf, 36, false);
if (r < 0)
return r;
for (j = 0, p = buf; j < 16; j++) {
int a, b;
if (p >= buf + 35)
return -EIO;
if (*p == '-') {
p++;
if (p >= buf + 35)
return -EIO;
}
a = unhexchar(p[0]);
b = unhexchar(p[1]);
if (a < 0 || b < 0)
return -EIO;
t.bytes[j] = a << 4 | b;
p += 2;
}
saved_boot_id = t;
saved_boot_id_valid = true;
*ret = t;
return 0;
}
_public_ int sd_id128_randomize(sd_id128_t *ret) {
sd_id128_t t;
int r;

View file

@ -104,6 +104,7 @@ int sd_event_get_tid(sd_event *e, pid_t *tid);
int sd_event_get_exit_code(sd_event *e, int *code);
int sd_event_set_watchdog(sd_event *e, int b);
int sd_event_get_watchdog(sd_event *e);
int sd_event_get_iteration(sd_event *e, uint64_t *ret);
sd_event_source* sd_event_source_ref(sd_event_source *s);
sd_event_source* sd_event_source_unref(sd_event_source *s);