systemd: merge branch 'systemd' into master
This commit is contained in:
@@ -67,20 +67,34 @@ SYSTEMD_NM_CFLAGS_PATHS = \
|
||||
libsystemd_nm_la_SOURCES = \
|
||||
systemd/nm-sd-adapt.c \
|
||||
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/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.h \
|
||||
systemd/src/basic/fs-util.c \
|
||||
systemd/src/basic/fs-util.h \
|
||||
systemd/src/basic/hashmap.c \
|
||||
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.h \
|
||||
systemd/src/basic/in-addr-util.c \
|
||||
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/log.h \
|
||||
systemd/src/basic/macro.h \
|
||||
systemd/src/basic/mempool.c \
|
||||
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.h \
|
||||
systemd/src/basic/prioq.c \
|
||||
@@ -93,10 +107,15 @@ libsystemd_nm_la_SOURCES = \
|
||||
systemd/src/basic/set.h \
|
||||
systemd/src/basic/socket-util.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.h \
|
||||
systemd/src/basic/time-util.c \
|
||||
systemd/src/basic/time-util.h \
|
||||
systemd/src/basic/umask-util.h \
|
||||
systemd/src/basic/unaligned.h \
|
||||
systemd/src/basic/utf8.c \
|
||||
systemd/src/basic/utf8.h \
|
||||
|
@@ -762,6 +762,12 @@ ip6_start (NMDhcpClient *client,
|
||||
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);
|
||||
if (r < 0) {
|
||||
nm_log_warn (LOGD_DHCP6, "(%s): failed to start DHCP (%d)", iface, r);
|
||||
|
@@ -23,6 +23,7 @@
|
||||
#include <errno.h>
|
||||
|
||||
#include "sd-event.h"
|
||||
#include "fd-util.h"
|
||||
#include "time-util.h"
|
||||
|
||||
struct sd_event_source {
|
||||
|
83
src/systemd/src/basic/alloc-util.c
Normal file
83
src/systemd/src/basic/alloc-util.c
Normal 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;
|
||||
}
|
110
src/systemd/src/basic/alloc-util.h
Normal file
110
src/systemd/src/basic/alloc-util.h
Normal 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_); \
|
||||
})
|
484
src/systemd/src/basic/escape.c
Normal file
484
src/systemd/src/basic/escape.c
Normal 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;
|
||||
}
|
50
src/systemd/src/basic/escape.h
Normal file
50
src/systemd/src/basic/escape.h
Normal 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);
|
359
src/systemd/src/basic/fd-util.c
Normal file
359
src/systemd/src/basic/fd-util.c
Normal 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;
|
||||
}
|
77
src/systemd/src/basic/fd-util.h
Normal file
77
src/systemd/src/basic/fd-util.h
Normal 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);
|
@@ -23,11 +23,24 @@
|
||||
|
||||
#include <unistd.h>
|
||||
|
||||
#include "util.h"
|
||||
#include "strv.h"
|
||||
#include "utf8.h"
|
||||
#include "alloc-util.h"
|
||||
#include "ctype.h"
|
||||
#include "escape.h"
|
||||
#include "fd-util.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) {
|
||||
|
||||
@@ -53,7 +66,7 @@ static int write_string_file_atomic(const char *fn, const char *line, bool enfor
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
fchmod_umask(fileno(f), 0644);
|
||||
(void) fchmod_umask(fileno(f), 0644);
|
||||
|
||||
r = write_string_stream(f, line, enforce_newline);
|
||||
if (r >= 0) {
|
||||
@@ -62,13 +75,14 @@ static int write_string_file_atomic(const char *fn, const char *line, bool enfor
|
||||
}
|
||||
|
||||
if (r < 0)
|
||||
unlink(p);
|
||||
(void) unlink(p);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
int write_string_file(const char *fn, const char *line, WriteStringFileFlags flags) {
|
||||
_cleanup_fclose_ FILE *f = NULL;
|
||||
int q, r;
|
||||
|
||||
assert(fn);
|
||||
assert(line);
|
||||
@@ -76,30 +90,58 @@ int write_string_file(const char *fn, const char *line, WriteStringFileFlags fla
|
||||
if (flags & WRITE_STRING_FILE_ATOMIC) {
|
||||
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) {
|
||||
f = fopen(fn, "we");
|
||||
if (!f)
|
||||
return -errno;
|
||||
if (!f) {
|
||||
r = -errno;
|
||||
goto fail;
|
||||
}
|
||||
} else {
|
||||
int fd;
|
||||
|
||||
/* We manually build our own version of fopen(..., "we") that
|
||||
* works without O_CREAT */
|
||||
fd = open(fn, O_WRONLY|O_CLOEXEC|O_NOCTTY);
|
||||
if (fd < 0)
|
||||
return -errno;
|
||||
if (fd < 0) {
|
||||
r = -errno;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
f = fdopen(fd, "we");
|
||||
if (!f) {
|
||||
r = -errno;
|
||||
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) {
|
||||
@@ -130,15 +172,41 @@ int read_one_line_file(const char *fn, char **line) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int verify_one_line_file(const char *fn, const char *line) {
|
||||
_cleanup_free_ char *value = NULL;
|
||||
int r;
|
||||
int verify_file(const char *fn, const char *blob, bool accept_extra_nl) {
|
||||
_cleanup_fclose_ FILE *f = NULL;
|
||||
_cleanup_free_ char *buf = NULL;
|
||||
size_t l, k;
|
||||
|
||||
r = read_one_line_file(fn, &value);
|
||||
if (r < 0)
|
||||
return r;
|
||||
assert(fn);
|
||||
assert(blob);
|
||||
|
||||
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) {
|
||||
@@ -847,3 +915,336 @@ int get_proc_field(const char *filename, const char *pattern, const char *termin
|
||||
*field = f;
|
||||
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;
|
||||
}
|
||||
|
@@ -23,15 +23,20 @@
|
||||
|
||||
#include "nm-sd-adapt.h"
|
||||
|
||||
#include <dirent.h>
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include <stdio.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include "macro.h"
|
||||
#include "time-util.h"
|
||||
|
||||
typedef enum {
|
||||
WRITE_STRING_FILE_CREATE = 1,
|
||||
WRITE_STRING_FILE_ATOMIC = 2,
|
||||
WRITE_STRING_FILE_AVOID_NEWLINE = 4,
|
||||
WRITE_STRING_FILE_VERIFY_ON_FAILURE = 8,
|
||||
} WriteStringFileFlags;
|
||||
|
||||
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_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 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 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);
|
||||
|
512
src/systemd/src/basic/fs-util.c
Normal file
512
src/systemd/src/basic/fs-util.c
Normal 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 */
|
77
src/systemd/src/basic/fs-util.h
Normal file
77
src/systemd/src/basic/fs-util.h
Normal 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];
|
||||
};
|
@@ -22,18 +22,22 @@
|
||||
|
||||
#include "nm-sd-adapt.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <errno.h>
|
||||
#include <pthread.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "util.h"
|
||||
#include "alloc-util.h"
|
||||
#include "hashmap.h"
|
||||
#include "set.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 "strv.h"
|
||||
#include "mempool.h"
|
||||
#include "random-util.h"
|
||||
#include "util.h"
|
||||
|
||||
#ifdef ENABLE_DEBUG_HASHMAP
|
||||
#include "list.h"
|
||||
@@ -380,7 +384,7 @@ static unsigned base_bucket_hash(HashmapBase *h, const void *p) {
|
||||
|
||||
h->hash_ops->hash(p, &state);
|
||||
|
||||
siphash24_finalize((uint8_t*)&hash, &state);
|
||||
hash = siphash24_finalize(&state);
|
||||
|
||||
return (unsigned) (hash % n_buckets(h));
|
||||
}
|
||||
|
700
src/systemd/src/basic/hexdecoct.c
Normal file
700
src/systemd/src/basic/hexdecoct.c
Normal 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;
|
||||
}
|
||||
}
|
56
src/systemd/src/basic/hexdecoct.h
Normal file
56
src/systemd/src/basic/hexdecoct.h
Normal 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);
|
@@ -21,11 +21,14 @@
|
||||
|
||||
#include "nm-sd-adapt.h"
|
||||
|
||||
#include <sys/utsname.h>
|
||||
#include <ctype.h>
|
||||
#include <sys/utsname.h>
|
||||
|
||||
#include "util.h"
|
||||
#include "fd-util.h"
|
||||
#include "fileio.h"
|
||||
#include "hostname-util.h"
|
||||
#include "string-util.h"
|
||||
#include "util.h"
|
||||
|
||||
bool hostname_is_set(void) {
|
||||
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
|
||||
* in the name. Note that due to the restricted charset and length
|
||||
* 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) {
|
||||
unsigned n_dots = 0;
|
||||
|
@@ -23,6 +23,7 @@
|
||||
|
||||
#include <arpa/inet.h>
|
||||
|
||||
#include "alloc-util.h"
|
||||
#include "in-addr-util.h"
|
||||
|
||||
int in_addr_is_null(int family, const union in_addr_union *u) {
|
||||
|
263
src/systemd/src/basic/io-util.c
Normal file
263
src/systemd/src/basic/io-util.c
Normal 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;
|
||||
}
|
78
src/systemd/src/basic/io-util.h
Normal file
78
src/systemd/src/basic/io-util.h
Normal 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;
|
||||
}
|
@@ -23,14 +23,15 @@
|
||||
|
||||
#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 <stdarg.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/signalfd.h>
|
||||
#include <syslog.h>
|
||||
|
||||
#include "sd-id128.h"
|
||||
|
||||
#include "macro.h"
|
||||
|
||||
typedef enum LogTarget{
|
||||
|
@@ -24,11 +24,10 @@
|
||||
#include "nm-sd-adapt.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <sys/param.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/uio.h>
|
||||
#include <inttypes.h>
|
||||
#include <stdbool.h>
|
||||
#include <sys/param.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#define _printf_(a,b) __attribute__ ((format (printf, a, b)))
|
||||
#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 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_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
|
||||
* specified type as a decimal string. Adds in extra space for a
|
||||
* negative '-' prefix (hence works correctly on signed
|
||||
@@ -421,6 +319,15 @@ do { \
|
||||
sizeof(type) <= 4 ? 10 : \
|
||||
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) \
|
||||
(v) = (b) ? ((v) | (flag)) : ((v) & ~(flag))
|
||||
|
||||
@@ -438,21 +345,6 @@ do { \
|
||||
_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
|
||||
* version */
|
||||
#ifndef thread_local
|
||||
@@ -477,10 +369,6 @@ do { \
|
||||
#define noreturn __attribute__((noreturn))
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#define UID_INVALID ((uid_t) -1)
|
||||
#define GID_INVALID ((gid_t) -1)
|
||||
#define MODE_INVALID ((mode_t) -1)
|
||||
#endif /* NM_IGNORED */
|
||||
|
||||
#define DEFINE_TRIVIAL_CLEANUP_FUNC(type, func) \
|
||||
@@ -490,7 +378,4 @@ do { \
|
||||
} \
|
||||
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"
|
||||
|
@@ -22,8 +22,8 @@
|
||||
|
||||
#include "nm-sd-adapt.h"
|
||||
|
||||
#include "mempool.h"
|
||||
#include "macro.h"
|
||||
#include "mempool.h"
|
||||
#include "util.h"
|
||||
|
||||
struct pool {
|
||||
|
534
src/systemd/src/basic/parse-util.c
Normal file
534
src/systemd/src/basic/parse-util.c
Normal 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;
|
||||
}
|
96
src/systemd/src/basic/parse-util.h
Normal file
96
src/systemd/src/basic/parse-util.h
Normal 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);
|
@@ -21,25 +21,41 @@
|
||||
|
||||
#include "nm-sd-adapt.h"
|
||||
|
||||
#if 0 /* NM_IGNORED */
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/statvfs.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "macro.h"
|
||||
#include "util.h"
|
||||
/* When we include libgen.h because we need dirname() we immediately
|
||||
* 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 "strv.h"
|
||||
#include "macro.h"
|
||||
#include "missing.h"
|
||||
#include "parse-util.h"
|
||||
#endif /* NM_IGNORED */
|
||||
#include "path-util.h"
|
||||
#if 0 /* NM_IGNORED */
|
||||
#include "missing.h"
|
||||
#include "fileio.h"
|
||||
#include "stat-util.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) {
|
||||
return p[0] == '/';
|
||||
}
|
||||
@@ -48,61 +64,25 @@ bool is_path(const char *p) {
|
||||
return !!strchr(p, '/');
|
||||
}
|
||||
|
||||
int path_get_parent(const char *path, char **_r) {
|
||||
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) {
|
||||
int path_split_and_make_absolute(const char *p, char ***ret) {
|
||||
char **l;
|
||||
int r;
|
||||
|
||||
assert(p);
|
||||
assert(ret);
|
||||
|
||||
l = strv_split(p, ":");
|
||||
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);
|
||||
return NULL;
|
||||
return r;
|
||||
}
|
||||
|
||||
return l;
|
||||
*ret = l;
|
||||
return r;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
char *path_make_absolute_cwd(const char *p) {
|
||||
_cleanup_free_ char *cwd = NULL;
|
||||
int path_make_absolute_cwd(const char *p, char **ret) {
|
||||
char *c;
|
||||
|
||||
assert(p);
|
||||
assert(ret);
|
||||
|
||||
/* Similar to path_make_absolute(), but prefixes with the
|
||||
* current working directory. */
|
||||
|
||||
if (path_is_absolute(p))
|
||||
return strdup(p);
|
||||
c = strdup(p);
|
||||
else {
|
||||
_cleanup_free_ char *cwd = NULL;
|
||||
|
||||
cwd = get_current_dir_name();
|
||||
if (!cwd)
|
||||
return NULL;
|
||||
cwd = get_current_dir_name();
|
||||
if (!cwd)
|
||||
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) {
|
||||
@@ -220,8 +209,9 @@ int path_make_relative(const char *from_dir, const char *to_path, char **_r) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
char **path_strv_make_absolute_cwd(char **l) {
|
||||
int path_strv_make_absolute_cwd(char **l) {
|
||||
char **s;
|
||||
int r;
|
||||
|
||||
/* Goes through every item in the string list and makes it
|
||||
* 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) {
|
||||
char *t;
|
||||
|
||||
t = path_make_absolute_cwd(*s);
|
||||
if (!t)
|
||||
return NULL;
|
||||
r = path_make_absolute_cwd(*s, &t);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
free(*s);
|
||||
*s = t;
|
||||
}
|
||||
|
||||
return l;
|
||||
return 0;
|
||||
}
|
||||
|
||||
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.
|
||||
* Here a relative path is ordered before an absolute path. */
|
||||
d = (a[0] == '/') - (b[0] == '/');
|
||||
if (d)
|
||||
if (d != 0)
|
||||
return d;
|
||||
|
||||
for (;;) {
|
||||
@@ -441,12 +431,12 @@ int path_compare(const char *a, const char *b) {
|
||||
|
||||
/* Alphabetical sort: "/foo/aaa" before "/foo/b" */
|
||||
d = memcmp(a, b, MIN(j, k));
|
||||
if (d)
|
||||
if (d != 0)
|
||||
return (d > 0) - (d < 0); /* sign of d */
|
||||
|
||||
/* Sort "/foo/a" before "/foo/aaa" */
|
||||
d = (j > k) - (j < k); /* sign of (j - k) */
|
||||
if (d)
|
||||
if (d != 0)
|
||||
return d;
|
||||
|
||||
a += j;
|
||||
@@ -478,294 +468,66 @@ char* path_join(const char *root, const char *path, const char *rest) {
|
||||
NULL);
|
||||
}
|
||||
|
||||
static int fd_fdinfo_mnt_id(int fd, const char *filename, int flags, int *mnt_id) {
|
||||
char path[strlen("/proc/self/fdinfo/") + DECIMAL_STR_MAX(int)];
|
||||
_cleanup_free_ char *fdinfo = NULL;
|
||||
_cleanup_close_ int subfd = -1;
|
||||
char *p;
|
||||
int r;
|
||||
int find_binary(const char *name, char **ret) {
|
||||
int last_error, r;
|
||||
const char *p;
|
||||
|
||||
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);
|
||||
|
||||
if (is_path(name)) {
|
||||
if (local && access(name, X_OK) < 0)
|
||||
if (access(name, X_OK) < 0)
|
||||
return -errno;
|
||||
|
||||
if (filename) {
|
||||
char *p;
|
||||
|
||||
p = path_make_absolute_cwd(name);
|
||||
if (!p)
|
||||
return -ENOMEM;
|
||||
|
||||
*filename = p;
|
||||
if (ret) {
|
||||
r = path_make_absolute_cwd(name, ret);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
return 0;
|
||||
} else {
|
||||
const char *path;
|
||||
const char *word, *state;
|
||||
size_t l;
|
||||
}
|
||||
|
||||
/**
|
||||
* Plain getenv, not secure_getenv, because we want
|
||||
* to actually allow the user to pick the binary.
|
||||
*/
|
||||
path = getenv("PATH");
|
||||
if (!path)
|
||||
path = DEFAULT_PATH;
|
||||
/**
|
||||
* Plain getenv, not secure_getenv, because we want
|
||||
* to actually allow the user to pick the binary.
|
||||
*/
|
||||
p = getenv("PATH");
|
||||
if (!p)
|
||||
p = DEFAULT_PATH;
|
||||
|
||||
FOREACH_WORD_SEPARATOR(word, l, path, ":", state) {
|
||||
_cleanup_free_ char *p = NULL;
|
||||
last_error = -ENOENT;
|
||||
|
||||
if (asprintf(&p, "%.*s/%s", (int) l, word, name) < 0)
|
||||
return -ENOMEM;
|
||||
for (;;) {
|
||||
_cleanup_free_ char *j = NULL, *element = NULL;
|
||||
|
||||
if (access(p, X_OK) < 0)
|
||||
continue;
|
||||
r = extract_first_word(&p, &element, ":", EXTRACT_RELAX|EXTRACT_DONT_COALESCE_SEPARATORS);
|
||||
if (r < 0)
|
||||
return r;
|
||||
if (r == 0)
|
||||
break;
|
||||
|
||||
if (filename) {
|
||||
*filename = path_kill_slashes(p);
|
||||
p = NULL;
|
||||
if (!path_is_absolute(element))
|
||||
continue;
|
||||
|
||||
j = strjoin(element, "/", name, NULL);
|
||||
if (!j)
|
||||
return -ENOMEM;
|
||||
|
||||
if (access(j, X_OK) >= 0) {
|
||||
/* Found it! */
|
||||
|
||||
if (ret) {
|
||||
*ret = path_kill_slashes(j);
|
||||
j = NULL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -ENOENT;
|
||||
last_error = -errno;
|
||||
}
|
||||
|
||||
return last_error;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
int fsck_exists(const char *fstype) {
|
||||
static int binary_is_good(const char *binary) {
|
||||
_cleanup_free_ char *p = NULL, *d = NULL;
|
||||
const char *checker;
|
||||
int r;
|
||||
|
||||
checker = strjoina("fsck.", fstype);
|
||||
|
||||
r = find_binary(checker, true, &p);
|
||||
r = find_binary(binary, &p);
|
||||
if (r == -ENOENT)
|
||||
return 0;
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
@@ -818,13 +579,39 @@ int fsck_exists(const char *fstype) {
|
||||
* fsck */
|
||||
|
||||
r = readlink_malloc(p, &d);
|
||||
if (r >= 0 &&
|
||||
(path_equal(d, "/bin/true") ||
|
||||
path_equal(d, "/usr/bin/true") ||
|
||||
path_equal(d, "/dev/null")))
|
||||
return -ENOENT;
|
||||
if (r == -EINVAL) /* not a symlink */
|
||||
return 1;
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
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) {
|
||||
@@ -860,4 +647,169 @@ char *prefix_root(const char *root, const char *path) {
|
||||
strcpy(p, path);
|
||||
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 */
|
||||
|
@@ -38,11 +38,10 @@
|
||||
#endif
|
||||
|
||||
bool is_path(const char *p) _pure_;
|
||||
char** path_split_and_make_absolute(const char *p);
|
||||
int path_get_parent(const char *path, char **parent);
|
||||
int path_split_and_make_absolute(const char *p, char ***ret);
|
||||
bool path_is_absolute(const char *p) _pure_;
|
||||
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);
|
||||
char* path_kill_slashes(char *path);
|
||||
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);
|
||||
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_uniq(char **l, const char *prefix);
|
||||
|
||||
int fd_is_mount_point(int fd, const char *filename, int flags);
|
||||
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);
|
||||
int find_binary(const char *name, char **filename);
|
||||
|
||||
bool paths_check_timestamp(const char* const* paths, usec_t *paths_ts_usec, bool update);
|
||||
|
||||
int fsck_exists(const char *fstype);
|
||||
int mkfs_exists(const char *fstype);
|
||||
|
||||
/* Iterates through the path prefixes of the specified path, going up
|
||||
* 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; \
|
||||
})
|
||||
|
||||
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);
|
||||
|
@@ -31,8 +31,9 @@
|
||||
|
||||
#include "nm-sd-adapt.h"
|
||||
|
||||
#include "util.h"
|
||||
#include "alloc-util.h"
|
||||
#include "prioq.h"
|
||||
#include "util.h"
|
||||
|
||||
struct prioq_item {
|
||||
void *data;
|
||||
|
@@ -19,22 +19,24 @@
|
||||
|
||||
#include "nm-sd-adapt.h"
|
||||
|
||||
#include <stdint.h>
|
||||
#include <errno.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <time.h>
|
||||
#include <linux/random.h>
|
||||
#include <stdint.h>
|
||||
#ifdef HAVE_SYS_AUXV_H
|
||||
#include <sys/auxv.h>
|
||||
#endif
|
||||
#include <linux/random.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include <time.h>
|
||||
|
||||
#include "random-util.h"
|
||||
#include "time-util.h"
|
||||
#include "fd-util.h"
|
||||
#include "io-util.h"
|
||||
#if 0 /* NM_IGNORED */
|
||||
#include "missing.h"
|
||||
#endif
|
||||
#include "random-util.h"
|
||||
#include "time-util.h"
|
||||
#include "util.h"
|
||||
|
||||
int dev_urandom(void *p, size_t n) {
|
||||
|
@@ -19,9 +19,9 @@
|
||||
|
||||
#include "nm-sd-adapt.h"
|
||||
|
||||
#include "sparse-endian.h"
|
||||
|
||||
#include "siphash24.h"
|
||||
#include "sparse-endian.h"
|
||||
#include "unaligned.h"
|
||||
#include "util.h"
|
||||
|
||||
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(k);
|
||||
|
||||
k0 = le64toh(*(le64_t*) k);
|
||||
k1 = le64toh(*(le64_t*) (k + 8));
|
||||
k0 = unaligned_read_le64(k);
|
||||
k1 = unaligned_read_le64(k + 8);
|
||||
|
||||
/* "somepseudorandomlygeneratedbytes" */
|
||||
state->v0 = 0x736f6d6570736575ULL ^ k0;
|
||||
state->v1 = 0x646f72616e646f6dULL ^ k1;
|
||||
state->v2 = 0x6c7967656e657261ULL ^ k0;
|
||||
state->v3 = 0x7465646279746573ULL ^ k1;
|
||||
state->padding = 0;
|
||||
state->inlen = 0;
|
||||
*state = (struct siphash) {
|
||||
/* "somepseudorandomlygeneratedbytes" */
|
||||
.v0 = 0x736f6d6570736575ULL ^ k0,
|
||||
.v1 = 0x646f72616e646f6dULL ^ k1,
|
||||
.v2 = 0x6c7967656e657261ULL ^ k0,
|
||||
.v3 = 0x7465646279746573ULL ^ k1,
|
||||
.padding = 0,
|
||||
.inlen = 0,
|
||||
};
|
||||
}
|
||||
|
||||
void siphash24_compress(const void *_in, size_t inlen, struct siphash *state) {
|
||||
uint64_t m;
|
||||
|
||||
const uint8_t *in = _in;
|
||||
const uint8_t *end = in + inlen;
|
||||
unsigned left = state->inlen & 7;
|
||||
size_t left = state->inlen & 7;
|
||||
uint64_t m;
|
||||
|
||||
assert(in);
|
||||
assert(state);
|
||||
|
||||
/* update total length */
|
||||
/* Update total length */
|
||||
state->inlen += inlen;
|
||||
|
||||
/* if padding exists, fill it out */
|
||||
/* If padding exists, fill it out */
|
||||
if (left > 0) {
|
||||
for ( ; in < end && left < 8; in ++, left ++ )
|
||||
state->padding |= ( ( uint64_t )*in ) << (left * 8);
|
||||
for ( ; in < end && left < 8; in ++, left ++)
|
||||
state->padding |= ((uint64_t) *in) << (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;
|
||||
|
||||
#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) compress padding %08x %08x\n", state->inlen, (uint32_t) (state->padding >> 32), (uint32_t)state->padding);
|
||||
#endif
|
||||
|
||||
state->v3 ^= state->padding;
|
||||
sipround(state);
|
||||
sipround(state);
|
||||
@@ -103,10 +107,10 @@ void siphash24_compress(const void *_in, size_t inlen, struct siphash *state) {
|
||||
state->padding = 0;
|
||||
}
|
||||
|
||||
end -= ( state->inlen % sizeof (uint64_t) );
|
||||
end -= (state->inlen % sizeof(uint64_t));
|
||||
|
||||
for ( ; in < end; in += 8 ) {
|
||||
m = le64toh(*(le64_t*) in);
|
||||
for ( ; in < end; in += 8) {
|
||||
m = unaligned_read_le64(in);
|
||||
#ifdef DEBUG
|
||||
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);
|
||||
@@ -121,38 +125,41 @@ void siphash24_compress(const void *_in, size_t inlen, struct siphash *state) {
|
||||
}
|
||||
|
||||
left = state->inlen & 7;
|
||||
|
||||
switch(left)
|
||||
{
|
||||
case 7: state->padding |= ((uint64_t) in[6]) << 48;
|
||||
|
||||
case 6: state->padding |= ((uint64_t) in[5]) << 40;
|
||||
|
||||
case 5: state->padding |= ((uint64_t) in[4]) << 32;
|
||||
|
||||
case 4: state->padding |= ((uint64_t) in[3]) << 24;
|
||||
|
||||
case 3: state->padding |= ((uint64_t) in[2]) << 16;
|
||||
|
||||
case 2: state->padding |= ((uint64_t) in[1]) << 8;
|
||||
|
||||
case 1: state->padding |= ((uint64_t) in[0]); break;
|
||||
|
||||
case 0: break;
|
||||
switch (left) {
|
||||
case 7:
|
||||
state->padding |= ((uint64_t) in[6]) << 48;
|
||||
case 6:
|
||||
state->padding |= ((uint64_t) in[5]) << 40;
|
||||
case 5:
|
||||
state->padding |= ((uint64_t) in[4]) << 32;
|
||||
case 4:
|
||||
state->padding |= ((uint64_t) in[3]) << 24;
|
||||
case 3:
|
||||
state->padding |= ((uint64_t) in[2]) << 16;
|
||||
case 2:
|
||||
state->padding |= ((uint64_t) in[1]) << 8;
|
||||
case 1:
|
||||
state->padding |= ((uint64_t) in[0]);
|
||||
case 0:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void siphash24_finalize(uint8_t out[8], struct siphash *state) {
|
||||
uint64_t siphash24_finalize(struct siphash *state) {
|
||||
uint64_t b;
|
||||
|
||||
b = state->padding | (( ( uint64_t )state->inlen ) << 56);
|
||||
assert(state);
|
||||
|
||||
b = state->padding | (((uint64_t) state->inlen) << 56);
|
||||
|
||||
#ifdef DEBUG
|
||||
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) v2 %08x %08x\n", state->inlen, (uint32_t) (state->v2 >> 32), (uint32_t)state->v2);
|
||||
printf("(%3zu) v3 %08x %08x\n", state->inlen, (uint32_t) (state->v3 >> 32), (uint32_t)state->v3);
|
||||
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) v2 %08x %08x\n", state->inlen, (uint32_t) (state->v2 >> 32), (uint32_t) state->v2);
|
||||
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);
|
||||
#endif
|
||||
|
||||
state->v3 ^= b;
|
||||
sipround(state);
|
||||
sipround(state);
|
||||
@@ -171,14 +178,17 @@ void siphash24_finalize(uint8_t out[8], struct siphash *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 */
|
||||
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]) {
|
||||
struct siphash state;
|
||||
|
||||
assert(in);
|
||||
assert(k);
|
||||
|
||||
siphash24_init(&state, k);
|
||||
siphash24_compress(_in, inlen, &state);
|
||||
siphash24_finalize(out, &state);
|
||||
siphash24_compress(in, inlen, &state);
|
||||
|
||||
return siphash24_finalize(&state);
|
||||
}
|
||||
|
@@ -6,16 +6,16 @@
|
||||
#include <sys/types.h>
|
||||
|
||||
struct siphash {
|
||||
uint64_t v0;
|
||||
uint64_t v1;
|
||||
uint64_t v2;
|
||||
uint64_t v3;
|
||||
uint64_t padding;
|
||||
size_t inlen;
|
||||
uint64_t v0;
|
||||
uint64_t v1;
|
||||
uint64_t v2;
|
||||
uint64_t v3;
|
||||
uint64_t padding;
|
||||
size_t inlen;
|
||||
};
|
||||
|
||||
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_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]);
|
||||
|
@@ -23,9 +23,9 @@
|
||||
|
||||
#include "nm-sd-adapt.h"
|
||||
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <netinet/ether.h>
|
||||
#include <netinet/in.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/un.h>
|
||||
#include <linux/netlink.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);
|
||||
|
||||
#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)))
|
||||
|
37
src/systemd/src/basic/string-table.c
Normal file
37
src/systemd/src/basic/string-table.c
Normal 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;
|
||||
}
|
90
src/systemd/src/basic/string-table.h
Normal file
90
src/systemd/src/basic/string-table.h
Normal 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__
|
806
src/systemd/src/basic/string-util.c
Normal file
806
src/systemd/src/basic/string-util.c
Normal 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;
|
||||
}
|
186
src/systemd/src/basic/string-util.h
Normal file
186
src/systemd/src/basic/string-util.h
Normal 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_;
|
@@ -21,13 +21,16 @@
|
||||
|
||||
#include "nm-sd-adapt.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdarg.h>
|
||||
#include <string.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 "util.h"
|
||||
|
||||
char *strv_find(char **l, const char *name) {
|
||||
char **i;
|
||||
@@ -88,6 +91,15 @@ char **strv_free(char **l) {
|
||||
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 **r, **k;
|
||||
|
||||
@@ -190,17 +202,48 @@ char **strv_new(const char *x, ...) {
|
||||
return r;
|
||||
}
|
||||
|
||||
int strv_extend_strv(char ***a, char **b) {
|
||||
int r;
|
||||
char **s;
|
||||
int strv_extend_strv(char ***a, char **b, bool filter_duplicates) {
|
||||
char **s, **t;
|
||||
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) {
|
||||
r = strv_extend(a, *s);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (filter_duplicates && strv_contains(t, *s))
|
||||
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) {
|
||||
@@ -622,6 +665,41 @@ char **strv_split_nulstr(const char *s) {
|
||||
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) {
|
||||
char **i;
|
||||
|
||||
@@ -648,8 +726,12 @@ char **strv_sort(char **l) {
|
||||
}
|
||||
|
||||
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)
|
||||
if (!streq_ptr(*a, *b))
|
||||
@@ -784,7 +866,7 @@ int strv_extend_n(char ***l, const char *value, size_t n) {
|
||||
return 0;
|
||||
|
||||
rollback:
|
||||
for (j = k; j < i; i++)
|
||||
for (j = k; j < i; j++)
|
||||
free(nl[j]);
|
||||
|
||||
nl[k] = NULL;
|
||||
|
@@ -23,10 +23,13 @@
|
||||
|
||||
#include "nm-sd-adapt.h"
|
||||
|
||||
#include <fnmatch.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdbool.h>
|
||||
#include <fnmatch.h>
|
||||
|
||||
#if 0 /* NM_IGNORED */
|
||||
#include "extract-word.h"
|
||||
#endif /* NM_IGNORED */
|
||||
#include "util.h"
|
||||
|
||||
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 _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);
|
||||
|
||||
char **strv_copy(char * const *l);
|
||||
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(char ***l, const char *value);
|
||||
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_newlines(const char *s);
|
||||
|
||||
#if 0 /* NM_IGNORED */
|
||||
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_quoted(char **l);
|
||||
|
||||
char **strv_parse_nulstr(const char *s, size_t l);
|
||||
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_;
|
||||
|
||||
|
@@ -21,15 +21,22 @@
|
||||
|
||||
#include "nm-sd-adapt.h"
|
||||
|
||||
#include <time.h>
|
||||
#include <string.h>
|
||||
#include <sys/timex.h>
|
||||
#include <sys/timerfd.h>
|
||||
#include <sys/timex.h>
|
||||
|
||||
#include "util.h"
|
||||
#include "time-util.h"
|
||||
#include "alloc-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 "string-util.h"
|
||||
#include "strv.h"
|
||||
#include "time-util.h"
|
||||
#include "util.h"
|
||||
|
||||
usec_t now(clockid_t clock_id) {
|
||||
struct timespec ts;
|
||||
@@ -208,11 +215,8 @@ static char *format_timestamp_internal(char *buf, size_t l, usec_t t, bool utc)
|
||||
return NULL;
|
||||
|
||||
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)
|
||||
return NULL;
|
||||
|
||||
@@ -238,10 +242,7 @@ static char *format_timestamp_internal_us(char *buf, size_t l, usec_t t, bool ut
|
||||
return NULL;
|
||||
|
||||
sec = (time_t) (t / USEC_PER_SEC);
|
||||
if (utc)
|
||||
gmtime_r(&sec, &tm);
|
||||
else
|
||||
localtime_r(&sec, &tm);
|
||||
localtime_or_gmtime_r(&sec, &tm, utc);
|
||||
|
||||
if (strftime(buf, l, "%a %Y-%m-%d %H:%M:%S", &tm) <= 0)
|
||||
return NULL;
|
||||
@@ -329,15 +330,15 @@ char *format_timespan(char *buf, size_t l, usec_t t, usec_t accuracy) {
|
||||
const char *suffix;
|
||||
usec_t usec;
|
||||
} table[] = {
|
||||
{ "y", USEC_PER_YEAR },
|
||||
{ "month", USEC_PER_MONTH },
|
||||
{ "w", USEC_PER_WEEK },
|
||||
{ "d", USEC_PER_DAY },
|
||||
{ "h", USEC_PER_HOUR },
|
||||
{ "min", USEC_PER_MINUTE },
|
||||
{ "s", USEC_PER_SEC },
|
||||
{ "ms", USEC_PER_MSEC },
|
||||
{ "us", 1 },
|
||||
{ "y", USEC_PER_YEAR },
|
||||
{ "month", USEC_PER_MONTH },
|
||||
{ "w", USEC_PER_WEEK },
|
||||
{ "d", USEC_PER_DAY },
|
||||
{ "h", USEC_PER_HOUR },
|
||||
{ "min", USEC_PER_MINUTE },
|
||||
{ "s", USEC_PER_SEC },
|
||||
{ "ms", USEC_PER_MSEC },
|
||||
{ "us", 1 },
|
||||
};
|
||||
|
||||
unsigned i;
|
||||
@@ -489,9 +490,10 @@ int parse_timestamp(const char *t, usec_t *usec) {
|
||||
};
|
||||
|
||||
const char *k;
|
||||
const char *utc;
|
||||
struct tm tm, copy;
|
||||
time_t x;
|
||||
usec_t plus = 0, minus = 0, ret;
|
||||
usec_t x_usec, plus = 0, minus = 0, ret;
|
||||
int r, weekday = -1;
|
||||
unsigned i;
|
||||
|
||||
@@ -516,28 +518,15 @@ int parse_timestamp(const char *t, usec_t *usec) {
|
||||
assert(t);
|
||||
assert(usec);
|
||||
|
||||
x = time(NULL);
|
||||
assert_se(localtime_r(&x, &tm));
|
||||
tm.tm_isdst = -1;
|
||||
if (t[0] == '@')
|
||||
return parse_sec(t + 1, usec);
|
||||
|
||||
ret = now(CLOCK_REALTIME);
|
||||
|
||||
if (streq(t, "now"))
|
||||
goto finish;
|
||||
|
||||
else if (streq(t, "today")) {
|
||||
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] == '+') {
|
||||
else if (t[0] == '+') {
|
||||
r = parse_sec(t+1, &plus);
|
||||
if (r < 0)
|
||||
return r;
|
||||
@@ -551,35 +540,51 @@ int parse_timestamp(const char *t, usec_t *usec) {
|
||||
|
||||
goto finish;
|
||||
|
||||
} else if (t[0] == '@')
|
||||
return parse_sec(t + 1, usec);
|
||||
} else if ((k = endswith(t, " ago"))) {
|
||||
t = strndupa(t, k - t);
|
||||
|
||||
else if (endswith(t, " ago")) {
|
||||
_cleanup_free_ char *z;
|
||||
|
||||
z = strndup(t, strlen(t) - 4);
|
||||
if (!z)
|
||||
return -ENOMEM;
|
||||
|
||||
r = parse_sec(z, &minus);
|
||||
r = parse_sec(t, &minus);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
goto finish;
|
||||
} else if (endswith(t, " left")) {
|
||||
_cleanup_free_ char *z;
|
||||
|
||||
z = strndup(t, strlen(t) - 4);
|
||||
if (!z)
|
||||
return -ENOMEM;
|
||||
} else if ((k = endswith(t, " left"))) {
|
||||
t = strndupa(t, k - t);
|
||||
|
||||
r = parse_sec(z, &plus);
|
||||
r = parse_sec(t, &plus);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
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++) {
|
||||
size_t skip;
|
||||
|
||||
@@ -597,66 +602,95 @@ int parse_timestamp(const char *t, usec_t *usec) {
|
||||
|
||||
copy = tm;
|
||||
k = strptime(t, "%y-%m-%d %H:%M:%S", &tm);
|
||||
if (k && *k == 0)
|
||||
goto finish;
|
||||
if (k) {
|
||||
if (*k == '.')
|
||||
goto parse_usec;
|
||||
else if (*k == 0)
|
||||
goto from_tm;
|
||||
}
|
||||
|
||||
tm = copy;
|
||||
k = strptime(t, "%Y-%m-%d %H:%M:%S", &tm);
|
||||
if (k && *k == 0)
|
||||
goto finish;
|
||||
if (k) {
|
||||
if (*k == '.')
|
||||
goto parse_usec;
|
||||
else if (*k == 0)
|
||||
goto from_tm;
|
||||
}
|
||||
|
||||
tm = copy;
|
||||
k = strptime(t, "%y-%m-%d %H:%M", &tm);
|
||||
if (k && *k == 0) {
|
||||
tm.tm_sec = 0;
|
||||
goto finish;
|
||||
goto from_tm;
|
||||
}
|
||||
|
||||
tm = copy;
|
||||
k = strptime(t, "%Y-%m-%d %H:%M", &tm);
|
||||
if (k && *k == 0) {
|
||||
tm.tm_sec = 0;
|
||||
goto finish;
|
||||
goto from_tm;
|
||||
}
|
||||
|
||||
tm = copy;
|
||||
k = strptime(t, "%y-%m-%d", &tm);
|
||||
if (k && *k == 0) {
|
||||
tm.tm_sec = tm.tm_min = tm.tm_hour = 0;
|
||||
goto finish;
|
||||
goto from_tm;
|
||||
}
|
||||
|
||||
tm = copy;
|
||||
k = strptime(t, "%Y-%m-%d", &tm);
|
||||
if (k && *k == 0) {
|
||||
tm.tm_sec = tm.tm_min = tm.tm_hour = 0;
|
||||
goto finish;
|
||||
goto from_tm;
|
||||
}
|
||||
|
||||
tm = copy;
|
||||
k = strptime(t, "%H:%M:%S", &tm);
|
||||
if (k && *k == 0)
|
||||
goto finish;
|
||||
if (k) {
|
||||
if (*k == '.')
|
||||
goto parse_usec;
|
||||
else if (*k == 0)
|
||||
goto from_tm;
|
||||
}
|
||||
|
||||
tm = copy;
|
||||
k = strptime(t, "%H:%M", &tm);
|
||||
if (k && *k == 0) {
|
||||
tm.tm_sec = 0;
|
||||
goto finish;
|
||||
goto from_tm;
|
||||
}
|
||||
|
||||
return -EINVAL;
|
||||
|
||||
finish:
|
||||
x = mktime(&tm);
|
||||
parse_usec:
|
||||
{
|
||||
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)
|
||||
return -EINVAL;
|
||||
|
||||
if (weekday >= 0 && tm.tm_wday != weekday)
|
||||
return -EINVAL;
|
||||
|
||||
ret = (usec_t) x * USEC_PER_SEC;
|
||||
ret = (usec_t) x * USEC_PER_SEC + x_usec;
|
||||
|
||||
finish:
|
||||
ret += plus;
|
||||
if (ret > minus)
|
||||
ret -= minus;
|
||||
@@ -668,39 +702,40 @@ finish:
|
||||
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 {
|
||||
const char *suffix;
|
||||
usec_t usec;
|
||||
} table[] = {
|
||||
{ "seconds", USEC_PER_SEC },
|
||||
{ "second", USEC_PER_SEC },
|
||||
{ "sec", USEC_PER_SEC },
|
||||
{ "s", USEC_PER_SEC },
|
||||
{ "seconds", USEC_PER_SEC },
|
||||
{ "second", USEC_PER_SEC },
|
||||
{ "sec", USEC_PER_SEC },
|
||||
{ "s", USEC_PER_SEC },
|
||||
{ "minutes", USEC_PER_MINUTE },
|
||||
{ "minute", USEC_PER_MINUTE },
|
||||
{ "min", USEC_PER_MINUTE },
|
||||
{ "months", USEC_PER_MONTH },
|
||||
{ "month", USEC_PER_MONTH },
|
||||
{ "msec", USEC_PER_MSEC },
|
||||
{ "ms", USEC_PER_MSEC },
|
||||
{ "m", USEC_PER_MINUTE },
|
||||
{ "hours", USEC_PER_HOUR },
|
||||
{ "hour", USEC_PER_HOUR },
|
||||
{ "hr", USEC_PER_HOUR },
|
||||
{ "h", USEC_PER_HOUR },
|
||||
{ "days", USEC_PER_DAY },
|
||||
{ "day", USEC_PER_DAY },
|
||||
{ "d", USEC_PER_DAY },
|
||||
{ "weeks", USEC_PER_WEEK },
|
||||
{ "week", USEC_PER_WEEK },
|
||||
{ "w", USEC_PER_WEEK },
|
||||
{ "years", USEC_PER_YEAR },
|
||||
{ "year", USEC_PER_YEAR },
|
||||
{ "y", USEC_PER_YEAR },
|
||||
{ "usec", 1ULL },
|
||||
{ "us", 1ULL },
|
||||
{ "", USEC_PER_SEC }, /* default is sec */
|
||||
{ "minute", USEC_PER_MINUTE },
|
||||
{ "min", USEC_PER_MINUTE },
|
||||
{ "months", USEC_PER_MONTH },
|
||||
{ "month", USEC_PER_MONTH },
|
||||
{ "M", USEC_PER_MONTH },
|
||||
{ "msec", USEC_PER_MSEC },
|
||||
{ "ms", USEC_PER_MSEC },
|
||||
{ "m", USEC_PER_MINUTE },
|
||||
{ "hours", USEC_PER_HOUR },
|
||||
{ "hour", USEC_PER_HOUR },
|
||||
{ "hr", USEC_PER_HOUR },
|
||||
{ "h", USEC_PER_HOUR },
|
||||
{ "days", USEC_PER_DAY },
|
||||
{ "day", USEC_PER_DAY },
|
||||
{ "d", USEC_PER_DAY },
|
||||
{ "weeks", USEC_PER_WEEK },
|
||||
{ "week", USEC_PER_WEEK },
|
||||
{ "w", USEC_PER_WEEK },
|
||||
{ "years", USEC_PER_YEAR },
|
||||
{ "year", USEC_PER_YEAR },
|
||||
{ "y", USEC_PER_YEAR },
|
||||
{ "usec", 1ULL },
|
||||
{ "us", 1ULL },
|
||||
};
|
||||
|
||||
const char *p, *s;
|
||||
@@ -709,6 +744,7 @@ int parse_sec(const char *t, usec_t *usec) {
|
||||
|
||||
assert(t);
|
||||
assert(usec);
|
||||
assert(default_unit > 0);
|
||||
|
||||
p = t;
|
||||
|
||||
@@ -727,6 +763,7 @@ int parse_sec(const char *t, usec_t *usec) {
|
||||
long long l, z = 0;
|
||||
char *e;
|
||||
unsigned i, n = 0;
|
||||
usec_t multiplier, k;
|
||||
|
||||
p += strspn(p, WHITESPACE);
|
||||
|
||||
@@ -769,21 +806,24 @@ int parse_sec(const char *t, usec_t *usec) {
|
||||
|
||||
for (i = 0; i < ELEMENTSOF(table); i++)
|
||||
if (startswith(e, table[i].suffix)) {
|
||||
usec_t k = (usec_t) z * table[i].usec;
|
||||
|
||||
for (; n > 0; n--)
|
||||
k /= 10;
|
||||
|
||||
r += (usec_t) l * table[i].usec + k;
|
||||
multiplier = table[i].usec;
|
||||
p = e + strlen(table[i].suffix);
|
||||
|
||||
something = true;
|
||||
break;
|
||||
}
|
||||
|
||||
if (i >= ELEMENTSOF(table))
|
||||
return -EINVAL;
|
||||
if (i >= ELEMENTSOF(table)) {
|
||||
multiplier = default_unit;
|
||||
p = e;
|
||||
}
|
||||
|
||||
something = true;
|
||||
|
||||
k = (usec_t) z * multiplier;
|
||||
|
||||
for (; n > 0; n--)
|
||||
k /= 10;
|
||||
|
||||
r += (usec_t) l * multiplier + k;
|
||||
}
|
||||
|
||||
*usec = r;
|
||||
@@ -791,6 +831,10 @@ int parse_sec(const char *t, usec_t *usec) {
|
||||
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) {
|
||||
static const struct {
|
||||
const char *suffix;
|
||||
@@ -1079,4 +1123,26 @@ int get_timezone(char **tz) {
|
||||
*tz = z;
|
||||
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 */
|
||||
|
@@ -23,8 +23,9 @@
|
||||
|
||||
#include "nm-sd-adapt.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <inttypes.h>
|
||||
#include <stdio.h>
|
||||
#include <time.h>
|
||||
|
||||
typedef uint64_t usec_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_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);
|
||||
|
||||
bool ntp_synced(void);
|
||||
@@ -119,3 +121,8 @@ clockid_t clock_boottime_or_monotonic(void);
|
||||
"xstrftime: " #buf "[] must be big enough")
|
||||
|
||||
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);
|
||||
|
50
src/systemd/src/basic/umask-util.h
Normal file
50
src/systemd/src/basic/umask-util.h
Normal 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)
|
@@ -23,8 +23,11 @@
|
||||
|
||||
#include "nm-sd-adapt.h"
|
||||
|
||||
#include <endian.h>
|
||||
#include <stdint.h>
|
||||
|
||||
/* BE */
|
||||
|
||||
static inline uint16_t unaligned_read_be16(const void *_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 + 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));
|
||||
}
|
||||
|
@@ -46,11 +46,13 @@
|
||||
#include "nm-sd-adapt.h"
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdlib.h>
|
||||
#include <inttypes.h>
|
||||
#include <string.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "alloc-util.h"
|
||||
#include "hexdecoct.h"
|
||||
#include "utf8.h"
|
||||
#include "util.h"
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
@@ -24,12 +24,10 @@
|
||||
#include "nm-sd-adapt.h"
|
||||
|
||||
#include <alloca.h>
|
||||
#include <dirent.h>
|
||||
#include <fcntl.h>
|
||||
#include <inttypes.h>
|
||||
#include <limits.h>
|
||||
#include <locale.h>
|
||||
#include <mntent.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
@@ -52,49 +50,9 @@
|
||||
#endif /* NM_IGNORED */
|
||||
#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_;
|
||||
#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) {
|
||||
return b ? "yes" : "no";
|
||||
}
|
||||
@@ -107,347 +65,13 @@ static inline const char* one_zero(bool b) {
|
||||
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[]);
|
||||
|
||||
bool nulstr_contains(const char*nulstr, const char *needle);
|
||||
|
||||
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_;
|
||||
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);
|
||||
|
||||
#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) \
|
||||
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 char **saved_argv;
|
||||
|
||||
@@ -484,184 +87,36 @@ bool kexec_loaded(void);
|
||||
|
||||
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 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);
|
||||
|
||||
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,
|
||||
int (*compar) (const void *, const void *, void *),
|
||||
void *arg);
|
||||
|
||||
#if 0 /* NM_IGNORED */
|
||||
#define _(String) gettext (String)
|
||||
#define N_(String) String
|
||||
#endif
|
||||
void init_gettext(void);
|
||||
bool is_locale_utf8(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;
|
||||
|
||||
typedef enum DrawSpecialChar {
|
||||
DRAW_TREE_VERTICAL,
|
||||
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);
|
||||
assert(base);
|
||||
qsort(base, nmemb, size, compar);
|
||||
}
|
||||
|
||||
int on_ac_power(void);
|
||||
|
||||
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
|
||||
|
||||
#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
|
||||
#define memzero(x,l) (memset((x), 0, (l)))
|
||||
#define zero(x) (memzero(&(x), sizeof(x)))
|
||||
|
||||
static inline void *mempset(void *s, int c, size_t n) {
|
||||
memset(s, c, 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) {
|
||||
errno = *saved_errno;
|
||||
}
|
||||
@@ -677,20 +132,6 @@ static inline int negative_errno(void) {
|
||||
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) {
|
||||
#if __SIZEOF_LONG_LONG__ == 8
|
||||
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;
|
||||
}
|
||||
|
||||
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_;
|
||||
|
||||
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 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);
|
||||
|
||||
#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);
|
||||
|
||||
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 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);
|
||||
|
||||
bool fdname_is_valid(const char *s);
|
||||
|
@@ -23,8 +23,9 @@
|
||||
#include <linux/filter.h>
|
||||
#include <arpa/inet.h>
|
||||
|
||||
#include "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) {
|
||||
struct sock_filter filter[] = {
|
||||
|
@@ -25,8 +25,8 @@
|
||||
|
||||
#include <netinet/if_ether.h>
|
||||
|
||||
#include "sparse-endian.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);
|
||||
|
||||
|
@@ -21,27 +21,29 @@
|
||||
|
||||
#include "nm-sd-adapt.h"
|
||||
|
||||
#include "sd-id128.h"
|
||||
#if 0 /* NM_IGNORED */
|
||||
#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"
|
||||
#if 0 /* NM_IGNORED */
|
||||
#include "udev-util.h"
|
||||
#include "virt.h"
|
||||
#else /* NM_IGNORED */
|
||||
#include <net/if.h>
|
||||
#endif /* NM_IGNORED */
|
||||
#include "siphash24.h"
|
||||
|
||||
#include "dhcp6-protocol.h"
|
||||
#include "dhcp-identifier.h"
|
||||
#include "network-internal.h"
|
||||
|
||||
#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)
|
||||
|
||||
int dhcp_identifier_set_duid_en(struct duid *duid, size_t *len) {
|
||||
sd_id128_t machine_id;
|
||||
uint64_t hash;
|
||||
int r;
|
||||
|
||||
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);
|
||||
|
||||
/* a bit of snake-oil perhaps, but no need to expose the machine-id
|
||||
directly */
|
||||
siphash24(duid->en.id, &machine_id, sizeof(machine_id), HASH_KEY.bytes);
|
||||
directly; duid->en.id might not be aligned, so we need to copy */
|
||||
hash = htole64(siphash24(&machine_id, sizeof(machine_id), HASH_KEY.bytes));
|
||||
memcpy(duid->en.id, &hash, sizeof(duid->en.id));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int dhcp_identifier_set_iaid(int ifindex, uint8_t *mac, size_t mac_len, void *_id) {
|
||||
#if 0 /* NM_IGNORED */
|
||||
/* 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 */
|
||||
|
||||
if (name)
|
||||
siphash24((uint8_t*)&id, name, strlen(name), HASH_KEY.bytes);
|
||||
id = siphash24(name, strlen(name), HASH_KEY.bytes);
|
||||
else
|
||||
/* 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 */
|
||||
unaligned_write_be32(_id, (id & 0xffffffff) ^ (id >> 32));
|
||||
|
@@ -23,10 +23,11 @@
|
||||
|
||||
#include "nm-sd-adapt.h"
|
||||
|
||||
#include "sd-id128.h"
|
||||
|
||||
#include "macro.h"
|
||||
#include "sparse-endian.h"
|
||||
#include "unaligned.h"
|
||||
#include "sd-id128.h"
|
||||
|
||||
/* RFC 3315 section 9.1:
|
||||
* A DUID can be no more than 128 octets long (not including the type code).
|
||||
|
@@ -24,15 +24,15 @@
|
||||
|
||||
#include "nm-sd-adapt.h"
|
||||
|
||||
#include <stdint.h>
|
||||
#include <linux/if_packet.h>
|
||||
#include <net/if_arp.h>
|
||||
#include <net/ethernet.h>
|
||||
|
||||
#include "socket-util.h"
|
||||
#include <net/if_arp.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "sd-dhcp-client.h"
|
||||
|
||||
#include "dhcp-protocol.h"
|
||||
#include "socket-util.h"
|
||||
|
||||
int dhcp_network_bind_raw_socket(int index, union sockaddr_union *link,
|
||||
uint32_t xid, const uint8_t *mac_addr,
|
||||
|
@@ -27,12 +27,11 @@
|
||||
#include <stdint.h>
|
||||
#include <linux/if_packet.h>
|
||||
|
||||
#include "util.h"
|
||||
#include "list.h"
|
||||
#include "sd-dhcp-client.h"
|
||||
|
||||
#include "dhcp-protocol.h"
|
||||
|
||||
#include "sd-dhcp-client.h"
|
||||
#include "list.h"
|
||||
#include "util.h"
|
||||
|
||||
struct sd_dhcp_route {
|
||||
struct in_addr dst_addr;
|
||||
|
@@ -20,18 +20,18 @@
|
||||
#include "nm-sd-adapt.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/if_arp.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <sys/socket.h>
|
||||
#include <linux/filter.h>
|
||||
|
||||
#include "socket-util.h"
|
||||
#include <linux/if_infiniband.h>
|
||||
#include <linux/if_packet.h>
|
||||
|
||||
#include "dhcp-internal.h"
|
||||
#include "fd-util.h"
|
||||
#include "socket-util.h"
|
||||
|
||||
static int _bind_raw_socket(int ifindex, union sockaddr_union *link,
|
||||
uint32_t xid, const uint8_t *mac_addr,
|
||||
|
@@ -21,10 +21,10 @@
|
||||
|
||||
#include "nm-sd-adapt.h"
|
||||
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "dhcp-internal.h"
|
||||
|
||||
|
@@ -21,13 +21,12 @@
|
||||
#include "nm-sd-adapt.h"
|
||||
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <net/ethernet.h>
|
||||
#include <net/if_arp.h>
|
||||
#include <string.h>
|
||||
|
||||
|
||||
#include "dhcp-protocol.h"
|
||||
#include "dhcp-internal.h"
|
||||
#include "dhcp-protocol.h"
|
||||
|
||||
#define DHCP_CLIENT_MIN_OPTIONS_SIZE 312
|
||||
|
||||
|
@@ -23,8 +23,8 @@
|
||||
|
||||
#include "nm-sd-adapt.h"
|
||||
|
||||
#include <netinet/udp.h>
|
||||
#include <netinet/ip.h>
|
||||
#include <netinet/udp.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "macro.h"
|
||||
@@ -139,6 +139,7 @@ enum {
|
||||
DHCP_OPTION_REBINDING_T2_TIME = 59,
|
||||
DHCP_OPTION_VENDOR_CLASS_IDENTIFIER = 60,
|
||||
DHCP_OPTION_CLIENT_IDENTIFIER = 61,
|
||||
DHCP_OPTION_FQDN = 81,
|
||||
DHCP_OPTION_NEW_POSIX_TIMEZONE = 100,
|
||||
DHCP_OPTION_NEW_TZDB_TIMEZONE = 101,
|
||||
DHCP_OPTION_CLASSLESS_STATIC_ROUTE = 121,
|
||||
@@ -146,3 +147,12 @@ enum {
|
||||
DHCP_OPTION_PRIVATE_LAST = 254,
|
||||
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),
|
||||
};
|
||||
|
@@ -26,10 +26,11 @@
|
||||
#include <net/ethernet.h>
|
||||
#include <netinet/in.h>
|
||||
|
||||
#include "sparse-endian.h"
|
||||
#include "sd-event.h"
|
||||
|
||||
#include "list.h"
|
||||
#include "macro.h"
|
||||
#include "sparse-endian.h"
|
||||
|
||||
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__)
|
||||
|
||||
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,
|
||||
size_t optlen, const void *optval);
|
||||
int dhcp6_option_append_ia(uint8_t **buf, size_t *buflen, DHCP6IA *ia);
|
||||
|
@@ -27,6 +27,7 @@
|
||||
#include <stdint.h>
|
||||
|
||||
#include "sd-dhcp6-lease.h"
|
||||
|
||||
#include "dhcp6-internal.h"
|
||||
|
||||
struct sd_dhcp6_lease {
|
||||
|
@@ -20,143 +20,38 @@
|
||||
#include "nm-sd-adapt.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 "socket-util.h"
|
||||
#include <netinet/ip6.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-protocol.h"
|
||||
|
||||
#define IN6ADDR_ALL_ROUTERS_MULTICAST_INIT \
|
||||
{ { { 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;
|
||||
}
|
||||
#include "fd-util.h"
|
||||
#include "socket-util.h"
|
||||
|
||||
int dhcp6_network_bind_udp_socket(int index, struct in6_addr *local_address) {
|
||||
struct in6_pktinfo pktinfo = {
|
||||
.ipi6_ifindex = index,
|
||||
};
|
||||
union sockaddr_union src = {
|
||||
.in6.sin6_family = AF_INET6,
|
||||
.in6.sin6_port = htobe16(DHCP6_PORT_CLIENT),
|
||||
.in6.sin6_addr = IN6ADDR_ANY_INIT,
|
||||
.in6.sin6_scope_id = index,
|
||||
};
|
||||
_cleanup_close_ int s = -1;
|
||||
int r, off = 0, on = 1;
|
||||
|
||||
if (local_address)
|
||||
memcpy(&src.in6.sin6_addr, local_address,
|
||||
sizeof(src.in6.sin6_addr));
|
||||
assert(index > 0);
|
||||
assert(local_address);
|
||||
|
||||
s = socket(AF_INET6, SOCK_DGRAM | SOCK_CLOEXEC | SOCK_NONBLOCK,
|
||||
IPPROTO_UDP);
|
||||
src.in6.sin6_addr = *local_address;
|
||||
|
||||
s = socket(AF_INET6, SOCK_DGRAM | SOCK_CLOEXEC | SOCK_NONBLOCK, IPPROTO_UDP);
|
||||
if (s < 0)
|
||||
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));
|
||||
if (r < 0)
|
||||
return -errno;
|
||||
@@ -165,6 +60,10 @@ int dhcp6_network_bind_udp_socket(int index, struct in6_addr *local_address) {
|
||||
if (r < 0)
|
||||
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));
|
||||
if (r < 0)
|
||||
return -errno;
|
||||
|
@@ -21,18 +21,18 @@
|
||||
|
||||
#include "nm-sd-adapt.h"
|
||||
|
||||
#include <netinet/in.h>
|
||||
#include <errno.h>
|
||||
#include <netinet/in.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "sparse-endian.h"
|
||||
#include "unaligned.h"
|
||||
#include "util.h"
|
||||
#include "strv.h"
|
||||
|
||||
#include "alloc-util.h"
|
||||
#include "dhcp6-internal.h"
|
||||
#include "dhcp6-protocol.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_TA_LEN 4
|
||||
@@ -346,7 +346,7 @@ int dhcp6_option_parse_domainname(const uint8_t *optval, uint16_t optlen, char *
|
||||
int r;
|
||||
|
||||
assert_return(optlen > 1, -ENODATA);
|
||||
assert_return(optval[optlen] == '\0', -EINVAL);
|
||||
assert_return(optval[optlen - 1] == '\0', -EINVAL);
|
||||
|
||||
while (pos < optlen) {
|
||||
_cleanup_free_ char *ret = NULL;
|
||||
|
@@ -22,9 +22,11 @@
|
||||
|
||||
#include "nm-sd-adapt.h"
|
||||
|
||||
#include "lldp-internal.h"
|
||||
#include "sd-lldp.h"
|
||||
|
||||
#include "alloc-util.h"
|
||||
#include "lldp-internal.h"
|
||||
|
||||
/* We store maximum 1K chassis entries */
|
||||
#define LLDP_MIB_MAX_CHASSIS 1024
|
||||
|
||||
|
@@ -24,11 +24,12 @@
|
||||
|
||||
#include "nm-sd-adapt.h"
|
||||
|
||||
#include "log.h"
|
||||
#include "sd-event.h"
|
||||
|
||||
#include "list.h"
|
||||
#include "lldp-tlv.h"
|
||||
#include "log.h"
|
||||
#include "prioq.h"
|
||||
#include "sd-event.h"
|
||||
|
||||
typedef struct lldp_neighbour_port lldp_neighbour_port;
|
||||
typedef struct lldp_chassis lldp_chassis;
|
||||
|
@@ -25,10 +25,11 @@
|
||||
#include <linux/filter.h>
|
||||
#include <linux/if_ether.h>
|
||||
|
||||
#include "socket-util.h"
|
||||
#include "lldp-tlv.h"
|
||||
#include "lldp-network.h"
|
||||
#include "fd-util.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) {
|
||||
typedef struct LLDPFrame {
|
||||
|
@@ -22,10 +22,11 @@
|
||||
|
||||
#include "nm-sd-adapt.h"
|
||||
|
||||
#include "alloc-util.h"
|
||||
#include "async.h"
|
||||
#include "lldp-port.h"
|
||||
#include "lldp-network.h"
|
||||
#include "lldp-internal.h"
|
||||
#include "lldp-network.h"
|
||||
#include "lldp-port.h"
|
||||
|
||||
int lldp_port_start(lldp_port *p) {
|
||||
int r;
|
||||
|
@@ -22,11 +22,12 @@
|
||||
|
||||
#include "nm-sd-adapt.h"
|
||||
|
||||
#include <net/ethernet.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <net/ethernet.h>
|
||||
|
||||
#include "macro.h"
|
||||
#include "alloc-util.h"
|
||||
#include "lldp-tlv.h"
|
||||
#include "macro.h"
|
||||
|
||||
int tlv_section_new(tlv_section **ret) {
|
||||
tlv_section *s;
|
||||
@@ -279,7 +280,7 @@ int tlv_packet_parse_pdu(tlv_packet *m, uint16_t size) {
|
||||
|
||||
p = m->pdu;
|
||||
|
||||
/* extract ethernet header */
|
||||
/* extract Ethernet header */
|
||||
memcpy(&m->mac, p, ETH_ALEN);
|
||||
p += sizeof(struct ether_header);
|
||||
|
||||
|
@@ -26,18 +26,18 @@
|
||||
|
||||
#include <net/ethernet.h>
|
||||
|
||||
#include "util.h"
|
||||
#include "lldp.h"
|
||||
#include "list.h"
|
||||
|
||||
#include "sd-lldp.h"
|
||||
|
||||
typedef struct tlv_packet tlv_packet;
|
||||
typedef struct tlv_section tlv_section;
|
||||
#include "list.h"
|
||||
#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
|
||||
|
||||
struct tlv_section {
|
||||
struct sd_lldp_section {
|
||||
uint16_t type;
|
||||
uint16_t length;
|
||||
uint8_t *oui;
|
||||
@@ -56,7 +56,7 @@ struct tlv_section {
|
||||
int tlv_section_new(tlv_section **ret);
|
||||
void tlv_section_free(tlv_section *ret);
|
||||
|
||||
struct tlv_packet {
|
||||
struct sd_lldp_packet {
|
||||
unsigned n_ref;
|
||||
|
||||
uint16_t type;
|
||||
|
@@ -21,26 +21,27 @@
|
||||
|
||||
#include "nm-sd-adapt.h"
|
||||
|
||||
#include <netinet/ether.h>
|
||||
#include <linux/if.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 */
|
||||
#include "strv.h"
|
||||
#include "siphash24.h"
|
||||
#include "condition.h"
|
||||
#include "conf-parser.h"
|
||||
#endif /* NM_IGNORED */
|
||||
#include "dhcp-lease-internal.h"
|
||||
#if 0 /* NM_IGNORED */
|
||||
#include "hexdecoct.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 "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 */
|
||||
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)
|
||||
|
||||
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;
|
||||
const char *name = NULL;
|
||||
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
|
||||
* use a fixed, but originally randomly created hash
|
||||
* key here. */
|
||||
siphash24(result, v, sz, HASH_KEY.bytes);
|
||||
*result = htole64(siphash24(v, sz, HASH_KEY.bytes));
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -400,8 +401,8 @@ void serialize_in6_addrs(FILE *f, const struct in6_addr *addresses,
|
||||
assert(size);
|
||||
|
||||
for (i = 0; i < size; i++)
|
||||
fprintf(f, SD_ICMP6_ND_ADDRESS_FORMAT_STR"%s",
|
||||
SD_ICMP6_ND_ADDRESS_FORMAT_VAL(addresses[i]),
|
||||
fprintf(f, SD_NDISC_ADDRESS_FORMAT_STR"%s",
|
||||
SD_NDISC_ADDRESS_FORMAT_VAL(addresses[i]),
|
||||
(i < (size - 1)) ? " ": "");
|
||||
}
|
||||
|
||||
|
@@ -26,8 +26,8 @@
|
||||
#include <stdbool.h>
|
||||
|
||||
#if 0 /* NM_IGNORED */
|
||||
#include "udev.h"
|
||||
#include "condition.h"
|
||||
#include "udev.h"
|
||||
|
||||
bool net_match_config(const struct ether_addr *match_mac,
|
||||
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,
|
||||
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);
|
||||
#endif /* NM_IGNORED */
|
||||
|
||||
|
@@ -19,24 +19,28 @@
|
||||
|
||||
#include "nm-sd-adapt.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <net/ethernet.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 <linux/if_infiniband.h>
|
||||
|
||||
#include "util.h"
|
||||
#include "random-util.h"
|
||||
#include "sd-dhcp-client.h"
|
||||
|
||||
#include "alloc-util.h"
|
||||
#include "async.h"
|
||||
|
||||
#include "dhcp-protocol.h"
|
||||
#include "dhcp-identifier.h"
|
||||
#include "dhcp-internal.h"
|
||||
#include "dhcp-lease-internal.h"
|
||||
#include "dhcp-identifier.h"
|
||||
#include "sd-dhcp-client.h"
|
||||
#include "dhcp-protocol.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_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);
|
||||
|
||||
if (!hostname_is_valid(hostname, false) && !dns_name_is_valid(hostname))
|
||||
return -EINVAL;
|
||||
|
||||
if (streq_ptr(client->hostname, hostname))
|
||||
return 0;
|
||||
|
||||
@@ -539,6 +546,24 @@ static int client_message_init(sd_dhcp_client *client, DHCPPacket **ret,
|
||||
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,
|
||||
size_t len) {
|
||||
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;
|
||||
}
|
||||
|
||||
/* it is unclear from RFC 2131 if client should send hostname in
|
||||
DHCPDISCOVER but dhclient does and so we do as well
|
||||
*/
|
||||
if (client->hostname) {
|
||||
r = dhcp_option_append(&discover->dhcp, optlen, &optoffset, 0,
|
||||
DHCP_OPTION_HOST_NAME,
|
||||
strlen(client->hostname), 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
|
||||
DHCPDISCOVER but dhclient does and so we do as well
|
||||
*/
|
||||
r = dhcp_option_append(&discover->dhcp, optlen, &optoffset, 0,
|
||||
DHCP_OPTION_HOST_NAME,
|
||||
strlen(client->hostname), client->hostname);
|
||||
} else
|
||||
r = client_append_fqdn_option(&discover->dhcp, optlen, &optoffset,
|
||||
client->hostname);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
@@ -688,9 +721,13 @@ static int client_send_request(sd_dhcp_client *client) {
|
||||
}
|
||||
|
||||
if (client->hostname) {
|
||||
r = dhcp_option_append(&request->dhcp, optlen, &optoffset, 0,
|
||||
DHCP_OPTION_HOST_NAME,
|
||||
strlen(client->hostname), client->hostname);
|
||||
if (dns_name_single_label(client->hostname))
|
||||
r = dhcp_option_append(&request->dhcp, optlen, &optoffset, 0,
|
||||
DHCP_OPTION_HOST_NAME,
|
||||
strlen(client->hostname), client->hostname);
|
||||
else
|
||||
r = client_append_fqdn_option(&request->dhcp, optlen, &optoffset,
|
||||
client->hostname);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
@@ -1267,8 +1304,7 @@ static int client_set_lease_timeouts(sd_dhcp_client *client) {
|
||||
return r;
|
||||
|
||||
log_dhcp_client(client, "lease expires in %s",
|
||||
format_timespan(time_string, FORMAT_TIMESPAN_MAX,
|
||||
lifetime_timeout - time_now, 0));
|
||||
format_timespan(time_string, FORMAT_TIMESPAN_MAX, lifetime_timeout - time_now, USEC_PER_SEC));
|
||||
|
||||
/* don't arm earlier timeouts if this has already expired */
|
||||
if (lifetime_timeout <= time_now)
|
||||
@@ -1294,8 +1330,7 @@ static int client_set_lease_timeouts(sd_dhcp_client *client) {
|
||||
return r;
|
||||
|
||||
log_dhcp_client(client, "T2 expires in %s",
|
||||
format_timespan(time_string, FORMAT_TIMESPAN_MAX,
|
||||
t2_timeout - time_now, 0));
|
||||
format_timespan(time_string, FORMAT_TIMESPAN_MAX, t2_timeout - time_now, USEC_PER_SEC));
|
||||
|
||||
/* don't arm earlier timeout if this has already expired */
|
||||
if (t2_timeout <= time_now)
|
||||
@@ -1320,8 +1355,7 @@ static int client_set_lease_timeouts(sd_dhcp_client *client) {
|
||||
return r;
|
||||
|
||||
log_dhcp_client(client, "T1 expires in %s",
|
||||
format_timespan(time_string, FORMAT_TIMESPAN_MAX,
|
||||
t1_timeout - time_now, 0));
|
||||
format_timespan(time_string, FORMAT_TIMESPAN_MAX, t1_timeout - time_now, USEC_PER_SEC));
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1520,7 +1554,7 @@ static int client_receive_message_udp(sd_event_source *s, int fd,
|
||||
expected_hlen = ETH_ALEN;
|
||||
expected_chaddr = (const struct ether_addr *) &client->mac_addr;
|
||||
} else {
|
||||
/* Non-ethernet links expect zero chaddr */
|
||||
/* Non-Ethernet links expect zero chaddr */
|
||||
expected_hlen = 0;
|
||||
expected_chaddr = &zero_mac;
|
||||
}
|
||||
|
@@ -20,22 +20,28 @@
|
||||
|
||||
#include "nm-sd-adapt.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <stdio.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 "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) {
|
||||
assert_return(lease, -EINVAL);
|
||||
assert_return(addr, -EINVAL);
|
||||
@@ -947,19 +953,19 @@ int dhcp_lease_load(sd_dhcp_lease **ret, const char *lease_file) {
|
||||
if (address) {
|
||||
r = inet_pton(AF_INET, address, &lease->address);
|
||||
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) {
|
||||
r = inet_pton(AF_INET, router, &lease->router);
|
||||
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) {
|
||||
r = inet_pton(AF_INET, netmask, &lease->subnet_mask);
|
||||
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
|
||||
lease->have_subnet_mask = true;
|
||||
}
|
||||
@@ -967,19 +973,19 @@ int dhcp_lease_load(sd_dhcp_lease **ret, const char *lease_file) {
|
||||
if (server_address) {
|
||||
r = inet_pton(AF_INET, server_address, &lease->server_address);
|
||||
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) {
|
||||
r = inet_pton(AF_INET, next_server, &lease->next_server);
|
||||
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) {
|
||||
r = inet_pton(AF_INET, broadcast, &lease->broadcast);
|
||||
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
|
||||
lease->have_broadcast = true;
|
||||
}
|
||||
|
@@ -26,19 +26,19 @@
|
||||
#include <sys/ioctl.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 "dhcp6-protocol.h"
|
||||
|
||||
#include "alloc-util.h"
|
||||
#include "dhcp-identifier.h"
|
||||
#include "dhcp6-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
|
||||
|
||||
@@ -49,6 +49,7 @@ struct sd_dhcp6_client {
|
||||
sd_event *event;
|
||||
int event_priority;
|
||||
int index;
|
||||
struct in6_addr local_address;
|
||||
uint8_t mac_addr[MAX_MAC_ADDR_LEN];
|
||||
size_t mac_addr_len;
|
||||
uint16_t arp_type;
|
||||
@@ -136,6 +137,18 @@ int sd_dhcp6_client_set_index(sd_dhcp6_client *client, int interface_index) {
|
||||
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(
|
||||
sd_dhcp6_client *client,
|
||||
const uint8_t *addr, size_t addr_len,
|
||||
@@ -212,9 +225,8 @@ int sd_dhcp6_client_set_duid(
|
||||
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(IN_SET(client->state, DHCP6_STATE_STOPPED), -EBUSY);
|
||||
|
||||
client->information_request = enabled;
|
||||
@@ -222,7 +234,7 @@ int sd_dhcp6_client_set_information_request(sd_dhcp6_client *client, bool enable
|
||||
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(enabled, -EINVAL);
|
||||
|
||||
@@ -263,12 +275,12 @@ 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) {
|
||||
assert_return(client, -EINVAL);
|
||||
assert_return(ret, -EINVAL);
|
||||
|
||||
if (!client->lease)
|
||||
return -ENOMSG;
|
||||
|
||||
*ret = client->lease;
|
||||
if (ret)
|
||||
*ret = client->lease;
|
||||
|
||||
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",
|
||||
format_timespan(time_string, FORMAT_TIMESPAN_MAX,
|
||||
client->retransmit_time, 0));
|
||||
format_timespan(time_string, FORMAT_TIMESPAN_MAX, client->retransmit_time, USEC_PER_SEC));
|
||||
|
||||
r = sd_event_add_time(client->event, &client->timeout_resend,
|
||||
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);
|
||||
|
||||
log_dhcp6_client(client, "T1 expires in %s",
|
||||
format_timespan(time_string,
|
||||
FORMAT_TIMESPAN_MAX,
|
||||
timeout, 0));
|
||||
format_timespan(time_string, FORMAT_TIMESPAN_MAX, timeout, USEC_PER_SEC));
|
||||
|
||||
r = sd_event_add_time(client->event,
|
||||
&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);
|
||||
|
||||
log_dhcp6_client(client, "T2 expires in %s",
|
||||
format_timespan(time_string,
|
||||
FORMAT_TIMESPAN_MAX,
|
||||
timeout, 0));
|
||||
format_timespan(time_string, FORMAT_TIMESPAN_MAX, timeout, USEC_PER_SEC));
|
||||
|
||||
r = sd_event_add_time(client->event,
|
||||
&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) {
|
||||
assert_return(client, -EINVAL);
|
||||
|
||||
client_stop(client, SD_DHCP6_CLIENT_EVENT_STOP);
|
||||
|
||||
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 r = 0;
|
||||
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->event, -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))
|
||||
return -EALREADY;
|
||||
return -EBUSY;
|
||||
|
||||
r = client_reset(client);
|
||||
if (r < 0)
|
||||
@@ -1152,7 +1168,7 @@ int sd_dhcp6_client_start(sd_dhcp6_client *client) {
|
||||
if (r < 0)
|
||||
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)
|
||||
return r;
|
||||
|
||||
@@ -1286,4 +1302,3 @@ int sd_dhcp6_client_new(sd_dhcp6_client **ret) {
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@@ -24,11 +24,11 @@
|
||||
|
||||
#include <errno.h>
|
||||
|
||||
#include "strv.h"
|
||||
#include "util.h"
|
||||
|
||||
#include "alloc-util.h"
|
||||
#include "dhcp6-lease-internal.h"
|
||||
#include "dhcp6-protocol.h"
|
||||
#include "strv.h"
|
||||
#include "util.h"
|
||||
|
||||
int dhcp6_lease_clear_timers(DHCP6IA *ia) {
|
||||
assert_return(ia, -EINVAL);
|
||||
|
@@ -26,17 +26,19 @@
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "sd-ipv4acd.h"
|
||||
|
||||
#include "alloc-util.h"
|
||||
#include "arp-util.h"
|
||||
#include "event-util.h"
|
||||
#include "fd-util.h"
|
||||
#include "in-addr-util.h"
|
||||
#include "list.h"
|
||||
#include "refcnt.h"
|
||||
#include "random-util.h"
|
||||
#include "refcnt.h"
|
||||
#include "siphash24.h"
|
||||
#include "util.h"
|
||||
|
||||
#include "arp-util.h"
|
||||
#include "sd-ipv4acd.h"
|
||||
|
||||
/* Constants from the RFC */
|
||||
#define PROBE_WAIT 1
|
||||
#define PROBE_NUM 3
|
||||
@@ -470,7 +472,7 @@ int sd_ipv4acd_set_address(sd_ipv4acd *ll, const struct in_addr *address){
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool sd_ipv4acd_is_running(sd_ipv4acd *ll) {
|
||||
int sd_ipv4acd_is_running(sd_ipv4acd *ll) {
|
||||
assert_return(ll, false);
|
||||
|
||||
return ll->state != IPV4ACD_STATE_INIT;
|
||||
|
@@ -20,13 +20,18 @@
|
||||
|
||||
#include "nm-sd-adapt.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <stdio.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 "in-addr-util.h"
|
||||
#include "list.h"
|
||||
#include "random-util.h"
|
||||
#include "refcnt.h"
|
||||
@@ -34,9 +39,6 @@
|
||||
#include "sparse-endian.h"
|
||||
#include "util.h"
|
||||
|
||||
#include "sd-ipv4acd.h"
|
||||
#include "sd-ipv4ll.h"
|
||||
|
||||
#define IPV4LL_NETWORK 0xA9FE0000L
|
||||
#define IPV4LL_NETMASK 0xFFFF0000L
|
||||
|
||||
@@ -101,6 +103,8 @@ int sd_ipv4ll_new(sd_ipv4ll **ret) {
|
||||
if (!ll)
|
||||
return -ENOMEM;
|
||||
|
||||
ll->n_ref = 1;
|
||||
|
||||
r = sd_ipv4acd_new(&ll->acd);
|
||||
if (r < 0)
|
||||
return r;
|
||||
@@ -109,8 +113,6 @@ int sd_ipv4ll_new(sd_ipv4ll **ret) {
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
ll->n_ref = 1;
|
||||
|
||||
*ret = ll;
|
||||
ll = NULL;
|
||||
|
||||
@@ -143,15 +145,14 @@ int sd_ipv4ll_set_mac(sd_ipv4ll *ll, const struct ether_addr *addr) {
|
||||
assert_return(ll, -EINVAL);
|
||||
|
||||
if (!ll->random_data) {
|
||||
uint8_t seed[8];
|
||||
uint64_t seed;
|
||||
|
||||
/* If no random data is set, generate some from the MAC */
|
||||
siphash24(seed, &addr->ether_addr_octet,
|
||||
ETH_ALEN, HASH_KEY.bytes);
|
||||
seed = siphash24(&addr->ether_addr_octet, ETH_ALEN, HASH_KEY.bytes);
|
||||
|
||||
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)
|
||||
return r;
|
||||
}
|
||||
@@ -228,12 +229,45 @@ int sd_ipv4ll_set_address_seed(sd_ipv4ll *ll, unsigned seed) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool sd_ipv4ll_is_running(sd_ipv4ll *ll) {
|
||||
int sd_ipv4ll_is_running(sd_ipv4ll *ll) {
|
||||
assert_return(ll, false);
|
||||
|
||||
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) {
|
||||
struct in_addr in_addr;
|
||||
be32_t addr;
|
||||
@@ -249,18 +283,15 @@ static int ipv4ll_pick_address(sd_ipv4ll *ll) {
|
||||
return r;
|
||||
addr = htonl((random & 0x0000FFFF) | IPV4LL_NETWORK);
|
||||
} while (addr == ll->address ||
|
||||
(ntohl(addr) & IPV4LL_NETMASK) != IPV4LL_NETWORK ||
|
||||
(ntohl(addr) & 0x0000FF00) == 0x0000 ||
|
||||
(ntohl(addr) & 0x0000FF00) == 0xFF00);
|
||||
|
||||
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)
|
||||
return r;
|
||||
|
||||
ll->address = addr;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@@ -24,15 +24,19 @@
|
||||
|
||||
#include <arpa/inet.h>
|
||||
|
||||
#include "siphash24.h"
|
||||
#include "hashmap.h"
|
||||
|
||||
#include "lldp-tlv.h"
|
||||
#include "lldp-port.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-port.h"
|
||||
#include "lldp-tlv.h"
|
||||
#include "lldp-util.h"
|
||||
#include "prioq.h"
|
||||
#include "siphash24.h"
|
||||
#include "string-util.h"
|
||||
|
||||
typedef enum LLDPAgentRXState {
|
||||
LLDP_AGENT_RX_WAIT_PORT_OPERATIONAL = 4,
|
||||
|
@@ -23,9 +23,10 @@
|
||||
|
||||
#include "nm-sd-adapt.h"
|
||||
|
||||
#include "util.h"
|
||||
#include "sd-event.h"
|
||||
|
||||
#include "util.h"
|
||||
|
||||
DEFINE_TRIVIAL_CLEANUP_FUNC(sd_event*, sd_event_unref);
|
||||
DEFINE_TRIVIAL_CLEANUP_FUNC(sd_event_source*, sd_event_source_unref);
|
||||
|
||||
|
@@ -25,10 +25,14 @@
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "util.h"
|
||||
#include "macro.h"
|
||||
#include "sd-id128.h"
|
||||
|
||||
#include "fd-util.h"
|
||||
#include "hexdecoct.h"
|
||||
#include "io-util.h"
|
||||
#include "macro.h"
|
||||
#include "random-util.h"
|
||||
#include "util.h"
|
||||
|
||||
#if 0 /* NM_IGNORED */
|
||||
_public_ char *sd_id128_to_string(sd_id128_t id, char s[SD_ID128_STRING_MAX]) {
|
||||
|
@@ -26,7 +26,11 @@
|
||||
#include <stringprep.h>
|
||||
#endif
|
||||
|
||||
#include "alloc-util.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) {
|
||||
const char *n;
|
||||
@@ -695,6 +699,7 @@ int dns_name_root(const char *name) {
|
||||
|
||||
return r == 0 && *name == 0;
|
||||
}
|
||||
#endif /* NM_IGNORED */
|
||||
|
||||
int dns_name_single_label(const char *name) {
|
||||
char label[DNS_LABEL_MAX+1];
|
||||
@@ -714,4 +719,37 @@ int dns_name_single_label(const char *name) {
|
||||
|
||||
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;
|
||||
}
|
||||
|
@@ -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_root(const char *name);
|
||||
#endif /* NM_IGNORED */
|
||||
|
||||
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);
|
||||
|
@@ -24,11 +24,17 @@
|
||||
|
||||
#include "nm-sd-adapt.h"
|
||||
|
||||
#include <netinet/in.h>
|
||||
#include <inttypes.h>
|
||||
#include <net/ethernet.h>
|
||||
#include <netinet/in.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include "sd-event.h"
|
||||
#include "sd-dhcp-lease.h"
|
||||
#include "sd-event.h"
|
||||
|
||||
#include "_sd-common.h"
|
||||
|
||||
_SD_BEGIN_DECLARATIONS;
|
||||
|
||||
enum {
|
||||
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);
|
||||
sd_event *sd_dhcp_client_get_event(sd_dhcp_client *client);
|
||||
|
||||
_SD_END_DECLARATIONS;
|
||||
|
||||
#endif
|
||||
|
@@ -25,8 +25,14 @@
|
||||
|
||||
#include "nm-sd-adapt.h"
|
||||
|
||||
#include <netinet/in.h>
|
||||
#include <inttypes.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;
|
||||
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_timezone(sd_dhcp_lease *lease, const char **timezone);
|
||||
|
||||
_SD_END_DECLARATIONS;
|
||||
|
||||
#endif
|
||||
|
@@ -24,11 +24,16 @@
|
||||
|
||||
#include "nm-sd-adapt.h"
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <net/ethernet.h>
|
||||
|
||||
#include "sd-event.h"
|
||||
#include <sys/types.h>
|
||||
|
||||
#include "sd-dhcp6-lease.h"
|
||||
#include "sd-event.h"
|
||||
|
||||
#include "_sd-common.h"
|
||||
|
||||
_SD_BEGIN_DECLARATIONS;
|
||||
|
||||
enum {
|
||||
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);
|
||||
|
||||
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,
|
||||
size_t addr_len, uint16_t arp_type);
|
||||
int sd_dhcp6_client_set_duid(sd_dhcp6_client *client, uint16_t type, uint8_t *duid,
|
||||
size_t duid_len);
|
||||
int sd_dhcp6_client_set_information_request(sd_dhcp6_client *client,
|
||||
bool enabled);
|
||||
int sd_dhcp6_client_get_information_request(sd_dhcp6_client *client,
|
||||
bool *enabled);
|
||||
int sd_dhcp6_client_set_information_request(sd_dhcp6_client *client, int enabled);
|
||||
int sd_dhcp6_client_get_information_request(sd_dhcp6_client *client, int *enabled);
|
||||
int sd_dhcp6_client_set_request_option(sd_dhcp6_client *client,
|
||||
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_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 priority);
|
||||
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);
|
||||
int sd_dhcp6_client_new(sd_dhcp6_client **ret);
|
||||
|
||||
_SD_END_DECLARATIONS;
|
||||
|
||||
#endif
|
||||
|
@@ -25,8 +25,13 @@
|
||||
|
||||
#include "nm-sd-adapt.h"
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <netinet/in.h>
|
||||
|
||||
#include "_sd-common.h"
|
||||
|
||||
_SD_BEGIN_DECLARATIONS;
|
||||
|
||||
typedef struct sd_dhcp6_lease sd_dhcp6_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_unref(sd_dhcp6_lease *lease);
|
||||
|
||||
_SD_END_DECLARATIONS;
|
||||
|
||||
#endif
|
||||
|
@@ -24,11 +24,11 @@
|
||||
|
||||
#include "nm-sd-adapt.h"
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/signalfd.h>
|
||||
#include <sys/epoll.h>
|
||||
#include <inttypes.h>
|
||||
#include <signal.h>
|
||||
#include <sys/epoll.h>
|
||||
#include <sys/signalfd.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include "_sd-common.h"
|
||||
|
||||
@@ -58,7 +58,8 @@ enum {
|
||||
SD_EVENT_PENDING,
|
||||
SD_EVENT_RUNNING,
|
||||
SD_EVENT_EXITING,
|
||||
SD_EVENT_FINISHED
|
||||
SD_EVENT_FINISHED,
|
||||
SD_EVENT_PREPARING,
|
||||
};
|
||||
|
||||
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_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_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_exit(sd_event *e, int code);
|
||||
|
||||
|
@@ -25,12 +25,15 @@
|
||||
|
||||
#include "nm-sd-adapt.h"
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <netinet/in.h>
|
||||
#include <net/ethernet.h>
|
||||
#include <netinet/in.h>
|
||||
|
||||
#include "sd-event.h"
|
||||
|
||||
#include "_sd-common.h"
|
||||
|
||||
_SD_BEGIN_DECLARATIONS;
|
||||
|
||||
enum {
|
||||
SD_IPV4ACD_EVENT_STOP = 0,
|
||||
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_index(sd_ipv4acd *ll, int interface_index);
|
||||
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_stop(sd_ipv4acd *ll);
|
||||
sd_ipv4acd *sd_ipv4acd_ref(sd_ipv4acd *ll);
|
||||
sd_ipv4acd *sd_ipv4acd_unref(sd_ipv4acd *ll);
|
||||
int sd_ipv4acd_new (sd_ipv4acd **ret);
|
||||
|
||||
_SD_END_DECLARATIONS;
|
||||
|
||||
#endif
|
||||
|
@@ -24,12 +24,15 @@
|
||||
|
||||
#include "nm-sd-adapt.h"
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <netinet/in.h>
|
||||
#include <net/ethernet.h>
|
||||
#include <netinet/in.h>
|
||||
|
||||
#include "sd-event.h"
|
||||
|
||||
#include "_sd-common.h"
|
||||
|
||||
_SD_BEGIN_DECLARATIONS;
|
||||
|
||||
enum {
|
||||
SD_IPV4LL_EVENT_STOP = 0,
|
||||
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_mac(sd_ipv4ll *ll, const struct ether_addr *addr);
|
||||
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);
|
||||
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_stop(sd_ipv4ll *ll);
|
||||
sd_ipv4ll *sd_ipv4ll_ref(sd_ipv4ll *ll);
|
||||
sd_ipv4ll *sd_ipv4ll_unref(sd_ipv4ll *ll);
|
||||
int sd_ipv4ll_new (sd_ipv4ll **ret);
|
||||
|
||||
_SD_END_DECLARATIONS;
|
||||
|
||||
#endif
|
||||
|
@@ -1,5 +1,8 @@
|
||||
/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
|
||||
|
||||
#ifndef foosdlldphfoo
|
||||
#define foosdlldphfoo
|
||||
|
||||
/***
|
||||
This file is part of systemd.
|
||||
|
||||
@@ -20,12 +23,17 @@
|
||||
along with systemd; If not, see <http://www.gnu.org/licenses/>.
|
||||
***/
|
||||
|
||||
#pragma once
|
||||
|
||||
#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_LLDP_EVENT_UPDATE_INFO = 0,
|
||||
};
|
||||
@@ -37,7 +45,7 @@ enum {
|
||||
};
|
||||
|
||||
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);
|
||||
|
||||
@@ -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_get_packets(sd_lldp *lldp, sd_lldp_packet ***tlvs);
|
||||
|
||||
_SD_END_DECLARATIONS;
|
||||
|
||||
#endif
|
||||
|
86
src/systemd/src/systemd/sd-ndisc.h
Normal file
86
src/systemd/src/systemd/sd-ndisc.h
Normal 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
|
Reference in New Issue
Block a user