systemd: merge branch 'systemd' into master

This commit is contained in:
Beniamino Galvani
2015-11-23 16:13:45 +01:00
87 changed files with 6476 additions and 7928 deletions

View File

@@ -67,20 +67,34 @@ SYSTEMD_NM_CFLAGS_PATHS = \
libsystemd_nm_la_SOURCES = \ libsystemd_nm_la_SOURCES = \
systemd/nm-sd-adapt.c \ systemd/nm-sd-adapt.c \
systemd/nm-sd-adapt.h \ systemd/nm-sd-adapt.h \
systemd/src/basic/alloc-util.c \
systemd/src/basic/alloc-util.h \
systemd/src/basic/async.h \ systemd/src/basic/async.h \
systemd/src/basic/escape.c \
systemd/src/basic/escape.h \
systemd/src/basic/fd-util.c \
systemd/src/basic/fd-util.h \
systemd/src/basic/fileio.c \ systemd/src/basic/fileio.c \
systemd/src/basic/fileio.h \ systemd/src/basic/fileio.h \
systemd/src/basic/fs-util.c \
systemd/src/basic/fs-util.h \
systemd/src/basic/hashmap.c \ systemd/src/basic/hashmap.c \
systemd/src/basic/hashmap.h \ systemd/src/basic/hashmap.h \
systemd/src/basic/hexdecoct.c \
systemd/src/basic/hexdecoct.h \
systemd/src/basic/hostname-util.c \ systemd/src/basic/hostname-util.c \
systemd/src/basic/hostname-util.h \ systemd/src/basic/hostname-util.h \
systemd/src/basic/in-addr-util.c \ systemd/src/basic/in-addr-util.c \
systemd/src/basic/in-addr-util.h \ systemd/src/basic/in-addr-util.h \
systemd/src/basic/io-util.c \
systemd/src/basic/io-util.h \
systemd/src/basic/list.h \ systemd/src/basic/list.h \
systemd/src/basic/log.h \ systemd/src/basic/log.h \
systemd/src/basic/macro.h \ systemd/src/basic/macro.h \
systemd/src/basic/mempool.c \ systemd/src/basic/mempool.c \
systemd/src/basic/mempool.h \ systemd/src/basic/mempool.h \
systemd/src/basic/parse-util.c \
systemd/src/basic/parse-util.h \
systemd/src/basic/path-util.c \ systemd/src/basic/path-util.c \
systemd/src/basic/path-util.h \ systemd/src/basic/path-util.h \
systemd/src/basic/prioq.c \ systemd/src/basic/prioq.c \
@@ -93,10 +107,15 @@ libsystemd_nm_la_SOURCES = \
systemd/src/basic/set.h \ systemd/src/basic/set.h \
systemd/src/basic/socket-util.h \ systemd/src/basic/socket-util.h \
systemd/src/basic/sparse-endian.h \ systemd/src/basic/sparse-endian.h \
systemd/src/basic/string-table.c \
systemd/src/basic/string-table.h \
systemd/src/basic/string-util.c \
systemd/src/basic/string-util.h \
systemd/src/basic/strv.c \ systemd/src/basic/strv.c \
systemd/src/basic/strv.h \ systemd/src/basic/strv.h \
systemd/src/basic/time-util.c \ systemd/src/basic/time-util.c \
systemd/src/basic/time-util.h \ systemd/src/basic/time-util.h \
systemd/src/basic/umask-util.h \
systemd/src/basic/unaligned.h \ systemd/src/basic/unaligned.h \
systemd/src/basic/utf8.c \ systemd/src/basic/utf8.c \
systemd/src/basic/utf8.h \ systemd/src/basic/utf8.h \

View File

@@ -762,6 +762,12 @@ ip6_start (NMDhcpClient *client,
sd_dhcp6_client_set_request_option (priv->client6, dhcp6_requests[i].num); sd_dhcp6_client_set_request_option (priv->client6, dhcp6_requests[i].num);
} }
r = sd_dhcp6_client_set_local_address (priv->client6, ll_addr);
if (r < 0) {
nm_log_warn (LOGD_DHCP6, "(%s): failed to set local address (%d)", iface, r);
goto error;
}
r = sd_dhcp6_client_start (priv->client6); r = sd_dhcp6_client_start (priv->client6);
if (r < 0) { if (r < 0) {
nm_log_warn (LOGD_DHCP6, "(%s): failed to start DHCP (%d)", iface, r); nm_log_warn (LOGD_DHCP6, "(%s): failed to start DHCP (%d)", iface, r);

View File

@@ -23,6 +23,7 @@
#include <errno.h> #include <errno.h>
#include "sd-event.h" #include "sd-event.h"
#include "fd-util.h"
#include "time-util.h" #include "time-util.h"
struct sd_event_source { struct sd_event_source {

View File

@@ -0,0 +1,83 @@
/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
/***
This file is part of systemd.
Copyright 2010 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 "nm-sd-adapt.h"
#include "alloc-util.h"
#include "util.h"
void* memdup(const void *p, size_t l) {
void *r;
assert(p);
r = malloc(l);
if (!r)
return NULL;
memcpy(r, p, l);
return r;
}
void* greedy_realloc(void **p, size_t *allocated, size_t need, size_t size) {
size_t a, newalloc;
void *q;
assert(p);
assert(allocated);
if (*allocated >= need)
return *p;
newalloc = MAX(need * 2, 64u / size);
a = newalloc * size;
/* check for overflows */
if (a < size * need)
return NULL;
q = realloc(*p, a);
if (!q)
return NULL;
*p = q;
*allocated = newalloc;
return q;
}
void* greedy_realloc0(void **p, size_t *allocated, size_t need, size_t size) {
size_t prev;
uint8_t *q;
assert(p);
assert(allocated);
prev = *allocated;
q = greedy_realloc(p, allocated, need, size);
if (!q)
return NULL;
if (*allocated > prev)
memzero(q + prev * size, (*allocated - prev) * size);
return q;
}

View File

@@ -0,0 +1,110 @@
/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
#pragma once
/***
This file is part of systemd.
Copyright 2010 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 "nm-sd-adapt.h"
#include <alloca.h>
#include <stdlib.h>
#include <string.h>
#include "macro.h"
#define new(t, n) ((t*) malloc_multiply(sizeof(t), (n)))
#define new0(t, n) ((t*) calloc((n), sizeof(t)))
#define newa(t, n) ((t*) alloca(sizeof(t)*(n)))
#define newa0(t, n) ((t*) alloca0(sizeof(t)*(n)))
#define newdup(t, p, n) ((t*) memdup_multiply(p, sizeof(t), (n)))
#define malloc0(n) (calloc(1, (n)))
static inline void *mfree(void *memory) {
free(memory);
return NULL;
}
void* memdup(const void *p, size_t l) _alloc_(2);
static inline void freep(void *p) {
free(*(void**) p);
}
#define _cleanup_free_ _cleanup_(freep)
_malloc_ _alloc_(1, 2) static inline void *malloc_multiply(size_t a, size_t b) {
if (_unlikely_(b != 0 && a > ((size_t) -1) / b))
return NULL;
return malloc(a * b);
}
_alloc_(2, 3) static inline void *realloc_multiply(void *p, size_t a, size_t b) {
if (_unlikely_(b != 0 && a > ((size_t) -1) / b))
return NULL;
return realloc(p, a * b);
}
_alloc_(2, 3) static inline void *memdup_multiply(const void *p, size_t a, size_t b) {
if (_unlikely_(b != 0 && a > ((size_t) -1) / b))
return NULL;
return memdup(p, a * b);
}
void* greedy_realloc(void **p, size_t *allocated, size_t need, size_t size);
void* greedy_realloc0(void **p, size_t *allocated, size_t need, size_t size);
#define GREEDY_REALLOC(array, allocated, need) \
greedy_realloc((void**) &(array), &(allocated), (need), sizeof((array)[0]))
#define GREEDY_REALLOC0(array, allocated, need) \
greedy_realloc0((void**) &(array), &(allocated), (need), sizeof((array)[0]))
#define alloca0(n) \
({ \
char *_new_; \
size_t _len_ = n; \
_new_ = alloca(_len_); \
(void *) memset(_new_, 0, _len_); \
})
/* It's not clear what alignment glibc/gcc alloca() guarantee, hence provide a guaranteed safe version */
#define alloca_align(size, align) \
({ \
void *_ptr_; \
size_t _mask_ = (align) - 1; \
_ptr_ = alloca((size) + _mask_); \
(void*)(((uintptr_t)_ptr_ + _mask_) & ~_mask_); \
})
#define alloca0_align(size, align) \
({ \
void *_new_; \
size_t _size_ = (size); \
_new_ = alloca_align(_size_, (align)); \
(void*)memset(_new_, 0, _size_); \
})

View File

@@ -0,0 +1,484 @@
/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
/***
This file is part of systemd.
Copyright 2010 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 "nm-sd-adapt.h"
#include "alloc-util.h"
#include "escape.h"
#include "hexdecoct.h"
#include "string-util.h"
#include "utf8.h"
#include "util.h"
size_t cescape_char(char c, char *buf) {
char * buf_old = buf;
switch (c) {
case '\a':
*(buf++) = '\\';
*(buf++) = 'a';
break;
case '\b':
*(buf++) = '\\';
*(buf++) = 'b';
break;
case '\f':
*(buf++) = '\\';
*(buf++) = 'f';
break;
case '\n':
*(buf++) = '\\';
*(buf++) = 'n';
break;
case '\r':
*(buf++) = '\\';
*(buf++) = 'r';
break;
case '\t':
*(buf++) = '\\';
*(buf++) = 't';
break;
case '\v':
*(buf++) = '\\';
*(buf++) = 'v';
break;
case '\\':
*(buf++) = '\\';
*(buf++) = '\\';
break;
case '"':
*(buf++) = '\\';
*(buf++) = '"';
break;
case '\'':
*(buf++) = '\\';
*(buf++) = '\'';
break;
default:
/* For special chars we prefer octal over
* hexadecimal encoding, simply because glib's
* g_strescape() does the same */
if ((c < ' ') || (c >= 127)) {
*(buf++) = '\\';
*(buf++) = octchar((unsigned char) c >> 6);
*(buf++) = octchar((unsigned char) c >> 3);
*(buf++) = octchar((unsigned char) c);
} else
*(buf++) = c;
break;
}
return buf - buf_old;
}
char *cescape(const char *s) {
char *r, *t;
const char *f;
assert(s);
/* Does C style string escaping. May be reversed with
* cunescape(). */
r = new(char, strlen(s)*4 + 1);
if (!r)
return NULL;
for (f = s, t = r; *f; f++)
t += cescape_char(*f, t);
*t = 0;
return r;
}
int cunescape_one(const char *p, size_t length, char *ret, uint32_t *ret_unicode) {
int r = 1;
assert(p);
assert(*p);
assert(ret);
/* Unescapes C style. Returns the unescaped character in ret,
* unless we encountered a \u sequence in which case the full
* unicode character is returned in ret_unicode, instead. */
if (length != (size_t) -1 && length < 1)
return -EINVAL;
switch (p[0]) {
case 'a':
*ret = '\a';
break;
case 'b':
*ret = '\b';
break;
case 'f':
*ret = '\f';
break;
case 'n':
*ret = '\n';
break;
case 'r':
*ret = '\r';
break;
case 't':
*ret = '\t';
break;
case 'v':
*ret = '\v';
break;
case '\\':
*ret = '\\';
break;
case '"':
*ret = '"';
break;
case '\'':
*ret = '\'';
break;
case 's':
/* This is an extension of the XDG syntax files */
*ret = ' ';
break;
case 'x': {
/* hexadecimal encoding */
int a, b;
if (length != (size_t) -1 && length < 3)
return -EINVAL;
a = unhexchar(p[1]);
if (a < 0)
return -EINVAL;
b = unhexchar(p[2]);
if (b < 0)
return -EINVAL;
/* Don't allow NUL bytes */
if (a == 0 && b == 0)
return -EINVAL;
*ret = (char) ((a << 4U) | b);
r = 3;
break;
}
case 'u': {
/* C++11 style 16bit unicode */
int a[4];
unsigned i;
uint32_t c;
if (length != (size_t) -1 && length < 5)
return -EINVAL;
for (i = 0; i < 4; i++) {
a[i] = unhexchar(p[1 + i]);
if (a[i] < 0)
return a[i];
}
c = ((uint32_t) a[0] << 12U) | ((uint32_t) a[1] << 8U) | ((uint32_t) a[2] << 4U) | (uint32_t) a[3];
/* Don't allow 0 chars */
if (c == 0)
return -EINVAL;
if (c < 128)
*ret = c;
else {
if (!ret_unicode)
return -EINVAL;
*ret = 0;
*ret_unicode = c;
}
r = 5;
break;
}
case 'U': {
/* C++11 style 32bit unicode */
int a[8];
unsigned i;
uint32_t c;
if (length != (size_t) -1 && length < 9)
return -EINVAL;
for (i = 0; i < 8; i++) {
a[i] = unhexchar(p[1 + i]);
if (a[i] < 0)
return a[i];
}
c = ((uint32_t) a[0] << 28U) | ((uint32_t) a[1] << 24U) | ((uint32_t) a[2] << 20U) | ((uint32_t) a[3] << 16U) |
((uint32_t) a[4] << 12U) | ((uint32_t) a[5] << 8U) | ((uint32_t) a[6] << 4U) | (uint32_t) a[7];
/* Don't allow 0 chars */
if (c == 0)
return -EINVAL;
/* Don't allow invalid code points */
if (!unichar_is_valid(c))
return -EINVAL;
if (c < 128)
*ret = c;
else {
if (!ret_unicode)
return -EINVAL;
*ret = 0;
*ret_unicode = c;
}
r = 9;
break;
}
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7': {
/* octal encoding */
int a, b, c;
uint32_t m;
if (length != (size_t) -1 && length < 3)
return -EINVAL;
a = unoctchar(p[0]);
if (a < 0)
return -EINVAL;
b = unoctchar(p[1]);
if (b < 0)
return -EINVAL;
c = unoctchar(p[2]);
if (c < 0)
return -EINVAL;
/* don't allow NUL bytes */
if (a == 0 && b == 0 && c == 0)
return -EINVAL;
/* Don't allow bytes above 255 */
m = ((uint32_t) a << 6U) | ((uint32_t) b << 3U) | (uint32_t) c;
if (m > 255)
return -EINVAL;
*ret = m;
r = 3;
break;
}
default:
return -EINVAL;
}
return r;
}
int cunescape_length_with_prefix(const char *s, size_t length, const char *prefix, UnescapeFlags flags, char **ret) {
char *r, *t;
const char *f;
size_t pl;
assert(s);
assert(ret);
/* Undoes C style string escaping, and optionally prefixes it. */
pl = prefix ? strlen(prefix) : 0;
r = new(char, pl+length+1);
if (!r)
return -ENOMEM;
if (prefix)
memcpy(r, prefix, pl);
for (f = s, t = r + pl; f < s + length; f++) {
size_t remaining;
uint32_t u;
char c;
int k;
remaining = s + length - f;
assert(remaining > 0);
if (*f != '\\') {
/* A literal literal, copy verbatim */
*(t++) = *f;
continue;
}
if (remaining == 1) {
if (flags & UNESCAPE_RELAX) {
/* A trailing backslash, copy verbatim */
*(t++) = *f;
continue;
}
free(r);
return -EINVAL;
}
k = cunescape_one(f + 1, remaining - 1, &c, &u);
if (k < 0) {
if (flags & UNESCAPE_RELAX) {
/* Invalid escape code, let's take it literal then */
*(t++) = '\\';
continue;
}
free(r);
return k;
}
if (c != 0)
/* Non-Unicode? Let's encode this directly */
*(t++) = c;
else
/* Unicode? Then let's encode this in UTF-8 */
t += utf8_encode_unichar(t, u);
f += k;
}
*t = 0;
*ret = r;
return t - r;
}
int cunescape_length(const char *s, size_t length, UnescapeFlags flags, char **ret) {
return cunescape_length_with_prefix(s, length, NULL, flags, ret);
}
int cunescape(const char *s, UnescapeFlags flags, char **ret) {
return cunescape_length(s, strlen(s), flags, ret);
}
char *xescape(const char *s, const char *bad) {
char *r, *t;
const char *f;
/* Escapes all chars in bad, in addition to \ and all special
* chars, in \xFF style escaping. May be reversed with
* cunescape(). */
r = new(char, strlen(s) * 4 + 1);
if (!r)
return NULL;
for (f = s, t = r; *f; f++) {
if ((*f < ' ') || (*f >= 127) ||
(*f == '\\') || strchr(bad, *f)) {
*(t++) = '\\';
*(t++) = 'x';
*(t++) = hexchar(*f >> 4);
*(t++) = hexchar(*f);
} else
*(t++) = *f;
}
*t = 0;
return r;
}
static char *strcpy_backslash_escaped(char *t, const char *s, const char *bad) {
assert(bad);
for (; *s; s++) {
if (*s == '\\' || strchr(bad, *s))
*(t++) = '\\';
*(t++) = *s;
}
return t;
}
char *shell_escape(const char *s, const char *bad) {
char *r, *t;
r = new(char, strlen(s)*2+1);
if (!r)
return NULL;
t = strcpy_backslash_escaped(r, s, bad);
*t = 0;
return r;
}
char *shell_maybe_quote(const char *s) {
const char *p;
char *r, *t;
assert(s);
/* Encloses a string in double quotes if necessary to make it
* OK as shell string. */
for (p = s; *p; p++)
if (*p <= ' ' ||
*p >= 127 ||
strchr(SHELL_NEED_QUOTES, *p))
break;
if (!*p)
return strdup(s);
r = new(char, 1+strlen(s)*2+1+1);
if (!r)
return NULL;
t = r;
*(t++) = '"';
t = mempcpy(t, s, p - s);
t = strcpy_backslash_escaped(t, p, SHELL_NEED_ESCAPE);
*(t++)= '"';
*t = 0;
return r;
}

View File

@@ -0,0 +1,50 @@
/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
#pragma once
/***
This file is part of systemd.
Copyright 2010 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 "nm-sd-adapt.h"
#include <inttypes.h>
#include <sys/types.h>
/* What characters are special in the shell? */
/* must be escaped outside and inside double-quotes */
#define SHELL_NEED_ESCAPE "\"\\`$"
/* can be escaped or double-quoted */
#define SHELL_NEED_QUOTES SHELL_NEED_ESCAPE GLOB_CHARS "'()<>|&;"
typedef enum UnescapeFlags {
UNESCAPE_RELAX = 1,
} UnescapeFlags;
char *cescape(const char *s);
size_t cescape_char(char c, char *buf);
int cunescape(const char *s, UnescapeFlags flags, char **ret);
int cunescape_length(const char *s, size_t length, UnescapeFlags flags, char **ret);
int cunescape_length_with_prefix(const char *s, size_t length, const char *prefix, UnescapeFlags flags, char **ret);
int cunescape_one(const char *p, size_t length, char *ret, uint32_t *ret_unicode);
char *xescape(const char *s, const char *bad);
char *shell_escape(const char *s, const char *bad);
char *shell_maybe_quote(const char *s);

View File

@@ -0,0 +1,359 @@
/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
/***
This file is part of systemd.
Copyright 2010 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 "nm-sd-adapt.h"
#if 0 /* NM_IGNORED */
#include "dirent-util.h"
#endif /* NM_IGNORED */
#include "fd-util.h"
#if 0 /* NM_IGNORED */
#include "parse-util.h"
#endif /* NM_IGNORED */
#include "socket-util.h"
#include "util.h"
int close_nointr(int fd) {
assert(fd >= 0);
if (close(fd) >= 0)
return 0;
/*
* Just ignore EINTR; a retry loop is the wrong thing to do on
* Linux.
*
* http://lkml.indiana.edu/hypermail/linux/kernel/0509.1/0877.html
* https://bugzilla.gnome.org/show_bug.cgi?id=682819
* http://utcc.utoronto.ca/~cks/space/blog/unix/CloseEINTR
* https://sites.google.com/site/michaelsafyan/software-engineering/checkforeintrwheninvokingclosethinkagain
*/
if (errno == EINTR)
return 0;
return -errno;
}
int safe_close(int fd) {
/*
* Like close_nointr() but cannot fail. Guarantees errno is
* unchanged. Is a NOP with negative fds passed, and returns
* -1, so that it can be used in this syntax:
*
* fd = safe_close(fd);
*/
if (fd >= 0) {
PROTECT_ERRNO;
/* The kernel might return pretty much any error code
* via close(), but the fd will be closed anyway. The
* only condition we want to check for here is whether
* the fd was invalid at all... */
assert_se(close_nointr(fd) != -EBADF);
}
return -1;
}
void safe_close_pair(int p[]) {
assert(p);
if (p[0] == p[1]) {
/* Special case pairs which use the same fd in both
* directions... */
p[0] = p[1] = safe_close(p[0]);
return;
}
p[0] = safe_close(p[0]);
p[1] = safe_close(p[1]);
}
void close_many(const int fds[], unsigned n_fd) {
unsigned i;
assert(fds || n_fd <= 0);
for (i = 0; i < n_fd; i++)
safe_close(fds[i]);
}
int fclose_nointr(FILE *f) {
assert(f);
/* Same as close_nointr(), but for fclose() */
if (fclose(f) == 0)
return 0;
if (errno == EINTR)
return 0;
return -errno;
}
FILE* safe_fclose(FILE *f) {
/* Same as safe_close(), but for fclose() */
if (f) {
PROTECT_ERRNO;
assert_se(fclose_nointr(f) != EBADF);
}
return NULL;
}
DIR* safe_closedir(DIR *d) {
if (d) {
PROTECT_ERRNO;
assert_se(closedir(d) >= 0 || errno != EBADF);
}
return NULL;
}
int fd_nonblock(int fd, bool nonblock) {
int flags, nflags;
assert(fd >= 0);
flags = fcntl(fd, F_GETFL, 0);
if (flags < 0)
return -errno;
if (nonblock)
nflags = flags | O_NONBLOCK;
else
nflags = flags & ~O_NONBLOCK;
if (nflags == flags)
return 0;
if (fcntl(fd, F_SETFL, nflags) < 0)
return -errno;
return 0;
}
int fd_cloexec(int fd, bool cloexec) {
int flags, nflags;
assert(fd >= 0);
flags = fcntl(fd, F_GETFD, 0);
if (flags < 0)
return -errno;
if (cloexec)
nflags = flags | FD_CLOEXEC;
else
nflags = flags & ~FD_CLOEXEC;
if (nflags == flags)
return 0;
if (fcntl(fd, F_SETFD, nflags) < 0)
return -errno;
return 0;
}
#if 0 /* NM_IGNORED */
_pure_ static bool fd_in_set(int fd, const int fdset[], unsigned n_fdset) {
unsigned i;
assert(n_fdset == 0 || fdset);
for (i = 0; i < n_fdset; i++)
if (fdset[i] == fd)
return true;
return false;
}
int close_all_fds(const int except[], unsigned n_except) {
_cleanup_closedir_ DIR *d = NULL;
struct dirent *de;
int r = 0;
assert(n_except == 0 || except);
d = opendir("/proc/self/fd");
if (!d) {
int fd;
struct rlimit rl;
/* 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 (fd_in_set(fd, except, n_except))
continue;
if (close_nointr(fd) < 0)
if (errno != EBADF && r == 0)
r = -errno;
}
return r;
}
while ((de = readdir(d))) {
int fd = -1;
if (hidden_file(de->d_name))
continue;
if (safe_atoi(de->d_name, &fd) < 0)
/* Let's better ignore this, just in case */
continue;
if (fd < 3)
continue;
if (fd == dirfd(d))
continue;
if (fd_in_set(fd, except, n_except))
continue;
if (close_nointr(fd) < 0) {
/* Valgrind has its own FD and doesn't want to have it closed */
if (errno != EBADF && r == 0)
r = -errno;
}
}
return r;
}
int same_fd(int a, int b) {
struct stat sta, stb;
pid_t pid;
int r, fa, fb;
assert(a >= 0);
assert(b >= 0);
/* Compares two file descriptors. Note that semantics are
* quite different depending on whether we have kcmp() or we
* don't. If we have kcmp() this will only return true for
* dup()ed file descriptors, but not otherwise. If we don't
* have kcmp() this will also return true for two fds of the same
* file, created by separate open() calls. Since we use this
* call mostly for filtering out duplicates in the fd store
* this difference hopefully doesn't matter too much. */
if (a == b)
return true;
/* Try to use kcmp() if we have it. */
pid = getpid();
r = kcmp(pid, pid, KCMP_FILE, a, b);
if (r == 0)
return true;
if (r > 0)
return false;
if (errno != ENOSYS)
return -errno;
/* We don't have kcmp(), use fstat() instead. */
if (fstat(a, &sta) < 0)
return -errno;
if (fstat(b, &stb) < 0)
return -errno;
if ((sta.st_mode & S_IFMT) != (stb.st_mode & S_IFMT))
return false;
/* We consider all device fds different, since two device fds
* might refer to quite different device contexts even though
* they share the same inode and backing dev_t. */
if (S_ISCHR(sta.st_mode) || S_ISBLK(sta.st_mode))
return false;
if (sta.st_dev != stb.st_dev || sta.st_ino != stb.st_ino)
return false;
/* The fds refer to the same inode on disk, let's also check
* if they have the same fd flags. This is useful to
* distinguish the read and write side of a pipe created with
* pipe(). */
fa = fcntl(a, F_GETFL);
if (fa < 0)
return -errno;
fb = fcntl(b, F_GETFL);
if (fb < 0)
return -errno;
return fa == fb;
}
#endif /* NM_IGNORED */
void cmsg_close_all(struct msghdr *mh) {
struct cmsghdr *cmsg;
assert(mh);
CMSG_FOREACH(cmsg, mh)
if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_RIGHTS)
close_many((int*) CMSG_DATA(cmsg), (cmsg->cmsg_len - CMSG_LEN(0)) / sizeof(int));
}
bool fdname_is_valid(const char *s) {
const char *p;
/* Validates a name for $LISTEN_FDNAMES. We basically allow
* everything ASCII that's not a control character. Also, as
* special exception the ":" character is not allowed, as we
* use that as field separator in $LISTEN_FDNAMES.
*
* Note that the empty string is explicitly allowed
* here. However, we limit the length of the names to 255
* characters. */
if (!s)
return false;
for (p = s; *p; p++) {
if (*p < ' ')
return false;
if (*p >= 127)
return false;
if (*p == ':')
return false;
}
return p - s < 256;
}

View File

@@ -0,0 +1,77 @@
/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
#pragma once
/***
This file is part of systemd.
Copyright 2010 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 "nm-sd-adapt.h"
#include <dirent.h>
#include <stdbool.h>
#include <stdio.h>
#include <sys/socket.h>
#include "macro.h"
/* Make sure we can distinguish fd 0 and NULL */
#define FD_TO_PTR(fd) INT_TO_PTR((fd)+1)
#define PTR_TO_FD(p) (PTR_TO_INT(p)-1)
int close_nointr(int fd);
int safe_close(int fd);
void safe_close_pair(int p[]);
void close_many(const int fds[], unsigned n_fd);
int fclose_nointr(FILE *f);
FILE* safe_fclose(FILE *f);
DIR* safe_closedir(DIR *f);
static inline void closep(int *fd) {
safe_close(*fd);
}
static inline void close_pairp(int (*p)[2]) {
safe_close_pair(*p);
}
static inline void fclosep(FILE **f) {
safe_fclose(*f);
}
DEFINE_TRIVIAL_CLEANUP_FUNC(FILE*, pclose);
DEFINE_TRIVIAL_CLEANUP_FUNC(DIR*, closedir);
#define _cleanup_close_ _cleanup_(closep)
#define _cleanup_fclose_ _cleanup_(fclosep)
#define _cleanup_pclose_ _cleanup_(pclosep)
#define _cleanup_closedir_ _cleanup_(closedirp)
#define _cleanup_close_pair_ _cleanup_(close_pairp)
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 same_fd(int a, int b);
void cmsg_close_all(struct msghdr *mh);
bool fdname_is_valid(const char *s);

View File

@@ -23,11 +23,24 @@
#include <unistd.h> #include <unistd.h>
#include "util.h" #include "alloc-util.h"
#include "strv.h"
#include "utf8.h"
#include "ctype.h" #include "ctype.h"
#include "escape.h"
#include "fd-util.h"
#include "fileio.h" #include "fileio.h"
#include "fs-util.h"
#include "hexdecoct.h"
#include "parse-util.h"
#include "path-util.h"
#include "random-util.h"
#if 0 /* NM_IGNORED */
#include "stdio-util.h"
#endif /* NM_IGNORED */
#include "string-util.h"
#include "strv.h"
#include "umask-util.h"
#include "utf8.h"
#include "util.h"
int write_string_stream(FILE *f, const char *line, bool enforce_newline) { int write_string_stream(FILE *f, const char *line, bool enforce_newline) {
@@ -53,7 +66,7 @@ static int write_string_file_atomic(const char *fn, const char *line, bool enfor
if (r < 0) if (r < 0)
return r; return r;
fchmod_umask(fileno(f), 0644); (void) fchmod_umask(fileno(f), 0644);
r = write_string_stream(f, line, enforce_newline); r = write_string_stream(f, line, enforce_newline);
if (r >= 0) { if (r >= 0) {
@@ -62,13 +75,14 @@ static int write_string_file_atomic(const char *fn, const char *line, bool enfor
} }
if (r < 0) if (r < 0)
unlink(p); (void) unlink(p);
return r; return r;
} }
int write_string_file(const char *fn, const char *line, WriteStringFileFlags flags) { int write_string_file(const char *fn, const char *line, WriteStringFileFlags flags) {
_cleanup_fclose_ FILE *f = NULL; _cleanup_fclose_ FILE *f = NULL;
int q, r;
assert(fn); assert(fn);
assert(line); assert(line);
@@ -76,30 +90,58 @@ int write_string_file(const char *fn, const char *line, WriteStringFileFlags fla
if (flags & WRITE_STRING_FILE_ATOMIC) { if (flags & WRITE_STRING_FILE_ATOMIC) {
assert(flags & WRITE_STRING_FILE_CREATE); assert(flags & WRITE_STRING_FILE_CREATE);
return write_string_file_atomic(fn, line, !(flags & WRITE_STRING_FILE_AVOID_NEWLINE)); r = write_string_file_atomic(fn, line, !(flags & WRITE_STRING_FILE_AVOID_NEWLINE));
if (r < 0)
goto fail;
return r;
} }
if (flags & WRITE_STRING_FILE_CREATE) { if (flags & WRITE_STRING_FILE_CREATE) {
f = fopen(fn, "we"); f = fopen(fn, "we");
if (!f) if (!f) {
return -errno; r = -errno;
goto fail;
}
} else { } else {
int fd; int fd;
/* We manually build our own version of fopen(..., "we") that /* We manually build our own version of fopen(..., "we") that
* works without O_CREAT */ * works without O_CREAT */
fd = open(fn, O_WRONLY|O_CLOEXEC|O_NOCTTY); fd = open(fn, O_WRONLY|O_CLOEXEC|O_NOCTTY);
if (fd < 0) if (fd < 0) {
return -errno; r = -errno;
goto fail;
}
f = fdopen(fd, "we"); f = fdopen(fd, "we");
if (!f) { if (!f) {
r = -errno;
safe_close(fd); safe_close(fd);
return -errno; goto fail;
} }
} }
return write_string_stream(f, line, !(flags & WRITE_STRING_FILE_AVOID_NEWLINE)); r = write_string_stream(f, line, !(flags & WRITE_STRING_FILE_AVOID_NEWLINE));
if (r < 0)
goto fail;
return 0;
fail:
if (!(flags & WRITE_STRING_FILE_VERIFY_ON_FAILURE))
return r;
f = safe_fclose(f);
/* OK, the operation failed, but let's see if the right
* contents in place already. If so, eat up the error. */
q = verify_file(fn, line, !(flags & WRITE_STRING_FILE_AVOID_NEWLINE));
if (q <= 0)
return r;
return 0;
} }
int read_one_line_file(const char *fn, char **line) { int read_one_line_file(const char *fn, char **line) {
@@ -130,15 +172,41 @@ int read_one_line_file(const char *fn, char **line) {
return 0; return 0;
} }
int verify_one_line_file(const char *fn, const char *line) { int verify_file(const char *fn, const char *blob, bool accept_extra_nl) {
_cleanup_free_ char *value = NULL; _cleanup_fclose_ FILE *f = NULL;
int r; _cleanup_free_ char *buf = NULL;
size_t l, k;
r = read_one_line_file(fn, &value); assert(fn);
if (r < 0) assert(blob);
return r;
return streq(value, line); l = strlen(blob);
if (accept_extra_nl && endswith(blob, "\n"))
accept_extra_nl = false;
buf = malloc(l + accept_extra_nl + 1);
if (!buf)
return -ENOMEM;
f = fopen(fn, "re");
if (!f)
return -errno;
/* We try to read one byte more than we need, so that we know whether we hit eof */
errno = 0;
k = fread(buf, 1, l + accept_extra_nl + 1, f);
if (ferror(f))
return errno > 0 ? -errno : -EIO;
if (k != l && k != l + accept_extra_nl)
return 0;
if (memcmp(buf, blob, l) != 0)
return 0;
if (k > l && buf[l] != '\n')
return 0;
return 1;
} }
int read_full_stream(FILE *f, char **contents, size_t *size) { int read_full_stream(FILE *f, char **contents, size_t *size) {
@@ -847,3 +915,336 @@ int get_proc_field(const char *filename, const char *pattern, const char *termin
*field = f; *field = f;
return 0; return 0;
} }
DIR *xopendirat(int fd, const char *name, int flags) {
int nfd;
DIR *d;
assert(!(flags & O_CREAT));
nfd = openat(fd, name, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC|flags, 0);
if (nfd < 0)
return NULL;
d = fdopendir(nfd);
if (!d) {
safe_close(nfd);
return NULL;
}
return d;
}
#if 0 /* NM_IGNORED */
static int search_and_fopen_internal(const char *path, const char *mode, const char *root, char **search, FILE **_f) {
char **i;
assert(path);
assert(mode);
assert(_f);
if (!path_strv_resolve_uniq(search, root))
return -ENOMEM;
STRV_FOREACH(i, search) {
_cleanup_free_ char *p = NULL;
FILE *f;
if (root)
p = strjoin(root, *i, "/", path, NULL);
else
p = strjoin(*i, "/", path, NULL);
if (!p)
return -ENOMEM;
f = fopen(p, mode);
if (f) {
*_f = f;
return 0;
}
if (errno != ENOENT)
return -errno;
}
return -ENOENT;
}
int search_and_fopen(const char *path, const char *mode, const char *root, const char **search, FILE **_f) {
_cleanup_strv_free_ char **copy = NULL;
assert(path);
assert(mode);
assert(_f);
if (path_is_absolute(path)) {
FILE *f;
f = fopen(path, mode);
if (f) {
*_f = f;
return 0;
}
return -errno;
}
copy = strv_copy((char**) search);
if (!copy)
return -ENOMEM;
return search_and_fopen_internal(path, mode, root, copy, _f);
}
int search_and_fopen_nulstr(const char *path, const char *mode, const char *root, const char *search, FILE **_f) {
_cleanup_strv_free_ char **s = NULL;
if (path_is_absolute(path)) {
FILE *f;
f = fopen(path, mode);
if (f) {
*_f = f;
return 0;
}
return -errno;
}
s = strv_split_nulstr(search);
if (!s)
return -ENOMEM;
return search_and_fopen_internal(path, mode, root, s, _f);
}
#endif /* NM_IGNORED */
int fopen_temporary(const char *path, FILE **_f, char **_temp_path) {
FILE *f;
char *t;
int r, fd;
assert(path);
assert(_f);
assert(_temp_path);
r = tempfn_xxxxxx(path, NULL, &t);
if (r < 0)
return r;
fd = mkostemp_safe(t, O_WRONLY|O_CLOEXEC);
if (fd < 0) {
free(t);
return -errno;
}
f = fdopen(fd, "we");
if (!f) {
unlink_noerrno(t);
free(t);
safe_close(fd);
return -errno;
}
*_f = f;
*_temp_path = t;
return 0;
}
int fflush_and_check(FILE *f) {
assert(f);
errno = 0;
fflush(f);
if (ferror(f))
return errno ? -errno : -EIO;
return 0;
}
/* This is much like like mkostemp() but is subject to umask(). */
int mkostemp_safe(char *pattern, int flags) {
_cleanup_umask_ mode_t u;
int fd;
assert(pattern);
u = umask(077);
fd = mkostemp(pattern, flags);
if (fd < 0)
return -errno;
return fd;
}
int open_tmpfile(const char *path, int flags) {
char *p;
int fd;
assert(path);
#ifdef O_TMPFILE
/* Try O_TMPFILE first, if it is supported */
fd = open(path, flags|O_TMPFILE|O_EXCL, S_IRUSR|S_IWUSR);
if (fd >= 0)
return fd;
#endif
/* Fall back to unguessable name + unlinking */
p = strjoina(path, "/systemd-tmp-XXXXXX");
fd = mkostemp_safe(p, flags);
if (fd < 0)
return fd;
unlink(p);
return fd;
}
int tempfn_xxxxxx(const char *p, const char *extra, char **ret) {
const char *fn;
char *t;
assert(p);
assert(ret);
/*
* Turns this:
* /foo/bar/waldo
*
* Into this:
* /foo/bar/.#<extra>waldoXXXXXX
*/
fn = basename(p);
if (!filename_is_valid(fn))
return -EINVAL;
if (extra == NULL)
extra = "";
t = new(char, strlen(p) + 2 + strlen(extra) + 6 + 1);
if (!t)
return -ENOMEM;
strcpy(stpcpy(stpcpy(stpcpy(mempcpy(t, p, fn - p), ".#"), extra), fn), "XXXXXX");
*ret = path_kill_slashes(t);
return 0;
}
int tempfn_random(const char *p, const char *extra, char **ret) {
const char *fn;
char *t, *x;
uint64_t u;
unsigned i;
assert(p);
assert(ret);
/*
* Turns this:
* /foo/bar/waldo
*
* Into this:
* /foo/bar/.#<extra>waldobaa2a261115984a9
*/
fn = basename(p);
if (!filename_is_valid(fn))
return -EINVAL;
if (!extra)
extra = "";
t = new(char, strlen(p) + 2 + strlen(extra) + 16 + 1);
if (!t)
return -ENOMEM;
x = stpcpy(stpcpy(stpcpy(mempcpy(t, p, fn - p), ".#"), extra), fn);
u = random_u64();
for (i = 0; i < 16; i++) {
*(x++) = hexchar(u & 0xF);
u >>= 4;
}
*x = 0;
*ret = path_kill_slashes(t);
return 0;
}
int tempfn_random_child(const char *p, const char *extra, char **ret) {
char *t, *x;
uint64_t u;
unsigned i;
assert(p);
assert(ret);
/* Turns this:
* /foo/bar/waldo
* Into this:
* /foo/bar/waldo/.#<extra>3c2b6219aa75d7d0
*/
if (!extra)
extra = "";
t = new(char, strlen(p) + 3 + strlen(extra) + 16 + 1);
if (!t)
return -ENOMEM;
x = stpcpy(stpcpy(stpcpy(t, p), "/.#"), extra);
u = random_u64();
for (i = 0; i < 16; i++) {
*(x++) = hexchar(u & 0xF);
u >>= 4;
}
*x = 0;
*ret = path_kill_slashes(t);
return 0;
}
#if 0 /* NM_IGNORED */
int write_timestamp_file_atomic(const char *fn, usec_t n) {
char ln[DECIMAL_STR_MAX(n)+2];
/* Creates a "timestamp" file, that contains nothing but a
* usec_t timestamp, formatted in ASCII. */
if (n <= 0 || n >= USEC_INFINITY)
return -ERANGE;
xsprintf(ln, USEC_FMT "\n", n);
return write_string_file(fn, ln, WRITE_STRING_FILE_CREATE|WRITE_STRING_FILE_ATOMIC);
}
#endif /* NM_IGNORED */
int read_timestamp_file(const char *fn, usec_t *ret) {
_cleanup_free_ char *ln = NULL;
uint64_t t;
int r;
r = read_one_line_file(fn, &ln);
if (r < 0)
return r;
r = safe_atou64(ln, &t);
if (r < 0)
return r;
if (t <= 0 || t >= (uint64_t) USEC_INFINITY)
return -ERANGE;
*ret = (usec_t) t;
return 0;
}

View File

@@ -23,15 +23,20 @@
#include "nm-sd-adapt.h" #include "nm-sd-adapt.h"
#include <dirent.h>
#include <stdbool.h>
#include <stddef.h> #include <stddef.h>
#include <stdio.h> #include <stdio.h>
#include <sys/types.h>
#include "macro.h" #include "macro.h"
#include "time-util.h"
typedef enum { typedef enum {
WRITE_STRING_FILE_CREATE = 1, WRITE_STRING_FILE_CREATE = 1,
WRITE_STRING_FILE_ATOMIC = 2, WRITE_STRING_FILE_ATOMIC = 2,
WRITE_STRING_FILE_AVOID_NEWLINE = 4, WRITE_STRING_FILE_AVOID_NEWLINE = 4,
WRITE_STRING_FILE_VERIFY_ON_FAILURE = 8,
} WriteStringFileFlags; } WriteStringFileFlags;
int write_string_stream(FILE *f, const char *line, bool enforce_newline); int write_string_stream(FILE *f, const char *line, bool enforce_newline);
@@ -41,7 +46,7 @@ int read_one_line_file(const char *fn, char **line);
int read_full_file(const char *fn, char **contents, size_t *size); int read_full_file(const char *fn, char **contents, size_t *size);
int read_full_stream(FILE *f, char **contents, size_t *size); int read_full_stream(FILE *f, char **contents, size_t *size);
int verify_one_line_file(const char *fn, const char *line); int verify_file(const char *fn, const char *blob, bool accept_extra_nl);
int parse_env_file(const char *fname, const char *separator, ...) _sentinel_; int parse_env_file(const char *fname, const char *separator, ...) _sentinel_;
int load_env_file(FILE *f, const char *fname, const char *separator, char ***l); int load_env_file(FILE *f, const char *fname, const char *separator, char ***l);
@@ -52,3 +57,30 @@ int write_env_file(const char *fname, char **l);
int executable_is_script(const char *path, char **interpreter); int executable_is_script(const char *path, char **interpreter);
int get_proc_field(const char *filename, const char *pattern, const char *terminator, char **field); int get_proc_field(const char *filename, const char *pattern, const char *terminator, char **field);
DIR *xopendirat(int dirfd, const char *name, int flags);
int search_and_fopen(const char *path, const char *mode, const char *root, const char **search, FILE **_f);
int search_and_fopen_nulstr(const char *path, const char *mode, const char *root, const char *search, FILE **_f);
#define FOREACH_LINE(line, f, on_error) \
for (;;) \
if (!fgets(line, sizeof(line), f)) { \
if (ferror(f)) { \
on_error; \
} \
break; \
} else
int fflush_and_check(FILE *f);
int fopen_temporary(const char *path, FILE **_f, char **_temp_path);
int mkostemp_safe(char *pattern, int flags);
int open_tmpfile(const char *path, int flags);
int tempfn_xxxxxx(const char *p, const char *extra, char **ret);
int tempfn_random(const char *p, const char *extra, char **ret);
int tempfn_random_child(const char *p, const char *extra, char **ret);
int write_timestamp_file_atomic(const char *fn, usec_t n);
int read_timestamp_file(const char *fn, usec_t *ret);

View File

@@ -0,0 +1,512 @@
/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
/***
This file is part of systemd.
Copyright 2010 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 "nm-sd-adapt.h"
#include "alloc-util.h"
#if 0 /* NM_IGNORED */
#include "dirent-util.h"
#endif /* NM_IGNORED */
#include "fd-util.h"
#include "fileio.h"
#include "fs-util.h"
#if 0 /* NM_IGNORED */
#include "mkdir.h"
#endif /* NM_IGNORED */
#include "parse-util.h"
#include "path-util.h"
#include "string-util.h"
#include "strv.h"
#if 0 /* NM_IGNORED */
#include "user-util.h"
#endif /* NM_IGNORED */
#include "util.h"
int unlink_noerrno(const char *path) {
PROTECT_ERRNO;
int r;
r = unlink(path);
if (r < 0)
return -errno;
return 0;
}
#if 0 /* NM_IGNORED */
int rmdir_parents(const char *path, const char *stop) {
size_t l;
int r = 0;
assert(path);
assert(stop);
l = strlen(path);
/* Skip trailing slashes */
while (l > 0 && path[l-1] == '/')
l--;
while (l > 0) {
char *t;
/* Skip last component */
while (l > 0 && path[l-1] != '/')
l--;
/* Skip trailing slashes */
while (l > 0 && path[l-1] == '/')
l--;
if (l <= 0)
break;
t = strndup(path, l);
if (!t)
return -ENOMEM;
if (path_startswith(stop, t)) {
free(t);
return 0;
}
r = rmdir(t);
free(t);
if (r < 0)
if (errno != ENOENT)
return -errno;
}
return 0;
}
int rename_noreplace(int olddirfd, const char *oldpath, int newdirfd, const char *newpath) {
struct stat buf;
int ret;
ret = renameat2(olddirfd, oldpath, newdirfd, newpath, RENAME_NOREPLACE);
if (ret >= 0)
return 0;
/* renameat2() exists since Linux 3.15, btrfs added support for it later.
* If it is not implemented, fallback to another method. */
if (!IN_SET(errno, EINVAL, ENOSYS))
return -errno;
/* The link()/unlink() fallback does not work on directories. But
* renameat() without RENAME_NOREPLACE gives the same semantics on
* directories, except when newpath is an *empty* directory. This is
* good enough. */
ret = fstatat(olddirfd, oldpath, &buf, AT_SYMLINK_NOFOLLOW);
if (ret >= 0 && S_ISDIR(buf.st_mode)) {
ret = renameat(olddirfd, oldpath, newdirfd, newpath);
return ret >= 0 ? 0 : -errno;
}
/* If it is not a directory, use the link()/unlink() fallback. */
ret = linkat(olddirfd, oldpath, newdirfd, newpath, 0);
if (ret < 0)
return -errno;
ret = unlinkat(olddirfd, oldpath, 0);
if (ret < 0) {
/* backup errno before the following unlinkat() alters it */
ret = errno;
(void) unlinkat(newdirfd, newpath, 0);
errno = ret;
return -errno;
}
return 0;
}
int readlinkat_malloc(int fd, const char *p, char **ret) {
size_t l = 100;
int r;
assert(p);
assert(ret);
for (;;) {
char *c;
ssize_t n;
c = new(char, l);
if (!c)
return -ENOMEM;
n = readlinkat(fd, p, c, l-1);
if (n < 0) {
r = -errno;
free(c);
return r;
}
if ((size_t) n < l-1) {
c[n] = 0;
*ret = c;
return 0;
}
free(c);
l *= 2;
}
}
int readlink_malloc(const char *p, char **ret) {
return readlinkat_malloc(AT_FDCWD, p, ret);
}
int readlink_value(const char *p, char **ret) {
_cleanup_free_ char *link = NULL;
char *value;
int r;
r = readlink_malloc(p, &link);
if (r < 0)
return r;
value = basename(link);
if (!value)
return -ENOENT;
value = strdup(value);
if (!value)
return -ENOMEM;
*ret = value;
return 0;
}
int readlink_and_make_absolute(const char *p, char **r) {
_cleanup_free_ char *target = NULL;
char *k;
int j;
assert(p);
assert(r);
j = readlink_malloc(p, &target);
if (j < 0)
return j;
k = file_in_same_dir(p, target);
if (!k)
return -ENOMEM;
*r = k;
return 0;
}
int readlink_and_canonicalize(const char *p, char **r) {
char *t, *s;
int j;
assert(p);
assert(r);
j = readlink_and_make_absolute(p, &t);
if (j < 0)
return j;
s = canonicalize_file_name(t);
if (s) {
free(t);
*r = s;
} else
*r = t;
path_kill_slashes(*r);
return 0;
}
int readlink_and_make_absolute_root(const char *root, const char *path, char **ret) {
_cleanup_free_ char *target = NULL, *t = NULL;
const char *full;
int r;
full = prefix_roota(root, path);
r = readlink_malloc(full, &target);
if (r < 0)
return r;
t = file_in_same_dir(path, target);
if (!t)
return -ENOMEM;
*ret = t;
t = NULL;
return 0;
}
int chmod_and_chown(const char *path, mode_t mode, uid_t uid, gid_t gid) {
assert(path);
/* Under the assumption that we are running privileged we
* first change the access mode and only then hand out
* ownership to avoid a window where access is too open. */
if (mode != MODE_INVALID)
if (chmod(path, mode) < 0)
return -errno;
if (uid != UID_INVALID || gid != GID_INVALID)
if (chown(path, uid, gid) < 0)
return -errno;
return 0;
}
int fchmod_and_fchown(int fd, mode_t mode, uid_t uid, gid_t gid) {
assert(fd >= 0);
/* Under the assumption that we are running privileged we
* first change the access mode and only then hand out
* ownership to avoid a window where access is too open. */
if (mode != MODE_INVALID)
if (fchmod(fd, mode) < 0)
return -errno;
if (uid != UID_INVALID || gid != GID_INVALID)
if (fchown(fd, uid, gid) < 0)
return -errno;
return 0;
}
#endif /* NM_IGNORED */
int fchmod_umask(int fd, mode_t m) {
mode_t u;
int r;
u = umask(0777);
r = fchmod(fd, m & (~u)) < 0 ? -errno : 0;
umask(u);
return r;
}
#if 0 /* NM_IGNORED */
int fd_warn_permissions(const char *path, int fd) {
struct stat st;
if (fstat(fd, &st) < 0)
return -errno;
if (st.st_mode & 0111)
log_warning("Configuration file %s is marked executable. Please remove executable permission bits. Proceeding anyway.", path);
if (st.st_mode & 0002)
log_warning("Configuration file %s is marked world-writable. Please remove world writability permission bits. Proceeding anyway.", path);
if (getpid() == 1 && (st.st_mode & 0044) != 0044)
log_warning("Configuration file %s is marked world-inaccessible. This has no effect as configuration data is accessible via APIs without restrictions. Proceeding anyway.", path);
return 0;
}
int touch_file(const char *path, bool parents, usec_t stamp, uid_t uid, gid_t gid, mode_t mode) {
_cleanup_close_ int fd;
int r;
assert(path);
if (parents)
mkdir_parents(path, 0755);
fd = open(path, O_WRONLY|O_CREAT|O_CLOEXEC|O_NOCTTY, mode > 0 ? mode : 0644);
if (fd < 0)
return -errno;
if (mode != MODE_INVALID) {
r = fchmod(fd, mode);
if (r < 0)
return -errno;
}
if (uid != UID_INVALID || gid != GID_INVALID) {
r = fchown(fd, uid, gid);
if (r < 0)
return -errno;
}
if (stamp != USEC_INFINITY) {
struct timespec ts[2];
timespec_store(&ts[0], stamp);
ts[1] = ts[0];
r = futimens(fd, ts);
} else
r = futimens(fd, NULL);
if (r < 0)
return -errno;
return 0;
}
int touch(const char *path) {
return touch_file(path, false, USEC_INFINITY, UID_INVALID, GID_INVALID, MODE_INVALID);
}
int symlink_idempotent(const char *from, const char *to) {
_cleanup_free_ char *p = NULL;
int r;
assert(from);
assert(to);
if (symlink(from, to) < 0) {
if (errno != EEXIST)
return -errno;
r = readlink_malloc(to, &p);
if (r < 0)
return r;
if (!streq(p, from))
return -EINVAL;
}
return 0;
}
int symlink_atomic(const char *from, const char *to) {
_cleanup_free_ char *t = NULL;
int r;
assert(from);
assert(to);
r = tempfn_random(to, NULL, &t);
if (r < 0)
return r;
if (symlink(from, t) < 0)
return -errno;
if (rename(t, to) < 0) {
unlink_noerrno(t);
return -errno;
}
return 0;
}
int mknod_atomic(const char *path, mode_t mode, dev_t dev) {
_cleanup_free_ char *t = NULL;
int r;
assert(path);
r = tempfn_random(path, NULL, &t);
if (r < 0)
return r;
if (mknod(t, mode, dev) < 0)
return -errno;
if (rename(t, path) < 0) {
unlink_noerrno(t);
return -errno;
}
return 0;
}
int mkfifo_atomic(const char *path, mode_t mode) {
_cleanup_free_ char *t = NULL;
int r;
assert(path);
r = tempfn_random(path, NULL, &t);
if (r < 0)
return r;
if (mkfifo(t, mode) < 0)
return -errno;
if (rename(t, path) < 0) {
unlink_noerrno(t);
return -errno;
}
return 0;
}
int get_files_in_directory(const char *path, char ***list) {
_cleanup_closedir_ DIR *d = NULL;
size_t bufsize = 0, n = 0;
_cleanup_strv_free_ char **l = NULL;
assert(path);
/* Returns all files in a directory in *list, and the number
* of files as return value. If list is NULL returns only the
* number. */
d = opendir(path);
if (!d)
return -errno;
for (;;) {
struct dirent *de;
errno = 0;
de = readdir(d);
if (!de && errno != 0)
return -errno;
if (!de)
break;
dirent_ensure_type(d, de);
if (!dirent_is_file(de))
continue;
if (list) {
/* one extra slot is needed for the terminating NULL */
if (!GREEDY_REALLOC(l, bufsize, n + 2))
return -ENOMEM;
l[n] = strdup(de->d_name);
if (!l[n])
return -ENOMEM;
l[++n] = NULL;
} else
n++;
}
if (list) {
*list = l;
l = NULL; /* avoid freeing */
}
return n;
}
#endif /* NM_IGNORED */

View File

@@ -0,0 +1,77 @@
/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
#pragma once
/***
This file is part of systemd.
Copyright 2010 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 "nm-sd-adapt.h"
#include <fcntl.h>
#include <limits.h>
#include <sys/inotify.h>
#include <sys/types.h>
#include <unistd.h>
#include "time-util.h"
int unlink_noerrno(const char *path);
int rmdir_parents(const char *path, const char *stop);
int rename_noreplace(int olddirfd, const char *oldpath, int newdirfd, const char *newpath);
int readlinkat_malloc(int fd, const char *p, char **ret);
int readlink_malloc(const char *p, char **r);
int readlink_value(const char *p, char **ret);
int readlink_and_make_absolute(const char *p, char **r);
int readlink_and_canonicalize(const char *p, char **r);
int readlink_and_make_absolute_root(const char *root, const char *path, char **ret);
int chmod_and_chown(const char *path, mode_t mode, uid_t uid, gid_t gid);
int fchmod_and_fchown(int fd, mode_t mode, uid_t uid, gid_t gid);
int fchmod_umask(int fd, mode_t mode);
int fd_warn_permissions(const char *path, int fd);
#define laccess(path, mode) faccessat(AT_FDCWD, (path), (mode), AT_SYMLINK_NOFOLLOW)
int touch_file(const char *path, bool parents, usec_t stamp, uid_t uid, gid_t gid, mode_t mode);
int touch(const char *path);
int symlink_idempotent(const char *from, const char *to);
int symlink_atomic(const char *from, const char *to);
int mknod_atomic(const char *path, mode_t mode, dev_t dev);
int mkfifo_atomic(const char *path, mode_t mode);
int get_files_in_directory(const char *path, char ***list);
#define INOTIFY_EVENT_MAX (sizeof(struct inotify_event) + NAME_MAX + 1)
#define FOREACH_INOTIFY_EVENT(e, buffer, sz) \
for ((e) = &buffer.ev; \
(uint8_t*) (e) < (uint8_t*) (buffer.raw) + (sz); \
(e) = (struct inotify_event*) ((uint8_t*) (e) + sizeof(struct inotify_event) + (e)->len))
union inotify_event_buffer {
struct inotify_event ev;
uint8_t raw[INOTIFY_EVENT_MAX];
};

View File

@@ -22,18 +22,22 @@
#include "nm-sd-adapt.h" #include "nm-sd-adapt.h"
#include <stdlib.h>
#include <errno.h> #include <errno.h>
#include <pthread.h> #include <pthread.h>
#include <stdlib.h>
#include "util.h" #include "alloc-util.h"
#include "hashmap.h" #include "hashmap.h"
#include "set.h"
#include "macro.h" #include "macro.h"
#include "mempool.h"
#if 0 /* NM_IGNORED */
#include "process-util.h"
#endif /* NM_IGNORED */
#include "random-util.h"
#include "set.h"
#include "siphash24.h" #include "siphash24.h"
#include "strv.h" #include "strv.h"
#include "mempool.h" #include "util.h"
#include "random-util.h"
#ifdef ENABLE_DEBUG_HASHMAP #ifdef ENABLE_DEBUG_HASHMAP
#include "list.h" #include "list.h"
@@ -380,7 +384,7 @@ static unsigned base_bucket_hash(HashmapBase *h, const void *p) {
h->hash_ops->hash(p, &state); h->hash_ops->hash(p, &state);
siphash24_finalize((uint8_t*)&hash, &state); hash = siphash24_finalize(&state);
return (unsigned) (hash % n_buckets(h)); return (unsigned) (hash % n_buckets(h));
} }

View File

@@ -0,0 +1,700 @@
/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
/***
This file is part of systemd.
Copyright 2010 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 "nm-sd-adapt.h"
#include <ctype.h>
#include <inttypes.h>
#include "alloc-util.h"
#include "hexdecoct.h"
#include "util.h"
char octchar(int x) {
return '0' + (x & 7);
}
int unoctchar(char c) {
if (c >= '0' && c <= '7')
return c - '0';
return -EINVAL;
}
char decchar(int x) {
return '0' + (x % 10);
}
int undecchar(char c) {
if (c >= '0' && c <= '9')
return c - '0';
return -EINVAL;
}
char hexchar(int x) {
static const char table[16] = "0123456789abcdef";
return table[x & 15];
}
int unhexchar(char c) {
if (c >= '0' && c <= '9')
return c - '0';
if (c >= 'a' && c <= 'f')
return c - 'a' + 10;
if (c >= 'A' && c <= 'F')
return c - 'A' + 10;
return -EINVAL;
}
char *hexmem(const void *p, size_t l) {
char *r, *z;
const uint8_t *x;
z = r = malloc(l * 2 + 1);
if (!r)
return NULL;
for (x = p; x < (const uint8_t*) p + l; x++) {
*(z++) = hexchar(*x >> 4);
*(z++) = hexchar(*x & 15);
}
*z = 0;
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;
assert(mem);
assert(len);
assert(p);
z = r = malloc((l + 1) / 2 + 1);
if (!r)
return -ENOMEM;
for (x = p; x < p + l; x += 2) {
int a, b;
a = unhexchar(x[0]);
if (a < 0)
return a;
else if (x+1 < p + l) {
b = unhexchar(x[1]);
if (b < 0)
return b;
} else
b = 0;
*(z++) = (uint8_t) a << 4 | (uint8_t) b;
}
*z = 0;
*mem = r;
r = NULL;
*len = (l + 1) / 2;
return 0;
}
/* https://tools.ietf.org/html/rfc4648#section-6
* Notice that base32hex differs from base32 in the alphabet it uses.
* The distinction is that the base32hex representation preserves the
* order of the underlying data when compared as bytestrings, this is
* useful when representing NSEC3 hashes, as one can then verify the
* order of hashes directly from their representation. */
char base32hexchar(int x) {
static const char table[32] = "0123456789"
"ABCDEFGHIJKLMNOPQRSTUV";
return table[x & 31];
}
int unbase32hexchar(char c) {
unsigned offset;
if (c >= '0' && c <= '9')
return c - '0';
offset = '9' - '0' + 1;
if (c >= 'A' && c <= 'V')
return c - 'A' + offset;
return -EINVAL;
}
char *base32hexmem(const void *p, size_t l, bool padding) {
char *r, *z;
const uint8_t *x;
size_t len;
if (padding)
/* five input bytes makes eight output bytes, padding is added so we must round up */
len = 8 * (l + 4) / 5;
else {
/* same, but round down as there is no padding */
len = 8 * l / 5;
switch (l % 5) {
case 4:
len += 7;
break;
case 3:
len += 5;
break;
case 2:
len += 4;
break;
case 1:
len += 2;
break;
}
}
z = r = malloc(len + 1);
if (!r)
return NULL;
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 */
*(z++) = base32hexchar(x[0] >> 3); /* 000XXXXX */
*(z++) = base32hexchar((x[0] & 7) << 2 | x[1] >> 6); /* 000XXXYY */
*(z++) = base32hexchar((x[1] & 63) >> 1); /* 000YYYYY */
*(z++) = base32hexchar((x[1] & 1) << 4 | x[2] >> 4); /* 000YZZZZ */
*(z++) = base32hexchar((x[2] & 15) << 1 | x[3] >> 7); /* 000ZZZZQ */
*(z++) = base32hexchar((x[3] & 127) >> 2); /* 000QQQQQ */
*(z++) = base32hexchar((x[3] & 3) << 3 | x[4] >> 5); /* 000QQWWW */
*(z++) = base32hexchar((x[4] & 31)); /* 000WWWWW */
}
switch (l % 5) {
case 4:
*(z++) = base32hexchar(x[0] >> 3); /* 000XXXXX */
*(z++) = base32hexchar((x[0] & 7) << 2 | x[1] >> 6); /* 000XXXYY */
*(z++) = base32hexchar((x[1] & 63) >> 1); /* 000YYYYY */
*(z++) = base32hexchar((x[1] & 1) << 4 | x[2] >> 4); /* 000YZZZZ */
*(z++) = base32hexchar((x[2] & 15) << 1 | x[3] >> 7); /* 000ZZZZQ */
*(z++) = base32hexchar((x[3] & 127) >> 2); /* 000QQQQQ */
*(z++) = base32hexchar((x[3] & 3) << 3); /* 000QQ000 */
if (padding)
*(z++) = '=';
break;
case 3:
*(z++) = base32hexchar(x[0] >> 3); /* 000XXXXX */
*(z++) = base32hexchar((x[0] & 7) << 2 | x[1] >> 6); /* 000XXXYY */
*(z++) = base32hexchar((x[1] & 63) >> 1); /* 000YYYYY */
*(z++) = base32hexchar((x[1] & 1) << 4 | x[2] >> 4); /* 000YZZZZ */
*(z++) = base32hexchar((x[2] & 15) << 1); /* 000ZZZZ0 */
if (padding) {
*(z++) = '=';
*(z++) = '=';
*(z++) = '=';
}
break;
case 2:
*(z++) = base32hexchar(x[0] >> 3); /* 000XXXXX */
*(z++) = base32hexchar((x[0] & 7) << 2 | x[1] >> 6); /* 000XXXYY */
*(z++) = base32hexchar((x[1] & 63) >> 1); /* 000YYYYY */
*(z++) = base32hexchar((x[1] & 1) << 4); /* 000Y0000 */
if (padding) {
*(z++) = '=';
*(z++) = '=';
*(z++) = '=';
*(z++) = '=';
}
break;
case 1:
*(z++) = base32hexchar(x[0] >> 3); /* 000XXXXX */
*(z++) = base32hexchar((x[0] & 7) << 2); /* 000XXX00 */
if (padding) {
*(z++) = '=';
*(z++) = '=';
*(z++) = '=';
*(z++) = '=';
*(z++) = '=';
*(z++) = '=';
}
break;
}
*z = 0;
return r;
}
int unbase32hexmem(const char *p, size_t l, bool padding, void **mem, size_t *_len) {
_cleanup_free_ uint8_t *r = NULL;
int a, b, c, d, e, f, g, h;
uint8_t *z;
const char *x;
size_t len;
unsigned pad = 0;
assert(p);
/* padding ensures any base32hex input has input divisible by 8 */
if (padding && l % 8 != 0)
return -EINVAL;
if (padding) {
/* strip the padding */
while (l > 0 && p[l - 1] == '=' && pad < 7) {
pad ++;
l --;
}
}
/* a group of eight input bytes needs five output bytes, in case of
padding we need to add some extra bytes */
len = (l / 8) * 5;
switch (l % 8) {
case 7:
len += 4;
break;
case 5:
len += 3;
break;
case 4:
len += 2;
break;
case 2:
len += 1;
break;
case 0:
break;
default:
return -EINVAL;
}
z = r = malloc(len + 1);
if (!r)
return -ENOMEM;
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 */
a = unbase32hexchar(x[0]);
if (a < 0)
return -EINVAL;
b = unbase32hexchar(x[1]);
if (b < 0)
return -EINVAL;
c = unbase32hexchar(x[2]);
if (c < 0)
return -EINVAL;
d = unbase32hexchar(x[3]);
if (d < 0)
return -EINVAL;
e = unbase32hexchar(x[4]);
if (e < 0)
return -EINVAL;
f = unbase32hexchar(x[5]);
if (f < 0)
return -EINVAL;
g = unbase32hexchar(x[6]);
if (g < 0)
return -EINVAL;
h = unbase32hexchar(x[7]);
if (h < 0)
return -EINVAL;
*(z++) = (uint8_t) a << 3 | (uint8_t) b >> 2; /* XXXXXYYY */
*(z++) = (uint8_t) b << 6 | (uint8_t) c << 1 | (uint8_t) d >> 4; /* YYZZZZZW */
*(z++) = (uint8_t) d << 4 | (uint8_t) e >> 1; /* WWWWSSSS */
*(z++) = (uint8_t) e << 7 | (uint8_t) f << 2 | (uint8_t) g >> 3; /* SQQQQQVV */
*(z++) = (uint8_t) g << 5 | (uint8_t) h; /* VVVRRRRR */
}
switch (l % 8) {
case 7:
a = unbase32hexchar(x[0]);
if (a < 0)
return -EINVAL;
b = unbase32hexchar(x[1]);
if (b < 0)
return -EINVAL;
c = unbase32hexchar(x[2]);
if (c < 0)
return -EINVAL;
d = unbase32hexchar(x[3]);
if (d < 0)
return -EINVAL;
e = unbase32hexchar(x[4]);
if (e < 0)
return -EINVAL;
f = unbase32hexchar(x[5]);
if (f < 0)
return -EINVAL;
g = unbase32hexchar(x[6]);
if (g < 0)
return -EINVAL;
/* g == 000VV000 */
if (g & 7)
return -EINVAL;
*(z++) = (uint8_t) a << 3 | (uint8_t) b >> 2; /* XXXXXYYY */
*(z++) = (uint8_t) b << 6 | (uint8_t) c << 1 | (uint8_t) d >> 4; /* YYZZZZZW */
*(z++) = (uint8_t) d << 4 | (uint8_t) e >> 1; /* WWWWSSSS */
*(z++) = (uint8_t) e << 7 | (uint8_t) f << 2 | (uint8_t) g >> 3; /* SQQQQQVV */
break;
case 5:
a = unbase32hexchar(x[0]);
if (a < 0)
return -EINVAL;
b = unbase32hexchar(x[1]);
if (b < 0)
return -EINVAL;
c = unbase32hexchar(x[2]);
if (c < 0)
return -EINVAL;
d = unbase32hexchar(x[3]);
if (d < 0)
return -EINVAL;
e = unbase32hexchar(x[4]);
if (e < 0)
return -EINVAL;
/* e == 000SSSS0 */
if (e & 1)
return -EINVAL;
*(z++) = (uint8_t) a << 3 | (uint8_t) b >> 2; /* XXXXXYYY */
*(z++) = (uint8_t) b << 6 | (uint8_t) c << 1 | (uint8_t) d >> 4; /* YYZZZZZW */
*(z++) = (uint8_t) d << 4 | (uint8_t) e >> 1; /* WWWWSSSS */
break;
case 4:
a = unbase32hexchar(x[0]);
if (a < 0)
return -EINVAL;
b = unbase32hexchar(x[1]);
if (b < 0)
return -EINVAL;
c = unbase32hexchar(x[2]);
if (c < 0)
return -EINVAL;
d = unbase32hexchar(x[3]);
if (d < 0)
return -EINVAL;
/* d == 000W0000 */
if (d & 15)
return -EINVAL;
*(z++) = (uint8_t) a << 3 | (uint8_t) b >> 2; /* XXXXXYYY */
*(z++) = (uint8_t) b << 6 | (uint8_t) c << 1 | (uint8_t) d >> 4; /* YYZZZZZW */
break;
case 2:
a = unbase32hexchar(x[0]);
if (a < 0)
return -EINVAL;
b = unbase32hexchar(x[1]);
if (b < 0)
return -EINVAL;
/* b == 000YYY00 */
if (b & 3)
return -EINVAL;
*(z++) = (uint8_t) a << 3 | (uint8_t) b >> 2; /* XXXXXYYY */
break;
case 0:
break;
default:
return -EINVAL;
}
*z = 0;
*mem = r;
r = NULL;
*_len = len;
return 0;
}
/* https://tools.ietf.org/html/rfc4648#section-4 */
char base64char(int x) {
static const char table[64] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"abcdefghijklmnopqrstuvwxyz"
"0123456789+/";
return table[x & 63];
}
int unbase64char(char c) {
unsigned offset;
if (c >= 'A' && c <= 'Z')
return c - 'A';
offset = 'Z' - 'A' + 1;
if (c >= 'a' && c <= 'z')
return c - 'a' + offset;
offset += 'z' - 'a' + 1;
if (c >= '0' && c <= '9')
return c - '0' + offset;
offset += '9' - '0' + 1;
if (c == '+')
return offset;
offset ++;
if (c == '/')
return offset;
return -EINVAL;
}
char *base64mem(const void *p, size_t l) {
char *r, *z;
const uint8_t *x;
/* three input bytes makes four output bytes, padding is added so we must round up */
z = r = malloc(4 * (l + 2) / 3 + 1);
if (!r)
return NULL;
for (x = p; x < (const uint8_t*) p + (l / 3) * 3; x += 3) {
/* x[0] == XXXXXXXX; x[1] == YYYYYYYY; x[2] == ZZZZZZZZ */
*(z++) = base64char(x[0] >> 2); /* 00XXXXXX */
*(z++) = base64char((x[0] & 3) << 4 | x[1] >> 4); /* 00XXYYYY */
*(z++) = base64char((x[1] & 15) << 2 | x[2] >> 6); /* 00YYYYZZ */
*(z++) = base64char(x[2] & 63); /* 00ZZZZZZ */
}
switch (l % 3) {
case 2:
*(z++) = base64char(x[0] >> 2); /* 00XXXXXX */
*(z++) = base64char((x[0] & 3) << 4 | x[1] >> 4); /* 00XXYYYY */
*(z++) = base64char((x[1] & 15) << 2); /* 00YYYY00 */
*(z++) = '=';
break;
case 1:
*(z++) = base64char(x[0] >> 2); /* 00XXXXXX */
*(z++) = base64char((x[0] & 3) << 4); /* 00XX0000 */
*(z++) = '=';
*(z++) = '=';
break;
}
*z = 0;
return r;
}
int unbase64mem(const char *p, size_t l, void **mem, size_t *_len) {
_cleanup_free_ uint8_t *r = NULL;
int a, b, c, d;
uint8_t *z;
const char *x;
size_t len;
assert(p);
/* padding ensures any base63 input has input divisible by 4 */
if (l % 4 != 0)
return -EINVAL;
/* strip the padding */
if (l > 0 && p[l - 1] == '=')
l --;
if (l > 0 && p[l - 1] == '=')
l --;
/* a group of four input bytes needs three output bytes, in case of
padding we need to add two or three extra bytes */
len = (l / 4) * 3 + (l % 4 ? (l % 4) - 1 : 0);
z = r = malloc(len + 1);
if (!r)
return -ENOMEM;
for (x = p; x < p + (l / 4) * 4; x += 4) {
/* a == 00XXXXXX; b == 00YYYYYY; c == 00ZZZZZZ; d == 00WWWWWW */
a = unbase64char(x[0]);
if (a < 0)
return -EINVAL;
b = unbase64char(x[1]);
if (b < 0)
return -EINVAL;
c = unbase64char(x[2]);
if (c < 0)
return -EINVAL;
d = unbase64char(x[3]);
if (d < 0)
return -EINVAL;
*(z++) = (uint8_t) a << 2 | (uint8_t) b >> 4; /* XXXXXXYY */
*(z++) = (uint8_t) b << 4 | (uint8_t) c >> 2; /* YYYYZZZZ */
*(z++) = (uint8_t) c << 6 | (uint8_t) d; /* ZZWWWWWW */
}
switch (l % 4) {
case 3:
a = unbase64char(x[0]);
if (a < 0)
return -EINVAL;
b = unbase64char(x[1]);
if (b < 0)
return -EINVAL;
c = unbase64char(x[2]);
if (c < 0)
return -EINVAL;
/* c == 00ZZZZ00 */
if (c & 3)
return -EINVAL;
*(z++) = (uint8_t) a << 2 | (uint8_t) b >> 4; /* XXXXXXYY */
*(z++) = (uint8_t) b << 4 | (uint8_t) c >> 2; /* YYYYZZZZ */
break;
case 2:
a = unbase64char(x[0]);
if (a < 0)
return -EINVAL;
b = unbase64char(x[1]);
if (b < 0)
return -EINVAL;
/* b == 00YY0000 */
if (b & 15)
return -EINVAL;
*(z++) = (uint8_t) a << 2 | (uint8_t) (b >> 4); /* XXXXXXYY */
break;
case 0:
break;
default:
return -EINVAL;
}
*z = 0;
*mem = r;
r = NULL;
*_len = len;
return 0;
}
void hexdump(FILE *f, const void *p, size_t s) {
const uint8_t *b = p;
unsigned n = 0;
assert(s == 0 || b);
while (s > 0) {
size_t i;
fprintf(f, "%04x ", n);
for (i = 0; i < 16; i++) {
if (i >= s)
fputs(" ", f);
else
fprintf(f, "%02x ", b[i]);
if (i == 7)
fputc(' ', f);
}
fputc(' ', f);
for (i = 0; i < 16; i++) {
if (i >= s)
fputc(' ', f);
else
fputc(isprint(b[i]) ? (char) b[i] : '.', f);
}
fputc('\n', f);
if (s < 16)
break;
n += 16;
b += 16;
s -= 16;
}
}

View File

@@ -0,0 +1,56 @@
/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
#pragma once
/***
This file is part of systemd.
Copyright 2010 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 "nm-sd-adapt.h"
#include <stdbool.h>
#include <stdio.h>
#include <sys/types.h>
#include "macro.h"
char octchar(int x) _const_;
int unoctchar(char c) _const_;
char decchar(int x) _const_;
int undecchar(char c) _const_;
char hexchar(int x) _const_;
int unhexchar(char c) _const_;
char *hexmem(const void *p, size_t l);
int unhexmem(const char *p, size_t l, void **mem, size_t *len);
char base32hexchar(int x) _const_;
int unbase32hexchar(char c) _const_;
char base64char(int x) _const_;
int unbase64char(char c) _const_;
char *base32hexmem(const void *p, size_t l, bool padding);
int unbase32hexmem(const char *p, size_t l, bool padding, void **mem, size_t *len);
char *base64mem(const void *p, size_t l);
int unbase64mem(const char *p, size_t l, void **mem, size_t *len);
void hexdump(FILE *f, const void *p, size_t s);

View File

@@ -21,11 +21,14 @@
#include "nm-sd-adapt.h" #include "nm-sd-adapt.h"
#include <sys/utsname.h>
#include <ctype.h> #include <ctype.h>
#include <sys/utsname.h>
#include "util.h" #include "fd-util.h"
#include "fileio.h"
#include "hostname-util.h" #include "hostname-util.h"
#include "string-util.h"
#include "util.h"
bool hostname_is_set(void) { bool hostname_is_set(void) {
struct utsname u; struct utsname u;
@@ -71,7 +74,7 @@ static bool hostname_valid_char(char c) {
* allow_trailing_dot is true and at least two components are present * allow_trailing_dot is true and at least two components are present
* in the name. Note that due to the restricted charset and length * in the name. Note that due to the restricted charset and length
* this call is substantially more conservative than * this call is substantially more conservative than
* dns_domain_is_valid(). * dns_name_is_valid().
*/ */
bool hostname_is_valid(const char *s, bool allow_trailing_dot) { bool hostname_is_valid(const char *s, bool allow_trailing_dot) {
unsigned n_dots = 0; unsigned n_dots = 0;

View File

@@ -23,6 +23,7 @@
#include <arpa/inet.h> #include <arpa/inet.h>
#include "alloc-util.h"
#include "in-addr-util.h" #include "in-addr-util.h"
int in_addr_is_null(int family, const union in_addr_union *u) { int in_addr_is_null(int family, const union in_addr_union *u) {

View File

@@ -0,0 +1,263 @@
/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
/***
This file is part of systemd.
Copyright 2010 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 "nm-sd-adapt.h"
#include <poll.h>
#include <unistd.h>
#include "io-util.h"
int flush_fd(int fd) {
struct pollfd pollfd = {
.fd = fd,
.events = POLLIN,
};
for (;;) {
char buf[LINE_MAX];
ssize_t l;
int r;
r = poll(&pollfd, 1, 0);
if (r < 0) {
if (errno == EINTR)
continue;
return -errno;
} else if (r == 0)
return 0;
l = read(fd, buf, sizeof(buf));
if (l < 0) {
if (errno == EINTR)
continue;
if (errno == EAGAIN)
return 0;
return -errno;
} else if (l == 0)
return 0;
}
}
ssize_t loop_read(int fd, void *buf, size_t nbytes, bool do_poll) {
uint8_t *p = buf;
ssize_t n = 0;
assert(fd >= 0);
assert(buf);
/* If called with nbytes == 0, let's call read() at least
* once, to validate the operation */
if (nbytes > (size_t) SSIZE_MAX)
return -EINVAL;
do {
ssize_t k;
k = read(fd, p, nbytes);
if (k < 0) {
if (errno == EINTR)
continue;
if (errno == EAGAIN && do_poll) {
/* We knowingly ignore any return value here,
* and expect that any error/EOF is reported
* via read() */
(void) fd_wait_for_event(fd, POLLIN, USEC_INFINITY);
continue;
}
return n > 0 ? n : -errno;
}
if (k == 0)
return n;
assert((size_t) k <= nbytes);
p += k;
nbytes -= k;
n += k;
} while (nbytes > 0);
return n;
}
int loop_read_exact(int fd, void *buf, size_t nbytes, bool do_poll) {
ssize_t n;
n = loop_read(fd, buf, nbytes, do_poll);
if (n < 0)
return (int) n;
if ((size_t) n != nbytes)
return -EIO;
return 0;
}
int loop_write(int fd, const void *buf, size_t nbytes, bool do_poll) {
const uint8_t *p = buf;
assert(fd >= 0);
assert(buf);
if (nbytes > (size_t) SSIZE_MAX)
return -EINVAL;
do {
ssize_t k;
k = write(fd, p, nbytes);
if (k < 0) {
if (errno == EINTR)
continue;
if (errno == EAGAIN && do_poll) {
/* We knowingly ignore any return value here,
* and expect that any error/EOF is reported
* via write() */
(void) fd_wait_for_event(fd, POLLOUT, USEC_INFINITY);
continue;
}
return -errno;
}
if (_unlikely_(nbytes > 0 && k == 0)) /* Can't really happen */
return -EIO;
assert((size_t) k <= nbytes);
p += k;
nbytes -= k;
} while (nbytes > 0);
return 0;
}
int pipe_eof(int fd) {
struct pollfd pollfd = {
.fd = fd,
.events = POLLIN|POLLHUP,
};
int r;
r = poll(&pollfd, 1, 0);
if (r < 0)
return -errno;
if (r == 0)
return 0;
return pollfd.revents & POLLHUP;
}
int fd_wait_for_event(int fd, int event, usec_t t) {
struct pollfd pollfd = {
.fd = fd,
.events = event,
};
struct timespec ts;
int r;
r = ppoll(&pollfd, 1, t == USEC_INFINITY ? NULL : timespec_store(&ts, t), NULL);
if (r < 0)
return -errno;
if (r == 0)
return 0;
return pollfd.revents;
}
static size_t nul_length(const uint8_t *p, size_t sz) {
size_t n = 0;
while (sz > 0) {
if (*p != 0)
break;
n++;
p++;
sz--;
}
return n;
}
ssize_t sparse_write(int fd, const void *p, size_t sz, size_t run_length) {
const uint8_t *q, *w, *e;
ssize_t l;
q = w = p;
e = q + sz;
while (q < e) {
size_t n;
n = nul_length(q, e - q);
/* If there are more than the specified run length of
* NUL bytes, or if this is the beginning or the end
* of the buffer, then seek instead of write */
if ((n > run_length) ||
(n > 0 && q == p) ||
(n > 0 && q + n >= e)) {
if (q > w) {
l = write(fd, w, q - w);
if (l < 0)
return -errno;
if (l != q -w)
return -EIO;
}
if (lseek(fd, n, SEEK_CUR) == (off_t) -1)
return -errno;
q += n;
w = q;
} else if (n > 0)
q += n;
else
q ++;
}
if (q > w) {
l = write(fd, w, q - w);
if (l < 0)
return -errno;
if (l != q - w)
return -EIO;
}
return q - (const uint8_t*) p;
}

View File

@@ -0,0 +1,78 @@
/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
#pragma once
/***
This file is part of systemd.
Copyright 2010 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 "nm-sd-adapt.h"
#include <stdbool.h>
#include <sys/types.h>
#include <sys/uio.h>
#include "time-util.h"
int flush_fd(int fd);
ssize_t loop_read(int fd, void *buf, size_t nbytes, bool do_poll);
int loop_read_exact(int fd, void *buf, size_t nbytes, bool do_poll);
int loop_write(int fd, const void *buf, size_t nbytes, bool do_poll);
int pipe_eof(int fd);
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);
#define IOVEC_SET_STRING(i, s) \
do { \
struct iovec *_i = &(i); \
char *_s = (char *)(s); \
_i->iov_base = _s; \
_i->iov_len = strlen(_s); \
} while(false)
static inline size_t IOVEC_TOTAL_SIZE(const struct iovec *i, unsigned n) {
unsigned j;
size_t r = 0;
for (j = 0; j < n; j++)
r += i[j].iov_len;
return r;
}
static inline size_t IOVEC_INCREMENT(struct iovec *i, unsigned n, size_t k) {
unsigned j;
for (j = 0; j < n; j++) {
size_t sub;
if (_unlikely_(k <= 0))
break;
sub = MIN(i[j].iov_len, k);
i[j].iov_len -= sub;
i[j].iov_base = (uint8_t*) i[j].iov_base + sub;
k -= sub;
}
return k;
}

View File

@@ -23,14 +23,15 @@
#include "nm-sd-adapt.h" #include "nm-sd-adapt.h"
#include <stdbool.h>
#include <stdarg.h>
#include <stdlib.h>
#include <syslog.h>
#include <sys/signalfd.h>
#include <errno.h> #include <errno.h>
#include <stdarg.h>
#include <stdbool.h>
#include <stdlib.h>
#include <sys/signalfd.h>
#include <syslog.h>
#include "sd-id128.h" #include "sd-id128.h"
#include "macro.h" #include "macro.h"
typedef enum LogTarget{ typedef enum LogTarget{

View File

@@ -24,11 +24,10 @@
#include "nm-sd-adapt.h" #include "nm-sd-adapt.h"
#include <assert.h> #include <assert.h>
#include <sys/param.h>
#include <sys/types.h>
#include <sys/uio.h>
#include <inttypes.h> #include <inttypes.h>
#include <stdbool.h> #include <stdbool.h>
#include <sys/param.h>
#include <sys/types.h>
#define _printf_(a,b) __attribute__ ((format (printf, a, b))) #define _printf_(a,b) __attribute__ ((format (printf, a, b)))
#define _alloc_(...) __attribute__ ((alloc_size(__VA_ARGS__))) #define _alloc_(...) __attribute__ ((alloc_size(__VA_ARGS__)))
@@ -306,111 +305,10 @@ static inline unsigned long ALIGN_POWER2(unsigned long u) {
#define PTR_TO_SIZE(p) ((size_t) ((uintptr_t) (p))) #define PTR_TO_SIZE(p) ((size_t) ((uintptr_t) (p)))
#define SIZE_TO_PTR(u) ((void *) ((uintptr_t) (u))) #define SIZE_TO_PTR(u) ((void *) ((uintptr_t) (u)))
/* The following macros add 1 when converting things, since UID 0 is a
* valid UID, while the pointer NULL is special */
#define PTR_TO_UID(p) ((uid_t) (((uintptr_t) (p))-1))
#define UID_TO_PTR(u) ((void*) (((uintptr_t) (u))+1))
#define PTR_TO_GID(p) ((gid_t) (((uintptr_t) (p))-1))
#define GID_TO_PTR(u) ((void*) (((uintptr_t) (u))+1))
#define PTR_TO_PID(p) ((pid_t) ((uintptr_t) p))
#define PID_TO_PTR(p) ((void*) ((uintptr_t) p))
#define memzero(x,l) (memset((x), 0, (l)))
#define zero(x) (memzero(&(x), sizeof(x)))
#define CHAR_TO_STR(x) ((char[2]) { x, 0 }) #define CHAR_TO_STR(x) ((char[2]) { x, 0 })
#define char_array_0(x) x[sizeof(x)-1] = 0; #define char_array_0(x) x[sizeof(x)-1] = 0;
#define IOVEC_SET_STRING(i, s) \
do { \
struct iovec *_i = &(i); \
char *_s = (char *)(s); \
_i->iov_base = _s; \
_i->iov_len = strlen(_s); \
} while(false)
static inline size_t IOVEC_TOTAL_SIZE(const struct iovec *i, unsigned n) {
unsigned j;
size_t r = 0;
for (j = 0; j < n; j++)
r += i[j].iov_len;
return r;
}
static inline size_t IOVEC_INCREMENT(struct iovec *i, unsigned n, size_t k) {
unsigned j;
for (j = 0; j < n; j++) {
size_t sub;
if (_unlikely_(k <= 0))
break;
sub = MIN(i[j].iov_len, k);
i[j].iov_len -= sub;
i[j].iov_base = (uint8_t*) i[j].iov_base + sub;
k -= sub;
}
return k;
}
#define VA_FORMAT_ADVANCE(format, ap) \
do { \
int _argtypes[128]; \
size_t _i, _k; \
_k = parse_printf_format((format), ELEMENTSOF(_argtypes), _argtypes); \
assert(_k < ELEMENTSOF(_argtypes)); \
for (_i = 0; _i < _k; _i++) { \
if (_argtypes[_i] & PA_FLAG_PTR) { \
(void) va_arg(ap, void*); \
continue; \
} \
\
switch (_argtypes[_i]) { \
case PA_INT: \
case PA_INT|PA_FLAG_SHORT: \
case PA_CHAR: \
(void) va_arg(ap, int); \
break; \
case PA_INT|PA_FLAG_LONG: \
(void) va_arg(ap, long int); \
break; \
case PA_INT|PA_FLAG_LONG_LONG: \
(void) va_arg(ap, long long int); \
break; \
case PA_WCHAR: \
(void) va_arg(ap, wchar_t); \
break; \
case PA_WSTRING: \
case PA_STRING: \
case PA_POINTER: \
(void) va_arg(ap, void*); \
break; \
case PA_FLOAT: \
case PA_DOUBLE: \
(void) va_arg(ap, double); \
break; \
case PA_DOUBLE|PA_FLAG_LONG_DOUBLE: \
(void) va_arg(ap, long double); \
break; \
default: \
assert_not_reached("Unknown format string argument."); \
} \
} \
} while(false)
/* 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)
/* Returns the number of chars needed to format variables of the /* Returns the number of chars needed to format variables of the
* specified type as a decimal string. Adds in extra space for a * specified type as a decimal string. Adds in extra space for a
* negative '-' prefix (hence works correctly on signed * negative '-' prefix (hence works correctly on signed
@@ -421,6 +319,15 @@ do { \
sizeof(type) <= 4 ? 10 : \ sizeof(type) <= 4 ? 10 : \
sizeof(type) <= 8 ? 20 : sizeof(int[-2*(sizeof(type) > 8)]))) sizeof(type) <= 8 ? 20 : sizeof(int[-2*(sizeof(type) > 8)])))
#define DECIMAL_STR_WIDTH(x) \
({ \
typeof(x) _x_ = (x); \
unsigned ans = 1; \
while (_x_ /= 10) \
ans++; \
ans; \
})
#define SET_FLAG(v, flag, b) \ #define SET_FLAG(v, flag, b) \
(v) = (b) ? ((v) | (flag)) : ((v) & ~(flag)) (v) = (b) ? ((v) | (flag)) : ((v) & ~(flag))
@@ -438,21 +345,6 @@ do { \
_found; \ _found; \
}) })
/* Return a nulstr for a standard cascade of configuration directories,
* suitable to pass to conf_files_list_nulstr or config_parse_many. */
#define CONF_DIRS_NULSTR(n) \
"/etc/" n ".d\0" \
"/run/" n ".d\0" \
"/usr/local/lib/" n ".d\0" \
"/usr/lib/" n ".d\0" \
CONF_DIR_SPLIT_USR(n)
#ifdef HAVE_SPLIT_USR
#define CONF_DIR_SPLIT_USR(n) "/lib/" n ".d\0"
#else
#define CONF_DIR_SPLIT_USR(n)
#endif
/* Define C11 thread_local attribute even on older gcc compiler /* Define C11 thread_local attribute even on older gcc compiler
* version */ * version */
#ifndef thread_local #ifndef thread_local
@@ -477,10 +369,6 @@ do { \
#define noreturn __attribute__((noreturn)) #define noreturn __attribute__((noreturn))
#endif #endif
#endif #endif
#define UID_INVALID ((uid_t) -1)
#define GID_INVALID ((gid_t) -1)
#define MODE_INVALID ((mode_t) -1)
#endif /* NM_IGNORED */ #endif /* NM_IGNORED */
#define DEFINE_TRIVIAL_CLEANUP_FUNC(type, func) \ #define DEFINE_TRIVIAL_CLEANUP_FUNC(type, func) \
@@ -490,7 +378,4 @@ do { \
} \ } \
struct __useless_struct_to_allow_trailing_semicolon__ struct __useless_struct_to_allow_trailing_semicolon__
#define CMSG_FOREACH(cmsg, mh) \
for ((cmsg) = CMSG_FIRSTHDR(mh); (cmsg); (cmsg) = CMSG_NXTHDR((mh), (cmsg)))
#include "log.h" #include "log.h"

View File

@@ -22,8 +22,8 @@
#include "nm-sd-adapt.h" #include "nm-sd-adapt.h"
#include "mempool.h"
#include "macro.h" #include "macro.h"
#include "mempool.h"
#include "util.h" #include "util.h"
struct pool { struct pool {

View File

@@ -0,0 +1,534 @@
/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
/***
This file is part of systemd.
Copyright 2010 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 "nm-sd-adapt.h"
#include "alloc-util.h"
#if 0 /* NM_IGNORED */
#include "extract-word.h"
#endif /* NM_IGNORED */
#include "parse-util.h"
#include "string-util.h"
#include "util.h"
int parse_boolean(const char *v) {
assert(v);
if (streq(v, "1") || strcaseeq(v, "yes") || strcaseeq(v, "y") || strcaseeq(v, "true") || strcaseeq(v, "t") || strcaseeq(v, "on"))
return 1;
else if (streq(v, "0") || strcaseeq(v, "no") || strcaseeq(v, "n") || strcaseeq(v, "false") || strcaseeq(v, "f") || strcaseeq(v, "off"))
return 0;
return -EINVAL;
}
int parse_pid(const char *s, pid_t* ret_pid) {
unsigned long ul = 0;
pid_t pid;
int r;
assert(s);
assert(ret_pid);
r = safe_atolu(s, &ul);
if (r < 0)
return r;
pid = (pid_t) ul;
if ((unsigned long) pid != ul)
return -ERANGE;
if (pid <= 0)
return -ERANGE;
*ret_pid = pid;
return 0;
}
int parse_mode(const char *s, mode_t *ret) {
char *x;
long l;
assert(s);
assert(ret);
s += strspn(s, WHITESPACE);
if (s[0] == '-')
return -ERANGE;
errno = 0;
l = strtol(s, &x, 8);
if (errno != 0)
return -errno;
if (!x || x == s || *x)
return -EINVAL;
if (l < 0 || l > 07777)
return -ERANGE;
*ret = (mode_t) l;
return 0;
}
int parse_ifindex(const char *s, int *ret) {
int ifi, r;
r = safe_atoi(s, &ifi);
if (r < 0)
return r;
if (ifi <= 0)
return -EINVAL;
*ret = ifi;
return 0;
}
int parse_size(const char *t, uint64_t base, uint64_t *size) {
/* Soo, sometimes we want to parse IEC binary suffixes, and
* sometimes SI decimal suffixes. This function can parse
* both. Which one is the right way depends on the
* context. Wikipedia suggests that SI is customary for
* hardware metrics and network speeds, while IEC is
* customary for most data sizes used by software and volatile
* (RAM) memory. Hence be careful which one you pick!
*
* In either case we use just K, M, G as suffix, and not Ki,
* Mi, Gi or so (as IEC would suggest). That's because that's
* frickin' ugly. But this means you really need to make sure
* to document which base you are parsing when you use this
* call. */
struct table {
const char *suffix;
unsigned long long factor;
};
static const struct table iec[] = {
{ "E", 1024ULL*1024ULL*1024ULL*1024ULL*1024ULL*1024ULL },
{ "P", 1024ULL*1024ULL*1024ULL*1024ULL*1024ULL },
{ "T", 1024ULL*1024ULL*1024ULL*1024ULL },
{ "G", 1024ULL*1024ULL*1024ULL },
{ "M", 1024ULL*1024ULL },
{ "K", 1024ULL },
{ "B", 1ULL },
{ "", 1ULL },
};
static const struct table si[] = {
{ "E", 1000ULL*1000ULL*1000ULL*1000ULL*1000ULL*1000ULL },
{ "P", 1000ULL*1000ULL*1000ULL*1000ULL*1000ULL },
{ "T", 1000ULL*1000ULL*1000ULL*1000ULL },
{ "G", 1000ULL*1000ULL*1000ULL },
{ "M", 1000ULL*1000ULL },
{ "K", 1000ULL },
{ "B", 1ULL },
{ "", 1ULL },
};
const struct table *table;
const char *p;
unsigned long long r = 0;
unsigned n_entries, start_pos = 0;
assert(t);
assert(base == 1000 || base == 1024);
assert(size);
if (base == 1000) {
table = si;
n_entries = ELEMENTSOF(si);
} else {
table = iec;
n_entries = ELEMENTSOF(iec);
}
p = t;
do {
unsigned long long l, tmp;
double frac = 0;
char *e;
unsigned i;
p += strspn(p, WHITESPACE);
errno = 0;
l = strtoull(p, &e, 10);
if (errno != 0)
return -errno;
if (e == p)
return -EINVAL;
if (*p == '-')
return -ERANGE;
if (*e == '.') {
e++;
/* strtoull() itself would accept space/+/- */
if (*e >= '0' && *e <= '9') {
unsigned long long l2;
char *e2;
l2 = strtoull(e, &e2, 10);
if (errno != 0)
return -errno;
/* Ignore failure. E.g. 10.M is valid */
frac = l2;
for (; e < e2; e++)
frac /= 10;
}
}
e += strspn(e, WHITESPACE);
for (i = start_pos; i < n_entries; i++)
if (startswith(e, table[i].suffix))
break;
if (i >= n_entries)
return -EINVAL;
if (l + (frac > 0) > ULLONG_MAX / table[i].factor)
return -ERANGE;
tmp = l * table[i].factor + (unsigned long long) (frac * table[i].factor);
if (tmp > ULLONG_MAX - r)
return -ERANGE;
r += tmp;
if ((unsigned long long) (uint64_t) r != r)
return -ERANGE;
p = e + strlen(table[i].suffix);
start_pos = i + 1;
} while (*p);
*size = r;
return 0;
}
#if 0 /* NM_IGNORED */
int parse_range(const char *t, unsigned *lower, unsigned *upper) {
_cleanup_free_ char *word = NULL;
unsigned l, u;
int r;
assert(lower);
assert(upper);
/* Extract the lower bound. */
r = extract_first_word(&t, &word, "-", EXTRACT_DONT_COALESCE_SEPARATORS);
if (r < 0)
return r;
if (r == 0)
return -EINVAL;
r = safe_atou(word, &l);
if (r < 0)
return r;
/* Check for the upper bound and extract it if needed */
if (!t)
/* Single number with no dashes. */
u = l;
else if (!*t)
/* Trailing dash is an error. */
return -EINVAL;
else {
r = safe_atou(t, &u);
if (r < 0)
return r;
}
*lower = l;
*upper = u;
return 0;
}
#endif /* NM_IGNORED */
char *format_bytes(char *buf, size_t l, uint64_t t) {
unsigned i;
/* This only does IEC units so far */
static const struct {
const char *suffix;
uint64_t factor;
} table[] = {
{ "E", UINT64_C(1024)*UINT64_C(1024)*UINT64_C(1024)*UINT64_C(1024)*UINT64_C(1024)*UINT64_C(1024) },
{ "P", UINT64_C(1024)*UINT64_C(1024)*UINT64_C(1024)*UINT64_C(1024)*UINT64_C(1024) },
{ "T", UINT64_C(1024)*UINT64_C(1024)*UINT64_C(1024)*UINT64_C(1024) },
{ "G", UINT64_C(1024)*UINT64_C(1024)*UINT64_C(1024) },
{ "M", UINT64_C(1024)*UINT64_C(1024) },
{ "K", UINT64_C(1024) },
};
if (t == (uint64_t) -1)
return NULL;
for (i = 0; i < ELEMENTSOF(table); i++) {
if (t >= table[i].factor) {
snprintf(buf, l,
"%" PRIu64 ".%" PRIu64 "%s",
t / table[i].factor,
((t*UINT64_C(10)) / table[i].factor) % UINT64_C(10),
table[i].suffix);
goto finish;
}
}
snprintf(buf, l, "%" PRIu64 "B", t);
finish:
buf[l-1] = 0;
return buf;
}
int safe_atou(const char *s, unsigned *ret_u) {
char *x = NULL;
unsigned long l;
assert(s);
assert(ret_u);
/* strtoul() is happy to parse negative values, and silently
* converts them to unsigned values without generating an
* error. We want a clean error, hence let's look for the "-"
* prefix on our own, and generate an error. But let's do so
* only after strtoul() validated that the string is clean
* otherwise, so that we return EINVAL preferably over
* ERANGE. */
s += strspn(s, WHITESPACE);
errno = 0;
l = strtoul(s, &x, 0);
if (errno != 0)
return -errno;
if (!x || x == s || *x)
return -EINVAL;
if (s[0] == '-')
return -ERANGE;
if ((unsigned long) (unsigned) l != l)
return -ERANGE;
*ret_u = (unsigned) l;
return 0;
}
int safe_atoi(const char *s, int *ret_i) {
char *x = NULL;
long l;
assert(s);
assert(ret_i);
errno = 0;
l = strtol(s, &x, 0);
if (errno != 0)
return -errno;
if (!x || x == s || *x)
return -EINVAL;
if ((long) (int) l != l)
return -ERANGE;
*ret_i = (int) l;
return 0;
}
int safe_atollu(const char *s, long long unsigned *ret_llu) {
char *x = NULL;
unsigned long long l;
assert(s);
assert(ret_llu);
s += strspn(s, WHITESPACE);
errno = 0;
l = strtoull(s, &x, 0);
if (errno != 0)
return -errno;
if (!x || x == s || *x)
return -EINVAL;
if (*s == '-')
return -ERANGE;
*ret_llu = l;
return 0;
}
int safe_atolli(const char *s, long long int *ret_lli) {
char *x = NULL;
long long l;
assert(s);
assert(ret_lli);
errno = 0;
l = strtoll(s, &x, 0);
if (errno != 0)
return -errno;
if (!x || x == s || *x)
return -EINVAL;
*ret_lli = l;
return 0;
}
int safe_atou8(const char *s, uint8_t *ret) {
char *x = NULL;
unsigned long l;
assert(s);
assert(ret);
s += strspn(s, WHITESPACE);
errno = 0;
l = strtoul(s, &x, 0);
if (errno != 0)
return -errno;
if (!x || x == s || *x)
return -EINVAL;
if (s[0] == '-')
return -ERANGE;
if ((unsigned long) (uint8_t) l != l)
return -ERANGE;
*ret = (uint8_t) l;
return 0;
}
int safe_atou16(const char *s, uint16_t *ret) {
char *x = NULL;
unsigned long l;
assert(s);
assert(ret);
s += strspn(s, WHITESPACE);
errno = 0;
l = strtoul(s, &x, 0);
if (errno != 0)
return -errno;
if (!x || x == s || *x)
return -EINVAL;
if (s[0] == '-')
return -ERANGE;
if ((unsigned long) (uint16_t) l != l)
return -ERANGE;
*ret = (uint16_t) l;
return 0;
}
int safe_atoi16(const char *s, int16_t *ret) {
char *x = NULL;
long l;
assert(s);
assert(ret);
errno = 0;
l = strtol(s, &x, 0);
if (errno != 0)
return -errno;
if (!x || x == s || *x)
return -EINVAL;
if ((long) (int16_t) l != l)
return -ERANGE;
*ret = (int16_t) l;
return 0;
}
int safe_atod(const char *s, double *ret_d) {
char *x = NULL;
double d = 0;
locale_t loc;
assert(s);
assert(ret_d);
loc = newlocale(LC_NUMERIC_MASK, "C", (locale_t) 0);
if (loc == (locale_t) 0)
return -errno;
errno = 0;
d = strtod_l(s, &x, loc);
if (errno != 0) {
freelocale(loc);
return -errno;
}
if (!x || x == s || *x) {
freelocale(loc);
return -EINVAL;
}
freelocale(loc);
*ret_d = (double) d;
return 0;
}
int parse_fractional_part_u(const char **p, size_t digits, unsigned *res) {
size_t i;
unsigned val = 0;
const char *s;
s = *p;
/* accept any number of digits, strtoull is limted to 19 */
for(i=0; i < digits; i++,s++) {
if (*s < '0' || *s > '9') {
if (i == 0)
return -EINVAL;
/* too few digits, pad with 0 */
for (; i < digits; i++)
val *= 10;
break;
}
val *= 10;
val += *s - '0';
}
/* maybe round up */
if (*s >= '5' && *s <= '9')
val++;
s += strspn(s, DIGITS);
*p = s;
*res = val;
return 0;
}

View File

@@ -0,0 +1,96 @@
/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
#pragma once
/***
This file is part of systemd.
Copyright 2010 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 "nm-sd-adapt.h"
#include <inttypes.h>
#include <sys/types.h>
#include "macro.h"
#define MODE_INVALID ((mode_t) -1)
int parse_boolean(const char *v) _pure_;
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_size(const char *t, uint64_t base, uint64_t *size);
int parse_range(const char *t, unsigned *lower, unsigned *upper);
#define FORMAT_BYTES_MAX 8
char *format_bytes(char *buf, size_t l, uint64_t t);
int safe_atou(const char *s, unsigned *ret_u);
int safe_atoi(const char *s, int *ret_i);
int safe_atollu(const char *s, unsigned long long *ret_u);
int safe_atolli(const char *s, long long int *ret_i);
int safe_atou8(const char *s, uint8_t *ret);
int safe_atou16(const char *s, uint16_t *ret);
int safe_atoi16(const char *s, int16_t *ret);
static inline int safe_atou32(const char *s, uint32_t *ret_u) {
assert_cc(sizeof(uint32_t) == sizeof(unsigned));
return safe_atou(s, (unsigned*) ret_u);
}
static inline int safe_atoi32(const char *s, int32_t *ret_i) {
assert_cc(sizeof(int32_t) == sizeof(int));
return safe_atoi(s, (int*) ret_i);
}
static inline int safe_atou64(const char *s, uint64_t *ret_u) {
assert_cc(sizeof(uint64_t) == sizeof(unsigned long long));
return safe_atollu(s, (unsigned long long*) ret_u);
}
static inline int safe_atoi64(const char *s, int64_t *ret_i) {
assert_cc(sizeof(int64_t) == sizeof(long long int));
return safe_atolli(s, (long long int*) ret_i);
}
#if LONG_MAX == INT_MAX
static inline int safe_atolu(const char *s, unsigned long *ret_u) {
assert_cc(sizeof(unsigned long) == sizeof(unsigned));
return safe_atou(s, (unsigned*) ret_u);
}
static inline int safe_atoli(const char *s, long int *ret_u) {
assert_cc(sizeof(long int) == sizeof(int));
return safe_atoi(s, (int*) ret_u);
}
#else
static inline int safe_atolu(const char *s, unsigned long *ret_u) {
assert_cc(sizeof(unsigned long) == sizeof(unsigned long long));
return safe_atollu(s, (unsigned long long*) ret_u);
}
static inline int safe_atoli(const char *s, long int *ret_u) {
assert_cc(sizeof(long int) == sizeof(long long int));
return safe_atolli(s, (long long int*) ret_u);
}
#endif
int safe_atod(const char *s, double *ret_d);
int parse_fractional_part_u(const char **s, size_t digits, unsigned *res);

View File

@@ -21,25 +21,41 @@
#include "nm-sd-adapt.h" #include "nm-sd-adapt.h"
#if 0 /* NM_IGNORED */
#include <string.h>
#include <unistd.h>
#include <errno.h> #include <errno.h>
#include <stdlib.h>
#include <stdio.h>
#include <fcntl.h> #include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/statvfs.h> #include <sys/statvfs.h>
#include <unistd.h>
#include "macro.h" /* When we include libgen.h because we need dirname() we immediately
#include "util.h" * undefine basename() since libgen.h defines it as a macro to the
* POSIX version which is really broken. We prefer GNU basename(). */
#include <libgen.h>
#undef basename
#include "alloc-util.h"
#if 0 /* NM_IGNORED */
#include "fd-util.h"
#include "fileio.h"
#include "fs-util.h"
#include "log.h" #include "log.h"
#include "strv.h" #include "macro.h"
#include "missing.h"
#include "parse-util.h"
#endif /* NM_IGNORED */ #endif /* NM_IGNORED */
#include "path-util.h" #include "path-util.h"
#if 0 /* NM_IGNORED */ #if 0 /* NM_IGNORED */
#include "missing.h" #include "stat-util.h"
#include "fileio.h" #endif /* NM_IGNORED */
#include "string-util.h"
#if 0 /* NM_IGNORED */
#include "strv.h"
#endif /* NM_IGNORED */
#include "util.h"
#if 0 /* NM_IGNORED */
bool path_is_absolute(const char *p) { bool path_is_absolute(const char *p) {
return p[0] == '/'; return p[0] == '/';
} }
@@ -48,61 +64,25 @@ bool is_path(const char *p) {
return !!strchr(p, '/'); return !!strchr(p, '/');
} }
int path_get_parent(const char *path, char **_r) { int path_split_and_make_absolute(const char *p, char ***ret) {
const char *e, *a = NULL, *b = NULL, *p;
char *r;
bool slash = false;
assert(path);
assert(_r);
if (!*path)
return -EINVAL;
for (e = path; *e; e++) {
if (!slash && *e == '/') {
a = b;
b = e;
slash = true;
} else if (slash && *e != '/')
slash = false;
}
if (*(e-1) == '/')
p = a;
else
p = b;
if (!p)
return -EINVAL;
if (p == path)
r = strdup("/");
else
r = strndup(path, p-path);
if (!r)
return -ENOMEM;
*_r = r;
return 0;
}
char **path_split_and_make_absolute(const char *p) {
char **l; char **l;
int r;
assert(p); assert(p);
assert(ret);
l = strv_split(p, ":"); l = strv_split(p, ":");
if (!l) if (!l)
return NULL; return -ENOMEM;
if (!path_strv_make_absolute_cwd(l)) { r = path_strv_make_absolute_cwd(l);
if (r < 0) {
strv_free(l); strv_free(l);
return NULL; return r;
} }
return l; *ret = l;
return r;
} }
char *path_make_absolute(const char *p, const char *prefix) { char *path_make_absolute(const char *p, const char *prefix) {
@@ -117,22 +97,31 @@ char *path_make_absolute(const char *p, const char *prefix) {
return strjoin(prefix, "/", p, NULL); return strjoin(prefix, "/", p, NULL);
} }
char *path_make_absolute_cwd(const char *p) { int path_make_absolute_cwd(const char *p, char **ret) {
_cleanup_free_ char *cwd = NULL; char *c;
assert(p); assert(p);
assert(ret);
/* Similar to path_make_absolute(), but prefixes with the /* Similar to path_make_absolute(), but prefixes with the
* current working directory. */ * current working directory. */
if (path_is_absolute(p)) if (path_is_absolute(p))
return strdup(p); c = strdup(p);
else {
_cleanup_free_ char *cwd = NULL;
cwd = get_current_dir_name(); cwd = get_current_dir_name();
if (!cwd) if (!cwd)
return NULL; return -errno;
return strjoin(cwd, "/", p, NULL); c = strjoin(cwd, "/", p, NULL);
}
if (!c)
return -ENOMEM;
*ret = c;
return 0;
} }
int path_make_relative(const char *from_dir, const char *to_path, char **_r) { int path_make_relative(const char *from_dir, const char *to_path, char **_r) {
@@ -220,8 +209,9 @@ int path_make_relative(const char *from_dir, const char *to_path, char **_r) {
return 0; return 0;
} }
char **path_strv_make_absolute_cwd(char **l) { int path_strv_make_absolute_cwd(char **l) {
char **s; char **s;
int r;
/* Goes through every item in the string list and makes it /* Goes through every item in the string list and makes it
* absolute. This works in place and won't rollback any * absolute. This works in place and won't rollback any
@@ -230,15 +220,15 @@ char **path_strv_make_absolute_cwd(char **l) {
STRV_FOREACH(s, l) { STRV_FOREACH(s, l) {
char *t; char *t;
t = path_make_absolute_cwd(*s); r = path_make_absolute_cwd(*s, &t);
if (!t) if (r < 0)
return NULL; return r;
free(*s); free(*s);
*s = t; *s = t;
} }
return l; return 0;
} }
char **path_strv_resolve(char **l, const char *prefix) { char **path_strv_resolve(char **l, const char *prefix) {
@@ -418,7 +408,7 @@ int path_compare(const char *a, const char *b) {
* Which one is sorted before the other does not really matter. * Which one is sorted before the other does not really matter.
* Here a relative path is ordered before an absolute path. */ * Here a relative path is ordered before an absolute path. */
d = (a[0] == '/') - (b[0] == '/'); d = (a[0] == '/') - (b[0] == '/');
if (d) if (d != 0)
return d; return d;
for (;;) { for (;;) {
@@ -441,12 +431,12 @@ int path_compare(const char *a, const char *b) {
/* Alphabetical sort: "/foo/aaa" before "/foo/b" */ /* Alphabetical sort: "/foo/aaa" before "/foo/b" */
d = memcmp(a, b, MIN(j, k)); d = memcmp(a, b, MIN(j, k));
if (d) if (d != 0)
return (d > 0) - (d < 0); /* sign of d */ return (d > 0) - (d < 0); /* sign of d */
/* Sort "/foo/a" before "/foo/aaa" */ /* Sort "/foo/a" before "/foo/aaa" */
d = (j > k) - (j < k); /* sign of (j - k) */ d = (j > k) - (j < k); /* sign of (j - k) */
if (d) if (d != 0)
return d; return d;
a += j; a += j;
@@ -478,294 +468,66 @@ char* path_join(const char *root, const char *path, const char *rest) {
NULL); NULL);
} }
static int fd_fdinfo_mnt_id(int fd, const char *filename, int flags, int *mnt_id) { int find_binary(const char *name, char **ret) {
char path[strlen("/proc/self/fdinfo/") + DECIMAL_STR_MAX(int)]; int last_error, r;
_cleanup_free_ char *fdinfo = NULL; const char *p;
_cleanup_close_ int subfd = -1;
char *p;
int r;
if ((flags & AT_EMPTY_PATH) && isempty(filename))
xsprintf(path, "/proc/self/fdinfo/%i", fd);
else {
subfd = openat(fd, filename, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_PATH);
if (subfd < 0)
return -errno;
xsprintf(path, "/proc/self/fdinfo/%i", subfd);
}
r = read_full_file(path, &fdinfo, NULL);
if (r == -ENOENT) /* The fdinfo directory is a relatively new addition */
return -EOPNOTSUPP;
if (r < 0)
return -errno;
p = startswith(fdinfo, "mnt_id:");
if (!p) {
p = strstr(fdinfo, "\nmnt_id:");
if (!p) /* The mnt_id field is a relatively new addition */
return -EOPNOTSUPP;
p += 8;
}
p += strspn(p, WHITESPACE);
p[strcspn(p, WHITESPACE)] = 0;
return safe_atoi(p, mnt_id);
}
int fd_is_mount_point(int fd, const char *filename, int flags) {
union file_handle_union h = FILE_HANDLE_INIT, h_parent = FILE_HANDLE_INIT;
int mount_id = -1, mount_id_parent = -1;
bool nosupp = false, check_st_dev = true;
struct stat a, b;
int r;
assert(fd >= 0);
assert(filename);
/* First we will try the name_to_handle_at() syscall, which
* tells us the mount id and an opaque file "handle". It is
* not supported everywhere though (kernel compile-time
* option, not all file systems are hooked up). If it works
* the mount id is usually good enough to tell us whether
* something is a mount point.
*
* If that didn't work we will try to read the mount id from
* /proc/self/fdinfo/<fd>. This is almost as good as
* name_to_handle_at(), however, does not return the
* opaque file handle. The opaque file handle is pretty useful
* to detect the root directory, which we should always
* consider a mount point. Hence we use this only as
* fallback. Exporting the mnt_id in fdinfo is a pretty recent
* kernel addition.
*
* As last fallback we do traditional fstat() based st_dev
* comparisons. This is how things were traditionally done,
* but unionfs breaks breaks this since it exposes file
* systems with a variety of st_dev reported. Also, btrfs
* subvolumes have different st_dev, even though they aren't
* real mounts of their own. */
r = name_to_handle_at(fd, filename, &h.handle, &mount_id, flags);
if (r < 0) {
if (errno == ENOSYS)
/* This kernel does not support name_to_handle_at()
* fall back to simpler logic. */
goto fallback_fdinfo;
else if (errno == EOPNOTSUPP)
/* This kernel or file system does not support
* name_to_handle_at(), hence let's see if the
* upper fs supports it (in which case it is a
* mount point), otherwise fallback to the
* traditional stat() logic */
nosupp = true;
else
return -errno;
}
r = name_to_handle_at(fd, "", &h_parent.handle, &mount_id_parent, AT_EMPTY_PATH);
if (r < 0) {
if (errno == EOPNOTSUPP) {
if (nosupp)
/* Neither parent nor child do name_to_handle_at()?
We have no choice but to fall back. */
goto fallback_fdinfo;
else
/* The parent can't do name_to_handle_at() but the
* directory we are interested in can?
* If so, it must be a mount point. */
return 1;
} else
return -errno;
}
/* The parent can do name_to_handle_at() but the
* directory we are interested in can't? If so, it
* must be a mount point. */
if (nosupp)
return 1;
/* If the file handle for the directory we are
* interested in and its parent are identical, we
* assume this is the root directory, which is a mount
* point. */
if (h.handle.handle_bytes == h_parent.handle.handle_bytes &&
h.handle.handle_type == h_parent.handle.handle_type &&
memcmp(h.handle.f_handle, h_parent.handle.f_handle, h.handle.handle_bytes) == 0)
return 1;
return mount_id != mount_id_parent;
fallback_fdinfo:
r = fd_fdinfo_mnt_id(fd, filename, flags, &mount_id);
if (r == -EOPNOTSUPP)
goto fallback_fstat;
if (r < 0)
return r;
r = fd_fdinfo_mnt_id(fd, "", AT_EMPTY_PATH, &mount_id_parent);
if (r < 0)
return r;
if (mount_id != mount_id_parent)
return 1;
/* Hmm, so, the mount ids are the same. This leaves one
* special case though for the root file system. For that,
* let's see if the parent directory has the same inode as we
* are interested in. Hence, let's also do fstat() checks now,
* too, but avoid the st_dev comparisons, since they aren't
* that useful on unionfs mounts. */
check_st_dev = false;
fallback_fstat:
/* yay for fstatat() taking a different set of flags than the other
* _at() above */
if (flags & AT_SYMLINK_FOLLOW)
flags &= ~AT_SYMLINK_FOLLOW;
else
flags |= AT_SYMLINK_NOFOLLOW;
if (fstatat(fd, filename, &a, flags) < 0)
return -errno;
if (fstatat(fd, "", &b, AT_EMPTY_PATH) < 0)
return -errno;
/* A directory with same device and inode as its parent? Must
* be the root directory */
if (a.st_dev == b.st_dev &&
a.st_ino == b.st_ino)
return 1;
return check_st_dev && (a.st_dev != b.st_dev);
}
/* flags can be AT_SYMLINK_FOLLOW or 0 */
int path_is_mount_point(const char *t, int flags) {
_cleanup_close_ int fd = -1;
_cleanup_free_ char *canonical = NULL, *parent = NULL;
int r;
assert(t);
if (path_equal(t, "/"))
return 1;
/* we need to resolve symlinks manually, we can't just rely on
* fd_is_mount_point() to do that for us; if we have a structure like
* /bin -> /usr/bin/ and /usr is a mount point, then the parent that we
* look at needs to be /usr, not /. */
if (flags & AT_SYMLINK_FOLLOW) {
canonical = canonicalize_file_name(t);
if (!canonical)
return -errno;
t = canonical;
}
r = path_get_parent(t, &parent);
if (r < 0)
return r;
fd = openat(AT_FDCWD, parent, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC|O_PATH);
if (fd < 0)
return -errno;
return fd_is_mount_point(fd, basename(t), flags);
}
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) {
char *p;
int r;
/* We use /usr/lib/os-release as flag file if something is an OS */
p = strjoina(path, "/usr/lib/os-release");
r = access(p, F_OK);
if (r >= 0)
return 1;
/* Also check for the old location in /etc, just in case. */
p = strjoina(path, "/etc/os-release");
r = access(p, F_OK);
return r >= 0;
}
int find_binary(const char *name, bool local, char **filename) {
assert(name); assert(name);
if (is_path(name)) { if (is_path(name)) {
if (local && access(name, X_OK) < 0) if (access(name, X_OK) < 0)
return -errno; return -errno;
if (filename) { if (ret) {
char *p; r = path_make_absolute_cwd(name, ret);
if (r < 0)
p = path_make_absolute_cwd(name); return r;
if (!p)
return -ENOMEM;
*filename = p;
} }
return 0; return 0;
} else { }
const char *path;
const char *word, *state;
size_t l;
/** /**
* Plain getenv, not secure_getenv, because we want * Plain getenv, not secure_getenv, because we want
* to actually allow the user to pick the binary. * to actually allow the user to pick the binary.
*/ */
path = getenv("PATH"); p = getenv("PATH");
if (!path) if (!p)
path = DEFAULT_PATH; p = DEFAULT_PATH;
FOREACH_WORD_SEPARATOR(word, l, path, ":", state) { last_error = -ENOENT;
_cleanup_free_ char *p = NULL;
if (asprintf(&p, "%.*s/%s", (int) l, word, name) < 0) for (;;) {
return -ENOMEM; _cleanup_free_ char *j = NULL, *element = NULL;
if (access(p, X_OK) < 0) r = extract_first_word(&p, &element, ":", EXTRACT_RELAX|EXTRACT_DONT_COALESCE_SEPARATORS);
if (r < 0)
return r;
if (r == 0)
break;
if (!path_is_absolute(element))
continue; continue;
if (filename) { j = strjoin(element, "/", name, NULL);
*filename = path_kill_slashes(p); if (!j)
p = NULL; return -ENOMEM;
if (access(j, X_OK) >= 0) {
/* Found it! */
if (ret) {
*ret = path_kill_slashes(j);
j = NULL;
} }
return 0; return 0;
} }
return -ENOENT; last_error = -errno;
} }
return last_error;
} }
bool paths_check_timestamp(const char* const* paths, usec_t *timestamp, bool update) { bool paths_check_timestamp(const char* const* paths, usec_t *timestamp, bool update) {
@@ -803,14 +565,13 @@ bool paths_check_timestamp(const char* const* paths, usec_t *timestamp, bool upd
return changed; return changed;
} }
int fsck_exists(const char *fstype) { static int binary_is_good(const char *binary) {
_cleanup_free_ char *p = NULL, *d = NULL; _cleanup_free_ char *p = NULL, *d = NULL;
const char *checker;
int r; int r;
checker = strjoina("fsck.", fstype); r = find_binary(binary, &p);
if (r == -ENOENT)
r = find_binary(checker, true, &p); return 0;
if (r < 0) if (r < 0)
return r; return r;
@@ -818,13 +579,39 @@ int fsck_exists(const char *fstype) {
* fsck */ * fsck */
r = readlink_malloc(p, &d); r = readlink_malloc(p, &d);
if (r >= 0 && if (r == -EINVAL) /* not a symlink */
(path_equal(d, "/bin/true") || return 1;
path_equal(d, "/usr/bin/true") || if (r < 0)
path_equal(d, "/dev/null"))) return r;
return -ENOENT;
return 0; return !path_equal(d, "true") &&
!path_equal(d, "/bin/true") &&
!path_equal(d, "/usr/bin/true") &&
!path_equal(d, "/dev/null");
}
int fsck_exists(const char *fstype) {
const char *checker;
assert(fstype);
if (streq(fstype, "auto"))
return -EINVAL;
checker = strjoina("fsck.", fstype);
return binary_is_good(checker);
}
int mkfs_exists(const char *fstype) {
const char *mkfs;
assert(fstype);
if (streq(fstype, "auto"))
return -EINVAL;
mkfs = strjoina("mkfs.", fstype);
return binary_is_good(mkfs);
} }
char *prefix_root(const char *root, const char *path) { char *prefix_root(const char *root, const char *path) {
@@ -860,4 +647,169 @@ char *prefix_root(const char *root, const char *path) {
strcpy(p, path); strcpy(p, path);
return n; return n;
} }
int parse_path_argument_and_warn(const char *path, bool suppress_root, char **arg) {
char *p;
int r;
/*
* This function is intended to be used in command line
* parsers, to handle paths that are passed in. It makes the
* path absolute, and reduces it to NULL if omitted or
* root (the latter optionally).
*
* NOTE THAT THIS WILL FREE THE PREVIOUS ARGUMENT POINTER ON
* SUCCESS! Hence, do not pass in uninitialized pointers.
*/
if (isempty(path)) {
*arg = mfree(*arg);
return 0;
}
r = path_make_absolute_cwd(path, &p);
if (r < 0)
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, "/"))
p = mfree(p);
free(*arg);
*arg = p;
return 0;
}
char* dirname_malloc(const char *path) {
char *d, *dir, *dir2;
assert(path);
d = strdup(path);
if (!d)
return NULL;
dir = dirname(d);
assert(dir);
if (dir == d)
return d;
dir2 = strdup(dir);
free(d);
return dir2;
}
#endif /* NM_IGNORED */
bool filename_is_valid(const char *p) {
const char *e;
if (isempty(p))
return false;
if (streq(p, "."))
return false;
if (streq(p, ".."))
return false;
e = strchrnul(p, '/');
if (*e != 0)
return false;
if (e - p > FILENAME_MAX)
return false;
return true;
}
#if 0 /* NM_IGNORED */
bool path_is_safe(const char *p) {
if (isempty(p))
return false;
if (streq(p, "..") || startswith(p, "../") || endswith(p, "/..") || strstr(p, "/../"))
return false;
if (strlen(p)+1 > PATH_MAX)
return false;
/* The following two checks are not really dangerous, but hey, they still are confusing */
if (streq(p, ".") || startswith(p, "./") || endswith(p, "/.") || strstr(p, "/./"))
return false;
if (strstr(p, "//"))
return false;
return true;
}
char *file_in_same_dir(const char *path, const char *filename) {
char *e, *ret;
size_t k;
assert(path);
assert(filename);
/* This removes the last component of path and appends
* filename, unless the latter is absolute anyway or the
* former isn't */
if (path_is_absolute(filename))
return strdup(filename);
e = strrchr(path, '/');
if (!e)
return strdup(filename);
k = strlen(filename);
ret = new(char, (e + 1 - path) + k + 1);
if (!ret)
return NULL;
memcpy(mempcpy(ret, path, e + 1 - path), filename, k + 1);
return ret;
}
bool hidden_file_allow_backup(const char *filename) {
assert(filename);
return
filename[0] == '.' ||
streq(filename, "lost+found") ||
streq(filename, "aquota.user") ||
streq(filename, "aquota.group") ||
endswith(filename, ".rpmnew") ||
endswith(filename, ".rpmsave") ||
endswith(filename, ".rpmorig") ||
endswith(filename, ".dpkg-old") ||
endswith(filename, ".dpkg-new") ||
endswith(filename, ".dpkg-tmp") ||
endswith(filename, ".dpkg-dist") ||
endswith(filename, ".dpkg-bak") ||
endswith(filename, ".dpkg-backup") ||
endswith(filename, ".dpkg-remove") ||
endswith(filename, ".swp");
}
bool hidden_file(const char *filename) {
assert(filename);
if (endswith(filename, "~"))
return true;
return hidden_file_allow_backup(filename);
}
bool is_device_path(const char *path) {
/* Returns true on paths that refer to a device, either in
* sysfs or in /dev */
return
path_startswith(path, "/dev/") ||
path_startswith(path, "/sys/");
}
#endif /* NM_IGNORED */ #endif /* NM_IGNORED */

View File

@@ -38,11 +38,10 @@
#endif #endif
bool is_path(const char *p) _pure_; bool is_path(const char *p) _pure_;
char** path_split_and_make_absolute(const char *p); int path_split_and_make_absolute(const char *p, char ***ret);
int path_get_parent(const char *path, char **parent);
bool path_is_absolute(const char *p) _pure_; bool path_is_absolute(const char *p) _pure_;
char* path_make_absolute(const char *p, const char *prefix); char* path_make_absolute(const char *p, const char *prefix);
char* path_make_absolute_cwd(const char *p); int path_make_absolute_cwd(const char *p, char **ret);
int path_make_relative(const char *from_dir, const char *to_path, char **_r); int path_make_relative(const char *from_dir, const char *to_path, char **_r);
char* path_kill_slashes(char *path); char* path_kill_slashes(char *path);
char* path_startswith(const char *path, const char *prefix) _pure_; char* path_startswith(const char *path, const char *prefix) _pure_;
@@ -51,20 +50,16 @@ bool path_equal(const char *a, const char *b) _pure_;
bool path_equal_or_files_same(const char *a, const char *b); bool path_equal_or_files_same(const char *a, const char *b);
char* path_join(const char *root, const char *path, const char *rest); char* path_join(const char *root, const char *path, const char *rest);
char** path_strv_make_absolute_cwd(char **l); int path_strv_make_absolute_cwd(char **l);
char** path_strv_resolve(char **l, const char *prefix); char** path_strv_resolve(char **l, const char *prefix);
char** path_strv_resolve_uniq(char **l, const char *prefix); char** path_strv_resolve_uniq(char **l, const char *prefix);
int fd_is_mount_point(int fd, const char *filename, int flags); int find_binary(const char *name, char **filename);
int path_is_mount_point(const char *path, int flags);
int path_is_read_only_fs(const char *path);
int path_is_os_tree(const char *path);
int find_binary(const char *name, bool local, char **filename);
bool paths_check_timestamp(const char* const* paths, usec_t *paths_ts_usec, bool update); bool paths_check_timestamp(const char* const* paths, usec_t *paths_ts_usec, bool update);
int fsck_exists(const char *fstype); int fsck_exists(const char *fstype);
int mkfs_exists(const char *fstype);
/* Iterates through the path prefixes of the specified path, going up /* Iterates through the path prefixes of the specified path, going up
* the tree, to root. Also returns "" (and not "/"!) for the root * the tree, to root. Also returns "" (and not "/"!) for the root
@@ -102,3 +97,17 @@ char *prefix_root(const char *root, const char *path);
} \ } \
_ret; \ _ret; \
}) })
int parse_path_argument_and_warn(const char *path, bool suppress_root, char **arg);
char* dirname_malloc(const char *path);
bool filename_is_valid(const char *p) _pure_;
bool path_is_safe(const char *p) _pure_;
char *file_in_same_dir(const char *path, const char *filename);
bool hidden_file_allow_backup(const char *filename);
bool hidden_file(const char *filename) _pure_;
bool is_device_path(const char *path);

View File

@@ -31,8 +31,9 @@
#include "nm-sd-adapt.h" #include "nm-sd-adapt.h"
#include "util.h" #include "alloc-util.h"
#include "prioq.h" #include "prioq.h"
#include "util.h"
struct prioq_item { struct prioq_item {
void *data; void *data;

View File

@@ -19,22 +19,24 @@
#include "nm-sd-adapt.h" #include "nm-sd-adapt.h"
#include <stdint.h>
#include <errno.h> #include <errno.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h> #include <fcntl.h>
#include <time.h> #include <linux/random.h>
#include <stdint.h>
#ifdef HAVE_SYS_AUXV_H #ifdef HAVE_SYS_AUXV_H
#include <sys/auxv.h> #include <sys/auxv.h>
#endif #endif
#include <linux/random.h> #include <sys/stat.h>
#include <sys/types.h>
#include <time.h>
#include "random-util.h" #include "fd-util.h"
#include "time-util.h" #include "io-util.h"
#if 0 /* NM_IGNORED */ #if 0 /* NM_IGNORED */
#include "missing.h" #include "missing.h"
#endif #endif
#include "random-util.h"
#include "time-util.h"
#include "util.h" #include "util.h"
int dev_urandom(void *p, size_t n) { int dev_urandom(void *p, size_t n) {

View File

@@ -19,9 +19,9 @@
#include "nm-sd-adapt.h" #include "nm-sd-adapt.h"
#include "sparse-endian.h"
#include "siphash24.h" #include "siphash24.h"
#include "sparse-endian.h"
#include "unaligned.h"
#include "util.h" #include "util.h"
static inline uint64_t rotate_left(uint64_t x, uint8_t b) { static inline uint64_t rotate_left(uint64_t x, uint8_t b) {
@@ -55,37 +55,40 @@ void siphash24_init(struct siphash *state, const uint8_t k[16]) {
assert(state); assert(state);
assert(k); assert(k);
k0 = le64toh(*(le64_t*) k); k0 = unaligned_read_le64(k);
k1 = le64toh(*(le64_t*) (k + 8)); k1 = unaligned_read_le64(k + 8);
*state = (struct siphash) {
/* "somepseudorandomlygeneratedbytes" */ /* "somepseudorandomlygeneratedbytes" */
state->v0 = 0x736f6d6570736575ULL ^ k0; .v0 = 0x736f6d6570736575ULL ^ k0,
state->v1 = 0x646f72616e646f6dULL ^ k1; .v1 = 0x646f72616e646f6dULL ^ k1,
state->v2 = 0x6c7967656e657261ULL ^ k0; .v2 = 0x6c7967656e657261ULL ^ k0,
state->v3 = 0x7465646279746573ULL ^ k1; .v3 = 0x7465646279746573ULL ^ k1,
state->padding = 0; .padding = 0,
state->inlen = 0; .inlen = 0,
};
} }
void siphash24_compress(const void *_in, size_t inlen, struct siphash *state) { void siphash24_compress(const void *_in, size_t inlen, struct siphash *state) {
uint64_t m;
const uint8_t *in = _in; const uint8_t *in = _in;
const uint8_t *end = in + inlen; const uint8_t *end = in + inlen;
unsigned left = state->inlen & 7; size_t left = state->inlen & 7;
uint64_t m;
assert(in); assert(in);
assert(state); assert(state);
/* update total length */ /* Update total length */
state->inlen += inlen; state->inlen += inlen;
/* if padding exists, fill it out */ /* If padding exists, fill it out */
if (left > 0) { if (left > 0) {
for ( ; in < end && left < 8; in ++, left ++) for ( ; in < end && left < 8; in ++, left ++)
state->padding |= ((uint64_t) *in) << (left * 8); state->padding |= ((uint64_t) *in) << (left * 8);
if (in == end && left < 8) if (in == end && left < 8)
/* we did not have enough input to fill out the padding completely */ /* We did not have enough input to fill out the padding completely */
return; return;
#ifdef DEBUG #ifdef DEBUG
@@ -95,6 +98,7 @@ void siphash24_compress(const void *_in, size_t inlen, struct siphash *state) {
printf("(%3zu) v3 %08x %08x\n", state->inlen, (uint32_t) (state->v3 >> 32), (uint32_t) state->v3); printf("(%3zu) v3 %08x %08x\n", state->inlen, (uint32_t) (state->v3 >> 32), (uint32_t) state->v3);
printf("(%3zu) compress padding %08x %08x\n", state->inlen, (uint32_t) (state->padding >> 32), (uint32_t)state->padding); printf("(%3zu) compress padding %08x %08x\n", state->inlen, (uint32_t) (state->padding >> 32), (uint32_t)state->padding);
#endif #endif
state->v3 ^= state->padding; state->v3 ^= state->padding;
sipround(state); sipround(state);
sipround(state); sipround(state);
@@ -106,7 +110,7 @@ void siphash24_compress(const void *_in, size_t inlen, struct siphash *state) {
end -= (state->inlen % sizeof(uint64_t)); end -= (state->inlen % sizeof(uint64_t));
for ( ; in < end; in += 8) { for ( ; in < end; in += 8) {
m = le64toh(*(le64_t*) in); m = unaligned_read_le64(in);
#ifdef DEBUG #ifdef DEBUG
printf("(%3zu) v0 %08x %08x\n", state->inlen, (uint32_t) (state->v0 >> 32), (uint32_t) state->v0); printf("(%3zu) v0 %08x %08x\n", state->inlen, (uint32_t) (state->v0 >> 32), (uint32_t) state->v0);
printf("(%3zu) v1 %08x %08x\n", state->inlen, (uint32_t) (state->v1 >> 32), (uint32_t) state->v1); printf("(%3zu) v1 %08x %08x\n", state->inlen, (uint32_t) (state->v1 >> 32), (uint32_t) state->v1);
@@ -121,31 +125,33 @@ void siphash24_compress(const void *_in, size_t inlen, struct siphash *state) {
} }
left = state->inlen & 7; left = state->inlen & 7;
switch (left) {
switch(left) case 7:
{ state->padding |= ((uint64_t) in[6]) << 48;
case 7: state->padding |= ((uint64_t) in[6]) << 48; case 6:
state->padding |= ((uint64_t) in[5]) << 40;
case 6: state->padding |= ((uint64_t) in[5]) << 40; case 5:
state->padding |= ((uint64_t) in[4]) << 32;
case 5: state->padding |= ((uint64_t) in[4]) << 32; case 4:
state->padding |= ((uint64_t) in[3]) << 24;
case 4: state->padding |= ((uint64_t) in[3]) << 24; case 3:
state->padding |= ((uint64_t) in[2]) << 16;
case 3: state->padding |= ((uint64_t) in[2]) << 16; case 2:
state->padding |= ((uint64_t) in[1]) << 8;
case 2: state->padding |= ((uint64_t) in[1]) << 8; case 1:
state->padding |= ((uint64_t) in[0]);
case 1: state->padding |= ((uint64_t) in[0]); break; case 0:
break;
case 0: break;
} }
} }
void siphash24_finalize(uint8_t out[8], struct siphash *state) { uint64_t siphash24_finalize(struct siphash *state) {
uint64_t b; uint64_t b;
assert(state);
b = state->padding | (((uint64_t) state->inlen) << 56); b = state->padding | (((uint64_t) state->inlen) << 56);
#ifdef DEBUG #ifdef DEBUG
printf("(%3zu) v0 %08x %08x\n", state->inlen, (uint32_t) (state->v0 >> 32), (uint32_t) state->v0); printf("(%3zu) v0 %08x %08x\n", state->inlen, (uint32_t) (state->v0 >> 32), (uint32_t) state->v0);
printf("(%3zu) v1 %08x %08x\n", state->inlen, (uint32_t) (state->v1 >> 32), (uint32_t) state->v1); printf("(%3zu) v1 %08x %08x\n", state->inlen, (uint32_t) (state->v1 >> 32), (uint32_t) state->v1);
@@ -153,6 +159,7 @@ void siphash24_finalize(uint8_t out[8], struct siphash *state) {
printf("(%3zu) v3 %08x %08x\n", state->inlen, (uint32_t) (state->v3 >> 32), (uint32_t) state->v3); printf("(%3zu) v3 %08x %08x\n", state->inlen, (uint32_t) (state->v3 >> 32), (uint32_t) state->v3);
printf("(%3zu) padding %08x %08x\n", state->inlen, (uint32_t) (state->padding >> 32), (uint32_t) state->padding); printf("(%3zu) padding %08x %08x\n", state->inlen, (uint32_t) (state->padding >> 32), (uint32_t) state->padding);
#endif #endif
state->v3 ^= b; state->v3 ^= b;
sipround(state); sipround(state);
sipround(state); sipround(state);
@@ -171,14 +178,17 @@ void siphash24_finalize(uint8_t out[8], struct siphash *state) {
sipround(state); sipround(state);
sipround(state); sipround(state);
*(le64_t*)out = htole64(state->v0 ^ state->v1 ^ state->v2 ^ state->v3); return state->v0 ^ state->v1 ^ state->v2 ^ state->v3;
} }
/* SipHash-2-4 */ uint64_t siphash24(const void *in, size_t inlen, const uint8_t k[16]) {
void siphash24(uint8_t out[8], const void *_in, size_t inlen, const uint8_t k[16]) {
struct siphash state; struct siphash state;
assert(in);
assert(k);
siphash24_init(&state, k); siphash24_init(&state, k);
siphash24_compress(_in, inlen, &state); siphash24_compress(in, inlen, &state);
siphash24_finalize(out, &state);
return siphash24_finalize(&state);
} }

View File

@@ -16,6 +16,6 @@ struct siphash {
void siphash24_init(struct siphash *state, const uint8_t k[16]); void siphash24_init(struct siphash *state, const uint8_t k[16]);
void siphash24_compress(const void *in, size_t inlen, struct siphash *state); void siphash24_compress(const void *in, size_t inlen, struct siphash *state);
void siphash24_finalize(uint8_t out[8], struct siphash *state); uint64_t siphash24_finalize(struct siphash *state);
void siphash24(uint8_t out[8], const void *in, size_t inlen, const uint8_t k[16]); uint64_t siphash24(const void *in, size_t inlen, const uint8_t k[16]);

View File

@@ -23,9 +23,9 @@
#include "nm-sd-adapt.h" #include "nm-sd-adapt.h"
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ether.h> #include <netinet/ether.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <sys/un.h> #include <sys/un.h>
#include <linux/netlink.h> #include <linux/netlink.h>
#include <linux/if_packet.h> #include <linux/if_packet.h>
@@ -118,6 +118,17 @@ int netlink_family_from_string(const char *s) _pure_;
bool sockaddr_equal(const union sockaddr_union *a, const union sockaddr_union *b); bool sockaddr_equal(const union sockaddr_union *a, const union sockaddr_union *b);
#define ETHER_ADDR_TO_STRING_MAX (3*6) int fd_inc_sndbuf(int fd, size_t n);
int fd_inc_rcvbuf(int fd, size_t n);
char* ether_addr_to_string(const struct ether_addr *addr, char buffer[ETHER_ADDR_TO_STRING_MAX]); int ip_tos_to_string_alloc(int i, char **s);
int ip_tos_from_string(const char *s);
int getpeercred(int fd, struct ucred *ucred);
int getpeersec(int fd, char **ret);
int send_one_fd(int transport_fd, int fd, int flags);
int receive_one_fd(int transport_fd, int flags);
#define CMSG_FOREACH(cmsg, mh) \
for ((cmsg) = CMSG_FIRSTHDR(mh); (cmsg); (cmsg) = CMSG_NXTHDR((mh), (cmsg)))

View File

@@ -0,0 +1,37 @@
/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
/***
This file is part of systemd.
Copyright 2010 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 "nm-sd-adapt.h"
#include "string-table.h"
ssize_t string_table_lookup(const char * const *table, size_t len, const char *key) {
size_t i;
if (!key)
return -1;
for (i = 0; i < len; ++i)
if (streq_ptr(table[i], key))
return (ssize_t) i;
return -1;
}

View File

@@ -0,0 +1,90 @@
/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
#pragma once
/***
This file is part of systemd.
Copyright 2010 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 "nm-sd-adapt.h"
#include <stddef.h>
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include "macro.h"
#include "parse-util.h"
#include "string-util.h"
ssize_t string_table_lookup(const char * const *table, size_t len, const char *key);
/* For basic lookup tables with strictly enumerated entries */
#define _DEFINE_STRING_TABLE_LOOKUP_TO_STRING(name,type,scope) \
scope const char *name##_to_string(type i) { \
if (i < 0 || i >= (type) ELEMENTSOF(name##_table)) \
return NULL; \
return name##_table[i]; \
}
#define _DEFINE_STRING_TABLE_LOOKUP_FROM_STRING(name,type,scope) \
scope type name##_from_string(const char *s) { \
return (type) string_table_lookup(name##_table, ELEMENTSOF(name##_table), s); \
}
#define _DEFINE_STRING_TABLE_LOOKUP(name,type,scope) \
_DEFINE_STRING_TABLE_LOOKUP_TO_STRING(name,type,scope) \
_DEFINE_STRING_TABLE_LOOKUP_FROM_STRING(name,type,scope) \
struct __useless_struct_to_allow_trailing_semicolon__
#define DEFINE_STRING_TABLE_LOOKUP(name,type) _DEFINE_STRING_TABLE_LOOKUP(name,type,)
#define DEFINE_PRIVATE_STRING_TABLE_LOOKUP(name,type) _DEFINE_STRING_TABLE_LOOKUP(name,type,static)
#define DEFINE_PRIVATE_STRING_TABLE_LOOKUP_TO_STRING(name,type) _DEFINE_STRING_TABLE_LOOKUP_TO_STRING(name,type,static)
#define DEFINE_PRIVATE_STRING_TABLE_LOOKUP_FROM_STRING(name,type) _DEFINE_STRING_TABLE_LOOKUP_FROM_STRING(name,type,static)
/* For string conversions where numbers are also acceptable */
#define DEFINE_STRING_TABLE_LOOKUP_WITH_FALLBACK(name,type,max) \
int name##_to_string_alloc(type i, char **str) { \
char *s; \
if (i < 0 || i > max) \
return -ERANGE; \
if (i < (type) ELEMENTSOF(name##_table)) { \
s = strdup(name##_table[i]); \
if (!s) \
return -ENOMEM; \
} else { \
if (asprintf(&s, "%i", i) < 0) \
return -ENOMEM; \
} \
*str = s; \
return 0; \
} \
type name##_from_string(const char *s) { \
type i; \
unsigned u = 0; \
if (!s) \
return (type) -1; \
for (i = 0; i < (type) ELEMENTSOF(name##_table); i++) \
if (streq_ptr(name##_table[i], s)) \
return i; \
if (safe_atou(s, &u) >= 0 && u <= max) \
return (type) u; \
return (type) -1; \
} \
struct __useless_struct_to_allow_trailing_semicolon__

View File

@@ -0,0 +1,806 @@
/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
/***
This file is part of systemd.
Copyright 2010 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 "nm-sd-adapt.h"
#include "alloc-util.h"
#if 0 /* NM_IGNORED */
#include "gunicode.h"
#endif /* NM_IGNORED */
#include "string-util.h"
#include "utf8.h"
#include "util.h"
int strcmp_ptr(const char *a, const char *b) {
/* Like strcmp(), but tries to make sense of NULL pointers */
if (a && b)
return strcmp(a, b);
if (!a && b)
return -1;
if (a && !b)
return 1;
return 0;
}
char* endswith(const char *s, const char *postfix) {
size_t sl, pl;
assert(s);
assert(postfix);
sl = strlen(s);
pl = strlen(postfix);
if (pl == 0)
return (char*) s + sl;
if (sl < pl)
return NULL;
if (memcmp(s + sl - pl, postfix, pl) != 0)
return NULL;
return (char*) s + sl - pl;
}
char* endswith_no_case(const char *s, const char *postfix) {
size_t sl, pl;
assert(s);
assert(postfix);
sl = strlen(s);
pl = strlen(postfix);
if (pl == 0)
return (char*) s + sl;
if (sl < pl)
return NULL;
if (strcasecmp(s + sl - pl, postfix) != 0)
return NULL;
return (char*) s + sl - pl;
}
char* first_word(const char *s, const char *word) {
size_t sl, wl;
const char *p;
assert(s);
assert(word);
/* Checks if the string starts with the specified word, either
* followed by NUL or by whitespace. Returns a pointer to the
* NUL or the first character after the whitespace. */
sl = strlen(s);
wl = strlen(word);
if (sl < wl)
return NULL;
if (wl == 0)
return (char*) s;
if (memcmp(s, word, wl) != 0)
return NULL;
p = s + wl;
if (*p == 0)
return (char*) p;
if (!strchr(WHITESPACE, *p))
return NULL;
p += strspn(p, WHITESPACE);
return (char*) p;
}
static size_t strcspn_escaped(const char *s, const char *reject) {
bool escaped = false;
int n;
for (n=0; s[n]; n++) {
if (escaped)
escaped = false;
else if (s[n] == '\\')
escaped = true;
else if (strchr(reject, s[n]))
break;
}
/* if s ends in \, return index of previous char */
return n - escaped;
}
/* Split a string into words. */
const char* split(const char **state, size_t *l, const char *separator, bool quoted) {
const char *current;
current = *state;
if (!*current) {
assert(**state == '\0');
return NULL;
}
current += strspn(current, separator);
if (!*current) {
*state = current;
return NULL;
}
if (quoted && strchr("\'\"", *current)) {
char quotechars[2] = {*current, '\0'};
*l = strcspn_escaped(current + 1, quotechars);
if (current[*l + 1] == '\0' || current[*l + 1] != quotechars[0] ||
(current[*l + 2] && !strchr(separator, current[*l + 2]))) {
/* right quote missing or garbage at the end */
*state = current;
return NULL;
}
*state = current++ + *l + 2;
} else if (quoted) {
*l = strcspn_escaped(current, separator);
if (current[*l] && !strchr(separator, current[*l])) {
/* unfinished escape */
*state = current;
return NULL;
}
*state = current + *l;
} else {
*l = strcspn(current, separator);
*state = current + *l;
}
return current;
}
char *strnappend(const char *s, const char *suffix, size_t b) {
size_t a;
char *r;
if (!s && !suffix)
return strdup("");
if (!s)
return strndup(suffix, b);
if (!suffix)
return strdup(s);
assert(s);
assert(suffix);
a = strlen(s);
if (b > ((size_t) -1) - a)
return NULL;
r = new(char, a+b+1);
if (!r)
return NULL;
memcpy(r, s, a);
memcpy(r+a, suffix, b);
r[a+b] = 0;
return r;
}
char *strappend(const char *s, const char *suffix) {
return strnappend(s, suffix, suffix ? strlen(suffix) : 0);
}
char *strjoin(const char *x, ...) {
va_list ap;
size_t l;
char *r, *p;
va_start(ap, x);
if (x) {
l = strlen(x);
for (;;) {
const char *t;
size_t n;
t = va_arg(ap, const char *);
if (!t)
break;
n = strlen(t);
if (n > ((size_t) -1) - l) {
va_end(ap);
return NULL;
}
l += n;
}
} else
l = 0;
va_end(ap);
r = new(char, l+1);
if (!r)
return NULL;
if (x) {
p = stpcpy(r, x);
va_start(ap, x);
for (;;) {
const char *t;
t = va_arg(ap, const char *);
if (!t)
break;
p = stpcpy(p, t);
}
va_end(ap);
} else
r[0] = 0;
return r;
}
char *strstrip(char *s) {
char *e;
/* Drops trailing whitespace. Modifies the string in
* place. Returns pointer to first non-space character */
s += strspn(s, WHITESPACE);
for (e = strchr(s, 0); e > s; e --)
if (!strchr(WHITESPACE, e[-1]))
break;
*e = 0;
return s;
}
char *delete_chars(char *s, const char *bad) {
char *f, *t;
/* Drops all whitespace, regardless where in the string */
for (f = s, t = s; *f; f++) {
if (strchr(bad, *f))
continue;
*(t++) = *f;
}
*t = 0;
return s;
}
char *truncate_nl(char *s) {
assert(s);
s[strcspn(s, NEWLINE)] = 0;
return s;
}
char *ascii_strlower(char *t) {
char *p;
assert(t);
for (p = t; *p; p++)
if (*p >= 'A' && *p <= 'Z')
*p = *p - 'A' + 'a';
return t;
}
bool chars_intersect(const char *a, const char *b) {
const char *p;
/* Returns true if any of the chars in a are in b. */
for (p = a; *p; p++)
if (strchr(b, *p))
return true;
return false;
}
bool string_has_cc(const char *p, const char *ok) {
const char *t;
assert(p);
/*
* Check if a string contains control characters. If 'ok' is
* non-NULL it may be a string containing additional CCs to be
* considered OK.
*/
for (t = p; *t; t++) {
if (ok && strchr(ok, *t))
continue;
if (*t > 0 && *t < ' ')
return true;
if (*t == 127)
return true;
}
return false;
}
#if 0 /* NM_IGNORED */
static char *ascii_ellipsize_mem(const char *s, size_t old_length, size_t new_length, unsigned percent) {
size_t x;
char *r;
assert(s);
assert(percent <= 100);
assert(new_length >= 3);
if (old_length <= 3 || old_length <= new_length)
return strndup(s, old_length);
r = new0(char, new_length+1);
if (!r)
return NULL;
x = (new_length * percent) / 100;
if (x > new_length - 3)
x = new_length - 3;
memcpy(r, s, x);
r[x] = '.';
r[x+1] = '.';
r[x+2] = '.';
memcpy(r + x + 3,
s + old_length - (new_length - x - 3),
new_length - x - 3);
return r;
}
char *ellipsize_mem(const char *s, size_t old_length, size_t new_length, unsigned percent) {
size_t x;
char *e;
const char *i, *j;
unsigned k, len, len2;
assert(s);
assert(percent <= 100);
assert(new_length >= 3);
/* if no multibyte characters use ascii_ellipsize_mem for speed */
if (ascii_is_valid(s))
return ascii_ellipsize_mem(s, old_length, new_length, percent);
if (old_length <= 3 || old_length <= new_length)
return strndup(s, old_length);
x = (new_length * percent) / 100;
if (x > new_length - 3)
x = new_length - 3;
k = 0;
for (i = s; k < x && i < s + old_length; i = utf8_next_char(i)) {
int c;
c = utf8_encoded_to_unichar(i);
if (c < 0)
return NULL;
k += unichar_iswide(c) ? 2 : 1;
}
if (k > x) /* last character was wide and went over quota */
x ++;
for (j = s + old_length; k < new_length && j > i; ) {
int c;
j = utf8_prev_char(j);
c = utf8_encoded_to_unichar(j);
if (c < 0)
return NULL;
k += unichar_iswide(c) ? 2 : 1;
}
assert(i <= j);
/* we don't actually need to ellipsize */
if (i == j)
return memdup(s, old_length + 1);
/* make space for ellipsis */
j = utf8_next_char(j);
len = i - s;
len2 = s + old_length - j;
e = new(char, len + 3 + len2 + 1);
if (!e)
return NULL;
/*
printf("old_length=%zu new_length=%zu x=%zu len=%u len2=%u k=%u\n",
old_length, new_length, x, len, len2, k);
*/
memcpy(e, s, len);
e[len] = 0xe2; /* tri-dot ellipsis: … */
e[len + 1] = 0x80;
e[len + 2] = 0xa6;
memcpy(e + len + 3, j, len2 + 1);
return e;
}
char *ellipsize(const char *s, size_t length, unsigned percent) {
return ellipsize_mem(s, strlen(s), length, percent);
}
#endif /* NM_IGNORED */
bool nulstr_contains(const char*nulstr, const char *needle) {
const char *i;
if (!nulstr)
return false;
NULSTR_FOREACH(i, nulstr)
if (streq(i, needle))
return true;
return false;
}
char* strshorten(char *s, size_t l) {
assert(s);
if (l < strlen(s))
s[l] = 0;
return s;
}
char *strreplace(const char *text, const char *old_string, const char *new_string) {
const char *f;
char *t, *r;
size_t l, old_len, new_len;
assert(text);
assert(old_string);
assert(new_string);
old_len = strlen(old_string);
new_len = strlen(new_string);
l = strlen(text);
r = new(char, l+1);
if (!r)
return NULL;
f = text;
t = r;
while (*f) {
char *a;
size_t d, nl;
if (!startswith(f, old_string)) {
*(t++) = *(f++);
continue;
}
d = t - r;
nl = l - old_len + new_len;
a = realloc(r, nl + 1);
if (!a)
goto oom;
l = nl;
r = a;
t = r + d;
t = stpcpy(t, new_string);
f += old_len;
}
*t = 0;
return r;
oom:
free(r);
return NULL;
}
char *strip_tab_ansi(char **ibuf, size_t *_isz) {
const char *i, *begin = NULL;
enum {
STATE_OTHER,
STATE_ESCAPE,
STATE_BRACKET
} state = STATE_OTHER;
char *obuf = NULL;
size_t osz = 0, isz;
FILE *f;
assert(ibuf);
assert(*ibuf);
/* Strips ANSI color and replaces TABs by 8 spaces */
isz = _isz ? *_isz : strlen(*ibuf);
f = open_memstream(&obuf, &osz);
if (!f)
return NULL;
for (i = *ibuf; i < *ibuf + isz + 1; i++) {
switch (state) {
case STATE_OTHER:
if (i >= *ibuf + isz) /* EOT */
break;
else if (*i == '\x1B')
state = STATE_ESCAPE;
else if (*i == '\t')
fputs(" ", f);
else
fputc(*i, f);
break;
case STATE_ESCAPE:
if (i >= *ibuf + isz) { /* EOT */
fputc('\x1B', f);
break;
} else if (*i == '[') {
state = STATE_BRACKET;
begin = i + 1;
} else {
fputc('\x1B', f);
fputc(*i, f);
state = STATE_OTHER;
}
break;
case STATE_BRACKET:
if (i >= *ibuf + isz || /* EOT */
(!(*i >= '0' && *i <= '9') && *i != ';' && *i != 'm')) {
fputc('\x1B', f);
fputc('[', f);
state = STATE_OTHER;
i = begin-1;
} else if (*i == 'm')
state = STATE_OTHER;
break;
}
}
if (ferror(f)) {
fclose(f);
free(obuf);
return NULL;
}
fclose(f);
free(*ibuf);
*ibuf = obuf;
if (_isz)
*_isz = osz;
return obuf;
}
char *strextend(char **x, ...) {
va_list ap;
size_t f, l;
char *r, *p;
assert(x);
l = f = *x ? strlen(*x) : 0;
va_start(ap, x);
for (;;) {
const char *t;
size_t n;
t = va_arg(ap, const char *);
if (!t)
break;
n = strlen(t);
if (n > ((size_t) -1) - l) {
va_end(ap);
return NULL;
}
l += n;
}
va_end(ap);
r = realloc(*x, l+1);
if (!r)
return NULL;
p = r + f;
va_start(ap, x);
for (;;) {
const char *t;
t = va_arg(ap, const char *);
if (!t)
break;
p = stpcpy(p, t);
}
va_end(ap);
*p = 0;
*x = r;
return r + l;
}
char *strrep(const char *s, unsigned n) {
size_t l;
char *r, *p;
unsigned i;
assert(s);
l = strlen(s);
p = r = malloc(l * n + 1);
if (!r)
return NULL;
for (i = 0; i < n; i++)
p = stpcpy(p, s);
*p = 0;
return r;
}
int split_pair(const char *s, const char *sep, char **l, char **r) {
char *x, *a, *b;
assert(s);
assert(sep);
assert(l);
assert(r);
if (isempty(sep))
return -EINVAL;
x = strstr(s, sep);
if (!x)
return -EINVAL;
a = strndup(s, x - s);
if (!a)
return -ENOMEM;
b = strdup(x + strlen(sep));
if (!b) {
free(a);
return -ENOMEM;
}
*l = a;
*r = b;
return 0;
}
int free_and_strdup(char **p, const char *s) {
char *t;
assert(p);
/* Replaces a string pointer with an strdup()ed new string,
* possibly freeing the old one. */
if (streq_ptr(*p, s))
return 0;
if (s) {
t = strdup(s);
if (!t)
return -ENOMEM;
} else
t = NULL;
free(*p);
*p = t;
return 1;
}
#pragma GCC push_options
#pragma GCC optimize("O0")
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;
}
#pragma GCC pop_options
char* string_erase(char *x) {
if (!x)
return NULL;
/* A delicious drop of snake-oil! To be called on memory where
* we stored passphrases or so, after we used them. */
return memory_erase(x, strlen(x));
}
char *string_free_erase(char *s) {
return mfree(string_erase(s));
}
bool string_is_safe(const char *p) {
const char *t;
if (!p)
return false;
for (t = p; *t; t++) {
if (*t > 0 && *t < ' ') /* no control characters */
return false;
if (strchr(QUOTES "\\\x7f", *t))
return false;
}
return true;
}

View File

@@ -0,0 +1,186 @@
/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
#pragma once
/***
This file is part of systemd.
Copyright 2010 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 "nm-sd-adapt.h"
#include <stdbool.h>
#include <string.h>
#include "macro.h"
/* What is interpreted as whitespace? */
#define WHITESPACE " \t\n\r"
#define NEWLINE "\n\r"
#define QUOTES "\"\'"
#define COMMENTS "#;"
#define GLOB_CHARS "*?["
#define DIGITS "0123456789"
#define LOWERCASE_LETTERS "abcdefghijklmnopqrstuvwxyz"
#define UPPERCASE_LETTERS "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
#define LETTERS LOWERCASE_LETTERS UPPERCASE_LETTERS
#define ALPHANUMERICAL LETTERS DIGITS
#define streq(a,b) (strcmp((a),(b)) == 0)
#define strneq(a, b, n) (strncmp((a), (b), (n)) == 0)
#define strcaseeq(a,b) (strcasecmp((a),(b)) == 0)
#define strncaseeq(a, b, n) (strncasecmp((a), (b), (n)) == 0)
int strcmp_ptr(const char *a, const char *b) _pure_;
static inline bool streq_ptr(const char *a, const char *b) {
return strcmp_ptr(a, b) == 0;
}
static inline const char* strempty(const char *s) {
return s ? s : "";
}
static inline const char* strnull(const char *s) {
return s ? s : "(null)";
}
static inline const char *strna(const char *s) {
return s ? s : "n/a";
}
static inline bool isempty(const char *p) {
return !p || !p[0];
}
static inline char *startswith(const char *s, const char *prefix) {
size_t l;
l = strlen(prefix);
if (strncmp(s, prefix, l) == 0)
return (char*) s + l;
return NULL;
}
static inline char *startswith_no_case(const char *s, const char *prefix) {
size_t l;
l = strlen(prefix);
if (strncasecmp(s, prefix, l) == 0)
return (char*) s + l;
return NULL;
}
char *endswith(const char *s, const char *postfix) _pure_;
char *endswith_no_case(const char *s, const char *postfix) _pure_;
char *first_word(const char *s, const char *word) _pure_;
const char* split(const char **state, size_t *l, const char *separator, bool quoted);
#define FOREACH_WORD(word, length, s, state) \
_FOREACH_WORD(word, length, s, WHITESPACE, false, state)
#define FOREACH_WORD_SEPARATOR(word, length, s, separator, state) \
_FOREACH_WORD(word, length, s, separator, false, state)
#define FOREACH_WORD_QUOTED(word, length, s, state) \
_FOREACH_WORD(word, length, s, WHITESPACE, true, state)
#define _FOREACH_WORD(word, length, s, separator, quoted, state) \
for ((state) = (s), (word) = split(&(state), &(length), (separator), (quoted)); (word); (word) = split(&(state), &(length), (separator), (quoted)))
char *strappend(const char *s, const char *suffix);
char *strnappend(const char *s, const char *suffix, size_t length);
char *strjoin(const char *x, ...) _sentinel_;
#define strjoina(a, ...) \
({ \
const char *_appendees_[] = { a, __VA_ARGS__ }; \
char *_d_, *_p_; \
int _len_ = 0; \
unsigned _i_; \
for (_i_ = 0; _i_ < ELEMENTSOF(_appendees_) && _appendees_[_i_]; _i_++) \
_len_ += strlen(_appendees_[_i_]); \
_p_ = _d_ = alloca(_len_ + 1); \
for (_i_ = 0; _i_ < ELEMENTSOF(_appendees_) && _appendees_[_i_]; _i_++) \
_p_ = stpcpy(_p_, _appendees_[_i_]); \
*_p_ = 0; \
_d_; \
})
char *strstrip(char *s);
char *delete_chars(char *s, const char *bad);
char *truncate_nl(char *s);
char *ascii_strlower(char *path);
bool chars_intersect(const char *a, const char *b) _pure_;
static inline bool _pure_ in_charset(const char *s, const char* charset) {
assert(s);
assert(charset);
return s[strspn(s, charset)] == '\0';
}
bool string_has_cc(const char *p, const char *ok) _pure_;
char *ellipsize_mem(const char *s, size_t old_length_bytes, size_t new_length_columns, unsigned percent);
char *ellipsize(const char *s, size_t length, unsigned percent);
bool nulstr_contains(const char*nulstr, const char *needle);
char* strshorten(char *s, size_t l);
char *strreplace(const char *text, const char *old_string, const char *new_string);
char *strip_tab_ansi(char **p, size_t *l);
char *strextend(char **x, ...) _sentinel_;
char *strrep(const char *s, unsigned n);
int split_pair(const char *s, const char *sep, char **l, char **r);
int free_and_strdup(char **p, const char *s);
/* Normal memmem() requires haystack to be nonnull, which is annoying for zero-length buffers */
static inline void *memmem_safe(const void *haystack, size_t haystacklen, const void *needle, size_t needlelen) {
if (needlelen <= 0)
return (void*) haystack;
if (haystacklen < needlelen)
return NULL;
assert(haystack);
assert(needle);
return memmem(haystack, haystacklen, needle, needlelen);
}
void* memory_erase(void *p, size_t l);
char *string_erase(char *x);
char *string_free_erase(char *s);
DEFINE_TRIVIAL_CLEANUP_FUNC(char *, string_free_erase);
#define _cleanup_string_free_erase_ _cleanup_(string_free_erasep)
bool string_is_safe(const char *p) _pure_;

View File

@@ -21,13 +21,16 @@
#include "nm-sd-adapt.h" #include "nm-sd-adapt.h"
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
#include <errno.h> #include <errno.h>
#include <stdarg.h>
#include <stdlib.h>
#include <string.h>
#include "util.h" #include "alloc-util.h"
#include "escape.h"
#include "string-util.h"
#include "strv.h" #include "strv.h"
#include "util.h"
char *strv_find(char **l, const char *name) { char *strv_find(char **l, const char *name) {
char **i; char **i;
@@ -88,6 +91,15 @@ char **strv_free(char **l) {
return NULL; return NULL;
} }
char **strv_free_erase(char **l) {
char **i;
STRV_FOREACH(i, l)
string_erase(*i);
return strv_free(l);
}
char **strv_copy(char * const *l) { char **strv_copy(char * const *l) {
char **r, **k; char **r, **k;
@@ -190,17 +202,48 @@ char **strv_new(const char *x, ...) {
return r; return r;
} }
int strv_extend_strv(char ***a, char **b) { int strv_extend_strv(char ***a, char **b, bool filter_duplicates) {
int r; char **s, **t;
char **s; size_t p, q, i = 0, j;
assert(a);
if (strv_isempty(b))
return 0;
p = strv_length(*a);
q = strv_length(b);
t = realloc(*a, sizeof(char*) * (p + q + 1));
if (!t)
return -ENOMEM;
t[p] = NULL;
*a = t;
STRV_FOREACH(s, b) { STRV_FOREACH(s, b) {
r = strv_extend(a, *s);
if (r < 0) if (filter_duplicates && strv_contains(t, *s))
return r; continue;
t[p+i] = strdup(*s);
if (!t[p+i])
goto rollback;
i++;
t[p+i] = NULL;
} }
return 0; assert(i <= q);
return (int) i;
rollback:
for (j = 0; j < i; j++)
free(t[p + j]);
t[p] = NULL;
return -ENOMEM;
} }
int strv_extend_strv_concat(char ***a, char **b, const char *suffix) { int strv_extend_strv_concat(char ***a, char **b, const char *suffix) {
@@ -622,6 +665,41 @@ char **strv_split_nulstr(const char *s) {
return r; return r;
} }
int strv_make_nulstr(char **l, char **p, size_t *q) {
size_t n_allocated = 0, n = 0;
_cleanup_free_ char *m = NULL;
char **i;
assert(p);
assert(q);
STRV_FOREACH(i, l) {
size_t z;
z = strlen(*i);
if (!GREEDY_REALLOC(m, n_allocated, n + z + 1))
return -ENOMEM;
memcpy(m + n, *i, z + 1);
n += z + 1;
}
if (!m) {
m = new0(char, 1);
if (!m)
return -ENOMEM;
n = 0;
}
*p = m;
*q = n;
m = NULL;
return 0;
}
bool strv_overlap(char **a, char **b) { bool strv_overlap(char **a, char **b) {
char **i; char **i;
@@ -648,8 +726,12 @@ char **strv_sort(char **l) {
} }
bool strv_equal(char **a, char **b) { bool strv_equal(char **a, char **b) {
if (!a || !b)
return a == b; if (strv_isempty(a))
return strv_isempty(b);
if (strv_isempty(b))
return false;
for ( ; *a || *b; ++a, ++b) for ( ; *a || *b; ++a, ++b)
if (!streq_ptr(*a, *b)) if (!streq_ptr(*a, *b))
@@ -784,7 +866,7 @@ int strv_extend_n(char ***l, const char *value, size_t n) {
return 0; return 0;
rollback: rollback:
for (j = k; j < i; i++) for (j = k; j < i; j++)
free(nl[j]); free(nl[j]);
nl[k] = NULL; nl[k] = NULL;

View File

@@ -23,10 +23,13 @@
#include "nm-sd-adapt.h" #include "nm-sd-adapt.h"
#include <fnmatch.h>
#include <stdarg.h> #include <stdarg.h>
#include <stdbool.h> #include <stdbool.h>
#include <fnmatch.h>
#if 0 /* NM_IGNORED */
#include "extract-word.h"
#endif /* NM_IGNORED */
#include "util.h" #include "util.h"
char *strv_find(char **l, const char *name) _pure_; char *strv_find(char **l, const char *name) _pure_;
@@ -37,12 +40,16 @@ char **strv_free(char **l);
DEFINE_TRIVIAL_CLEANUP_FUNC(char**, strv_free); DEFINE_TRIVIAL_CLEANUP_FUNC(char**, strv_free);
#define _cleanup_strv_free_ _cleanup_(strv_freep) #define _cleanup_strv_free_ _cleanup_(strv_freep)
char **strv_free_erase(char **l);
DEFINE_TRIVIAL_CLEANUP_FUNC(char**, strv_free_erase);
#define _cleanup_strv_free_erase_ _cleanup_(strv_free_erasep)
void strv_clear(char **l); void strv_clear(char **l);
char **strv_copy(char * const *l); char **strv_copy(char * const *l);
unsigned strv_length(char * const *l) _pure_; unsigned strv_length(char * const *l) _pure_;
int strv_extend_strv(char ***a, char **b); int strv_extend_strv(char ***a, char **b, bool filter_duplicates);
int strv_extend_strv_concat(char ***a, char **b, const char *suffix); int strv_extend_strv_concat(char ***a, char **b, const char *suffix);
int strv_extend(char ***l, const char *value); int strv_extend(char ***l, const char *value);
int strv_extendf(char ***l, const char *format, ...) _printf_(2,0); int strv_extendf(char ***l, const char *format, ...) _printf_(2,0);
@@ -75,13 +82,16 @@ static inline bool strv_isempty(char * const *l) {
char **strv_split(const char *s, const char *separator); char **strv_split(const char *s, const char *separator);
char **strv_split_newlines(const char *s); char **strv_split_newlines(const char *s);
#if 0 /* NM_IGNORED */
int strv_split_extract(char ***t, const char *s, const char *separators, ExtractFlags flags); int strv_split_extract(char ***t, const char *s, const char *separators, ExtractFlags flags);
#endif /* NM_IGNORED */
char *strv_join(char **l, const char *separator); char *strv_join(char **l, const char *separator);
char *strv_join_quoted(char **l); char *strv_join_quoted(char **l);
char **strv_parse_nulstr(const char *s, size_t l); char **strv_parse_nulstr(const char *s, size_t l);
char **strv_split_nulstr(const char *s); char **strv_split_nulstr(const char *s);
int strv_make_nulstr(char **l, char **p, size_t *n);
bool strv_overlap(char **a, char **b) _pure_; bool strv_overlap(char **a, char **b) _pure_;

View File

@@ -21,15 +21,22 @@
#include "nm-sd-adapt.h" #include "nm-sd-adapt.h"
#include <time.h>
#include <string.h> #include <string.h>
#include <sys/timex.h>
#include <sys/timerfd.h> #include <sys/timerfd.h>
#include <sys/timex.h>
#include "util.h" #include "alloc-util.h"
#include "time-util.h" #include "fd-util.h"
#include "fileio.h"
#if 0 /* NM_IGNORED */
#include "fs-util.h"
#include "parse-util.h"
#endif /* NM_IGNORED */
#include "path-util.h" #include "path-util.h"
#include "string-util.h"
#include "strv.h" #include "strv.h"
#include "time-util.h"
#include "util.h"
usec_t now(clockid_t clock_id) { usec_t now(clockid_t clock_id) {
struct timespec ts; struct timespec ts;
@@ -208,11 +215,8 @@ static char *format_timestamp_internal(char *buf, size_t l, usec_t t, bool utc)
return NULL; return NULL;
sec = (time_t) (t / USEC_PER_SEC); sec = (time_t) (t / USEC_PER_SEC);
localtime_or_gmtime_r(&sec, &tm, utc);
if (utc)
gmtime_r(&sec, &tm);
else
localtime_r(&sec, &tm);
if (strftime(buf, l, "%a %Y-%m-%d %H:%M:%S %Z", &tm) <= 0) if (strftime(buf, l, "%a %Y-%m-%d %H:%M:%S %Z", &tm) <= 0)
return NULL; return NULL;
@@ -238,10 +242,7 @@ static char *format_timestamp_internal_us(char *buf, size_t l, usec_t t, bool ut
return NULL; return NULL;
sec = (time_t) (t / USEC_PER_SEC); sec = (time_t) (t / USEC_PER_SEC);
if (utc) localtime_or_gmtime_r(&sec, &tm, utc);
gmtime_r(&sec, &tm);
else
localtime_r(&sec, &tm);
if (strftime(buf, l, "%a %Y-%m-%d %H:%M:%S", &tm) <= 0) if (strftime(buf, l, "%a %Y-%m-%d %H:%M:%S", &tm) <= 0)
return NULL; return NULL;
@@ -489,9 +490,10 @@ int parse_timestamp(const char *t, usec_t *usec) {
}; };
const char *k; const char *k;
const char *utc;
struct tm tm, copy; struct tm tm, copy;
time_t x; time_t x;
usec_t plus = 0, minus = 0, ret; usec_t x_usec, plus = 0, minus = 0, ret;
int r, weekday = -1; int r, weekday = -1;
unsigned i; unsigned i;
@@ -516,28 +518,15 @@ int parse_timestamp(const char *t, usec_t *usec) {
assert(t); assert(t);
assert(usec); assert(usec);
x = time(NULL); if (t[0] == '@')
assert_se(localtime_r(&x, &tm)); return parse_sec(t + 1, usec);
tm.tm_isdst = -1;
ret = now(CLOCK_REALTIME);
if (streq(t, "now")) if (streq(t, "now"))
goto finish; goto finish;
else if (streq(t, "today")) { else if (t[0] == '+') {
tm.tm_sec = tm.tm_min = tm.tm_hour = 0;
goto finish;
} else if (streq(t, "yesterday")) {
tm.tm_mday --;
tm.tm_sec = tm.tm_min = tm.tm_hour = 0;
goto finish;
} else if (streq(t, "tomorrow")) {
tm.tm_mday ++;
tm.tm_sec = tm.tm_min = tm.tm_hour = 0;
goto finish;
} else if (t[0] == '+') {
r = parse_sec(t+1, &plus); r = parse_sec(t+1, &plus);
if (r < 0) if (r < 0)
return r; return r;
@@ -551,35 +540,51 @@ int parse_timestamp(const char *t, usec_t *usec) {
goto finish; goto finish;
} else if (t[0] == '@') } else if ((k = endswith(t, " ago"))) {
return parse_sec(t + 1, usec); t = strndupa(t, k - t);
else if (endswith(t, " ago")) { r = parse_sec(t, &minus);
_cleanup_free_ char *z;
z = strndup(t, strlen(t) - 4);
if (!z)
return -ENOMEM;
r = parse_sec(z, &minus);
if (r < 0) if (r < 0)
return r; return r;
goto finish; goto finish;
} else if (endswith(t, " left")) {
_cleanup_free_ char *z;
z = strndup(t, strlen(t) - 4); } else if ((k = endswith(t, " left"))) {
if (!z) t = strndupa(t, k - t);
return -ENOMEM;
r = parse_sec(z, &plus); r = parse_sec(t, &plus);
if (r < 0) if (r < 0)
return r; return r;
goto finish; goto finish;
} }
utc = endswith_no_case(t, " UTC");
if (utc)
t = strndupa(t, utc - t);
x = ret / USEC_PER_SEC;
x_usec = 0;
assert_se(localtime_or_gmtime_r(&x, &tm, utc));
tm.tm_isdst = -1;
if (streq(t, "today")) {
tm.tm_sec = tm.tm_min = tm.tm_hour = 0;
goto from_tm;
} else if (streq(t, "yesterday")) {
tm.tm_mday --;
tm.tm_sec = tm.tm_min = tm.tm_hour = 0;
goto from_tm;
} else if (streq(t, "tomorrow")) {
tm.tm_mday ++;
tm.tm_sec = tm.tm_min = tm.tm_hour = 0;
goto from_tm;
}
for (i = 0; i < ELEMENTSOF(day_nr); i++) { for (i = 0; i < ELEMENTSOF(day_nr); i++) {
size_t skip; size_t skip;
@@ -597,66 +602,95 @@ int parse_timestamp(const char *t, usec_t *usec) {
copy = tm; copy = tm;
k = strptime(t, "%y-%m-%d %H:%M:%S", &tm); k = strptime(t, "%y-%m-%d %H:%M:%S", &tm);
if (k && *k == 0) if (k) {
goto finish; if (*k == '.')
goto parse_usec;
else if (*k == 0)
goto from_tm;
}
tm = copy; tm = copy;
k = strptime(t, "%Y-%m-%d %H:%M:%S", &tm); k = strptime(t, "%Y-%m-%d %H:%M:%S", &tm);
if (k && *k == 0) if (k) {
goto finish; if (*k == '.')
goto parse_usec;
else if (*k == 0)
goto from_tm;
}
tm = copy; tm = copy;
k = strptime(t, "%y-%m-%d %H:%M", &tm); k = strptime(t, "%y-%m-%d %H:%M", &tm);
if (k && *k == 0) { if (k && *k == 0) {
tm.tm_sec = 0; tm.tm_sec = 0;
goto finish; goto from_tm;
} }
tm = copy; tm = copy;
k = strptime(t, "%Y-%m-%d %H:%M", &tm); k = strptime(t, "%Y-%m-%d %H:%M", &tm);
if (k && *k == 0) { if (k && *k == 0) {
tm.tm_sec = 0; tm.tm_sec = 0;
goto finish; goto from_tm;
} }
tm = copy; tm = copy;
k = strptime(t, "%y-%m-%d", &tm); k = strptime(t, "%y-%m-%d", &tm);
if (k && *k == 0) { if (k && *k == 0) {
tm.tm_sec = tm.tm_min = tm.tm_hour = 0; tm.tm_sec = tm.tm_min = tm.tm_hour = 0;
goto finish; goto from_tm;
} }
tm = copy; tm = copy;
k = strptime(t, "%Y-%m-%d", &tm); k = strptime(t, "%Y-%m-%d", &tm);
if (k && *k == 0) { if (k && *k == 0) {
tm.tm_sec = tm.tm_min = tm.tm_hour = 0; tm.tm_sec = tm.tm_min = tm.tm_hour = 0;
goto finish; goto from_tm;
} }
tm = copy; tm = copy;
k = strptime(t, "%H:%M:%S", &tm); k = strptime(t, "%H:%M:%S", &tm);
if (k && *k == 0) if (k) {
goto finish; if (*k == '.')
goto parse_usec;
else if (*k == 0)
goto from_tm;
}
tm = copy; tm = copy;
k = strptime(t, "%H:%M", &tm); k = strptime(t, "%H:%M", &tm);
if (k && *k == 0) { if (k && *k == 0) {
tm.tm_sec = 0; tm.tm_sec = 0;
goto finish; goto from_tm;
} }
return -EINVAL; return -EINVAL;
finish: parse_usec:
x = mktime(&tm); {
unsigned add;
k++;
r = parse_fractional_part_u(&k, 6, &add);
if (r < 0)
return -EINVAL;
if (*k)
return -EINVAL;
x_usec = add;
}
from_tm:
x = mktime_or_timegm(&tm, utc);
if (x == (time_t) -1) if (x == (time_t) -1)
return -EINVAL; return -EINVAL;
if (weekday >= 0 && tm.tm_wday != weekday) if (weekday >= 0 && tm.tm_wday != weekday)
return -EINVAL; return -EINVAL;
ret = (usec_t) x * USEC_PER_SEC; ret = (usec_t) x * USEC_PER_SEC + x_usec;
finish:
ret += plus; ret += plus;
if (ret > minus) if (ret > minus)
ret -= minus; ret -= minus;
@@ -668,7 +702,8 @@ finish:
return 0; return 0;
} }
int parse_sec(const char *t, usec_t *usec) { int parse_time(const char *t, usec_t *usec, usec_t default_unit) {
static const struct { static const struct {
const char *suffix; const char *suffix;
usec_t usec; usec_t usec;
@@ -682,6 +717,7 @@ int parse_sec(const char *t, usec_t *usec) {
{ "min", USEC_PER_MINUTE }, { "min", USEC_PER_MINUTE },
{ "months", USEC_PER_MONTH }, { "months", USEC_PER_MONTH },
{ "month", USEC_PER_MONTH }, { "month", USEC_PER_MONTH },
{ "M", USEC_PER_MONTH },
{ "msec", USEC_PER_MSEC }, { "msec", USEC_PER_MSEC },
{ "ms", USEC_PER_MSEC }, { "ms", USEC_PER_MSEC },
{ "m", USEC_PER_MINUTE }, { "m", USEC_PER_MINUTE },
@@ -700,7 +736,6 @@ int parse_sec(const char *t, usec_t *usec) {
{ "y", USEC_PER_YEAR }, { "y", USEC_PER_YEAR },
{ "usec", 1ULL }, { "usec", 1ULL },
{ "us", 1ULL }, { "us", 1ULL },
{ "", USEC_PER_SEC }, /* default is sec */
}; };
const char *p, *s; const char *p, *s;
@@ -709,6 +744,7 @@ int parse_sec(const char *t, usec_t *usec) {
assert(t); assert(t);
assert(usec); assert(usec);
assert(default_unit > 0);
p = t; p = t;
@@ -727,6 +763,7 @@ int parse_sec(const char *t, usec_t *usec) {
long long l, z = 0; long long l, z = 0;
char *e; char *e;
unsigned i, n = 0; unsigned i, n = 0;
usec_t multiplier, k;
p += strspn(p, WHITESPACE); p += strspn(p, WHITESPACE);
@@ -769,21 +806,24 @@ int parse_sec(const char *t, usec_t *usec) {
for (i = 0; i < ELEMENTSOF(table); i++) for (i = 0; i < ELEMENTSOF(table); i++)
if (startswith(e, table[i].suffix)) { if (startswith(e, table[i].suffix)) {
usec_t k = (usec_t) z * table[i].usec; multiplier = table[i].usec;
p = e + strlen(table[i].suffix);
break;
}
if (i >= ELEMENTSOF(table)) {
multiplier = default_unit;
p = e;
}
something = true;
k = (usec_t) z * multiplier;
for (; n > 0; n--) for (; n > 0; n--)
k /= 10; k /= 10;
r += (usec_t) l * table[i].usec + k; r += (usec_t) l * multiplier + k;
p = e + strlen(table[i].suffix);
something = true;
break;
}
if (i >= ELEMENTSOF(table))
return -EINVAL;
} }
*usec = r; *usec = r;
@@ -791,6 +831,10 @@ int parse_sec(const char *t, usec_t *usec) {
return 0; return 0;
} }
int parse_sec(const char *t, usec_t *usec) {
return parse_time(t, usec, USEC_PER_SEC);
}
int parse_nsec(const char *t, nsec_t *nsec) { int parse_nsec(const char *t, nsec_t *nsec) {
static const struct { static const struct {
const char *suffix; const char *suffix;
@@ -1079,4 +1123,26 @@ int get_timezone(char **tz) {
*tz = z; *tz = z;
return 0; return 0;
} }
time_t mktime_or_timegm(struct tm *tm, bool utc) {
return utc ? timegm(tm) : mktime(tm);
}
struct tm *localtime_or_gmtime_r(const time_t *t, struct tm *tm, bool utc) {
return utc ? gmtime_r(t, tm) : localtime_r(t, tm);
}
unsigned long usec_to_jiffies(usec_t u) {
static thread_local unsigned long hz = 0;
long r;
if (hz == 0) {
r = sysconf(_SC_CLK_TCK);
assert(r > 0);
hz = (unsigned long) r;
}
return DIV_ROUND_UP(u , USEC_PER_SEC / hz);
}
#endif /* NM_IGNORED */ #endif /* NM_IGNORED */

View File

@@ -23,8 +23,9 @@
#include "nm-sd-adapt.h" #include "nm-sd-adapt.h"
#include <stdio.h>
#include <inttypes.h> #include <inttypes.h>
#include <stdio.h>
#include <time.h>
typedef uint64_t usec_t; typedef uint64_t usec_t;
typedef uint64_t nsec_t; typedef uint64_t nsec_t;
@@ -105,6 +106,7 @@ int dual_timestamp_deserialize(const char *value, dual_timestamp *t);
int parse_timestamp(const char *t, usec_t *usec); int parse_timestamp(const char *t, usec_t *usec);
int parse_sec(const char *t, usec_t *usec); int parse_sec(const char *t, usec_t *usec);
int parse_time(const char *t, usec_t *usec, usec_t default_unit);
int parse_nsec(const char *t, nsec_t *nsec); int parse_nsec(const char *t, nsec_t *nsec);
bool ntp_synced(void); bool ntp_synced(void);
@@ -119,3 +121,8 @@ clockid_t clock_boottime_or_monotonic(void);
"xstrftime: " #buf "[] must be big enough") "xstrftime: " #buf "[] must be big enough")
int get_timezone(char **timezone); int get_timezone(char **timezone);
time_t mktime_or_timegm(struct tm *tm, bool utc);
struct tm *localtime_or_gmtime_r(const time_t *t, struct tm *tm, bool utc);
unsigned long usec_to_jiffies(usec_t usec);

View File

@@ -0,0 +1,50 @@
/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
#pragma once
/***
This file is part of systemd.
Copyright 2010 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 "nm-sd-adapt.h"
#include <stdbool.h>
#include <sys/stat.h>
#include <sys/types.h>
#include "macro.h"
static inline void umaskp(mode_t *u) {
umask(*u);
}
#define _cleanup_umask_ _cleanup_(umaskp)
struct _umask_struct_ {
mode_t mask;
bool quit;
};
static inline void _reset_umask_(struct _umask_struct_ *s) {
umask(s->mask);
};
#define RUN_WITH_UMASK(mask) \
for (_cleanup_(_reset_umask_) struct _umask_struct_ _saved_umask_ = { umask(mask), false }; \
!_saved_umask_.quit ; \
_saved_umask_.quit = true)

View File

@@ -23,8 +23,11 @@
#include "nm-sd-adapt.h" #include "nm-sd-adapt.h"
#include <endian.h>
#include <stdint.h> #include <stdint.h>
/* BE */
static inline uint16_t unaligned_read_be16(const void *_u) { static inline uint16_t unaligned_read_be16(const void *_u) {
const uint8_t *u = _u; const uint8_t *u = _u;
@@ -66,3 +69,47 @@ static inline void unaligned_write_be64(void *_u, uint64_t a) {
unaligned_write_be32(u, (uint32_t) (a >> 32)); unaligned_write_be32(u, (uint32_t) (a >> 32));
unaligned_write_be32(u + 4, (uint32_t) a); unaligned_write_be32(u + 4, (uint32_t) a);
} }
/* LE */
static inline uint16_t unaligned_read_le16(const void *_u) {
const uint8_t *u = _u;
return (((uint16_t) u[1]) << 8) |
((uint16_t) u[0]);
}
static inline uint32_t unaligned_read_le32(const void *_u) {
const uint8_t *u = _u;
return (((uint32_t) unaligned_read_le16(u + 2)) << 16) |
((uint32_t) unaligned_read_le16(u));
}
static inline uint64_t unaligned_read_le64(const void *_u) {
const uint8_t *u = _u;
return (((uint64_t) unaligned_read_le32(u + 4)) << 32) |
((uint64_t) unaligned_read_le32(u));
}
static inline void unaligned_write_le16(void *_u, uint16_t a) {
uint8_t *u = _u;
u[0] = (uint8_t) a;
u[1] = (uint8_t) (a >> 8);
}
static inline void unaligned_write_le32(void *_u, uint32_t a) {
uint8_t *u = _u;
unaligned_write_le16(u, (uint16_t) a);
unaligned_write_le16(u + 2, (uint16_t) (a >> 16));
}
static inline void unaligned_write_le64(void *_u, uint64_t a) {
uint8_t *u = _u;
unaligned_write_le32(u, (uint32_t) a);
unaligned_write_le32(u + 4, (uint32_t) (a >> 32));
}

View File

@@ -46,11 +46,13 @@
#include "nm-sd-adapt.h" #include "nm-sd-adapt.h"
#include <errno.h> #include <errno.h>
#include <stdlib.h>
#include <inttypes.h> #include <inttypes.h>
#include <string.h>
#include <stdbool.h> #include <stdbool.h>
#include <stdlib.h>
#include <string.h>
#include "alloc-util.h"
#include "hexdecoct.h"
#include "utf8.h" #include "utf8.h"
#include "util.h" #include "util.h"

File diff suppressed because it is too large Load Diff

View File

@@ -24,12 +24,10 @@
#include "nm-sd-adapt.h" #include "nm-sd-adapt.h"
#include <alloca.h> #include <alloca.h>
#include <dirent.h>
#include <fcntl.h> #include <fcntl.h>
#include <inttypes.h> #include <inttypes.h>
#include <limits.h> #include <limits.h>
#include <locale.h> #include <locale.h>
#include <mntent.h>
#include <stdarg.h> #include <stdarg.h>
#include <stdbool.h> #include <stdbool.h>
#include <stddef.h> #include <stddef.h>
@@ -52,49 +50,9 @@
#endif /* NM_IGNORED */ #endif /* NM_IGNORED */
#include "time-util.h" #include "time-util.h"
/* What is interpreted as whitespace? */
#define WHITESPACE " \t\n\r"
#define NEWLINE "\n\r"
#define QUOTES "\"\'"
#define COMMENTS "#;"
#define GLOB_CHARS "*?["
/* What characters are special in the shell? */
/* must be escaped outside and inside double-quotes */
#define SHELL_NEED_ESCAPE "\"\\`$"
/* can be escaped or double-quoted */
#define SHELL_NEED_QUOTES SHELL_NEED_ESCAPE GLOB_CHARS "'()<>|&;"
#define FORMAT_BYTES_MAX 8
size_t page_size(void) _pure_; size_t page_size(void) _pure_;
#define PAGE_ALIGN(l) ALIGN_TO((l), page_size()) #define PAGE_ALIGN(l) ALIGN_TO((l), page_size())
#define streq(a,b) (strcmp((a),(b)) == 0)
#define strneq(a, b, n) (strncmp((a), (b), (n)) == 0)
#define strcaseeq(a,b) (strcasecmp((a),(b)) == 0)
#define strncaseeq(a, b, n) (strncasecmp((a), (b), (n)) == 0)
bool streq_ptr(const char *a, const char *b) _pure_;
int strcmp_ptr(const char *a, const char *b) _pure_;
#define new(t, n) ((t*) malloc_multiply(sizeof(t), (n)))
#define new0(t, n) ((t*) calloc((n), sizeof(t)))
#define newa(t, n) ((t*) alloca(sizeof(t)*(n)))
#define newa0(t, n) ((t*) alloca0(sizeof(t)*(n)))
#define newdup(t, p, n) ((t*) memdup_multiply(p, sizeof(t), (n)))
#define malloc0(n) (calloc(1, (n)))
static inline void *mfree(void *memory) {
free(memory);
return NULL;
}
static inline const char* yes_no(bool b) { static inline const char* yes_no(bool b) {
return b ? "yes" : "no"; return b ? "yes" : "no";
} }
@@ -107,347 +65,13 @@ static inline const char* one_zero(bool b) {
return b ? "1" : "0"; return b ? "1" : "0";
} }
static inline const char* strempty(const char *s) {
return s ? s : "";
}
static inline const char* strnull(const char *s) {
return s ? s : "(null)";
}
static inline const char *strna(const char *s) {
return s ? s : "n/a";
}
static inline bool isempty(const char *p) {
return !p || !p[0];
}
static inline char *startswith(const char *s, const char *prefix) {
size_t l;
l = strlen(prefix);
if (strncmp(s, prefix, l) == 0)
return (char*) s + l;
return NULL;
}
static inline char *startswith_no_case(const char *s, const char *prefix) {
size_t l;
l = strlen(prefix);
if (strncasecmp(s, prefix, l) == 0)
return (char*) s + l;
return NULL;
}
char *endswith(const char *s, const char *postfix) _pure_;
char *endswith_no_case(const char *s, const char *postfix) _pure_;
char *first_word(const char *s, const char *word) _pure_;
int close_nointr(int fd);
int safe_close(int fd);
void safe_close_pair(int p[]);
void close_many(const int fds[], unsigned n_fd);
int fclose_nointr(FILE *f);
FILE* safe_fclose(FILE *f);
DIR* safe_closedir(DIR *f);
int parse_size(const char *t, uint64_t base, uint64_t *size);
int parse_boolean(const char *v) _pure_;
int parse_pid(const char *s, pid_t* ret_pid);
int parse_uid(const char *s, uid_t* ret_uid);
#define parse_gid(s, ret_gid) parse_uid(s, ret_gid)
bool uid_is_valid(uid_t uid);
static inline bool gid_is_valid(gid_t gid) {
return uid_is_valid((uid_t) gid);
}
int safe_atou(const char *s, unsigned *ret_u);
int safe_atoi(const char *s, int *ret_i);
int safe_atollu(const char *s, unsigned long long *ret_u);
int safe_atolli(const char *s, long long int *ret_i);
int safe_atod(const char *s, double *ret_d);
int safe_atou8(const char *s, uint8_t *ret);
#if LONG_MAX == INT_MAX
static inline int safe_atolu(const char *s, unsigned long *ret_u) {
assert_cc(sizeof(unsigned long) == sizeof(unsigned));
return safe_atou(s, (unsigned*) ret_u);
}
static inline int safe_atoli(const char *s, long int *ret_u) {
assert_cc(sizeof(long int) == sizeof(int));
return safe_atoi(s, (int*) ret_u);
}
#else
static inline int safe_atolu(const char *s, unsigned long *ret_u) {
assert_cc(sizeof(unsigned long) == sizeof(unsigned long long));
return safe_atollu(s, (unsigned long long*) ret_u);
}
static inline int safe_atoli(const char *s, long int *ret_u) {
assert_cc(sizeof(long int) == sizeof(long long int));
return safe_atolli(s, (long long int*) ret_u);
}
#endif
static inline int safe_atou32(const char *s, uint32_t *ret_u) {
assert_cc(sizeof(uint32_t) == sizeof(unsigned));
return safe_atou(s, (unsigned*) ret_u);
}
static inline int safe_atoi32(const char *s, int32_t *ret_i) {
assert_cc(sizeof(int32_t) == sizeof(int));
return safe_atoi(s, (int*) ret_i);
}
static inline int safe_atou64(const char *s, uint64_t *ret_u) {
assert_cc(sizeof(uint64_t) == sizeof(unsigned long long));
return safe_atollu(s, (unsigned long long*) ret_u);
}
static inline int safe_atoi64(const char *s, int64_t *ret_i) {
assert_cc(sizeof(int64_t) == sizeof(long long int));
return safe_atolli(s, (long long int*) ret_i);
}
int safe_atou16(const char *s, uint16_t *ret);
int safe_atoi16(const char *s, int16_t *ret);
const char* split(const char **state, size_t *l, const char *separator, bool quoted);
#define FOREACH_WORD(word, length, s, state) \
_FOREACH_WORD(word, length, s, WHITESPACE, false, state)
#define FOREACH_WORD_SEPARATOR(word, length, s, separator, state) \
_FOREACH_WORD(word, length, s, separator, false, state)
#define FOREACH_WORD_QUOTED(word, length, s, state) \
_FOREACH_WORD(word, length, s, WHITESPACE, true, state)
#define _FOREACH_WORD(word, length, s, separator, quoted, state) \
for ((state) = (s), (word) = split(&(state), &(length), (separator), (quoted)); (word); (word) = split(&(state), &(length), (separator), (quoted)))
char *strappend(const char *s, const char *suffix);
char *strnappend(const char *s, const char *suffix, size_t length);
int readlinkat_malloc(int fd, const char *p, char **ret);
int readlink_malloc(const char *p, char **r);
int readlink_value(const char *p, char **ret);
int readlink_and_make_absolute(const char *p, char **r);
int readlink_and_canonicalize(const char *p, char **r);
char *strstrip(char *s);
char *delete_chars(char *s, const char *bad);
char *truncate_nl(char *s);
char *file_in_same_dir(const char *path, const char *filename);
int rmdir_parents(const char *path, const char *stop);
char hexchar(int x) _const_;
int unhexchar(char c) _const_;
char octchar(int x) _const_;
int unoctchar(char c) _const_;
char decchar(int x) _const_;
int undecchar(char c) _const_;
char base32hexchar(int x) _const_;
int unbase32hexchar(char c) _const_;
char base64char(int x) _const_;
int unbase64char(char c) _const_;
char *cescape(const char *s);
size_t cescape_char(char c, char *buf);
typedef enum UnescapeFlags {
UNESCAPE_RELAX = 1,
} UnescapeFlags;
int cunescape(const char *s, UnescapeFlags flags, char **ret);
int cunescape_length(const char *s, size_t length, UnescapeFlags flags, char **ret);
int cunescape_length_with_prefix(const char *s, size_t length, const char *prefix, UnescapeFlags flags, char **ret);
char *xescape(const char *s, const char *bad);
char *ascii_strlower(char *path);
bool dirent_is_file(const struct dirent *de) _pure_;
bool dirent_is_file_with_suffix(const struct dirent *de, const char *suffix) _pure_;
bool hidden_file(const char *filename) _pure_;
bool chars_intersect(const char *a, const char *b) _pure_;
/* For basic lookup tables with strictly enumerated entries */
#define _DEFINE_STRING_TABLE_LOOKUP_TO_STRING(name,type,scope) \
scope const char *name##_to_string(type i) { \
if (i < 0 || i >= (type) ELEMENTSOF(name##_table)) \
return NULL; \
return name##_table[i]; \
}
ssize_t string_table_lookup(const char * const *table, size_t len, const char *key);
#define _DEFINE_STRING_TABLE_LOOKUP_FROM_STRING(name,type,scope) \
scope type name##_from_string(const char *s) { \
return (type) string_table_lookup(name##_table, ELEMENTSOF(name##_table), s); \
}
#define _DEFINE_STRING_TABLE_LOOKUP(name,type,scope) \
_DEFINE_STRING_TABLE_LOOKUP_TO_STRING(name,type,scope) \
_DEFINE_STRING_TABLE_LOOKUP_FROM_STRING(name,type,scope) \
struct __useless_struct_to_allow_trailing_semicolon__
#define DEFINE_STRING_TABLE_LOOKUP(name,type) _DEFINE_STRING_TABLE_LOOKUP(name,type,)
#define DEFINE_PRIVATE_STRING_TABLE_LOOKUP(name,type) _DEFINE_STRING_TABLE_LOOKUP(name,type,static)
#define DEFINE_PRIVATE_STRING_TABLE_LOOKUP_TO_STRING(name,type) _DEFINE_STRING_TABLE_LOOKUP_TO_STRING(name,type,static)
#define DEFINE_PRIVATE_STRING_TABLE_LOOKUP_FROM_STRING(name,type) _DEFINE_STRING_TABLE_LOOKUP_FROM_STRING(name,type,static)
/* For string conversions where numbers are also acceptable */
#define DEFINE_STRING_TABLE_LOOKUP_WITH_FALLBACK(name,type,max) \
int name##_to_string_alloc(type i, char **str) { \
char *s; \
if (i < 0 || i > max) \
return -ERANGE; \
if (i < (type) ELEMENTSOF(name##_table)) { \
s = strdup(name##_table[i]); \
if (!s) \
return -ENOMEM; \
} else { \
if (asprintf(&s, "%i", i) < 0) \
return -ENOMEM; \
} \
*str = s; \
return 0; \
} \
type name##_from_string(const char *s) { \
type i; \
unsigned u = 0; \
if (!s) \
return (type) -1; \
for (i = 0; i < (type) ELEMENTSOF(name##_table); i++) \
if (streq_ptr(name##_table[i], s)) \
return i; \
if (safe_atou(s, &u) >= 0 && u <= max) \
return (type) u; \
return (type) -1; \
} \
struct __useless_struct_to_allow_trailing_semicolon__
int fd_nonblock(int fd, bool nonblock);
int fd_cloexec(int fd, bool cloexec);
int close_all_fds(const int except[], unsigned n_except);
bool fstype_is_network(const char *fstype);
int flush_fd(int fd);
int fopen_temporary(const char *path, FILE **_f, char **_temp_path);
ssize_t loop_read(int fd, void *buf, size_t nbytes, bool do_poll);
int loop_read_exact(int fd, void *buf, size_t nbytes, bool do_poll);
int loop_write(int fd, const void *buf, size_t nbytes, bool do_poll);
bool is_device_path(const char *path);
int dir_is_empty(const char *path);
char* dirname_malloc(const char *path);
char* lookup_uid(uid_t uid);
char* getlogname_malloc(void);
char* getusername_malloc(void);
int chmod_and_chown(const char *path, mode_t mode, uid_t uid, gid_t gid);
int fchmod_and_fchown(int fd, mode_t mode, uid_t uid, gid_t gid);
bool is_temporary_fs(const struct statfs *s) _pure_;
int fd_is_temporary_fs(int fd);
int pipe_eof(int fd);
#define xsprintf(buf, fmt, ...) \
assert_message_se((size_t) snprintf(buf, ELEMENTSOF(buf), fmt, __VA_ARGS__) < ELEMENTSOF(buf), \
"xsprintf: " #buf "[] must be big enough")
int files_same(const char *filea, const char *fileb);
int running_in_chroot(void);
char *ellipsize(const char *s, size_t length, unsigned percent);
/* bytes columns */
char *ellipsize_mem(const char *s, size_t old_length, size_t new_length, unsigned percent);
int touch_file(const char *path, bool parents, usec_t stamp, uid_t uid, gid_t gid, mode_t mode);
int touch(const char *path);
noreturn void freeze(void);
bool null_or_empty(struct stat *st) _pure_;
int null_or_empty_path(const char *fn);
int null_or_empty_fd(int fd);
DIR *xopendirat(int dirfd, const char *name, int flags);
char *fstab_node_to_udev_node(const char *p);
void execute_directories(const char* const* directories, usec_t timeout, char *argv[]); void execute_directories(const char* const* directories, usec_t timeout, char *argv[]);
bool nulstr_contains(const char*nulstr, const char *needle);
bool plymouth_running(void); bool plymouth_running(void);
char* strshorten(char *s, size_t l);
int symlink_idempotent(const char *from, const char *to);
int symlink_atomic(const char *from, const char *to);
int mknod_atomic(const char *path, mode_t mode, dev_t dev);
int mkfifo_atomic(const char *path, mode_t mode);
int fchmod_umask(int fd, mode_t mode);
bool display_is_local(const char *display) _pure_; bool display_is_local(const char *display) _pure_;
int socket_from_display(const char *display, char **path); int socket_from_display(const char *display, char **path);
int get_user_creds(const char **username, uid_t *uid, gid_t *gid, const char **home, const char **shell);
int get_group_creds(const char **groupname, gid_t *gid);
int in_gid(gid_t gid);
int in_group(const char *name);
char* uid_to_name(uid_t uid);
char* gid_to_name(gid_t gid);
int glob_exists(const char *path);
int glob_extend(char ***strv, const char *path);
int dirent_ensure_type(DIR *d, struct dirent *de);
int get_files_in_directory(const char *path, char ***list);
char *strjoin(const char *x, ...) _sentinel_;
#if 0 /* NM_IGNORED */
bool is_main_thread(void);
#endif /* NM_IGNORED */
static inline bool _pure_ in_charset(const char *s, const char* charset) {
assert(s);
assert(charset);
return s[strspn(s, charset)] == '\0';
}
int block_get_whole_disk(dev_t d, dev_t *ret); int block_get_whole_disk(dev_t d, dev_t *ret);
#define NULSTR_FOREACH(i, l) \ #define NULSTR_FOREACH(i, l) \
@@ -456,27 +80,6 @@ int block_get_whole_disk(dev_t d, dev_t *ret);
#define NULSTR_FOREACH_PAIR(i, j, l) \ #define NULSTR_FOREACH_PAIR(i, j, l) \
for ((i) = (l), (j) = strchr((i), 0)+1; (i) && *(i); (i) = strchr((j), 0)+1, (j) = *(i) ? strchr((i), 0)+1 : (i)) for ((i) = (l), (j) = strchr((i), 0)+1; (i) && *(i); (i) = strchr((j), 0)+1, (j) = *(i) ? strchr((i), 0)+1 : (i))
int ioprio_class_to_string_alloc(int i, char **s);
int ioprio_class_from_string(const char *s);
const char *sigchld_code_to_string(int i) _const_;
int sigchld_code_from_string(const char *s) _pure_;
int log_facility_unshifted_to_string_alloc(int i, char **s);
int log_facility_unshifted_from_string(const char *s);
int log_level_to_string_alloc(int i, char **s);
int log_level_from_string(const char *s);
int sched_policy_to_string_alloc(int i, char **s);
int sched_policy_from_string(const char *s);
const char *rlimit_to_string(int i) _const_;
int rlimit_from_string(const char *s) _pure_;
int ip_tos_to_string_alloc(int i, char **s);
int ip_tos_from_string(const char *s);
extern int saved_argc; extern int saved_argc;
extern char **saved_argv; extern char **saved_argv;
@@ -484,184 +87,36 @@ bool kexec_loaded(void);
int prot_from_flags(int flags) _const_; int prot_from_flags(int flags) _const_;
char *format_bytes(char *buf, size_t l, uint64_t t);
int fd_wait_for_event(int fd, int event, usec_t timeout);
void* memdup(const void *p, size_t l) _alloc_(2);
int fd_inc_sndbuf(int fd, size_t n);
int fd_inc_rcvbuf(int fd, size_t n);
int fork_agent(pid_t *pid, const int except[], unsigned n_except, const char *path, ...); int fork_agent(pid_t *pid, const int except[], unsigned n_except, const char *path, ...);
int setrlimit_closest(int resource, const struct rlimit *rlim);
bool http_url_is_valid(const char *url) _pure_;
bool documentation_url_is_valid(const char *url) _pure_;
bool http_etag_is_valid(const char *etag);
bool in_initrd(void); bool in_initrd(void);
int get_home_dir(char **ret);
int get_shell(char **_ret);
static inline void freep(void *p) {
free(*(void**) p);
}
static inline void closep(int *fd) {
safe_close(*fd);
}
static inline void umaskp(mode_t *u) {
umask(*u);
}
static inline void close_pairp(int (*p)[2]) {
safe_close_pair(*p);
}
static inline void fclosep(FILE **f) {
safe_fclose(*f);
}
DEFINE_TRIVIAL_CLEANUP_FUNC(FILE*, pclose);
DEFINE_TRIVIAL_CLEANUP_FUNC(DIR*, closedir);
DEFINE_TRIVIAL_CLEANUP_FUNC(FILE*, endmntent);
#define _cleanup_free_ _cleanup_(freep)
#define _cleanup_close_ _cleanup_(closep)
#define _cleanup_umask_ _cleanup_(umaskp)
#define _cleanup_globfree_ _cleanup_(globfree)
#define _cleanup_fclose_ _cleanup_(fclosep)
#define _cleanup_pclose_ _cleanup_(pclosep)
#define _cleanup_closedir_ _cleanup_(closedirp)
#define _cleanup_endmntent_ _cleanup_(endmntentp)
#define _cleanup_close_pair_ _cleanup_(close_pairp)
_malloc_ _alloc_(1, 2) static inline void *malloc_multiply(size_t a, size_t b) {
if (_unlikely_(b != 0 && a > ((size_t) -1) / b))
return NULL;
return malloc(a * b);
}
_alloc_(2, 3) static inline void *realloc_multiply(void *p, size_t a, size_t b) {
if (_unlikely_(b != 0 && a > ((size_t) -1) / b))
return NULL;
return realloc(p, a * b);
}
_alloc_(2, 3) static inline void *memdup_multiply(const void *p, size_t a, size_t b) {
if (_unlikely_(b != 0 && a > ((size_t) -1) / b))
return NULL;
return memdup(p, a * b);
}
bool filename_is_valid(const char *p) _pure_;
bool path_is_safe(const char *p) _pure_;
bool string_is_safe(const char *p) _pure_;
bool string_has_cc(const char *p, const char *ok) _pure_;
/**
* Check if a string contains any glob patterns.
*/
_pure_ static inline bool string_is_glob(const char *p) {
return !!strpbrk(p, GLOB_CHARS);
}
void *xbsearch_r(const void *key, const void *base, size_t nmemb, size_t size, void *xbsearch_r(const void *key, const void *base, size_t nmemb, size_t size,
int (*compar) (const void *, const void *, void *), int (*compar) (const void *, const void *, void *),
void *arg); void *arg);
#if 0 /* NM_IGNORED */ /**
#define _(String) gettext (String) * Normal qsort requires base to be nonnull. Here were require
#define N_(String) String * that only if nmemb > 0.
#endif */
void init_gettext(void); static inline void qsort_safe(void *base, size_t nmemb, size_t size, comparison_fn_t compar) {
bool is_locale_utf8(void); if (nmemb <= 1)
return;
typedef enum DrawSpecialChar { assert(base);
DRAW_TREE_VERTICAL, qsort(base, nmemb, size, compar);
DRAW_TREE_BRANCH, }
DRAW_TREE_RIGHT,
DRAW_TREE_SPACE,
DRAW_TRIANGULAR_BULLET,
DRAW_BLACK_CIRCLE,
DRAW_ARROW,
DRAW_DASH,
_DRAW_SPECIAL_CHAR_MAX
} DrawSpecialChar;
const char *draw_special_char(DrawSpecialChar ch);
char *strreplace(const char *text, const char *old_string, const char *new_string);
char *strip_tab_ansi(char **p, size_t *l);
int on_ac_power(void); int on_ac_power(void);
int search_and_fopen(const char *path, const char *mode, const char *root, const char **search, FILE **_f); #define memzero(x,l) (memset((x), 0, (l)))
int search_and_fopen_nulstr(const char *path, const char *mode, const char *root, const char *search, FILE **_f); #define zero(x) (memzero(&(x), sizeof(x)))
#define FOREACH_LINE(line, f, on_error) \
for (;;) \
if (!fgets(line, sizeof(line), f)) { \
if (ferror(f)) { \
on_error; \
} \
break; \
} else
#define FOREACH_DIRENT(de, d, on_error) \
for (errno = 0, de = readdir(d);; errno = 0, de = readdir(d)) \
if (!de) { \
if (errno > 0) { \
on_error; \
} \
break; \
} else if (hidden_file((de)->d_name)) \
continue; \
else
#define FOREACH_DIRENT_ALL(de, d, on_error) \
for (errno = 0, de = readdir(d);; errno = 0, de = readdir(d)) \
if (!de) { \
if (errno > 0) { \
on_error; \
} \
break; \
} else
static inline void *mempset(void *s, int c, size_t n) { static inline void *mempset(void *s, int c, size_t n) {
memset(s, c, n); memset(s, c, n);
return (uint8_t*)s + n; return (uint8_t*)s + n;
} }
char *hexmem(const void *p, size_t l);
int unhexmem(const char *p, size_t l, void **mem, size_t *len);
char *base32hexmem(const void *p, size_t l, bool padding);
int unbase32hexmem(const char *p, size_t l, bool padding, void **mem, size_t *len);
char *base64mem(const void *p, size_t l);
int unbase64mem(const char *p, size_t l, void **mem, size_t *len);
char *strextend(char **x, ...) _sentinel_;
char *strrep(const char *s, unsigned n);
void* greedy_realloc(void **p, size_t *allocated, size_t need, size_t size);
void* greedy_realloc0(void **p, size_t *allocated, size_t need, size_t size);
#define GREEDY_REALLOC(array, allocated, need) \
greedy_realloc((void**) &(array), &(allocated), (need), sizeof((array)[0]))
#define GREEDY_REALLOC0(array, allocated, need) \
greedy_realloc0((void**) &(array), &(allocated), (need), sizeof((array)[0]))
static inline void _reset_errno_(int *saved_errno) { static inline void _reset_errno_(int *saved_errno) {
errno = *saved_errno; errno = *saved_errno;
} }
@@ -677,20 +132,6 @@ static inline int negative_errno(void) {
return -errno; return -errno;
} }
struct _umask_struct_ {
mode_t mask;
bool quit;
};
static inline void _reset_umask_(struct _umask_struct_ *s) {
umask(s->mask);
};
#define RUN_WITH_UMASK(mask) \
for (_cleanup_(_reset_umask_) struct _umask_struct_ _saved_umask_ = { umask(mask), false }; \
!_saved_umask_.quit ; \
_saved_umask_.quit = true)
static inline unsigned u64log2(uint64_t n) { static inline unsigned u64log2(uint64_t n) {
#if __SIZEOF_LONG_LONG__ == 8 #if __SIZEOF_LONG_LONG__ == 8
return (n > 1) ? (unsigned) __builtin_clzll(n) ^ 63U : 0; return (n > 1) ? (unsigned) __builtin_clzll(n) ^ 63U : 0;
@@ -728,232 +169,15 @@ static inline unsigned log2u_round_up(unsigned x) {
return log2u(x - 1) + 1; return log2u(x - 1) + 1;
} }
static inline bool logind_running(void) {
return access("/run/systemd/seats/", F_OK) >= 0;
}
#define DECIMAL_STR_WIDTH(x) \
({ \
typeof(x) _x_ = (x); \
unsigned ans = 1; \
while (_x_ /= 10) \
ans++; \
ans; \
})
int unlink_noerrno(const char *path);
#define alloca0(n) \
({ \
char *_new_; \
size_t _len_ = n; \
_new_ = alloca(_len_); \
(void *) memset(_new_, 0, _len_); \
})
/* It's not clear what alignment glibc/gcc alloca() guarantee, hence provide a guaranteed safe version */
#define alloca_align(size, align) \
({ \
void *_ptr_; \
size_t _mask_ = (align) - 1; \
_ptr_ = alloca((size) + _mask_); \
(void*)(((uintptr_t)_ptr_ + _mask_) & ~_mask_); \
})
#define alloca0_align(size, align) \
({ \
void *_new_; \
size_t _size_ = (size); \
_new_ = alloca_align(_size_, (align)); \
(void*)memset(_new_, 0, _size_); \
})
#define strjoina(a, ...) \
({ \
const char *_appendees_[] = { a, __VA_ARGS__ }; \
char *_d_, *_p_; \
int _len_ = 0; \
unsigned _i_; \
for (_i_ = 0; _i_ < ELEMENTSOF(_appendees_) && _appendees_[_i_]; _i_++) \
_len_ += strlen(_appendees_[_i_]); \
_p_ = _d_ = alloca(_len_ + 1); \
for (_i_ = 0; _i_ < ELEMENTSOF(_appendees_) && _appendees_[_i_]; _i_++) \
_p_ = stpcpy(_p_, _appendees_[_i_]); \
*_p_ = 0; \
_d_; \
})
bool id128_is_valid(const char *s) _pure_; bool id128_is_valid(const char *s) _pure_;
int split_pair(const char *s, const char *sep, char **l, char **r);
int shall_restore_state(void);
/**
* Normal qsort requires base to be nonnull. Here were require
* that only if nmemb > 0.
*/
static inline void qsort_safe(void *base, size_t nmemb, size_t size, comparison_fn_t compar) {
if (nmemb <= 1)
return;
assert(base);
qsort(base, nmemb, size, compar);
}
/* Normal memmem() requires haystack to be nonnull, which is annoying for zero-length buffers */
static inline void *memmem_safe(const void *haystack, size_t haystacklen, const void *needle, size_t needlelen) {
if (needlelen <= 0)
return (void*) haystack;
if (haystacklen < needlelen)
return NULL;
assert(haystack);
assert(needle);
return memmem(haystack, haystacklen, needle, needlelen);
}
int proc_cmdline(char **ret);
int parse_proc_cmdline(int (*parse_word)(const char *key, const char *value));
int get_proc_cmdline_key(const char *parameter, char **value);
int container_get_leader(const char *machine, pid_t *pid); 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); int namespace_open(pid_t pid, int *pidns_fd, int *mntns_fd, int *netns_fd, int *userns_fd, int *root_fd);
int namespace_enter(int pidns_fd, int mntns_fd, int netns_fd, int userns_fd, int root_fd); int namespace_enter(int pidns_fd, int mntns_fd, int netns_fd, int userns_fd, int root_fd);
#if 0 /* NM_IGNORED */
int getpeercred(int fd, struct ucred *ucred);
int getpeersec(int fd, char **ret);
#endif /* NM_IGNORED */
int writev_safe(int fd, const struct iovec *w, int j);
int mkostemp_safe(char *pattern, int flags);
int open_tmpfile(const char *path, int flags);
int fd_warn_permissions(const char *path, int fd);
#ifndef PERSONALITY_INVALID
/* personality(7) documents that 0xffffffffUL is used for querying the
* current personality, hence let's use that here as error
* indicator. */
#define PERSONALITY_INVALID 0xffffffffLU
#endif
unsigned long personality_from_string(const char *p);
const char *personality_to_string(unsigned long);
uint64_t physical_memory(void); uint64_t physical_memory(void);
void hexdump(FILE *f, const void *p, size_t s);
#if 0 /* NM_IGNORED */
union file_handle_union {
struct file_handle handle;
char padding[sizeof(struct file_handle) + MAX_HANDLE_SZ];
};
#define FILE_HANDLE_INIT { .handle.handle_bytes = MAX_HANDLE_SZ }
#endif /* NM_IGNORED */
int update_reboot_param_file(const char *param); int update_reboot_param_file(const char *param);
int umount_recursive(const char *target, int flags);
int bind_remount_recursive(const char *prefix, bool ro);
int fflush_and_check(FILE *f);
int tempfn_xxxxxx(const char *p, const char *extra, char **ret);
int tempfn_random(const char *p, const char *extra, char **ret);
int tempfn_random_child(const char *p, const char *extra, char **ret);
int take_password_lock(const char *root);
int is_symlink(const char *path);
int is_dir(const char *path, bool follow);
int is_device_node(const char *path);
typedef enum ExtractFlags {
EXTRACT_RELAX = 1,
EXTRACT_CUNESCAPE = 2,
EXTRACT_CUNESCAPE_RELAX = 4,
EXTRACT_QUOTES = 8,
EXTRACT_DONT_COALESCE_SEPARATORS = 16,
} ExtractFlags;
int extract_first_word(const char **p, char **ret, const char *separators, ExtractFlags flags);
int extract_first_word_and_warn(const char **p, char **ret, const char *separators, ExtractFlags flags, const char *unit, const char *filename, unsigned line, const char *rvalue);
int extract_many_words(const char **p, const char *separators, ExtractFlags flags, ...) _sentinel_;
int free_and_strdup(char **p, const char *s);
#define INOTIFY_EVENT_MAX (sizeof(struct inotify_event) + NAME_MAX + 1)
#define FOREACH_INOTIFY_EVENT(e, buffer, sz) \
for ((e) = &buffer.ev; \
(uint8_t*) (e) < (uint8_t*) (buffer.raw) + (sz); \
(e) = (struct inotify_event*) ((uint8_t*) (e) + sizeof(struct inotify_event) + (e)->len))
union inotify_event_buffer {
struct inotify_event ev;
uint8_t raw[INOTIFY_EVENT_MAX];
};
#define laccess(path, mode) faccessat(AT_FDCWD, (path), (mode), AT_SYMLINK_NOFOLLOW)
int ptsname_malloc(int fd, char **ret);
int openpt_in_namespace(pid_t pid, int flags);
ssize_t fgetxattrat_fake(int dirfd, const char *filename, const char *attribute, void *value, size_t size, int flags);
int fd_setcrtime(int fd, usec_t usec);
int fd_getcrtime(int fd, usec_t *usec);
int path_getcrtime(const char *p, usec_t *usec);
int fd_getcrtime_at(int dirfd, const char *name, usec_t *usec, int flags);
int same_fd(int a, int b);
int chattr_fd(int fd, unsigned value, unsigned mask);
int chattr_path(const char *p, unsigned value, unsigned mask);
int read_attr_fd(int fd, unsigned *ret);
int read_attr_path(const char *p, unsigned *ret);
#define RLIMIT_MAKE_CONST(lim) ((struct rlimit) { lim, lim })
ssize_t sparse_write(int fd, const void *p, size_t sz, size_t run_length);
void sigkill_wait(pid_t *pid);
#define _cleanup_sigkill_wait_ _cleanup_(sigkill_wait)
int syslog_parse_priority(const char **p, int *priority, bool with_facility);
void cmsg_close_all(struct msghdr *mh);
int rename_noreplace(int olddirfd, const char *oldpath, int newdirfd, const char *newpath);
char *shell_escape(const char *s, const char *bad);
char *shell_maybe_quote(const char *s);
int parse_mode(const char *s, mode_t *ret);
int mount_move_root(const char *path);
int reset_uid_gid(void);
int getxattr_malloc(const char *path, const char *name, char **value, bool allow_symlink);
int fgetxattr_malloc(int fd, const char *name, char **value);
int send_one_fd(int transport_fd, int fd, int flags);
int receive_one_fd(int transport_fd, int flags);
void nop_signal_handler(int sig);
int version(void); int version(void);
bool fdname_is_valid(const char *s);

View File

@@ -23,8 +23,9 @@
#include <linux/filter.h> #include <linux/filter.h>
#include <arpa/inet.h> #include <arpa/inet.h>
#include "util.h"
#include "arp-util.h" #include "arp-util.h"
#include "fd-util.h"
#include "util.h"
int arp_network_bind_raw_socket(int ifindex, be32_t address, const struct ether_addr *eth_mac) { int arp_network_bind_raw_socket(int ifindex, be32_t address, const struct ether_addr *eth_mac) {
struct sock_filter filter[] = { struct sock_filter filter[] = {

View File

@@ -25,8 +25,8 @@
#include <netinet/if_ether.h> #include <netinet/if_ether.h>
#include "sparse-endian.h"
#include "socket-util.h" #include "socket-util.h"
#include "sparse-endian.h"
int arp_network_bind_raw_socket(int index, be32_t address, const struct ether_addr *eth_mac); int arp_network_bind_raw_socket(int index, be32_t address, const struct ether_addr *eth_mac);

View File

@@ -21,27 +21,29 @@
#include "nm-sd-adapt.h" #include "nm-sd-adapt.h"
#include "sd-id128.h"
#if 0 /* NM_IGNORED */ #if 0 /* NM_IGNORED */
#include "libudev.h" #include "libudev.h"
#include "udev-util.h" #endif /* NM_IGNORED */
#include "sd-id128.h"
#include "virt.h" #include "dhcp-identifier.h"
#include "dhcp6-protocol.h"
#include "network-internal.h"
#include "siphash24.h"
#include "sparse-endian.h" #include "sparse-endian.h"
#if 0 /* NM_IGNORED */
#include "udev-util.h"
#include "virt.h"
#else /* NM_IGNORED */ #else /* NM_IGNORED */
#include <net/if.h> #include <net/if.h>
#endif /* NM_IGNORED */ #endif /* NM_IGNORED */
#include "siphash24.h"
#include "dhcp6-protocol.h"
#include "dhcp-identifier.h"
#include "network-internal.h"
#define SYSTEMD_PEN 43793 #define SYSTEMD_PEN 43793
#define HASH_KEY SD_ID128_MAKE(80,11,8c,c2,fe,4a,03,ee,3e,d6,0c,6f,36,39,14,09) #define HASH_KEY SD_ID128_MAKE(80,11,8c,c2,fe,4a,03,ee,3e,d6,0c,6f,36,39,14,09)
int dhcp_identifier_set_duid_en(struct duid *duid, size_t *len) { int dhcp_identifier_set_duid_en(struct duid *duid, size_t *len) {
sd_id128_t machine_id; sd_id128_t machine_id;
uint64_t hash;
int r; int r;
assert(duid); assert(duid);
@@ -57,13 +59,13 @@ int dhcp_identifier_set_duid_en(struct duid *duid, size_t *len) {
*len = sizeof(duid->type) + sizeof(duid->en); *len = sizeof(duid->type) + sizeof(duid->en);
/* a bit of snake-oil perhaps, but no need to expose the machine-id /* a bit of snake-oil perhaps, but no need to expose the machine-id
directly */ directly; duid->en.id might not be aligned, so we need to copy */
siphash24(duid->en.id, &machine_id, sizeof(machine_id), HASH_KEY.bytes); hash = htole64(siphash24(&machine_id, sizeof(machine_id), HASH_KEY.bytes));
memcpy(duid->en.id, &hash, sizeof(duid->en.id));
return 0; return 0;
} }
int dhcp_identifier_set_iaid(int ifindex, uint8_t *mac, size_t mac_len, void *_id) { int dhcp_identifier_set_iaid(int ifindex, uint8_t *mac, size_t mac_len, void *_id) {
#if 0 /* NM_IGNORED */ #if 0 /* NM_IGNORED */
/* name is a pointer to memory in the udev_device struct, so must /* name is a pointer to memory in the udev_device struct, so must
@@ -100,10 +102,12 @@ int dhcp_identifier_set_iaid(int ifindex, uint8_t *mac, size_t mac_len, void *_i
#endif /* NM_IGNORED */ #endif /* NM_IGNORED */
if (name) if (name)
siphash24((uint8_t*)&id, name, strlen(name), HASH_KEY.bytes); id = siphash24(name, strlen(name), HASH_KEY.bytes);
else else
/* fall back to MAC address if no predictable name available */ /* fall back to MAC address if no predictable name available */
siphash24((uint8_t*)&id, mac, mac_len, HASH_KEY.bytes); id = siphash24(mac, mac_len, HASH_KEY.bytes);
id = htole64(id);
/* fold into 32 bits */ /* fold into 32 bits */
unaligned_write_be32(_id, (id & 0xffffffff) ^ (id >> 32)); unaligned_write_be32(_id, (id & 0xffffffff) ^ (id >> 32));

View File

@@ -23,10 +23,11 @@
#include "nm-sd-adapt.h" #include "nm-sd-adapt.h"
#include "sd-id128.h"
#include "macro.h" #include "macro.h"
#include "sparse-endian.h" #include "sparse-endian.h"
#include "unaligned.h" #include "unaligned.h"
#include "sd-id128.h"
/* RFC 3315 section 9.1: /* RFC 3315 section 9.1:
* A DUID can be no more than 128 octets long (not including the type code). * A DUID can be no more than 128 octets long (not including the type code).

View File

@@ -24,15 +24,15 @@
#include "nm-sd-adapt.h" #include "nm-sd-adapt.h"
#include <stdint.h>
#include <linux/if_packet.h> #include <linux/if_packet.h>
#include <net/if_arp.h>
#include <net/ethernet.h> #include <net/ethernet.h>
#include <net/if_arp.h>
#include "socket-util.h" #include <stdint.h>
#include "sd-dhcp-client.h" #include "sd-dhcp-client.h"
#include "dhcp-protocol.h" #include "dhcp-protocol.h"
#include "socket-util.h"
int dhcp_network_bind_raw_socket(int index, union sockaddr_union *link, int dhcp_network_bind_raw_socket(int index, union sockaddr_union *link,
uint32_t xid, const uint8_t *mac_addr, uint32_t xid, const uint8_t *mac_addr,

View File

@@ -27,12 +27,11 @@
#include <stdint.h> #include <stdint.h>
#include <linux/if_packet.h> #include <linux/if_packet.h>
#include "util.h" #include "sd-dhcp-client.h"
#include "list.h"
#include "dhcp-protocol.h" #include "dhcp-protocol.h"
#include "list.h"
#include "sd-dhcp-client.h" #include "util.h"
struct sd_dhcp_route { struct sd_dhcp_route {
struct in_addr dst_addr; struct in_addr dst_addr;

View File

@@ -20,18 +20,18 @@
#include "nm-sd-adapt.h" #include "nm-sd-adapt.h"
#include <errno.h> #include <errno.h>
#include <sys/socket.h>
#include <string.h>
#include <linux/if_packet.h>
#include <linux/if_infiniband.h>
#include <net/ethernet.h> #include <net/ethernet.h>
#include <net/if_arp.h> #include <net/if_arp.h>
#include <stdio.h> #include <stdio.h>
#include <string.h>
#include <sys/socket.h>
#include <linux/filter.h> #include <linux/filter.h>
#include <linux/if_infiniband.h>
#include "socket-util.h" #include <linux/if_packet.h>
#include "dhcp-internal.h" #include "dhcp-internal.h"
#include "fd-util.h"
#include "socket-util.h"
static int _bind_raw_socket(int ifindex, union sockaddr_union *link, static int _bind_raw_socket(int ifindex, union sockaddr_union *link,
uint32_t xid, const uint8_t *mac_addr, uint32_t xid, const uint8_t *mac_addr,

View File

@@ -21,10 +21,10 @@
#include "nm-sd-adapt.h" #include "nm-sd-adapt.h"
#include <stdint.h>
#include <string.h>
#include <errno.h> #include <errno.h>
#include <stdint.h>
#include <stdio.h> #include <stdio.h>
#include <string.h>
#include "dhcp-internal.h" #include "dhcp-internal.h"

View File

@@ -21,13 +21,12 @@
#include "nm-sd-adapt.h" #include "nm-sd-adapt.h"
#include <errno.h> #include <errno.h>
#include <string.h>
#include <net/ethernet.h> #include <net/ethernet.h>
#include <net/if_arp.h> #include <net/if_arp.h>
#include <string.h>
#include "dhcp-protocol.h"
#include "dhcp-internal.h" #include "dhcp-internal.h"
#include "dhcp-protocol.h"
#define DHCP_CLIENT_MIN_OPTIONS_SIZE 312 #define DHCP_CLIENT_MIN_OPTIONS_SIZE 312

View File

@@ -23,8 +23,8 @@
#include "nm-sd-adapt.h" #include "nm-sd-adapt.h"
#include <netinet/udp.h>
#include <netinet/ip.h> #include <netinet/ip.h>
#include <netinet/udp.h>
#include <stdint.h> #include <stdint.h>
#include "macro.h" #include "macro.h"
@@ -139,6 +139,7 @@ enum {
DHCP_OPTION_REBINDING_T2_TIME = 59, DHCP_OPTION_REBINDING_T2_TIME = 59,
DHCP_OPTION_VENDOR_CLASS_IDENTIFIER = 60, DHCP_OPTION_VENDOR_CLASS_IDENTIFIER = 60,
DHCP_OPTION_CLIENT_IDENTIFIER = 61, DHCP_OPTION_CLIENT_IDENTIFIER = 61,
DHCP_OPTION_FQDN = 81,
DHCP_OPTION_NEW_POSIX_TIMEZONE = 100, DHCP_OPTION_NEW_POSIX_TIMEZONE = 100,
DHCP_OPTION_NEW_TZDB_TIMEZONE = 101, DHCP_OPTION_NEW_TZDB_TIMEZONE = 101,
DHCP_OPTION_CLASSLESS_STATIC_ROUTE = 121, DHCP_OPTION_CLASSLESS_STATIC_ROUTE = 121,
@@ -146,3 +147,12 @@ enum {
DHCP_OPTION_PRIVATE_LAST = 254, DHCP_OPTION_PRIVATE_LAST = 254,
DHCP_OPTION_END = 255, DHCP_OPTION_END = 255,
}; };
#define DHCP_MAX_FQDN_LENGTH 255
enum {
DHCP_FQDN_FLAG_S = (1 << 0),
DHCP_FQDN_FLAG_O = (1 << 1),
DHCP_FQDN_FLAG_E = (1 << 2),
DHCP_FQDN_FLAG_N = (1 << 3),
};

View File

@@ -26,10 +26,11 @@
#include <net/ethernet.h> #include <net/ethernet.h>
#include <netinet/in.h> #include <netinet/in.h>
#include "sparse-endian.h"
#include "sd-event.h" #include "sd-event.h"
#include "list.h" #include "list.h"
#include "macro.h" #include "macro.h"
#include "sparse-endian.h"
typedef struct DHCP6Address DHCP6Address; typedef struct DHCP6Address DHCP6Address;
@@ -60,9 +61,6 @@ typedef struct DHCP6IA DHCP6IA;
#define log_dhcp6_client(p, fmt, ...) log_internal(LOG_DEBUG, 0, __FILE__, __LINE__, __func__, "DHCPv6 CLIENT: " fmt, ##__VA_ARGS__) #define log_dhcp6_client(p, fmt, ...) log_internal(LOG_DEBUG, 0, __FILE__, __LINE__, __func__, "DHCPv6 CLIENT: " fmt, ##__VA_ARGS__)
int dhcp_network_icmp6_bind_router_solicitation(int index);
int dhcp_network_icmp6_send_router_solicitation(int s, const struct ether_addr *ether_addr);
int dhcp6_option_append(uint8_t **buf, size_t *buflen, uint16_t code, int dhcp6_option_append(uint8_t **buf, size_t *buflen, uint16_t code,
size_t optlen, const void *optval); size_t optlen, const void *optval);
int dhcp6_option_append_ia(uint8_t **buf, size_t *buflen, DHCP6IA *ia); int dhcp6_option_append_ia(uint8_t **buf, size_t *buflen, DHCP6IA *ia);

View File

@@ -27,6 +27,7 @@
#include <stdint.h> #include <stdint.h>
#include "sd-dhcp6-lease.h" #include "sd-dhcp6-lease.h"
#include "dhcp6-internal.h" #include "dhcp6-internal.h"
struct sd_dhcp6_lease { struct sd_dhcp6_lease {

View File

@@ -20,143 +20,38 @@
#include "nm-sd-adapt.h" #include "nm-sd-adapt.h"
#include <errno.h> #include <errno.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <string.h>
#include <linux/if_packet.h>
#include <stdio.h>
#include <unistd.h>
#include <netinet/ip6.h>
#include <netinet/icmp6.h>
#include <netinet/in.h> #include <netinet/in.h>
#include <netinet/ip6.h>
#include "socket-util.h" #include <stdio.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <unistd.h>
#include <linux/if_packet.h>
#include "dhcp6-internal.h" #include "dhcp6-internal.h"
#include "dhcp6-protocol.h" #include "dhcp6-protocol.h"
#include "fd-util.h"
#define IN6ADDR_ALL_ROUTERS_MULTICAST_INIT \ #include "socket-util.h"
{ { { 0xff, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02 } } }
#define IN6ADDR_ALL_NODES_MULTICAST_INIT \
{ { { 0xff, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 } } }
int dhcp_network_icmp6_bind_router_solicitation(int index) {
struct icmp6_filter filter = { };
struct ipv6_mreq mreq = {
.ipv6mr_multiaddr = IN6ADDR_ALL_NODES_MULTICAST_INIT,
.ipv6mr_interface = index,
};
_cleanup_close_ int s = -1;
int r, zero = 0, hops = 255;
s = socket(AF_INET6, SOCK_RAW | SOCK_CLOEXEC | SOCK_NONBLOCK,
IPPROTO_ICMPV6);
if (s < 0)
return -errno;
ICMP6_FILTER_SETBLOCKALL(&filter);
ICMP6_FILTER_SETPASS(ND_ROUTER_ADVERT, &filter);
r = setsockopt(s, IPPROTO_ICMPV6, ICMP6_FILTER, &filter,
sizeof(filter));
if (r < 0)
return -errno;
/* RFC 3315, section 6.7, bullet point 2 may indicate that an
IPV6_PKTINFO socket option also applies for ICMPv6 multicast.
Empirical experiments indicates otherwise and therefore an
IPV6_MULTICAST_IF socket option is used here instead */
r = setsockopt(s, IPPROTO_IPV6, IPV6_MULTICAST_IF, &index,
sizeof(index));
if (r < 0)
return -errno;
r = setsockopt(s, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, &zero,
sizeof(zero));
if (r < 0)
return -errno;
r = setsockopt(s, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &hops,
sizeof(hops));
if (r < 0)
return -errno;
r = setsockopt(s, IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP, &mreq,
sizeof(mreq));
if (r < 0)
return -errno;
r = s;
s = -1;
return r;
}
int dhcp_network_icmp6_send_router_solicitation(int s, const struct ether_addr *ether_addr) {
struct sockaddr_in6 dst = {
.sin6_family = AF_INET6,
.sin6_addr = IN6ADDR_ALL_ROUTERS_MULTICAST_INIT,
};
struct {
struct nd_router_solicit rs;
struct nd_opt_hdr rs_opt;
struct ether_addr rs_opt_mac;
} _packed_ rs = {
.rs.nd_rs_type = ND_ROUTER_SOLICIT,
};
struct iovec iov[1] = {
{ &rs, },
};
struct msghdr msg = {
.msg_name = &dst,
.msg_namelen = sizeof(dst),
.msg_iov = iov,
.msg_iovlen = 1,
};
int r;
if (ether_addr) {
memcpy(&rs.rs_opt_mac, ether_addr, ETH_ALEN);
rs.rs_opt.nd_opt_type = ND_OPT_SOURCE_LINKADDR;
rs.rs_opt.nd_opt_len = 1;
iov[0].iov_len = sizeof(rs);
} else
iov[0].iov_len = sizeof(rs.rs);
r = sendmsg(s, &msg, 0);
if (r < 0)
return -errno;
return 0;
}
int dhcp6_network_bind_udp_socket(int index, struct in6_addr *local_address) { int dhcp6_network_bind_udp_socket(int index, struct in6_addr *local_address) {
struct in6_pktinfo pktinfo = {
.ipi6_ifindex = index,
};
union sockaddr_union src = { union sockaddr_union src = {
.in6.sin6_family = AF_INET6, .in6.sin6_family = AF_INET6,
.in6.sin6_port = htobe16(DHCP6_PORT_CLIENT), .in6.sin6_port = htobe16(DHCP6_PORT_CLIENT),
.in6.sin6_addr = IN6ADDR_ANY_INIT, .in6.sin6_scope_id = index,
}; };
_cleanup_close_ int s = -1; _cleanup_close_ int s = -1;
int r, off = 0, on = 1; int r, off = 0, on = 1;
if (local_address) assert(index > 0);
memcpy(&src.in6.sin6_addr, local_address, assert(local_address);
sizeof(src.in6.sin6_addr));
s = socket(AF_INET6, SOCK_DGRAM | SOCK_CLOEXEC | SOCK_NONBLOCK, src.in6.sin6_addr = *local_address;
IPPROTO_UDP);
s = socket(AF_INET6, SOCK_DGRAM | SOCK_CLOEXEC | SOCK_NONBLOCK, IPPROTO_UDP);
if (s < 0) if (s < 0)
return -errno; return -errno;
r = setsockopt(s, IPPROTO_IPV6, IPV6_PKTINFO, &pktinfo,
sizeof(pktinfo));
if (r < 0)
return -errno;
r = setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof(on)); r = setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof(on));
if (r < 0) if (r < 0)
return -errno; return -errno;
@@ -165,6 +60,10 @@ int dhcp6_network_bind_udp_socket(int index, struct in6_addr *local_address) {
if (r < 0) if (r < 0)
return -errno; return -errno;
r = setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
if (r < 0)
return -errno;
r = bind(s, &src.sa, sizeof(src.in6)); r = bind(s, &src.sa, sizeof(src.in6));
if (r < 0) if (r < 0)
return -errno; return -errno;

View File

@@ -21,18 +21,18 @@
#include "nm-sd-adapt.h" #include "nm-sd-adapt.h"
#include <netinet/in.h>
#include <errno.h> #include <errno.h>
#include <netinet/in.h>
#include <string.h> #include <string.h>
#include "sparse-endian.h" #include "alloc-util.h"
#include "unaligned.h"
#include "util.h"
#include "strv.h"
#include "dhcp6-internal.h" #include "dhcp6-internal.h"
#include "dhcp6-protocol.h" #include "dhcp6-protocol.h"
#include "dns-domain.h" #include "dns-domain.h"
#include "sparse-endian.h"
#include "strv.h"
#include "unaligned.h"
#include "util.h"
#define DHCP6_OPTION_IA_NA_LEN 12 #define DHCP6_OPTION_IA_NA_LEN 12
#define DHCP6_OPTION_IA_TA_LEN 4 #define DHCP6_OPTION_IA_TA_LEN 4
@@ -346,7 +346,7 @@ int dhcp6_option_parse_domainname(const uint8_t *optval, uint16_t optlen, char *
int r; int r;
assert_return(optlen > 1, -ENODATA); assert_return(optlen > 1, -ENODATA);
assert_return(optval[optlen] == '\0', -EINVAL); assert_return(optval[optlen - 1] == '\0', -EINVAL);
while (pos < optlen) { while (pos < optlen) {
_cleanup_free_ char *ret = NULL; _cleanup_free_ char *ret = NULL;

View File

@@ -22,9 +22,11 @@
#include "nm-sd-adapt.h" #include "nm-sd-adapt.h"
#include "lldp-internal.h"
#include "sd-lldp.h" #include "sd-lldp.h"
#include "alloc-util.h"
#include "lldp-internal.h"
/* We store maximum 1K chassis entries */ /* We store maximum 1K chassis entries */
#define LLDP_MIB_MAX_CHASSIS 1024 #define LLDP_MIB_MAX_CHASSIS 1024

View File

@@ -24,11 +24,12 @@
#include "nm-sd-adapt.h" #include "nm-sd-adapt.h"
#include "log.h" #include "sd-event.h"
#include "list.h" #include "list.h"
#include "lldp-tlv.h" #include "lldp-tlv.h"
#include "log.h"
#include "prioq.h" #include "prioq.h"
#include "sd-event.h"
typedef struct lldp_neighbour_port lldp_neighbour_port; typedef struct lldp_neighbour_port lldp_neighbour_port;
typedef struct lldp_chassis lldp_chassis; typedef struct lldp_chassis lldp_chassis;

View File

@@ -25,10 +25,11 @@
#include <linux/filter.h> #include <linux/filter.h>
#include <linux/if_ether.h> #include <linux/if_ether.h>
#include "socket-util.h" #include "fd-util.h"
#include "lldp-tlv.h"
#include "lldp-network.h"
#include "lldp-internal.h" #include "lldp-internal.h"
#include "lldp-network.h"
#include "lldp-tlv.h"
#include "socket-util.h"
int lldp_network_bind_raw_socket(int ifindex) { int lldp_network_bind_raw_socket(int ifindex) {
typedef struct LLDPFrame { typedef struct LLDPFrame {

View File

@@ -22,10 +22,11 @@
#include "nm-sd-adapt.h" #include "nm-sd-adapt.h"
#include "alloc-util.h"
#include "async.h" #include "async.h"
#include "lldp-port.h"
#include "lldp-network.h"
#include "lldp-internal.h" #include "lldp-internal.h"
#include "lldp-network.h"
#include "lldp-port.h"
int lldp_port_start(lldp_port *p) { int lldp_port_start(lldp_port *p) {
int r; int r;

View File

@@ -22,11 +22,12 @@
#include "nm-sd-adapt.h" #include "nm-sd-adapt.h"
#include <net/ethernet.h>
#include <arpa/inet.h> #include <arpa/inet.h>
#include <net/ethernet.h>
#include "macro.h" #include "alloc-util.h"
#include "lldp-tlv.h" #include "lldp-tlv.h"
#include "macro.h"
int tlv_section_new(tlv_section **ret) { int tlv_section_new(tlv_section **ret) {
tlv_section *s; tlv_section *s;
@@ -279,7 +280,7 @@ int tlv_packet_parse_pdu(tlv_packet *m, uint16_t size) {
p = m->pdu; p = m->pdu;
/* extract ethernet header */ /* extract Ethernet header */
memcpy(&m->mac, p, ETH_ALEN); memcpy(&m->mac, p, ETH_ALEN);
p += sizeof(struct ether_header); p += sizeof(struct ether_header);

View File

@@ -26,18 +26,18 @@
#include <net/ethernet.h> #include <net/ethernet.h>
#include "util.h"
#include "lldp.h"
#include "list.h"
#include "sd-lldp.h" #include "sd-lldp.h"
typedef struct tlv_packet tlv_packet; #include "list.h"
typedef struct tlv_section tlv_section; #include "lldp.h"
#include "util.h"
typedef struct sd_lldp_packet tlv_packet;
typedef struct sd_lldp_section tlv_section;
#define LLDP_OUI_LEN 3 #define LLDP_OUI_LEN 3
struct tlv_section { struct sd_lldp_section {
uint16_t type; uint16_t type;
uint16_t length; uint16_t length;
uint8_t *oui; uint8_t *oui;
@@ -56,7 +56,7 @@ struct tlv_section {
int tlv_section_new(tlv_section **ret); int tlv_section_new(tlv_section **ret);
void tlv_section_free(tlv_section *ret); void tlv_section_free(tlv_section *ret);
struct tlv_packet { struct sd_lldp_packet {
unsigned n_ref; unsigned n_ref;
uint16_t type; uint16_t type;

View File

@@ -21,26 +21,27 @@
#include "nm-sd-adapt.h" #include "nm-sd-adapt.h"
#include <netinet/ether.h>
#include <linux/if.h>
#include <arpa/inet.h> #include <arpa/inet.h>
#include <linux/if.h>
#include <netinet/ether.h>
#include "sd-ndisc.h"
#include "alloc-util.h"
#if 0 /* NM_IGNORED */ #if 0 /* NM_IGNORED */
#include "strv.h" #include "condition.h"
#include "siphash24.h" #include "conf-parser.h"
#endif /* NM_IGNORED */ #endif /* NM_IGNORED */
#include "dhcp-lease-internal.h" #include "dhcp-lease-internal.h"
#if 0 /* NM_IGNORED */ #include "hexdecoct.h"
#include "log.h" #include "log.h"
#include "utf8.h"
#endif /* NM_IGNORED */
#include "util.h"
#if 0 /* NM_IGNORED */
#include "conf-parser.h"
#include "condition.h"
#endif /* NM_IGNORED */
#include "network-internal.h" #include "network-internal.h"
#include "sd-icmp6-nd.h" #include "parse-util.h"
#include "siphash24.h"
#include "string-util.h"
#include "strv.h"
#include "utf8.h"
#include "util.h"
#if 0 /* NM_IGNORED */ #if 0 /* NM_IGNORED */
const char *net_get_name(struct udev_device *device) { const char *net_get_name(struct udev_device *device) {
@@ -60,7 +61,7 @@ const char *net_get_name(struct udev_device *device) {
#define HASH_KEY SD_ID128_MAKE(d3,1e,48,fa,90,fe,4b,4c,9d,af,d5,d7,a1,b1,2e,8a) #define HASH_KEY SD_ID128_MAKE(d3,1e,48,fa,90,fe,4b,4c,9d,af,d5,d7,a1,b1,2e,8a)
int net_get_unique_predictable_data(struct udev_device *device, uint8_t result[8]) { int net_get_unique_predictable_data(struct udev_device *device, uint64_t *result) {
size_t l, sz = 0; size_t l, sz = 0;
const char *name = NULL; const char *name = NULL;
int r; int r;
@@ -85,7 +86,7 @@ int net_get_unique_predictable_data(struct udev_device *device, uint8_t result[8
/* Let's hash the machine ID plus the device name. We /* Let's hash the machine ID plus the device name. We
* use a fixed, but originally randomly created hash * use a fixed, but originally randomly created hash
* key here. */ * key here. */
siphash24(result, v, sz, HASH_KEY.bytes); *result = htole64(siphash24(v, sz, HASH_KEY.bytes));
return 0; return 0;
} }
@@ -400,8 +401,8 @@ void serialize_in6_addrs(FILE *f, const struct in6_addr *addresses,
assert(size); assert(size);
for (i = 0; i < size; i++) for (i = 0; i < size; i++)
fprintf(f, SD_ICMP6_ND_ADDRESS_FORMAT_STR"%s", fprintf(f, SD_NDISC_ADDRESS_FORMAT_STR"%s",
SD_ICMP6_ND_ADDRESS_FORMAT_VAL(addresses[i]), SD_NDISC_ADDRESS_FORMAT_VAL(addresses[i]),
(i < (size - 1)) ? " ": ""); (i < (size - 1)) ? " ": "");
} }

View File

@@ -26,8 +26,8 @@
#include <stdbool.h> #include <stdbool.h>
#if 0 /* NM_IGNORED */ #if 0 /* NM_IGNORED */
#include "udev.h"
#include "condition.h" #include "condition.h"
#include "udev.h"
bool net_match_config(const struct ether_addr *match_mac, bool net_match_config(const struct ether_addr *match_mac,
char * const *match_path, char * const *match_path,
@@ -65,7 +65,7 @@ int config_parse_ifalias(const char *unit, const char *filename, unsigned line,
const char *section, unsigned section_line, const char *lvalue, const char *section, unsigned section_line, const char *lvalue,
int ltype, const char *rvalue, void *data, void *userdata); int ltype, const char *rvalue, void *data, void *userdata);
int net_get_unique_predictable_data(struct udev_device *device, uint8_t result[8]); int net_get_unique_predictable_data(struct udev_device *device, uint64_t *result);
const char *net_get_name(struct udev_device *device); const char *net_get_name(struct udev_device *device);
#endif /* NM_IGNORED */ #endif /* NM_IGNORED */

View File

@@ -19,24 +19,28 @@
#include "nm-sd-adapt.h" #include "nm-sd-adapt.h"
#include <stdlib.h>
#include <errno.h> #include <errno.h>
#include <string.h>
#include <stdio.h>
#include <net/ethernet.h> #include <net/ethernet.h>
#include <net/if_arp.h> #include <net/if_arp.h>
#include <linux/if_infiniband.h> #include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/ioctl.h> #include <sys/ioctl.h>
#include <linux/if_infiniband.h>
#include "util.h" #include "sd-dhcp-client.h"
#include "random-util.h"
#include "alloc-util.h"
#include "async.h" #include "async.h"
#include "dhcp-identifier.h"
#include "dhcp-protocol.h"
#include "dhcp-internal.h" #include "dhcp-internal.h"
#include "dhcp-lease-internal.h" #include "dhcp-lease-internal.h"
#include "dhcp-identifier.h" #include "dhcp-protocol.h"
#include "sd-dhcp-client.h" #include "dns-domain.h"
#include "hostname-util.h"
#include "random-util.h"
#include "string-util.h"
#include "util.h"
#define MAX_CLIENT_ID_LEN (sizeof(uint32_t) + MAX_DUID_LEN) /* Arbitrary limit */ #define MAX_CLIENT_ID_LEN (sizeof(uint32_t) + MAX_DUID_LEN) /* Arbitrary limit */
#define MAX_MAC_ADDR_LEN CONST_MAX(INFINIBAND_ALEN, ETH_ALEN) #define MAX_MAC_ADDR_LEN CONST_MAX(INFINIBAND_ALEN, ETH_ALEN)
@@ -298,6 +302,9 @@ int sd_dhcp_client_set_hostname(sd_dhcp_client *client,
assert_return(client, -EINVAL); assert_return(client, -EINVAL);
if (!hostname_is_valid(hostname, false) && !dns_name_is_valid(hostname))
return -EINVAL;
if (streq_ptr(client->hostname, hostname)) if (streq_ptr(client->hostname, hostname))
return 0; return 0;
@@ -539,6 +546,24 @@ static int client_message_init(sd_dhcp_client *client, DHCPPacket **ret,
return 0; return 0;
} }
static int client_append_fqdn_option(DHCPMessage *message, size_t optlen, size_t *optoffset,
const char *fqdn) {
uint8_t buffer[3 + DHCP_MAX_FQDN_LENGTH];
int r;
buffer[0] = DHCP_FQDN_FLAG_S | /* Request server to perform A RR DNS updates */
DHCP_FQDN_FLAG_E; /* Canonical wire format */
buffer[1] = 0; /* RCODE1 (deprecated) */
buffer[2] = 0; /* RCODE2 (deprecated) */
r = dns_name_to_wire_format(fqdn, buffer + 3, sizeof(buffer) - 3);
if (r > 0)
r = dhcp_option_append(message, optlen, optoffset, 0,
DHCP_OPTION_FQDN, 3 + r, buffer);
return r;
}
static int dhcp_client_send_raw(sd_dhcp_client *client, DHCPPacket *packet, static int dhcp_client_send_raw(sd_dhcp_client *client, DHCPPacket *packet,
size_t len) { size_t len) {
dhcp_packet_append_ip_headers(packet, INADDR_ANY, DHCP_PORT_CLIENT, dhcp_packet_append_ip_headers(packet, INADDR_ANY, DHCP_PORT_CLIENT,
@@ -576,13 +601,21 @@ static int client_send_discover(sd_dhcp_client *client) {
return r; return r;
} }
if (client->hostname) {
/* According to RFC 4702 "clients that send the Client FQDN option in
their messages MUST NOT also send the Host Name option". Just send
one of the two depending on the hostname type.
*/
if (dns_name_single_label(client->hostname)) {
/* it is unclear from RFC 2131 if client should send hostname in /* it is unclear from RFC 2131 if client should send hostname in
DHCPDISCOVER but dhclient does and so we do as well DHCPDISCOVER but dhclient does and so we do as well
*/ */
if (client->hostname) {
r = dhcp_option_append(&discover->dhcp, optlen, &optoffset, 0, r = dhcp_option_append(&discover->dhcp, optlen, &optoffset, 0,
DHCP_OPTION_HOST_NAME, DHCP_OPTION_HOST_NAME,
strlen(client->hostname), client->hostname); strlen(client->hostname), client->hostname);
} else
r = client_append_fqdn_option(&discover->dhcp, optlen, &optoffset,
client->hostname);
if (r < 0) if (r < 0)
return r; return r;
} }
@@ -688,9 +721,13 @@ static int client_send_request(sd_dhcp_client *client) {
} }
if (client->hostname) { if (client->hostname) {
if (dns_name_single_label(client->hostname))
r = dhcp_option_append(&request->dhcp, optlen, &optoffset, 0, r = dhcp_option_append(&request->dhcp, optlen, &optoffset, 0,
DHCP_OPTION_HOST_NAME, DHCP_OPTION_HOST_NAME,
strlen(client->hostname), client->hostname); strlen(client->hostname), client->hostname);
else
r = client_append_fqdn_option(&request->dhcp, optlen, &optoffset,
client->hostname);
if (r < 0) if (r < 0)
return r; return r;
} }
@@ -1267,8 +1304,7 @@ static int client_set_lease_timeouts(sd_dhcp_client *client) {
return r; return r;
log_dhcp_client(client, "lease expires in %s", log_dhcp_client(client, "lease expires in %s",
format_timespan(time_string, FORMAT_TIMESPAN_MAX, format_timespan(time_string, FORMAT_TIMESPAN_MAX, lifetime_timeout - time_now, USEC_PER_SEC));
lifetime_timeout - time_now, 0));
/* don't arm earlier timeouts if this has already expired */ /* don't arm earlier timeouts if this has already expired */
if (lifetime_timeout <= time_now) if (lifetime_timeout <= time_now)
@@ -1294,8 +1330,7 @@ static int client_set_lease_timeouts(sd_dhcp_client *client) {
return r; return r;
log_dhcp_client(client, "T2 expires in %s", log_dhcp_client(client, "T2 expires in %s",
format_timespan(time_string, FORMAT_TIMESPAN_MAX, format_timespan(time_string, FORMAT_TIMESPAN_MAX, t2_timeout - time_now, USEC_PER_SEC));
t2_timeout - time_now, 0));
/* don't arm earlier timeout if this has already expired */ /* don't arm earlier timeout if this has already expired */
if (t2_timeout <= time_now) if (t2_timeout <= time_now)
@@ -1320,8 +1355,7 @@ static int client_set_lease_timeouts(sd_dhcp_client *client) {
return r; return r;
log_dhcp_client(client, "T1 expires in %s", log_dhcp_client(client, "T1 expires in %s",
format_timespan(time_string, FORMAT_TIMESPAN_MAX, format_timespan(time_string, FORMAT_TIMESPAN_MAX, t1_timeout - time_now, USEC_PER_SEC));
t1_timeout - time_now, 0));
return 0; return 0;
} }
@@ -1520,7 +1554,7 @@ static int client_receive_message_udp(sd_event_source *s, int fd,
expected_hlen = ETH_ALEN; expected_hlen = ETH_ALEN;
expected_chaddr = (const struct ether_addr *) &client->mac_addr; expected_chaddr = (const struct ether_addr *) &client->mac_addr;
} else { } else {
/* Non-ethernet links expect zero chaddr */ /* Non-Ethernet links expect zero chaddr */
expected_hlen = 0; expected_hlen = 0;
expected_chaddr = &zero_mac; expected_chaddr = &zero_mac;
} }

View File

@@ -20,22 +20,28 @@
#include "nm-sd-adapt.h" #include "nm-sd-adapt.h"
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <stdio.h>
#include <arpa/inet.h> #include <arpa/inet.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "fileio.h"
#include "unaligned.h"
#include "in-addr-util.h"
#include "hostname-util.h"
#include "dns-domain.h"
#include "network-internal.h"
#include "dhcp-protocol.h"
#include "dhcp-lease-internal.h"
#include "sd-dhcp-lease.h" #include "sd-dhcp-lease.h"
#include "alloc-util.h"
#include "dhcp-lease-internal.h"
#include "dhcp-protocol.h"
#include "dns-domain.h"
#include "fd-util.h"
#include "fileio.h"
#include "hexdecoct.h"
#include "hostname-util.h"
#include "in-addr-util.h"
#include "network-internal.h"
#include "parse-util.h"
#include "string-util.h"
#include "unaligned.h"
int sd_dhcp_lease_get_address(sd_dhcp_lease *lease, struct in_addr *addr) { int sd_dhcp_lease_get_address(sd_dhcp_lease *lease, struct in_addr *addr) {
assert_return(lease, -EINVAL); assert_return(lease, -EINVAL);
assert_return(addr, -EINVAL); assert_return(addr, -EINVAL);
@@ -947,19 +953,19 @@ int dhcp_lease_load(sd_dhcp_lease **ret, const char *lease_file) {
if (address) { if (address) {
r = inet_pton(AF_INET, address, &lease->address); r = inet_pton(AF_INET, address, &lease->address);
if (r <= 0) if (r <= 0)
log_debug_errno(errno, "Failed to parse address %s, ignoring: %m", address); log_debug("Failed to parse address %s, ignoring.", address);
} }
if (router) { if (router) {
r = inet_pton(AF_INET, router, &lease->router); r = inet_pton(AF_INET, router, &lease->router);
if (r <= 0) if (r <= 0)
log_debug_errno(errno, "Failed to parse router %s, ignoring: %m", router); log_debug("Failed to parse router %s, ignoring.", router);
} }
if (netmask) { if (netmask) {
r = inet_pton(AF_INET, netmask, &lease->subnet_mask); r = inet_pton(AF_INET, netmask, &lease->subnet_mask);
if (r <= 0) if (r <= 0)
log_debug_errno(errno, "Failed to parse netmask %s, ignoring: %m", netmask); log_debug("Failed to parse netmask %s, ignoring.", netmask);
else else
lease->have_subnet_mask = true; lease->have_subnet_mask = true;
} }
@@ -967,19 +973,19 @@ int dhcp_lease_load(sd_dhcp_lease **ret, const char *lease_file) {
if (server_address) { if (server_address) {
r = inet_pton(AF_INET, server_address, &lease->server_address); r = inet_pton(AF_INET, server_address, &lease->server_address);
if (r <= 0) if (r <= 0)
log_debug_errno(errno, "Failed to parse netmask %s, ignoring: %m", server_address); log_debug("Failed to parse server address %s, ignoring.", server_address);
} }
if (next_server) { if (next_server) {
r = inet_pton(AF_INET, next_server, &lease->next_server); r = inet_pton(AF_INET, next_server, &lease->next_server);
if (r <= 0) if (r <= 0)
log_debug_errno(errno, "Failed to parse next server %s, ignoring: %m", next_server); log_debug("Failed to parse next server %s, ignoring.", next_server);
} }
if (broadcast) { if (broadcast) {
r = inet_pton(AF_INET, broadcast, &lease->broadcast); r = inet_pton(AF_INET, broadcast, &lease->broadcast);
if (r <= 0) if (r <= 0)
log_debug_errno(errno, "Failed to parse broadcast address %s, ignoring: %m", broadcast); log_debug("Failed to parse broadcast address %s, ignoring.", broadcast);
else else
lease->have_broadcast = true; lease->have_broadcast = true;
} }

View File

@@ -26,19 +26,19 @@
#include <sys/ioctl.h> #include <sys/ioctl.h>
#include <linux/if_infiniband.h> #include <linux/if_infiniband.h>
#if 0 /* NM_IGNORED */
#include "udev.h"
#include "udev-util.h"
#endif /* NM_IGNORED */
#include "util.h"
#include "random-util.h"
#include "network-internal.h"
#include "sd-dhcp6-client.h" #include "sd-dhcp6-client.h"
#include "dhcp6-protocol.h"
#include "alloc-util.h"
#include "dhcp-identifier.h"
#include "dhcp6-internal.h" #include "dhcp6-internal.h"
#include "dhcp6-lease-internal.h" #include "dhcp6-lease-internal.h"
#include "dhcp-identifier.h" #include "dhcp6-protocol.h"
#include "fd-util.h"
#include "in-addr-util.h"
#include "network-internal.h"
#include "random-util.h"
#include "string-table.h"
#include "util.h"
#define MAX_MAC_ADDR_LEN INFINIBAND_ALEN #define MAX_MAC_ADDR_LEN INFINIBAND_ALEN
@@ -49,6 +49,7 @@ struct sd_dhcp6_client {
sd_event *event; sd_event *event;
int event_priority; int event_priority;
int index; int index;
struct in6_addr local_address;
uint8_t mac_addr[MAX_MAC_ADDR_LEN]; uint8_t mac_addr[MAX_MAC_ADDR_LEN];
size_t mac_addr_len; size_t mac_addr_len;
uint16_t arp_type; uint16_t arp_type;
@@ -136,6 +137,18 @@ int sd_dhcp6_client_set_index(sd_dhcp6_client *client, int interface_index) {
return 0; return 0;
} }
int sd_dhcp6_client_set_local_address(sd_dhcp6_client *client, const struct in6_addr *local_address) {
assert_return(client, -EINVAL);
assert_return(local_address, -EINVAL);
assert_return(in_addr_is_link_local(AF_INET6, (const union in_addr_union *) local_address) > 0, -EINVAL);
assert_return(IN_SET(client->state, DHCP6_STATE_STOPPED), -EBUSY);
client->local_address = *local_address;
return 0;
}
int sd_dhcp6_client_set_mac( int sd_dhcp6_client_set_mac(
sd_dhcp6_client *client, sd_dhcp6_client *client,
const uint8_t *addr, size_t addr_len, const uint8_t *addr, size_t addr_len,
@@ -212,9 +225,8 @@ int sd_dhcp6_client_set_duid(
return 0; return 0;
} }
int sd_dhcp6_client_set_information_request(sd_dhcp6_client *client, bool enabled) { int sd_dhcp6_client_set_information_request(sd_dhcp6_client *client, int enabled) {
assert_return(client, -EINVAL); assert_return(client, -EINVAL);
assert_return(IN_SET(client->state, DHCP6_STATE_STOPPED), -EBUSY); assert_return(IN_SET(client->state, DHCP6_STATE_STOPPED), -EBUSY);
client->information_request = enabled; client->information_request = enabled;
@@ -222,7 +234,7 @@ int sd_dhcp6_client_set_information_request(sd_dhcp6_client *client, bool enable
return 0; return 0;
} }
int sd_dhcp6_client_get_information_request(sd_dhcp6_client *client, bool *enabled) { int sd_dhcp6_client_get_information_request(sd_dhcp6_client *client, int *enabled) {
assert_return(client, -EINVAL); assert_return(client, -EINVAL);
assert_return(enabled, -EINVAL); assert_return(enabled, -EINVAL);
@@ -263,11 +275,11 @@ int sd_dhcp6_client_set_request_option(sd_dhcp6_client *client, uint16_t option)
int sd_dhcp6_client_get_lease(sd_dhcp6_client *client, sd_dhcp6_lease **ret) { int sd_dhcp6_client_get_lease(sd_dhcp6_client *client, sd_dhcp6_lease **ret) {
assert_return(client, -EINVAL); assert_return(client, -EINVAL);
assert_return(ret, -EINVAL);
if (!client->lease) if (!client->lease)
return -ENOMSG; return -ENOMSG;
if (ret)
*ret = client->lease; *ret = client->lease;
return 0; return 0;
@@ -599,8 +611,7 @@ static int client_timeout_resend(sd_event_source *s, uint64_t usec,
} }
log_dhcp6_client(client, "Next retransmission in %s", log_dhcp6_client(client, "Next retransmission in %s",
format_timespan(time_string, FORMAT_TIMESPAN_MAX, format_timespan(time_string, FORMAT_TIMESPAN_MAX, client->retransmit_time, USEC_PER_SEC));
client->retransmit_time, 0));
r = sd_event_add_time(client->event, &client->timeout_resend, r = sd_event_add_time(client->event, &client->timeout_resend,
clock_boottime_or_monotonic(), clock_boottime_or_monotonic(),
@@ -1052,9 +1063,7 @@ static int client_start(sd_dhcp6_client *client, enum DHCP6State state) {
timeout = client_timeout_compute_random(be32toh(client->lease->ia.lifetime_t1) * USEC_PER_SEC); timeout = client_timeout_compute_random(be32toh(client->lease->ia.lifetime_t1) * USEC_PER_SEC);
log_dhcp6_client(client, "T1 expires in %s", log_dhcp6_client(client, "T1 expires in %s",
format_timespan(time_string, format_timespan(time_string, FORMAT_TIMESPAN_MAX, timeout, USEC_PER_SEC));
FORMAT_TIMESPAN_MAX,
timeout, 0));
r = sd_event_add_time(client->event, r = sd_event_add_time(client->event,
&client->lease->ia.timeout_t1, &client->lease->ia.timeout_t1,
@@ -1076,9 +1085,7 @@ static int client_start(sd_dhcp6_client *client, enum DHCP6State state) {
timeout = client_timeout_compute_random(be32toh(client->lease->ia.lifetime_t2) * USEC_PER_SEC); timeout = client_timeout_compute_random(be32toh(client->lease->ia.lifetime_t2) * USEC_PER_SEC);
log_dhcp6_client(client, "T2 expires in %s", log_dhcp6_client(client, "T2 expires in %s",
format_timespan(time_string, format_timespan(time_string, FORMAT_TIMESPAN_MAX, timeout, USEC_PER_SEC));
FORMAT_TIMESPAN_MAX,
timeout, 0));
r = sd_event_add_time(client->event, r = sd_event_add_time(client->event,
&client->lease->ia.timeout_t2, &client->lease->ia.timeout_t2,
@@ -1124,11 +1131,19 @@ static int client_start(sd_dhcp6_client *client, enum DHCP6State state) {
} }
int sd_dhcp6_client_stop(sd_dhcp6_client *client) { int sd_dhcp6_client_stop(sd_dhcp6_client *client) {
assert_return(client, -EINVAL);
client_stop(client, SD_DHCP6_CLIENT_EVENT_STOP); client_stop(client, SD_DHCP6_CLIENT_EVENT_STOP);
return 0; return 0;
} }
int sd_dhcp6_client_is_running(sd_dhcp6_client *client) {
assert_return(client, -EINVAL);
return client->state != DHCP6_STATE_STOPPED;
}
int sd_dhcp6_client_start(sd_dhcp6_client *client) { int sd_dhcp6_client_start(sd_dhcp6_client *client) {
int r = 0; int r = 0;
enum DHCP6State state = DHCP6_STATE_SOLICITATION; enum DHCP6State state = DHCP6_STATE_SOLICITATION;
@@ -1136,9 +1151,10 @@ int sd_dhcp6_client_start(sd_dhcp6_client *client) {
assert_return(client, -EINVAL); assert_return(client, -EINVAL);
assert_return(client->event, -EINVAL); assert_return(client->event, -EINVAL);
assert_return(client->index > 0, -EINVAL); assert_return(client->index > 0, -EINVAL);
assert_return(in_addr_is_link_local(AF_INET6, (const union in_addr_union *) &client->local_address) > 0, -EINVAL);
if (!IN_SET(client->state, DHCP6_STATE_STOPPED)) if (!IN_SET(client->state, DHCP6_STATE_STOPPED))
return -EALREADY; return -EBUSY;
r = client_reset(client); r = client_reset(client);
if (r < 0) if (r < 0)
@@ -1152,7 +1168,7 @@ int sd_dhcp6_client_start(sd_dhcp6_client *client) {
if (r < 0) if (r < 0)
return r; return r;
r = dhcp6_network_bind_udp_socket(client->index, NULL); r = dhcp6_network_bind_udp_socket(client->index, &client->local_address);
if (r < 0) if (r < 0)
return r; return r;
@@ -1286,4 +1302,3 @@ int sd_dhcp6_client_new(sd_dhcp6_client **ret) {
return 0; return 0;
} }

View File

@@ -24,11 +24,11 @@
#include <errno.h> #include <errno.h>
#include "strv.h" #include "alloc-util.h"
#include "util.h"
#include "dhcp6-lease-internal.h" #include "dhcp6-lease-internal.h"
#include "dhcp6-protocol.h" #include "dhcp6-protocol.h"
#include "strv.h"
#include "util.h"
int dhcp6_lease_clear_timers(DHCP6IA *ia) { int dhcp6_lease_clear_timers(DHCP6IA *ia) {
assert_return(ia, -EINVAL); assert_return(ia, -EINVAL);

View File

@@ -26,17 +26,19 @@
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include "sd-ipv4acd.h"
#include "alloc-util.h"
#include "arp-util.h"
#include "event-util.h" #include "event-util.h"
#include "fd-util.h"
#include "in-addr-util.h" #include "in-addr-util.h"
#include "list.h" #include "list.h"
#include "refcnt.h"
#include "random-util.h" #include "random-util.h"
#include "refcnt.h"
#include "siphash24.h" #include "siphash24.h"
#include "util.h" #include "util.h"
#include "arp-util.h"
#include "sd-ipv4acd.h"
/* Constants from the RFC */ /* Constants from the RFC */
#define PROBE_WAIT 1 #define PROBE_WAIT 1
#define PROBE_NUM 3 #define PROBE_NUM 3
@@ -470,7 +472,7 @@ int sd_ipv4acd_set_address(sd_ipv4acd *ll, const struct in_addr *address){
return 0; return 0;
} }
bool sd_ipv4acd_is_running(sd_ipv4acd *ll) { int sd_ipv4acd_is_running(sd_ipv4acd *ll) {
assert_return(ll, false); assert_return(ll, false);
return ll->state != IPV4ACD_STATE_INIT; return ll->state != IPV4ACD_STATE_INIT;

View File

@@ -20,13 +20,18 @@
#include "nm-sd-adapt.h" #include "nm-sd-adapt.h"
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <stdio.h>
#include <arpa/inet.h> #include <arpa/inet.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "sd-ipv4acd.h"
#include "sd-ipv4ll.h"
#include "alloc-util.h"
#include "event-util.h" #include "event-util.h"
#include "in-addr-util.h"
#include "list.h" #include "list.h"
#include "random-util.h" #include "random-util.h"
#include "refcnt.h" #include "refcnt.h"
@@ -34,9 +39,6 @@
#include "sparse-endian.h" #include "sparse-endian.h"
#include "util.h" #include "util.h"
#include "sd-ipv4acd.h"
#include "sd-ipv4ll.h"
#define IPV4LL_NETWORK 0xA9FE0000L #define IPV4LL_NETWORK 0xA9FE0000L
#define IPV4LL_NETMASK 0xFFFF0000L #define IPV4LL_NETMASK 0xFFFF0000L
@@ -101,6 +103,8 @@ int sd_ipv4ll_new(sd_ipv4ll **ret) {
if (!ll) if (!ll)
return -ENOMEM; return -ENOMEM;
ll->n_ref = 1;
r = sd_ipv4acd_new(&ll->acd); r = sd_ipv4acd_new(&ll->acd);
if (r < 0) if (r < 0)
return r; return r;
@@ -109,8 +113,6 @@ int sd_ipv4ll_new(sd_ipv4ll **ret) {
if (r < 0) if (r < 0)
return r; return r;
ll->n_ref = 1;
*ret = ll; *ret = ll;
ll = NULL; ll = NULL;
@@ -143,15 +145,14 @@ int sd_ipv4ll_set_mac(sd_ipv4ll *ll, const struct ether_addr *addr) {
assert_return(ll, -EINVAL); assert_return(ll, -EINVAL);
if (!ll->random_data) { if (!ll->random_data) {
uint8_t seed[8]; uint64_t seed;
/* If no random data is set, generate some from the MAC */ /* If no random data is set, generate some from the MAC */
siphash24(seed, &addr->ether_addr_octet, seed = siphash24(&addr->ether_addr_octet, ETH_ALEN, HASH_KEY.bytes);
ETH_ALEN, HASH_KEY.bytes);
assert_cc(sizeof(unsigned) <= 8); assert_cc(sizeof(unsigned) <= 8);
r = sd_ipv4ll_set_address_seed(ll, *(unsigned*)seed); r = sd_ipv4ll_set_address_seed(ll, (unsigned) htole64(seed));
if (r < 0) if (r < 0)
return r; return r;
} }
@@ -228,12 +229,45 @@ int sd_ipv4ll_set_address_seed(sd_ipv4ll *ll, unsigned seed) {
return 0; return 0;
} }
bool sd_ipv4ll_is_running(sd_ipv4ll *ll) { int sd_ipv4ll_is_running(sd_ipv4ll *ll) {
assert_return(ll, false); assert_return(ll, false);
return sd_ipv4acd_is_running(ll->acd); return sd_ipv4acd_is_running(ll->acd);
} }
static bool ipv4ll_address_is_valid(const struct in_addr *address) {
uint32_t addr;
assert(address);
if (!in_addr_is_link_local(AF_INET, (const union in_addr_union *) address))
return false;
addr = be32toh(address->s_addr);
if ((addr & 0x0000FF00) == 0x0000 ||
(addr & 0x0000FF00) == 0xFF00)
return false;
return true;
}
int sd_ipv4ll_set_address(sd_ipv4ll *ll, const struct in_addr *address) {
int r;
assert_return(ll, -EINVAL);
assert_return(address, -EINVAL);
assert_return(ipv4ll_address_is_valid(address), -EINVAL);
r = sd_ipv4acd_set_address(ll->acd, address);
if (r < 0)
return r;
ll->address = address->s_addr;
return 0;
}
static int ipv4ll_pick_address(sd_ipv4ll *ll) { static int ipv4ll_pick_address(sd_ipv4ll *ll) {
struct in_addr in_addr; struct in_addr in_addr;
be32_t addr; be32_t addr;
@@ -249,18 +283,15 @@ static int ipv4ll_pick_address(sd_ipv4ll *ll) {
return r; return r;
addr = htonl((random & 0x0000FFFF) | IPV4LL_NETWORK); addr = htonl((random & 0x0000FFFF) | IPV4LL_NETWORK);
} while (addr == ll->address || } while (addr == ll->address ||
(ntohl(addr) & IPV4LL_NETMASK) != IPV4LL_NETWORK ||
(ntohl(addr) & 0x0000FF00) == 0x0000 || (ntohl(addr) & 0x0000FF00) == 0x0000 ||
(ntohl(addr) & 0x0000FF00) == 0xFF00); (ntohl(addr) & 0x0000FF00) == 0xFF00);
in_addr.s_addr = addr; in_addr.s_addr = addr;
r = sd_ipv4acd_set_address(ll->acd, &in_addr); r = sd_ipv4ll_set_address(ll, &in_addr);
if (r < 0) if (r < 0)
return r; return r;
ll->address = addr;
return 0; return 0;
} }

View File

@@ -24,15 +24,19 @@
#include <arpa/inet.h> #include <arpa/inet.h>
#include "siphash24.h"
#include "hashmap.h"
#include "lldp-tlv.h"
#include "lldp-port.h"
#include "sd-lldp.h" #include "sd-lldp.h"
#include "prioq.h"
#include "alloc-util.h"
#include "fd-util.h"
#include "fileio.h"
#include "hashmap.h"
#include "lldp-internal.h" #include "lldp-internal.h"
#include "lldp-port.h"
#include "lldp-tlv.h"
#include "lldp-util.h" #include "lldp-util.h"
#include "prioq.h"
#include "siphash24.h"
#include "string-util.h"
typedef enum LLDPAgentRXState { typedef enum LLDPAgentRXState {
LLDP_AGENT_RX_WAIT_PORT_OPERATIONAL = 4, LLDP_AGENT_RX_WAIT_PORT_OPERATIONAL = 4,

View File

@@ -23,9 +23,10 @@
#include "nm-sd-adapt.h" #include "nm-sd-adapt.h"
#include "util.h"
#include "sd-event.h" #include "sd-event.h"
#include "util.h"
DEFINE_TRIVIAL_CLEANUP_FUNC(sd_event*, sd_event_unref); DEFINE_TRIVIAL_CLEANUP_FUNC(sd_event*, sd_event_unref);
DEFINE_TRIVIAL_CLEANUP_FUNC(sd_event_source*, sd_event_source_unref); DEFINE_TRIVIAL_CLEANUP_FUNC(sd_event_source*, sd_event_source_unref);

View File

@@ -25,10 +25,14 @@
#include <fcntl.h> #include <fcntl.h>
#include <unistd.h> #include <unistd.h>
#include "util.h"
#include "macro.h"
#include "sd-id128.h" #include "sd-id128.h"
#include "fd-util.h"
#include "hexdecoct.h"
#include "io-util.h"
#include "macro.h"
#include "random-util.h" #include "random-util.h"
#include "util.h"
#if 0 /* NM_IGNORED */ #if 0 /* NM_IGNORED */
_public_ char *sd_id128_to_string(sd_id128_t id, char s[SD_ID128_STRING_MAX]) { _public_ char *sd_id128_to_string(sd_id128_t id, char s[SD_ID128_STRING_MAX]) {

View File

@@ -26,7 +26,11 @@
#include <stringprep.h> #include <stringprep.h>
#endif #endif
#include "alloc-util.h"
#include "dns-domain.h" #include "dns-domain.h"
#include "hexdecoct.h"
#include "parse-util.h"
#include "string-util.h"
int dns_label_unescape(const char **name, char *dest, size_t sz) { int dns_label_unescape(const char **name, char *dest, size_t sz) {
const char *n; const char *n;
@@ -695,6 +699,7 @@ int dns_name_root(const char *name) {
return r == 0 && *name == 0; return r == 0 && *name == 0;
} }
#endif /* NM_IGNORED */
int dns_name_single_label(const char *name) { int dns_name_single_label(const char *name) {
char label[DNS_LABEL_MAX+1]; char label[DNS_LABEL_MAX+1];
@@ -714,4 +719,37 @@ int dns_name_single_label(const char *name) {
return r == 0 && *name == 0; return r == 0 && *name == 0;
} }
#endif /* NM_IGNORED */
/* Encode a domain name according to RFC 1035 Section 3.1 */
int dns_name_to_wire_format(const char *domain, uint8_t *buffer, size_t len) {
uint8_t *label_length;
uint8_t *out;
int r;
assert_return(buffer, -EINVAL);
assert_return(domain, -EINVAL);
assert_return(domain[0], -EINVAL);
out = buffer;
do {
/* reserve a byte for label length */
if (len == 0)
return -ENOBUFS;
len--;
label_length = out;
out++;
/* convert and copy a single label */
r = dns_label_unescape(&domain, (char *) out, len);
if (r < 0)
return r;
/* fill label length, move forward */
*label_length = r;
out += r;
len -= r;
} while (r != 0);
return out - buffer;
}

View File

@@ -70,6 +70,8 @@ int dns_name_reverse(int family, const union in_addr_union *a, char **ret);
int dns_name_address(const char *p, int *family, union in_addr_union *a); int dns_name_address(const char *p, int *family, union in_addr_union *a);
int dns_name_root(const char *name); int dns_name_root(const char *name);
#endif /* NM_IGNORED */
int dns_name_single_label(const char *name); int dns_name_single_label(const char *name);
#endif /* NM_IGNORED */ int dns_name_to_wire_format(const char *domain, uint8_t *buffer, size_t len);

View File

@@ -24,11 +24,17 @@
#include "nm-sd-adapt.h" #include "nm-sd-adapt.h"
#include <netinet/in.h> #include <inttypes.h>
#include <net/ethernet.h> #include <net/ethernet.h>
#include <netinet/in.h>
#include <sys/types.h>
#include "sd-event.h"
#include "sd-dhcp-lease.h" #include "sd-dhcp-lease.h"
#include "sd-event.h"
#include "_sd-common.h"
_SD_BEGIN_DECLARATIONS;
enum { enum {
SD_DHCP_CLIENT_EVENT_STOP = 0, SD_DHCP_CLIENT_EVENT_STOP = 0,
@@ -74,4 +80,6 @@ int sd_dhcp_client_attach_event(sd_dhcp_client *client, sd_event *event, int pri
int sd_dhcp_client_detach_event(sd_dhcp_client *client); int sd_dhcp_client_detach_event(sd_dhcp_client *client);
sd_event *sd_dhcp_client_get_event(sd_dhcp_client *client); sd_event *sd_dhcp_client_get_event(sd_dhcp_client *client);
_SD_END_DECLARATIONS;
#endif #endif

View File

@@ -25,8 +25,14 @@
#include "nm-sd-adapt.h" #include "nm-sd-adapt.h"
#include <netinet/in.h> #include <inttypes.h>
#include <net/ethernet.h> #include <net/ethernet.h>
#include <netinet/in.h>
#include <sys/types.h>
#include "_sd-common.h"
_SD_BEGIN_DECLARATIONS;
typedef struct sd_dhcp_lease sd_dhcp_lease; typedef struct sd_dhcp_lease sd_dhcp_lease;
struct sd_dhcp_route; struct sd_dhcp_route;
@@ -54,4 +60,6 @@ int sd_dhcp_lease_get_vendor_specific(sd_dhcp_lease *lease, const void **data, s
int sd_dhcp_lease_get_client_id(sd_dhcp_lease *lease, const void **client_id, size_t *client_id_len); int sd_dhcp_lease_get_client_id(sd_dhcp_lease *lease, const void **client_id, size_t *client_id_len);
int sd_dhcp_lease_get_timezone(sd_dhcp_lease *lease, const char **timezone); int sd_dhcp_lease_get_timezone(sd_dhcp_lease *lease, const char **timezone);
_SD_END_DECLARATIONS;
#endif #endif

View File

@@ -24,11 +24,16 @@
#include "nm-sd-adapt.h" #include "nm-sd-adapt.h"
#include <inttypes.h>
#include <net/ethernet.h> #include <net/ethernet.h>
#include <sys/types.h>
#include "sd-event.h"
#include "sd-dhcp6-lease.h" #include "sd-dhcp6-lease.h"
#include "sd-event.h"
#include "_sd-common.h"
_SD_BEGIN_DECLARATIONS;
enum { enum {
SD_DHCP6_CLIENT_EVENT_STOP = 0, SD_DHCP6_CLIENT_EVENT_STOP = 0,
@@ -46,14 +51,13 @@ int sd_dhcp6_client_set_callback(sd_dhcp6_client *client,
sd_dhcp6_client_cb_t cb, void *userdata); sd_dhcp6_client_cb_t cb, void *userdata);
int sd_dhcp6_client_set_index(sd_dhcp6_client *client, int interface_index); int sd_dhcp6_client_set_index(sd_dhcp6_client *client, int interface_index);
int sd_dhcp6_client_set_local_address(sd_dhcp6_client *client, const struct in6_addr *local_address);
int sd_dhcp6_client_set_mac(sd_dhcp6_client *client, const uint8_t *addr, int sd_dhcp6_client_set_mac(sd_dhcp6_client *client, const uint8_t *addr,
size_t addr_len, uint16_t arp_type); size_t addr_len, uint16_t arp_type);
int sd_dhcp6_client_set_duid(sd_dhcp6_client *client, uint16_t type, uint8_t *duid, int sd_dhcp6_client_set_duid(sd_dhcp6_client *client, uint16_t type, uint8_t *duid,
size_t duid_len); size_t duid_len);
int sd_dhcp6_client_set_information_request(sd_dhcp6_client *client, int sd_dhcp6_client_set_information_request(sd_dhcp6_client *client, int enabled);
bool enabled); int sd_dhcp6_client_get_information_request(sd_dhcp6_client *client, int *enabled);
int sd_dhcp6_client_get_information_request(sd_dhcp6_client *client,
bool *enabled);
int sd_dhcp6_client_set_request_option(sd_dhcp6_client *client, int sd_dhcp6_client_set_request_option(sd_dhcp6_client *client,
uint16_t option); uint16_t option);
@@ -61,6 +65,7 @@ int sd_dhcp6_client_get_lease(sd_dhcp6_client *client, sd_dhcp6_lease **ret);
int sd_dhcp6_client_stop(sd_dhcp6_client *client); int sd_dhcp6_client_stop(sd_dhcp6_client *client);
int sd_dhcp6_client_start(sd_dhcp6_client *client); int sd_dhcp6_client_start(sd_dhcp6_client *client);
int sd_dhcp6_client_is_running(sd_dhcp6_client *client);
int sd_dhcp6_client_attach_event(sd_dhcp6_client *client, sd_event *event, int sd_dhcp6_client_attach_event(sd_dhcp6_client *client, sd_event *event,
int priority); int priority);
int sd_dhcp6_client_detach_event(sd_dhcp6_client *client); int sd_dhcp6_client_detach_event(sd_dhcp6_client *client);
@@ -69,4 +74,6 @@ sd_dhcp6_client *sd_dhcp6_client_ref(sd_dhcp6_client *client);
sd_dhcp6_client *sd_dhcp6_client_unref(sd_dhcp6_client *client); sd_dhcp6_client *sd_dhcp6_client_unref(sd_dhcp6_client *client);
int sd_dhcp6_client_new(sd_dhcp6_client **ret); int sd_dhcp6_client_new(sd_dhcp6_client **ret);
_SD_END_DECLARATIONS;
#endif #endif

View File

@@ -25,8 +25,13 @@
#include "nm-sd-adapt.h" #include "nm-sd-adapt.h"
#include <inttypes.h>
#include <netinet/in.h> #include <netinet/in.h>
#include "_sd-common.h"
_SD_BEGIN_DECLARATIONS;
typedef struct sd_dhcp6_lease sd_dhcp6_lease; typedef struct sd_dhcp6_lease sd_dhcp6_lease;
void sd_dhcp6_lease_reset_address_iter(sd_dhcp6_lease *lease); void sd_dhcp6_lease_reset_address_iter(sd_dhcp6_lease *lease);
@@ -44,4 +49,6 @@ int sd_dhcp6_lease_get_ntp_fqdn(sd_dhcp6_lease *lease, char ***ntp_fqdn);
sd_dhcp6_lease *sd_dhcp6_lease_ref(sd_dhcp6_lease *lease); sd_dhcp6_lease *sd_dhcp6_lease_ref(sd_dhcp6_lease *lease);
sd_dhcp6_lease *sd_dhcp6_lease_unref(sd_dhcp6_lease *lease); sd_dhcp6_lease *sd_dhcp6_lease_unref(sd_dhcp6_lease *lease);
_SD_END_DECLARATIONS;
#endif #endif

View File

@@ -24,11 +24,11 @@
#include "nm-sd-adapt.h" #include "nm-sd-adapt.h"
#include <sys/types.h>
#include <sys/signalfd.h>
#include <sys/epoll.h>
#include <inttypes.h> #include <inttypes.h>
#include <signal.h> #include <signal.h>
#include <sys/epoll.h>
#include <sys/signalfd.h>
#include <sys/types.h>
#include "_sd-common.h" #include "_sd-common.h"
@@ -58,7 +58,8 @@ enum {
SD_EVENT_PENDING, SD_EVENT_PENDING,
SD_EVENT_RUNNING, SD_EVENT_RUNNING,
SD_EVENT_EXITING, SD_EVENT_EXITING,
SD_EVENT_FINISHED SD_EVENT_FINISHED,
SD_EVENT_PREPARING,
}; };
enum { enum {
@@ -89,9 +90,9 @@ int sd_event_add_post(sd_event *e, sd_event_source **s, sd_event_handler_t callb
int sd_event_add_exit(sd_event *e, sd_event_source **s, sd_event_handler_t callback, void *userdata); int sd_event_add_exit(sd_event *e, sd_event_source **s, sd_event_handler_t callback, void *userdata);
int sd_event_prepare(sd_event *e); int sd_event_prepare(sd_event *e);
int sd_event_wait(sd_event *e, uint64_t timeout); int sd_event_wait(sd_event *e, uint64_t usec);
int sd_event_dispatch(sd_event *e); int sd_event_dispatch(sd_event *e);
int sd_event_run(sd_event *e, uint64_t timeout); int sd_event_run(sd_event *e, uint64_t usec);
int sd_event_loop(sd_event *e); int sd_event_loop(sd_event *e);
int sd_event_exit(sd_event *e, int code); int sd_event_exit(sd_event *e, int code);

View File

@@ -25,12 +25,15 @@
#include "nm-sd-adapt.h" #include "nm-sd-adapt.h"
#include <stdbool.h>
#include <netinet/in.h>
#include <net/ethernet.h> #include <net/ethernet.h>
#include <netinet/in.h>
#include "sd-event.h" #include "sd-event.h"
#include "_sd-common.h"
_SD_BEGIN_DECLARATIONS;
enum { enum {
SD_IPV4ACD_EVENT_STOP = 0, SD_IPV4ACD_EVENT_STOP = 0,
SD_IPV4ACD_EVENT_BIND = 1, SD_IPV4ACD_EVENT_BIND = 1,
@@ -47,11 +50,13 @@ int sd_ipv4acd_set_callback(sd_ipv4acd *ll, sd_ipv4acd_cb_t cb, void *userdata);
int sd_ipv4acd_set_mac(sd_ipv4acd *ll, const struct ether_addr *addr); int sd_ipv4acd_set_mac(sd_ipv4acd *ll, const struct ether_addr *addr);
int sd_ipv4acd_set_index(sd_ipv4acd *ll, int interface_index); int sd_ipv4acd_set_index(sd_ipv4acd *ll, int interface_index);
int sd_ipv4acd_set_address(sd_ipv4acd *ll, const struct in_addr *address); int sd_ipv4acd_set_address(sd_ipv4acd *ll, const struct in_addr *address);
bool sd_ipv4acd_is_running(sd_ipv4acd *ll); int sd_ipv4acd_is_running(sd_ipv4acd *ll);
int sd_ipv4acd_start(sd_ipv4acd *ll); int sd_ipv4acd_start(sd_ipv4acd *ll);
int sd_ipv4acd_stop(sd_ipv4acd *ll); int sd_ipv4acd_stop(sd_ipv4acd *ll);
sd_ipv4acd *sd_ipv4acd_ref(sd_ipv4acd *ll); sd_ipv4acd *sd_ipv4acd_ref(sd_ipv4acd *ll);
sd_ipv4acd *sd_ipv4acd_unref(sd_ipv4acd *ll); sd_ipv4acd *sd_ipv4acd_unref(sd_ipv4acd *ll);
int sd_ipv4acd_new (sd_ipv4acd **ret); int sd_ipv4acd_new (sd_ipv4acd **ret);
_SD_END_DECLARATIONS;
#endif #endif

View File

@@ -24,12 +24,15 @@
#include "nm-sd-adapt.h" #include "nm-sd-adapt.h"
#include <stdbool.h>
#include <netinet/in.h>
#include <net/ethernet.h> #include <net/ethernet.h>
#include <netinet/in.h>
#include "sd-event.h" #include "sd-event.h"
#include "_sd-common.h"
_SD_BEGIN_DECLARATIONS;
enum { enum {
SD_IPV4LL_EVENT_STOP = 0, SD_IPV4LL_EVENT_STOP = 0,
SD_IPV4LL_EVENT_BIND = 1, SD_IPV4LL_EVENT_BIND = 1,
@@ -45,12 +48,15 @@ int sd_ipv4ll_get_address(sd_ipv4ll *ll, struct in_addr *address);
int sd_ipv4ll_set_callback(sd_ipv4ll *ll, sd_ipv4ll_cb_t cb, void *userdata); int sd_ipv4ll_set_callback(sd_ipv4ll *ll, sd_ipv4ll_cb_t cb, void *userdata);
int sd_ipv4ll_set_mac(sd_ipv4ll *ll, const struct ether_addr *addr); int sd_ipv4ll_set_mac(sd_ipv4ll *ll, const struct ether_addr *addr);
int sd_ipv4ll_set_index(sd_ipv4ll *ll, int interface_index); int sd_ipv4ll_set_index(sd_ipv4ll *ll, int interface_index);
int sd_ipv4ll_set_address(sd_ipv4ll *ll, const struct in_addr *address);
int sd_ipv4ll_set_address_seed(sd_ipv4ll *ll, unsigned seed); int sd_ipv4ll_set_address_seed(sd_ipv4ll *ll, unsigned seed);
bool sd_ipv4ll_is_running(sd_ipv4ll *ll); int sd_ipv4ll_is_running(sd_ipv4ll *ll);
int sd_ipv4ll_start(sd_ipv4ll *ll); int sd_ipv4ll_start(sd_ipv4ll *ll);
int sd_ipv4ll_stop(sd_ipv4ll *ll); int sd_ipv4ll_stop(sd_ipv4ll *ll);
sd_ipv4ll *sd_ipv4ll_ref(sd_ipv4ll *ll); sd_ipv4ll *sd_ipv4ll_ref(sd_ipv4ll *ll);
sd_ipv4ll *sd_ipv4ll_unref(sd_ipv4ll *ll); sd_ipv4ll *sd_ipv4ll_unref(sd_ipv4ll *ll);
int sd_ipv4ll_new (sd_ipv4ll **ret); int sd_ipv4ll_new (sd_ipv4ll **ret);
_SD_END_DECLARATIONS;
#endif #endif

View File

@@ -1,5 +1,8 @@
/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
#ifndef foosdlldphfoo
#define foosdlldphfoo
/*** /***
This file is part of systemd. This file is part of systemd.
@@ -20,12 +23,17 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>. along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/ ***/
#pragma once
#include "nm-sd-adapt.h" #include "nm-sd-adapt.h"
#include <inttypes.h>
#include <net/ethernet.h>
#include "sd-event.h" #include "sd-event.h"
#include "_sd-common.h"
_SD_BEGIN_DECLARATIONS;
enum { enum {
SD_LLDP_EVENT_UPDATE_INFO = 0, SD_LLDP_EVENT_UPDATE_INFO = 0,
}; };
@@ -37,7 +45,7 @@ enum {
}; };
typedef struct sd_lldp sd_lldp; typedef struct sd_lldp sd_lldp;
typedef struct tlv_packet sd_lldp_packet; typedef struct sd_lldp_packet sd_lldp_packet;
typedef void (*sd_lldp_cb_t)(sd_lldp *lldp, int event, void *userdata); typedef void (*sd_lldp_cb_t)(sd_lldp *lldp, int event, void *userdata);
@@ -74,3 +82,7 @@ sd_lldp_packet *sd_lldp_packet_unref(sd_lldp_packet *tlv);
int sd_lldp_packet_get_destination_type(sd_lldp_packet *tlv, int *dest); int sd_lldp_packet_get_destination_type(sd_lldp_packet *tlv, int *dest);
int sd_lldp_get_packets(sd_lldp *lldp, sd_lldp_packet ***tlvs); int sd_lldp_get_packets(sd_lldp *lldp, sd_lldp_packet ***tlvs);
_SD_END_DECLARATIONS;
#endif

View File

@@ -0,0 +1,86 @@
/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
#ifndef foosdndiscfoo
#define foosdndiscfoo
/***
This file is part of systemd.
Copyright (C) 2014 Intel Corporation. All rights reserved.
systemd is free software; you can redistribute it and/or modify it
under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 2.1 of the License, or
(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 "nm-sd-adapt.h"
#include <inttypes.h>
#include <net/ethernet.h>
#include "sd-event.h"
#include "_sd-common.h"
_SD_BEGIN_DECLARATIONS;
enum {
SD_NDISC_EVENT_STOP = 0,
SD_NDISC_EVENT_TIMEOUT = 1,
};
typedef struct sd_ndisc sd_ndisc;
typedef void(*sd_ndisc_router_callback_t)(sd_ndisc *nd, uint8_t flags, const struct in6_addr *gateway, unsigned lifetime, int pref, void *userdata);
typedef void(*sd_ndisc_prefix_onlink_callback_t)(sd_ndisc *nd, const struct in6_addr *prefix, unsigned prefixlen,
unsigned lifetime, void *userdata);
typedef void(*sd_ndisc_prefix_autonomous_callback_t)(sd_ndisc *nd, const struct in6_addr *prefix, unsigned prefixlen,
unsigned lifetime_prefered, unsigned lifetime_valid, void *userdata);
typedef void(*sd_ndisc_callback_t)(sd_ndisc *nd, int event, void *userdata);
int sd_ndisc_set_callback(sd_ndisc *nd,
sd_ndisc_router_callback_t rcb,
sd_ndisc_prefix_onlink_callback_t plcb,
sd_ndisc_prefix_autonomous_callback_t pacb,
sd_ndisc_callback_t cb,
void *userdata);
int sd_ndisc_set_index(sd_ndisc *nd, int interface_index);
int sd_ndisc_set_mac(sd_ndisc *nd, const struct ether_addr *mac_addr);
int sd_ndisc_attach_event(sd_ndisc *nd, sd_event *event, int priority);
int sd_ndisc_detach_event(sd_ndisc *nd);
sd_event *sd_ndisc_get_event(sd_ndisc *nd);
sd_ndisc *sd_ndisc_ref(sd_ndisc *nd);
sd_ndisc *sd_ndisc_unref(sd_ndisc *nd);
int sd_ndisc_new(sd_ndisc **ret);
int sd_ndisc_get_mtu(sd_ndisc *nd, uint32_t *mtu);
int sd_ndisc_stop(sd_ndisc *nd);
int sd_ndisc_router_discovery_start(sd_ndisc *nd);
#define SD_NDISC_ADDRESS_FORMAT_STR "%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x"
#define SD_NDISC_ADDRESS_FORMAT_VAL(address) \
be16toh((address).s6_addr16[0]), \
be16toh((address).s6_addr16[1]), \
be16toh((address).s6_addr16[2]), \
be16toh((address).s6_addr16[3]), \
be16toh((address).s6_addr16[4]), \
be16toh((address).s6_addr16[5]), \
be16toh((address).s6_addr16[6]), \
be16toh((address).s6_addr16[7])
_SD_END_DECLARATIONS;
#endif