mirror of
https://gitlab.freedesktop.org/NetworkManager/NetworkManager.git
synced 2026-01-04 04:00:17 +01:00
dhcp: merge branch 'th/systemd-dhcp-integration' (bgo #742719)
Update internal dhcp library with new code from upstream systemd. HEAD=117cb022b13cedf4035e2a778b8d61528075a8b4 MERGE=$(git rev-list --merges -n1 $HEAD) # how did we modify the systemd code? git diffs $MERGE^1 $HEAD -- :/src/dhcp-manager/systemd-dhcp/ # what changed in systemd since last merge: git diffs $MERGE^2 $HEAD -- :/src/dhcp-manager/systemd-dhcp/src/libsystemd-network/ https://bugzilla.gnome.org/show_bug.cgi?id=742719
This commit is contained in:
commit
4e07f61173
37 changed files with 3513 additions and 842 deletions
|
|
@ -65,6 +65,9 @@ SYSTEMD_DHCP_CFLAGS = \
|
|||
-I$(top_srcdir)/src/dhcp-manager/systemd-dhcp
|
||||
|
||||
libsystemd_dhcp_la_SOURCES = \
|
||||
dhcp-manager/systemd-dhcp/src/libsystemd/sd-id128/sd-id128.c \
|
||||
dhcp-manager/systemd-dhcp/src/libsystemd-network/dhcp-identifier.c \
|
||||
dhcp-manager/systemd-dhcp/src/libsystemd-network/dhcp-identifier.h \
|
||||
dhcp-manager/systemd-dhcp/src/libsystemd-network/dhcp-network.c \
|
||||
dhcp-manager/systemd-dhcp/src/libsystemd-network/dhcp-packet.c \
|
||||
dhcp-manager/systemd-dhcp/src/libsystemd-network/dhcp-internal.h \
|
||||
|
|
@ -96,8 +99,11 @@ libsystemd_dhcp_la_SOURCES = \
|
|||
dhcp-manager/systemd-dhcp/src/shared/util.h \
|
||||
dhcp-manager/systemd-dhcp/src/shared/in-addr-util.h \
|
||||
dhcp-manager/systemd-dhcp/src/shared/list.h \
|
||||
dhcp-manager/systemd-dhcp/src/shared/log.h \
|
||||
dhcp-manager/systemd-dhcp/src/shared/fileio.h \
|
||||
dhcp-manager/systemd-dhcp/src/shared/fileio.c \
|
||||
dhcp-manager/systemd-dhcp/src/shared/path-util.c \
|
||||
dhcp-manager/systemd-dhcp/src/shared/path-util.h \
|
||||
dhcp-manager/systemd-dhcp/src/shared/strv.h \
|
||||
dhcp-manager/systemd-dhcp/src/shared/strv.c \
|
||||
dhcp-manager/systemd-dhcp/src/shared/unaligned.h \
|
||||
|
|
|
|||
|
|
@ -746,12 +746,6 @@ ip6_start (NMDhcpClient *client,
|
|||
goto error;
|
||||
}
|
||||
|
||||
r = sd_dhcp6_client_set_ifname (priv->client6, iface);
|
||||
if (r < 0) {
|
||||
nm_log_warn (LOGD_DHCP6, "(%s): failed to set DHCP ifname (%d)", iface, r);
|
||||
goto error;
|
||||
}
|
||||
|
||||
r = sd_dhcp6_client_set_callback (priv->client6, dhcp6_event_cb, client);
|
||||
if (r < 0) {
|
||||
nm_log_warn (LOGD_DHCP6, "(%s): failed to set DHCP callback (%d)", iface, r);
|
||||
|
|
|
|||
|
|
@ -36,14 +36,20 @@
|
|||
#include <unistd.h>
|
||||
#include <sys/syscall.h>
|
||||
|
||||
#include <net/if_arp.h>
|
||||
#include <sys/resource.h>
|
||||
|
||||
#include "nm-logging.h"
|
||||
|
||||
static inline guint32
|
||||
/*****************************************************************************/
|
||||
|
||||
static inline NMLogLevel
|
||||
_slog_level_to_nm (int slevel)
|
||||
{
|
||||
switch (slevel) {
|
||||
case LOG_DEBUG: return LOGL_DEBUG;
|
||||
case LOG_WARNING: return LOGL_WARN;
|
||||
case LOG_CRIT:
|
||||
case LOG_ERR: return LOGL_ERR;
|
||||
case LOG_INFO:
|
||||
case LOG_NOTICE:
|
||||
|
|
@ -51,39 +57,37 @@ _slog_level_to_nm (int slevel)
|
|||
}
|
||||
}
|
||||
|
||||
#define log_meta(level, file, line, func, format, ...) \
|
||||
G_STMT_START { \
|
||||
guint32 _l = _slog_level_to_nm ((level)); \
|
||||
if (nm_logging_enabled (_l, LOGD_DHCP)) { \
|
||||
const char *_location = strrchr (file "", '/'); \
|
||||
#define log_internal(level, error, file, line, func, format, ...) \
|
||||
({ \
|
||||
int _nm_e = (error); \
|
||||
NMLogLevel _nm_l = _slog_level_to_nm ((level)); \
|
||||
if (nm_logging_enabled (_nm_l, LOGD_DHCP)) { \
|
||||
const char *_nm_location = strrchr ((""file), '/'); \
|
||||
\
|
||||
_nm_log (_location ? _location + 1 : file, line, func, _l, LOGD_DHCP, 0, format, ## __VA_ARGS__); \
|
||||
_nm_log (_nm_location ? _nm_location + 1 : (""file), (line), (func), _nm_l, LOGD_DHCP, _nm_e, ("%s"format), "sd-dhcp: ", ## __VA_ARGS__); \
|
||||
} \
|
||||
} G_STMT_END
|
||||
(_nm_e > 0 ? -_nm_e : _nm_e); \
|
||||
})
|
||||
|
||||
#define log_debug(...) log_full(LOG_DEBUG, __VA_ARGS__)
|
||||
#define log_error(...) log_full(LOG_ERR, __VA_ARGS__)
|
||||
#define log_full(level, ...) log_meta((level), __FILE__, __LINE__, __func__, __VA_ARGS__);
|
||||
#define log_full_errno(level, error, ...) \
|
||||
({ \
|
||||
log_internal(level, error, __FILE__, __LINE__, __func__, __VA_ARGS__); \
|
||||
})
|
||||
|
||||
#define log_dhcp_client(client, fmt, ...) \
|
||||
log_meta(LOG_DEBUG, __FILE__, __LINE__, __func__, "DHCP CLIENT (0x%x): " fmt, client->xid, ##__VA_ARGS__)
|
||||
|
||||
#define log_assert_failed(e, file, line, func) \
|
||||
#define log_assert_failed(text, file, line, func) \
|
||||
G_STMT_START { \
|
||||
nm_log_err (LOGD_DHCP, #file ":" #line "(" #func "): assertion failed: " # e); \
|
||||
g_assert (FALSE); \
|
||||
} G_STMT_END
|
||||
|
||||
#define log_assert_failed_unreachable(t, file, line, func) \
|
||||
G_STMT_START { \
|
||||
nm_log_err (LOGD_DHCP, #file ":" #line "(" #func "): assert unreachable: " # t); \
|
||||
log_internal (LOG_CRIT, 0, file, line, func, "Assertion '%s' failed at %s:%u, function %s(). Aborting.", text, file, line, func); \
|
||||
g_assert_not_reached (); \
|
||||
} G_STMT_END
|
||||
|
||||
#define log_assert_failed_return(e, file, line, func) \
|
||||
nm_log_err (LOGD_DHCP, #file ":" #line "(" #func "): assert return: " # e); \
|
||||
#define log_assert_failed_return(text, file, line, func) \
|
||||
G_STMT_START { \
|
||||
log_internal (LOG_DEBUG, 0, file, line, func, "Assertion '%s' failed at %s:%u, function %s(). Ignoring.", text, file, line, func); \
|
||||
g_return_if_fail_warning (G_LOG_DOMAIN, G_STRFUNC, text); \
|
||||
} G_STMT_END
|
||||
|
||||
#define log_oom nm_log_err(LOGD_CORE, "%s:%s/%s: OOM", __FILE__, __LINE__, __func__)
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
/* Can't include both net/if.h and linux/if.h; so have to define this here */
|
||||
#ifndef IFNAMSIZ
|
||||
|
|
|
|||
|
|
@ -0,0 +1,111 @@
|
|||
/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
|
||||
|
||||
/***
|
||||
This file is part of systemd.
|
||||
|
||||
Copyright (C) 2015 Tom Gundersen <teg@jklmen>
|
||||
|
||||
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 "sd-id128.h"
|
||||
#if 0 /* NM_IGNORED a*/
|
||||
#include "libudev.h"
|
||||
#include "udev-util.h"
|
||||
|
||||
#include "virt.h"
|
||||
#include "sparse-endian.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;
|
||||
int r;
|
||||
|
||||
assert(duid);
|
||||
assert(len);
|
||||
|
||||
r = sd_id128_get_machine(&machine_id);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
duid->type = htobe16(DHCP6_DUID_EN);
|
||||
duid->en.pen = htobe32(SYSTEMD_PEN);
|
||||
*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);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int dhcp_identifier_set_iaid(int ifindex, uint8_t *mac, size_t mac_len, uint32_t *_id) {
|
||||
#if 0 /* NM_IGNORED */
|
||||
/* name is a pointer to memory in the udev_device struct, so must
|
||||
have the same scope */
|
||||
_cleanup_udev_device_unref_ struct udev_device *device = NULL;
|
||||
#else /* NM_IGNORED */
|
||||
char name_buf[IF_NAMESIZE];
|
||||
#endif /* NM_IGNORED */
|
||||
const char *name = NULL;
|
||||
uint64_t id;
|
||||
|
||||
#if 0 /* NM_IGNORED */
|
||||
if (detect_container(NULL) <= 0) {
|
||||
/* not in a container, udev will be around */
|
||||
_cleanup_udev_unref_ struct udev *udev;
|
||||
char ifindex_str[2 + DECIMAL_STR_MAX(int)];
|
||||
|
||||
udev = udev_new();
|
||||
if (!udev)
|
||||
return -ENOMEM;
|
||||
|
||||
sprintf(ifindex_str, "n%d", ifindex);
|
||||
device = udev_device_new_from_device_id(udev, ifindex_str);
|
||||
if (device) {
|
||||
if (udev_device_get_is_initialized(device) <= 0)
|
||||
/* not yet ready */
|
||||
return -EBUSY;
|
||||
|
||||
name = net_get_name(device);
|
||||
}
|
||||
}
|
||||
#else /* NM_IGNORED */
|
||||
name = if_indextoname(ifindex, name_buf);
|
||||
#endif /* NM_IGNORED */
|
||||
|
||||
if (name)
|
||||
siphash24((uint8_t*)&id, 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);
|
||||
|
||||
/* fold into 32 bits */
|
||||
*_id = (id & 0xffffffff) ^ (id >> 32);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -0,0 +1,65 @@
|
|||
/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
|
||||
|
||||
#pragma once
|
||||
|
||||
/***
|
||||
This file is part of systemd.
|
||||
|
||||
Copyright (C) 2015 Tom Gundersen <teg@jklmen>
|
||||
|
||||
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 "macro.h"
|
||||
#include "sparse-endian.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).
|
||||
*/
|
||||
#define MAX_DUID_LEN 128
|
||||
|
||||
struct duid {
|
||||
uint16_t type;
|
||||
union {
|
||||
struct {
|
||||
/* DHCP6_DUID_LLT */
|
||||
uint16_t htype;
|
||||
uint32_t time;
|
||||
uint8_t haddr[0];
|
||||
} _packed_ llt;
|
||||
struct {
|
||||
/* DHCP6_DUID_EN */
|
||||
uint32_t pen;
|
||||
uint8_t id[8];
|
||||
} _packed_ en;
|
||||
struct {
|
||||
/* DHCP6_DUID_LL */
|
||||
int16_t htype;
|
||||
uint8_t haddr[0];
|
||||
} _packed_ ll;
|
||||
struct {
|
||||
/* DHCP6_DUID_UUID */
|
||||
sd_id128_t uuid;
|
||||
} _packed_ uuid;
|
||||
struct {
|
||||
uint8_t data[MAX_DUID_LEN];
|
||||
} _packed_ raw;
|
||||
};
|
||||
} _packed_;
|
||||
|
||||
int dhcp_identifier_set_duid_en(struct duid *duid, size_t *len);
|
||||
int dhcp_identifier_set_iaid(int ifindex, uint8_t *mac, size_t mac_len, uint32_t *_id);
|
||||
|
|
@ -73,4 +73,4 @@ DEFINE_TRIVIAL_CLEANUP_FUNC(sd_dhcp_client*, sd_dhcp_client_unref);
|
|||
#define DHCP_CLIENT_DONT_DESTROY(client) \
|
||||
_cleanup_dhcp_client_unref_ _unused_ sd_dhcp_client *_dont_destroy_##client = sd_dhcp_client_ref(client)
|
||||
|
||||
#define log_dhcp_client(client, fmt, ...) log_meta(LOG_DEBUG, __FILE__, __LINE__, __func__, "DHCP CLIENT (0x%x): " fmt, client->xid, ##__VA_ARGS__)
|
||||
#define log_dhcp_client(client, fmt, ...) log_internal(LOG_DEBUG, 0, __FILE__, __LINE__, __func__, "DHCP CLIENT (0x%x): " fmt, client->xid, ##__VA_ARGS__)
|
||||
|
|
|
|||
|
|
@ -20,7 +20,6 @@
|
|||
#include "nm-sd-adapt.h"
|
||||
|
||||
#include <errno.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <string.h>
|
||||
#include <linux/if_packet.h>
|
||||
|
|
@ -28,7 +27,6 @@
|
|||
#include <net/ethernet.h>
|
||||
#include <net/if_arp.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <linux/filter.h>
|
||||
|
||||
#include "socket-util.h"
|
||||
|
|
@ -65,7 +63,7 @@ static int _bind_raw_socket(int ifindex, union sockaddr_union *link,
|
|||
BPF_STMT(BPF_LD + BPF_B + BPF_ABS, offsetof(DHCPPacket, dhcp.htype)), /* A <- DHCP header type */
|
||||
BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, arp_type, 1, 0), /* header type == arp_type ? */
|
||||
BPF_STMT(BPF_RET + BPF_K, 0), /* ignore */
|
||||
BPF_STMT(BPF_LD + BPF_B + BPF_ABS, offsetof(DHCPPacket, dhcp.hlen)), /* A <- mac address length */
|
||||
BPF_STMT(BPF_LD + BPF_B + BPF_ABS, offsetof(DHCPPacket, dhcp.hlen)), /* A <- MAC address length */
|
||||
BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, dhcp_hlen, 1, 0), /* address length == dhcp_hlen ? */
|
||||
BPF_STMT(BPF_RET + BPF_K, 0), /* ignore */
|
||||
BPF_STMT(BPF_LD + BPF_W + BPF_ABS, offsetof(DHCPPacket, dhcp.xid)), /* A <- client identifier */
|
||||
|
|
|
|||
|
|
@ -20,22 +20,14 @@
|
|||
|
||||
#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 <sys/param.h>
|
||||
|
||||
#include "util.h"
|
||||
#include "list.h"
|
||||
|
||||
#include "dhcp-protocol.h"
|
||||
#include "dhcp-lease-internal.h"
|
||||
#include "dhcp-internal.h"
|
||||
#include "sd-dhcp-lease.h"
|
||||
#include "sd-dhcp-client.h"
|
||||
|
||||
#define DHCP_CLIENT_MIN_OPTIONS_SIZE 312
|
||||
|
||||
|
|
|
|||
|
|
@ -58,7 +58,7 @@ struct DHCP6IA {
|
|||
|
||||
typedef struct DHCP6IA DHCP6IA;
|
||||
|
||||
#define log_dhcp6_client(p, fmt, ...) log_meta(LOG_DEBUG, __FILE__, __LINE__, __func__, "DHCPv6 CLIENT: " fmt, ##__VA_ARGS__)
|
||||
#define log_dhcp6_client(p, fmt, ...) log_internal(LOG_DEBUG, 0, __FILE__, __LINE__, __func__, "DHCPv6 CLIENT: " fmt, ##__VA_ARGS__)
|
||||
|
||||
int dhcp_network_icmp6_bind_router_solicitation(int index);
|
||||
int dhcp_network_icmp6_send_router_solicitation(int s, const struct ether_addr *ether_addr);
|
||||
|
|
|
|||
|
|
@ -53,6 +53,8 @@ enum {
|
|||
DHCP6_PORT_CLIENT = 546,
|
||||
};
|
||||
|
||||
#define DHCP6_INF_TIMEOUT 1 * USEC_PER_SEC
|
||||
#define DHCP6_INF_MAX_RT 120 * USEC_PER_SEC
|
||||
#define DHCP6_SOL_MAX_DELAY 1 * USEC_PER_SEC
|
||||
#define DHCP6_SOL_TIMEOUT 1 * USEC_PER_SEC
|
||||
#define DHCP6_SOL_MAX_RT 120 * USEC_PER_SEC
|
||||
|
|
@ -73,6 +75,7 @@ enum {
|
|||
|
||||
enum DHCP6State {
|
||||
DHCP6_STATE_STOPPED = 0,
|
||||
DHCP6_STATE_INFORMATION_REQUEST = 1,
|
||||
DHCP6_STATE_SOLICITATION = 2,
|
||||
DHCP6_STATE_REQUEST = 3,
|
||||
DHCP6_STATE_BOUND = 4,
|
||||
|
|
|
|||
|
|
@ -24,12 +24,10 @@
|
|||
#include <netinet/ether.h>
|
||||
#include <linux/if.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <fnmatch.h>
|
||||
|
||||
#if 0 /* NM_IGNORED */
|
||||
#include "strv.h"
|
||||
#include "siphash24.h"
|
||||
#include "libudev-private.h"
|
||||
#endif /* NM_IGNORED */
|
||||
#include "dhcp-lease-internal.h"
|
||||
#if 0 /* NM_IGNORED */
|
||||
|
|
@ -92,10 +90,10 @@ int net_get_unique_predictable_data(struct udev_device *device, uint8_t result[8
|
|||
}
|
||||
|
||||
bool net_match_config(const struct ether_addr *match_mac,
|
||||
const char *match_path,
|
||||
const char *match_driver,
|
||||
const char *match_type,
|
||||
const char *match_name,
|
||||
char * const *match_paths,
|
||||
char * const *match_drivers,
|
||||
char * const *match_types,
|
||||
char * const *match_names,
|
||||
Condition *match_host,
|
||||
Condition *match_virt,
|
||||
Condition *match_kernel,
|
||||
|
|
@ -108,37 +106,37 @@ bool net_match_config(const struct ether_addr *match_mac,
|
|||
const char *dev_name) {
|
||||
|
||||
if (match_host && !condition_test(match_host))
|
||||
return 0;
|
||||
return false;
|
||||
|
||||
if (match_virt && !condition_test(match_virt))
|
||||
return 0;
|
||||
return false;
|
||||
|
||||
if (match_kernel && !condition_test(match_kernel))
|
||||
return 0;
|
||||
return false;
|
||||
|
||||
if (match_arch && !condition_test(match_arch))
|
||||
return 0;
|
||||
return false;
|
||||
|
||||
if (match_mac && (!dev_mac || memcmp(match_mac, dev_mac, ETH_ALEN)))
|
||||
return 0;
|
||||
return false;
|
||||
|
||||
if (match_path && (!dev_path || fnmatch(match_path, dev_path, 0)))
|
||||
return 0;
|
||||
if (!strv_isempty(match_paths) &&
|
||||
(!dev_path || !strv_fnmatch(match_paths, dev_path, 0)))
|
||||
return false;
|
||||
|
||||
if (match_driver) {
|
||||
if (dev_parent_driver && !streq(match_driver, dev_parent_driver))
|
||||
return 0;
|
||||
else if (!streq_ptr(match_driver, dev_driver))
|
||||
return 0;
|
||||
}
|
||||
if (!strv_isempty(match_drivers) &&
|
||||
(!dev_driver || !strv_fnmatch(match_drivers, dev_driver, 0)))
|
||||
return false;
|
||||
|
||||
if (match_type && !streq_ptr(match_type, dev_type))
|
||||
return 0;
|
||||
if (!strv_isempty(match_types) &&
|
||||
(!dev_type || !strv_fnmatch_or_empty(match_types, dev_type, 0)))
|
||||
return false;
|
||||
|
||||
if (match_name && (!dev_name || fnmatch(match_name, dev_name, 0)))
|
||||
return 0;
|
||||
if (!strv_isempty(match_names) &&
|
||||
(!dev_name || !strv_fnmatch_or_empty(match_names, dev_name, 0)))
|
||||
return false;
|
||||
|
||||
return 1;
|
||||
return true;
|
||||
}
|
||||
|
||||
int config_parse_net_condition(const char *unit,
|
||||
|
|
@ -221,6 +219,49 @@ int config_parse_ifname(const char *unit,
|
|||
return 0;
|
||||
}
|
||||
|
||||
int config_parse_ifnames(const char *unit,
|
||||
const char *filename,
|
||||
unsigned line,
|
||||
const char *section,
|
||||
unsigned section_line,
|
||||
const char *lvalue,
|
||||
int ltype,
|
||||
const char *rvalue,
|
||||
void *data,
|
||||
void *userdata) {
|
||||
|
||||
char ***sv = data;
|
||||
const char *word, *state;
|
||||
size_t l;
|
||||
int r;
|
||||
|
||||
assert(filename);
|
||||
assert(lvalue);
|
||||
assert(rvalue);
|
||||
assert(data);
|
||||
|
||||
FOREACH_WORD(word, l, rvalue, state) {
|
||||
char *n;
|
||||
|
||||
n = strndup(word, l);
|
||||
if (!n)
|
||||
return log_oom();
|
||||
|
||||
if (!ascii_is_valid(n) || strlen(n) >= IFNAMSIZ) {
|
||||
log_syntax(unit, LOG_ERR, filename, line, EINVAL,
|
||||
"Interface name is not ASCII clean or is too long, ignoring assignment: %s", rvalue);
|
||||
free(n);
|
||||
return 0;
|
||||
}
|
||||
|
||||
r = strv_consume(sv, n);
|
||||
if (r < 0)
|
||||
return log_oom();
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int config_parse_ifalias(const char *unit,
|
||||
const char *filename,
|
||||
unsigned line,
|
||||
|
|
@ -233,7 +274,7 @@ int config_parse_ifalias(const char *unit,
|
|||
void *userdata) {
|
||||
|
||||
char **s = data;
|
||||
char *n;
|
||||
_cleanup_free_ char *n = NULL;
|
||||
|
||||
assert(filename);
|
||||
assert(lvalue);
|
||||
|
|
@ -247,17 +288,15 @@ int config_parse_ifalias(const char *unit,
|
|||
if (!ascii_is_valid(n) || strlen(n) >= IFALIASZ) {
|
||||
log_syntax(unit, LOG_ERR, filename, line, EINVAL,
|
||||
"Interface alias is not ASCII clean or is too long, ignoring assignment: %s", rvalue);
|
||||
free(n);
|
||||
return 0;
|
||||
}
|
||||
|
||||
free(*s);
|
||||
if (*n)
|
||||
if (*n) {
|
||||
*s = n;
|
||||
else {
|
||||
free(n);
|
||||
n = NULL;
|
||||
} else
|
||||
*s = NULL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -23,8 +23,6 @@
|
|||
|
||||
#include "nm-sd-adapt.h"
|
||||
|
||||
#include <netinet/ether.h>
|
||||
#include <netinet/in.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#if 0 /* NM_IGNORED */
|
||||
|
|
@ -32,10 +30,10 @@
|
|||
#include "condition.h"
|
||||
|
||||
bool net_match_config(const struct ether_addr *match_mac,
|
||||
const char *match_path,
|
||||
const char *match_driver,
|
||||
const char *match_type,
|
||||
const char *match_name,
|
||||
char * const *match_path,
|
||||
char * const *match_driver,
|
||||
char * const *match_type,
|
||||
char * const *match_name,
|
||||
Condition *match_host,
|
||||
Condition *match_virt,
|
||||
Condition *match_kernel,
|
||||
|
|
@ -59,6 +57,10 @@ int config_parse_ifname(const char *unit, const char *filename, unsigned line,
|
|||
const char *section, unsigned section_line, const char *lvalue,
|
||||
int ltype, const char *rvalue, void *data, void *userdata);
|
||||
|
||||
int config_parse_ifnames(const char *unit, const char *filename, unsigned line,
|
||||
const char *section, unsigned section_line, const char *lvalue,
|
||||
int ltype, const char *rvalue, void *data, void *userdata);
|
||||
|
||||
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);
|
||||
|
|
|
|||
|
|
@ -26,21 +26,19 @@
|
|||
#include <net/ethernet.h>
|
||||
#include <net/if_arp.h>
|
||||
#include <linux/if_infiniband.h>
|
||||
#include <netinet/ether.h>
|
||||
#include <sys/param.h>
|
||||
#include <sys/ioctl.h>
|
||||
|
||||
#include "util.h"
|
||||
#include "list.h"
|
||||
#include "refcnt.h"
|
||||
#include "async.h"
|
||||
|
||||
#include "dhcp-protocol.h"
|
||||
#include "dhcp-internal.h"
|
||||
#include "dhcp-lease-internal.h"
|
||||
#include "dhcp-identifier.h"
|
||||
#include "sd-dhcp-client.h"
|
||||
|
||||
#define MAX_CLIENT_ID_LEN 64 /* Arbitrary limit */
|
||||
#define MAX_CLIENT_ID_LEN (sizeof(uint32_t) + MAX_DUID_LEN) /* Arbitrary limit */
|
||||
#define MAX_MAC_ADDR_LEN INFINIBAND_ALEN
|
||||
|
||||
struct sd_dhcp_client {
|
||||
|
|
@ -62,29 +60,31 @@ struct sd_dhcp_client {
|
|||
uint8_t mac_addr[MAX_MAC_ADDR_LEN];
|
||||
size_t mac_addr_len;
|
||||
uint16_t arp_type;
|
||||
union {
|
||||
struct {
|
||||
uint8_t type; /* 0: Generic (non-LL) (RFC 2132) */
|
||||
uint8_t data[MAX_CLIENT_ID_LEN];
|
||||
} _packed_ gen;
|
||||
struct {
|
||||
uint8_t type; /* 1: Ethernet Link-Layer (RFC 2132) */
|
||||
uint8_t haddr[ETH_ALEN];
|
||||
} _packed_ eth;
|
||||
struct {
|
||||
uint8_t type; /* 2 - 254: ARP/Link-Layer (RFC 2132) */
|
||||
uint8_t haddr[0];
|
||||
} _packed_ ll;
|
||||
struct {
|
||||
uint8_t type; /* 255: Node-specific (RFC 4361) */
|
||||
uint8_t iaid[4];
|
||||
uint8_t duid[MAX_CLIENT_ID_LEN - 4];
|
||||
} _packed_ ns;
|
||||
struct {
|
||||
uint8_t type;
|
||||
uint8_t data[MAX_CLIENT_ID_LEN];
|
||||
} _packed_ raw;
|
||||
} client_id;
|
||||
struct {
|
||||
uint8_t type;
|
||||
union {
|
||||
struct {
|
||||
/* 0: Generic (non-LL) (RFC 2132) */
|
||||
uint8_t data[MAX_CLIENT_ID_LEN];
|
||||
} _packed_ gen;
|
||||
struct {
|
||||
/* 1: Ethernet Link-Layer (RFC 2132) */
|
||||
uint8_t haddr[ETH_ALEN];
|
||||
} _packed_ eth;
|
||||
struct {
|
||||
/* 2 - 254: ARP/Link-Layer (RFC 2132) */
|
||||
uint8_t haddr[0];
|
||||
} _packed_ ll;
|
||||
struct {
|
||||
/* 255: Node-specific (RFC 4361) */
|
||||
uint32_t iaid;
|
||||
struct duid duid;
|
||||
} _packed_ ns;
|
||||
struct {
|
||||
uint8_t data[MAX_CLIENT_ID_LEN];
|
||||
} _packed_ raw;
|
||||
};
|
||||
} _packed_ client_id;
|
||||
size_t client_id_len;
|
||||
char *hostname;
|
||||
char *vendor_class_identifier;
|
||||
|
|
@ -241,10 +241,9 @@ int sd_dhcp_client_get_client_id(sd_dhcp_client *client, uint8_t *type,
|
|||
*data = NULL;
|
||||
*data_len = 0;
|
||||
if (client->client_id_len) {
|
||||
*type = client->client_id.raw.type;
|
||||
*type = client->client_id.type;
|
||||
*data = client->client_id.raw.data;
|
||||
*data_len = client->client_id_len -
|
||||
sizeof (client->client_id.raw.type);
|
||||
*data_len = client->client_id_len - sizeof(client->client_id.type);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
|
@ -272,8 +271,8 @@ int sd_dhcp_client_set_client_id(sd_dhcp_client *client, uint8_t type,
|
|||
break;
|
||||
}
|
||||
|
||||
if (client->client_id_len == data_len + sizeof (client->client_id.raw.type) &&
|
||||
client->client_id.raw.type == type &&
|
||||
if (client->client_id_len == data_len + sizeof(client->client_id.type) &&
|
||||
client->client_id.type == type &&
|
||||
memcmp(&client->client_id.raw.data, data, data_len) == 0)
|
||||
return 0;
|
||||
|
||||
|
|
@ -284,9 +283,9 @@ int sd_dhcp_client_set_client_id(sd_dhcp_client *client, uint8_t type,
|
|||
client_stop(client, DHCP_EVENT_STOP);
|
||||
}
|
||||
|
||||
client->client_id.raw.type = type;
|
||||
client->client_id.type = type;
|
||||
memcpy(&client->client_id.raw.data, data, data_len);
|
||||
client->client_id_len = data_len + sizeof (client->client_id.raw.type);
|
||||
client->client_id_len = data_len + sizeof (client->client_id.type);
|
||||
|
||||
if (need_restart && client->state != DHCP_STATE_STOPPED)
|
||||
sd_dhcp_client_start(client);
|
||||
|
|
@ -402,7 +401,7 @@ static void client_stop(sd_dhcp_client *client, int error) {
|
|||
|
||||
static int client_message_init(sd_dhcp_client *client, DHCPPacket **ret,
|
||||
uint8_t type, size_t *_optlen, size_t *_optoffset) {
|
||||
_cleanup_free_ DHCPPacket *packet = NULL;
|
||||
_cleanup_free_ DHCPPacket *packet;
|
||||
size_t optlen, optoffset, size;
|
||||
be16_t max_size;
|
||||
usec_t time_now;
|
||||
|
|
@ -416,8 +415,6 @@ static int client_message_init(sd_dhcp_client *client, DHCPPacket **ret,
|
|||
assert(_optoffset);
|
||||
assert(type == DHCP_DISCOVER || type == DHCP_REQUEST);
|
||||
|
||||
/* See RFC2131 section 4.4.1 */
|
||||
|
||||
optlen = DHCP_MIN_OPTIONS_SIZE;
|
||||
size = sizeof(DHCPPacket) + optlen;
|
||||
|
||||
|
|
@ -465,12 +462,21 @@ static int client_message_init(sd_dhcp_client *client, DHCPPacket **ret,
|
|||
if (client->arp_type == ARPHRD_ETHER)
|
||||
memcpy(&packet->dhcp.chaddr, &client->mac_addr, ETH_ALEN);
|
||||
|
||||
/* If no client identifier exists, construct one from an ethernet
|
||||
address if present */
|
||||
if (client->client_id_len == 0 && client->arp_type == ARPHRD_ETHER) {
|
||||
client->client_id.eth.type = ARPHRD_ETHER;
|
||||
memcpy(&client->client_id.eth.haddr, &client->mac_addr, ETH_ALEN);
|
||||
client->client_id_len = sizeof (client->client_id.eth);
|
||||
/* If no client identifier exists, construct an RFC 4361-compliant one */
|
||||
if (client->client_id_len == 0) {
|
||||
size_t duid_len;
|
||||
|
||||
client->client_id.type = 255;
|
||||
|
||||
r = dhcp_identifier_set_iaid(client->index, client->mac_addr, client->mac_addr_len, &client->client_id.ns.iaid);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = dhcp_identifier_set_duid_en(&client->client_id.ns.duid, &duid_len);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
client->client_id_len = sizeof(client->client_id.type) + sizeof(client->client_id.ns.iaid) + duid_len;
|
||||
}
|
||||
|
||||
/* Some DHCP servers will refuse to issue an DHCP lease if the Client
|
||||
|
|
@ -479,7 +485,7 @@ static int client_message_init(sd_dhcp_client *client, DHCPPacket **ret,
|
|||
r = dhcp_option_append(&packet->dhcp, optlen, &optoffset, 0,
|
||||
DHCP_OPTION_CLIENT_IDENTIFIER,
|
||||
client->client_id_len,
|
||||
&client->client_id.raw);
|
||||
&client->client_id);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
|
@ -504,7 +510,7 @@ static int client_message_init(sd_dhcp_client *client, DHCPPacket **ret,
|
|||
|
||||
Note (from ConnMan): Some DHCP servers will send bigger DHCP packets
|
||||
than the defined default size unless the Maximum Messge Size option
|
||||
is explicitely set
|
||||
is explicitly set
|
||||
|
||||
RFC3442 "Requirements to Avoid Sizing Constraints":
|
||||
Because a full routing table can be quite large, the standard 576
|
||||
|
|
@ -1035,7 +1041,7 @@ static int client_handle_offer(sd_dhcp_client *client, DHCPMessage *offer,
|
|||
|
||||
if (client->client_id_len) {
|
||||
r = dhcp_lease_set_client_id(lease,
|
||||
(uint8_t *) &client->client_id.raw,
|
||||
(uint8_t *) &client->client_id,
|
||||
client->client_id_len);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
|
@ -1102,7 +1108,7 @@ static int client_handle_ack(sd_dhcp_client *client, DHCPMessage *ack,
|
|||
|
||||
if (client->client_id_len) {
|
||||
r = dhcp_lease_set_client_id(lease,
|
||||
(uint8_t *) &client->client_id.raw,
|
||||
(uint8_t *) &client->client_id,
|
||||
client->client_id_len);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
|
@ -1386,8 +1392,10 @@ static int client_handle_message(sd_dhcp_client *client, DHCPMessage *message,
|
|||
client->last_addr = client->lease->address;
|
||||
|
||||
r = client_set_lease_timeouts(client);
|
||||
if (r < 0)
|
||||
if (r < 0) {
|
||||
log_dhcp_client(client, "could not set lease timeouts");
|
||||
goto error;
|
||||
}
|
||||
|
||||
r = dhcp_network_bind_udp_socket(client->lease->address,
|
||||
DHCP_PORT_CLIENT);
|
||||
|
|
@ -1615,7 +1623,7 @@ int sd_dhcp_client_start(sd_dhcp_client *client) {
|
|||
|
||||
r = client_start(client);
|
||||
if (r >= 0)
|
||||
log_dhcp_client(client, "STARTED on ifindex %u", client->index);
|
||||
log_dhcp_client(client, "STARTED on ifindex %i", client->index);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
|
@ -1674,7 +1682,7 @@ sd_dhcp_client *sd_dhcp_client_ref(sd_dhcp_client *client) {
|
|||
}
|
||||
|
||||
sd_dhcp_client *sd_dhcp_client_unref(sd_dhcp_client *client) {
|
||||
if (client && REFCNT_DEC(client->n_ref) <= 0) {
|
||||
if (client && REFCNT_DEC(client->n_ref) == 0) {
|
||||
log_dhcp_client(client, "FREE");
|
||||
|
||||
client_initialize(client);
|
||||
|
|
|
|||
|
|
@ -24,24 +24,15 @@
|
|||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <net/ethernet.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <sys/param.h>
|
||||
|
||||
#include "util.h"
|
||||
#include "list.h"
|
||||
#if 0 /* NM_IGNORED */
|
||||
#include "mkdir.h"
|
||||
#endif /* NM_IGNORED */
|
||||
#include "fileio.h"
|
||||
#include "unaligned.h"
|
||||
#include "in-addr-util.h"
|
||||
|
||||
#include "dhcp-protocol.h"
|
||||
#include "dhcp-internal.h"
|
||||
#include "dhcp-lease-internal.h"
|
||||
#include "sd-dhcp-lease.h"
|
||||
#include "sd-dhcp-client.h"
|
||||
#include "network-internal.h"
|
||||
|
||||
int sd_dhcp_lease_get_address(sd_dhcp_lease *lease, struct in_addr *addr) {
|
||||
|
|
@ -55,7 +46,7 @@ int sd_dhcp_lease_get_address(sd_dhcp_lease *lease, struct in_addr *addr) {
|
|||
|
||||
int sd_dhcp_lease_get_lifetime(sd_dhcp_lease *lease, uint32_t *lifetime) {
|
||||
assert_return(lease, -EINVAL);
|
||||
assert_return(lease, -EINVAL);
|
||||
assert_return(lifetime, -EINVAL);
|
||||
|
||||
*lifetime = lease->lifetime;
|
||||
|
||||
|
|
@ -197,7 +188,7 @@ sd_dhcp_lease *sd_dhcp_lease_ref(sd_dhcp_lease *lease) {
|
|||
}
|
||||
|
||||
sd_dhcp_lease *sd_dhcp_lease_unref(sd_dhcp_lease *lease) {
|
||||
if (lease && REFCNT_DEC(lease->n_ref) <= 0) {
|
||||
if (lease && REFCNT_DEC(lease->n_ref) == 0) {
|
||||
free(lease->hostname);
|
||||
free(lease->domainname);
|
||||
free(lease->dns);
|
||||
|
|
@ -501,11 +492,20 @@ int dhcp_lease_parse_options(uint8_t code, uint8_t len, const uint8_t *option,
|
|||
case DHCP_OPTION_DOMAIN_NAME:
|
||||
{
|
||||
_cleanup_free_ char *domainname = NULL;
|
||||
char *e;
|
||||
|
||||
r = lease_parse_string(option, len, &domainname);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
/* Chop off trailing dot of domain name that some DHCP
|
||||
* servers send us back. Internally we want to store
|
||||
* host names without trailing dots and
|
||||
* host_name_is_valid() doesn't accept them. */
|
||||
e = endswith(domainname, ".");
|
||||
if (e)
|
||||
*e = 0;
|
||||
|
||||
if (!hostname_is_valid(domainname) || is_localhost(domainname))
|
||||
break;
|
||||
|
||||
|
|
@ -518,11 +518,16 @@ int dhcp_lease_parse_options(uint8_t code, uint8_t len, const uint8_t *option,
|
|||
case DHCP_OPTION_HOST_NAME:
|
||||
{
|
||||
_cleanup_free_ char *hostname = NULL;
|
||||
char *e;
|
||||
|
||||
r = lease_parse_string(option, len, &hostname);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
e = endswith(hostname, ".");
|
||||
if (e)
|
||||
*e = 0;
|
||||
|
||||
if (!hostname_is_valid(hostname) || is_localhost(hostname))
|
||||
break;
|
||||
|
||||
|
|
@ -667,7 +672,7 @@ int sd_dhcp_lease_save(sd_dhcp_lease *lease, const char *lease_file) {
|
|||
|
||||
r = sd_dhcp_lease_get_client_id(lease, &client_id, &client_id_len);
|
||||
if (r >= 0) {
|
||||
_cleanup_free_ char *client_id_hex = NULL;
|
||||
_cleanup_free_ char *client_id_hex;
|
||||
|
||||
client_id_hex = hexmem (client_id, client_id_len);
|
||||
if (!client_id_hex) {
|
||||
|
|
@ -689,7 +694,7 @@ int sd_dhcp_lease_save(sd_dhcp_lease *lease, const char *lease_file) {
|
|||
|
||||
finish:
|
||||
if (r < 0)
|
||||
log_error("Failed to save lease data %s: %s", lease_file, strerror(-r));
|
||||
log_error_errno(r, "Failed to save lease data %s: %m", lease_file);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
|
@ -729,8 +734,7 @@ int sd_dhcp_lease_load(sd_dhcp_lease **ret, const char *lease_file) {
|
|||
if (r == -ENOENT)
|
||||
return 0;
|
||||
|
||||
log_error("Failed to read %s: %s", lease_file, strerror(-r));
|
||||
return r;
|
||||
return log_error_errno(r, "Failed to read %s: %m", lease_file);
|
||||
}
|
||||
|
||||
r = inet_pton(AF_INET, address, &addr);
|
||||
|
|
|
|||
|
|
@ -29,9 +29,7 @@
|
|||
#if 0 /* NM_IGNORED */
|
||||
#include "udev.h"
|
||||
#include "udev-util.h"
|
||||
#include "virt.h"
|
||||
#endif /* NM_IGNORED */
|
||||
#include "siphash24.h"
|
||||
#include "util.h"
|
||||
#include "refcnt.h"
|
||||
|
||||
|
|
@ -40,14 +38,7 @@
|
|||
#include "dhcp6-protocol.h"
|
||||
#include "dhcp6-internal.h"
|
||||
#include "dhcp6-lease-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)
|
||||
|
||||
/* RFC 3315 section 9.1:
|
||||
* A DUID can be no more than 128 octets long (not including the type code).
|
||||
*/
|
||||
#define MAX_DUID_LEN 128
|
||||
#include "dhcp-identifier.h"
|
||||
|
||||
#define MAX_MAC_ADDR_LEN INFINIBAND_ALEN
|
||||
|
||||
|
|
@ -61,12 +52,12 @@ struct sd_dhcp6_client {
|
|||
uint8_t mac_addr[MAX_MAC_ADDR_LEN];
|
||||
size_t mac_addr_len;
|
||||
uint16_t arp_type;
|
||||
char ifname[IFNAMSIZ];
|
||||
DHCP6IA ia_na;
|
||||
be32_t transaction_id;
|
||||
usec_t transaction_start;
|
||||
struct sd_dhcp6_lease *lease;
|
||||
int fd;
|
||||
bool information_request;
|
||||
be16_t *req_opts;
|
||||
size_t req_opts_allocated;
|
||||
size_t req_opts_len;
|
||||
|
|
@ -77,32 +68,7 @@ struct sd_dhcp6_client {
|
|||
sd_event_source *timeout_resend_expire;
|
||||
sd_dhcp6_client_cb_t cb;
|
||||
void *userdata;
|
||||
union {
|
||||
struct {
|
||||
uint16_t type; /* DHCP6_DUID_LLT */
|
||||
uint16_t htype;
|
||||
uint32_t time;
|
||||
uint8_t haddr[0];
|
||||
} _packed_ llt;
|
||||
struct {
|
||||
uint16_t type; /* DHCP6_DUID_EN */
|
||||
uint32_t pen;
|
||||
uint8_t id[8];
|
||||
} _packed_ en;
|
||||
struct {
|
||||
uint16_t type; /* DHCP6_DUID_LL */
|
||||
uint16_t htype;
|
||||
uint8_t haddr[0];
|
||||
} _packed_ ll;
|
||||
struct {
|
||||
uint16_t type; /* DHCP6_DUID_UUID */
|
||||
sd_id128_t uuid;
|
||||
} _packed_ uuid;
|
||||
struct {
|
||||
uint16_t type;
|
||||
uint8_t data[MAX_DUID_LEN];
|
||||
} _packed_ raw;
|
||||
} duid;
|
||||
struct duid duid;
|
||||
size_t duid_len;
|
||||
};
|
||||
|
||||
|
|
@ -205,19 +171,19 @@ int sd_dhcp6_client_set_duid(sd_dhcp6_client *client, uint16_t type, uint8_t *du
|
|||
|
||||
switch (type) {
|
||||
case DHCP6_DUID_LLT:
|
||||
if (duid_len <= sizeof(client->duid.llt) - 2)
|
||||
if (duid_len <= sizeof(client->duid.llt))
|
||||
return -EINVAL;
|
||||
break;
|
||||
case DHCP6_DUID_EN:
|
||||
if (duid_len != sizeof(client->duid.en) - 2)
|
||||
if (duid_len != sizeof(client->duid.en))
|
||||
return -EINVAL;
|
||||
break;
|
||||
case DHCP6_DUID_LL:
|
||||
if (duid_len <= sizeof(client->duid.ll) - 2)
|
||||
if (duid_len <= sizeof(client->duid.ll))
|
||||
return -EINVAL;
|
||||
break;
|
||||
case DHCP6_DUID_UUID:
|
||||
if (duid_len != sizeof(client->duid.uuid) - 2)
|
||||
if (duid_len != sizeof(client->duid.uuid))
|
||||
return -EINVAL;
|
||||
break;
|
||||
default:
|
||||
|
|
@ -225,9 +191,28 @@ int sd_dhcp6_client_set_duid(sd_dhcp6_client *client, uint16_t type, uint8_t *du
|
|||
break;
|
||||
}
|
||||
|
||||
client->duid.raw.type = htobe16(type);
|
||||
client->duid.type = htobe16(type);
|
||||
memcpy(&client->duid.raw.data, duid, duid_len);
|
||||
client->duid_len = duid_len + 2; /* +2 for sizeof(type) */
|
||||
client->duid_len = duid_len + sizeof(client->duid.type);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sd_dhcp6_client_set_information_request(sd_dhcp6_client *client,
|
||||
bool enabled) {
|
||||
assert_return(client, -EINVAL);
|
||||
|
||||
client->information_request = enabled;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sd_dhcp6_client_get_information_request(sd_dhcp6_client *client,
|
||||
bool *enabled) {
|
||||
assert_return(client, -EINVAL);
|
||||
assert_return(enabled, -EINVAL);
|
||||
|
||||
*enabled = client->information_request;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -338,6 +323,11 @@ static int client_send_message(sd_dhcp6_client *client, usec_t time_now) {
|
|||
message->transaction_id = client->transaction_id;
|
||||
|
||||
switch(client->state) {
|
||||
case DHCP6_STATE_INFORMATION_REQUEST:
|
||||
message->type = DHCP6_INFORMATION_REQUEST;
|
||||
|
||||
break;
|
||||
|
||||
case DHCP6_STATE_SOLICITATION:
|
||||
message->type = DHCP6_SOLICIT;
|
||||
|
||||
|
|
@ -499,6 +489,12 @@ static int client_timeout_resend(sd_event_source *s, uint64_t usec,
|
|||
client->timeout_resend = sd_event_source_unref(client->timeout_resend);
|
||||
|
||||
switch (client->state) {
|
||||
case DHCP6_STATE_INFORMATION_REQUEST:
|
||||
init_retransmit_time = DHCP6_INF_TIMEOUT;
|
||||
max_retransmit_time = DHCP6_INF_MAX_RT;
|
||||
|
||||
break;
|
||||
|
||||
case DHCP6_STATE_SOLICITATION:
|
||||
|
||||
if (client->retransmit_count && client->lease) {
|
||||
|
|
@ -631,24 +627,16 @@ error:
|
|||
}
|
||||
|
||||
static int client_ensure_iaid(sd_dhcp6_client *client) {
|
||||
const char *name;
|
||||
uint64_t id;
|
||||
int r;
|
||||
|
||||
assert(client);
|
||||
|
||||
if (client->ia_na.id)
|
||||
return 0;
|
||||
|
||||
name = client->ifname;
|
||||
if (name)
|
||||
siphash24((uint8_t*)&id, name, strlen(name), HASH_KEY.bytes);
|
||||
else
|
||||
/* fall back to mac address if no predictable name available */
|
||||
siphash24((uint8_t*)&id, &client->mac_addr,
|
||||
client->mac_addr_len, HASH_KEY.bytes);
|
||||
|
||||
/* fold into 32 bits */
|
||||
client->ia_na.id = (id & 0xffffffff) ^ (id >> 32);
|
||||
r = dhcp_identifier_set_iaid(client->index, client->mac_addr, client->mac_addr_len, &client->ia_na.id);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -726,6 +714,12 @@ static int client_parse_message(sd_dhcp6_client *client,
|
|||
break;
|
||||
|
||||
case DHCP6_OPTION_IA_NA:
|
||||
if (client->state == DHCP6_STATE_INFORMATION_REQUEST) {
|
||||
log_dhcp6_client(client, "Information request ignoring IA NA option");
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
r = dhcp6_option_parse_ia(&optval, &optlen, optcode,
|
||||
&lease->ia);
|
||||
if (r < 0 && r != -ENOMSG)
|
||||
|
|
@ -752,16 +746,21 @@ static int client_parse_message(sd_dhcp6_client *client,
|
|||
}
|
||||
}
|
||||
|
||||
if ((r < 0 && r != -ENOMSG) || !clientid) {
|
||||
if (r == -ENOMSG)
|
||||
r = 0;
|
||||
|
||||
if (r < 0 || !clientid) {
|
||||
log_dhcp6_client(client, "%s has incomplete options",
|
||||
dhcp6_message_type_to_string(message->type));
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
r = dhcp6_lease_get_serverid(lease, &id, &id_len);
|
||||
if (r < 0)
|
||||
log_dhcp6_client(client, "%s has no server id",
|
||||
dhcp6_message_type_to_string(message->type));
|
||||
if (client->state != DHCP6_STATE_INFORMATION_REQUEST) {
|
||||
r = dhcp6_lease_get_serverid(lease, &id, &id_len);
|
||||
if (r < 0)
|
||||
log_dhcp6_client(client, "%s has no server id",
|
||||
dhcp6_message_type_to_string(message->type));
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
|
@ -793,12 +792,15 @@ static int client_receive_reply(sd_dhcp6_client *client, DHCP6Message *reply,
|
|||
return 0;
|
||||
}
|
||||
|
||||
if (client->lease)
|
||||
if (client->lease) {
|
||||
dhcp6_lease_clear_timers(&client->lease->ia);
|
||||
client->lease = sd_dhcp6_lease_unref(client->lease);
|
||||
}
|
||||
|
||||
client->lease = sd_dhcp6_lease_unref(client->lease);
|
||||
client->lease = lease;
|
||||
lease = NULL;
|
||||
if (client->state != DHCP6_STATE_INFORMATION_REQUEST) {
|
||||
client->lease = lease;
|
||||
lease = NULL;
|
||||
}
|
||||
|
||||
return DHCP6_STATE_BOUND;
|
||||
}
|
||||
|
|
@ -825,7 +827,8 @@ static int client_receive_advertise(sd_dhcp6_client *client,
|
|||
return r;
|
||||
|
||||
r = dhcp6_lease_get_preference(client->lease, &pref_lease);
|
||||
if (!client->lease || r < 0 || pref_advertise > pref_lease) {
|
||||
|
||||
if (r < 0 || pref_advertise > pref_lease) {
|
||||
sd_dhcp6_lease_unref(client->lease);
|
||||
client->lease = lease;
|
||||
lease = NULL;
|
||||
|
|
@ -842,7 +845,7 @@ static int client_receive_message(sd_event_source *s, int fd, uint32_t revents,
|
|||
void *userdata) {
|
||||
sd_dhcp6_client *client = userdata;
|
||||
DHCP6_CLIENT_DONT_DESTROY(client);
|
||||
_cleanup_free_ DHCP6Message *message = NULL;
|
||||
_cleanup_free_ DHCP6Message *message;
|
||||
int r, buflen, len;
|
||||
|
||||
assert(s);
|
||||
|
|
@ -892,6 +895,17 @@ static int client_receive_message(sd_event_source *s, int fd, uint32_t revents,
|
|||
return 0;
|
||||
|
||||
switch (client->state) {
|
||||
case DHCP6_STATE_INFORMATION_REQUEST:
|
||||
r = client_receive_reply(client, message, len);
|
||||
if (r < 0)
|
||||
return 0;
|
||||
|
||||
client_notify(client, DHCP6_EVENT_INFORMATION_REQUEST);
|
||||
|
||||
client_start(client, DHCP6_STATE_STOPPED);
|
||||
|
||||
break;
|
||||
|
||||
case DHCP6_STATE_SOLICITATION:
|
||||
r = client_receive_advertise(client, message, len);
|
||||
|
||||
|
|
@ -967,37 +981,19 @@ static int client_start(sd_dhcp6_client *client, enum DHCP6State state)
|
|||
|
||||
switch (state) {
|
||||
case DHCP6_STATE_STOPPED:
|
||||
if (client->state == DHCP6_STATE_INFORMATION_REQUEST) {
|
||||
client->state = DHCP6_STATE_STOPPED;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* fall through */
|
||||
case DHCP6_STATE_SOLICITATION:
|
||||
|
||||
r = client_ensure_iaid(client);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = dhcp6_network_bind_udp_socket(client->index, NULL);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
client->fd = r;
|
||||
|
||||
r = sd_event_add_io(client->event, &client->receive_message,
|
||||
client->fd, EPOLLIN, client_receive_message,
|
||||
client);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = sd_event_source_set_priority(client->receive_message,
|
||||
client->event_priority);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = sd_event_source_set_description(client->receive_message, "dhcp6-receive-message");
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
client->state = DHCP6_STATE_SOLICITATION;
|
||||
|
||||
break;
|
||||
|
||||
case DHCP6_STATE_INFORMATION_REQUEST:
|
||||
case DHCP6_STATE_REQUEST:
|
||||
case DHCP6_STATE_RENEW:
|
||||
case DHCP6_STATE_REBIND:
|
||||
|
|
@ -1102,6 +1098,7 @@ int sd_dhcp6_client_stop(sd_dhcp6_client *client)
|
|||
int sd_dhcp6_client_start(sd_dhcp6_client *client)
|
||||
{
|
||||
int r = 0;
|
||||
enum DHCP6State state = DHCP6_STATE_SOLICITATION;
|
||||
|
||||
assert_return(client, -EINVAL);
|
||||
assert_return(client->event, -EINVAL);
|
||||
|
|
@ -1111,7 +1108,44 @@ int sd_dhcp6_client_start(sd_dhcp6_client *client)
|
|||
if (r < 0)
|
||||
return r;
|
||||
|
||||
return client_start(client, DHCP6_STATE_SOLICITATION);
|
||||
r = client_ensure_iaid(client);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = dhcp6_network_bind_udp_socket(client->index, NULL);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
client->fd = r;
|
||||
|
||||
r = sd_event_add_io(client->event, &client->receive_message,
|
||||
client->fd, EPOLLIN, client_receive_message,
|
||||
client);
|
||||
if (r < 0)
|
||||
goto error;
|
||||
|
||||
r = sd_event_source_set_priority(client->receive_message,
|
||||
client->event_priority);
|
||||
if (r < 0)
|
||||
goto error;
|
||||
|
||||
r = sd_event_source_set_description(client->receive_message,
|
||||
"dhcp6-receive-message");
|
||||
if (r < 0)
|
||||
goto error;
|
||||
|
||||
if (client->information_request)
|
||||
state = DHCP6_STATE_INFORMATION_REQUEST;
|
||||
|
||||
log_dhcp6_client(client, "Started in %s mode",
|
||||
client->information_request? "Information request":
|
||||
"Managed");
|
||||
|
||||
return client_start(client, state);
|
||||
|
||||
error:
|
||||
client_reset(client);
|
||||
return r;
|
||||
}
|
||||
|
||||
int sd_dhcp6_client_attach_event(sd_dhcp6_client *client, sd_event *event,
|
||||
|
|
@ -1158,7 +1192,7 @@ sd_dhcp6_client *sd_dhcp6_client_ref(sd_dhcp6_client *client) {
|
|||
}
|
||||
|
||||
sd_dhcp6_client *sd_dhcp6_client_unref(sd_dhcp6_client *client) {
|
||||
if (client && REFCNT_DEC(client->n_ref) <= 0) {
|
||||
if (client && REFCNT_DEC(client->n_ref) == 0) {
|
||||
client_reset(client);
|
||||
|
||||
sd_dhcp6_client_detach_event(client);
|
||||
|
|
@ -1176,7 +1210,6 @@ int sd_dhcp6_client_new(sd_dhcp6_client **ret)
|
|||
{
|
||||
_cleanup_dhcp6_client_unref_ sd_dhcp6_client *client = NULL;
|
||||
#if 0 /* NM_IGNORED */
|
||||
sd_id128_t machine_id;
|
||||
int r;
|
||||
#endif /* NM_IGNORED */
|
||||
size_t t;
|
||||
|
|
@ -1197,17 +1230,9 @@ int sd_dhcp6_client_new(sd_dhcp6_client **ret)
|
|||
|
||||
#if 0 /* NM_IGNORED */
|
||||
/* initialize DUID */
|
||||
client->duid.en.type = htobe16(DHCP6_DUID_EN);
|
||||
client->duid.en.pen = htobe32(SYSTEMD_PEN);
|
||||
client->duid_len = sizeof(client->duid.en);
|
||||
|
||||
r = sd_id128_get_machine(&machine_id);
|
||||
r = dhcp_identifier_set_duid_en(&client->duid, &client->duid_len);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
/* a bit of snake-oil perhaps, but no need to expose the machine-id
|
||||
directly */
|
||||
siphash24(client->duid.en.id, &machine_id, sizeof(machine_id), HASH_KEY.bytes);
|
||||
#endif /* NM_IGNORED */
|
||||
|
||||
client->req_opts_len = ELEMENTSOF(default_req_opts);
|
||||
|
|
@ -1225,16 +1250,3 @@ int sd_dhcp6_client_new(sd_dhcp6_client **ret)
|
|||
return 0;
|
||||
}
|
||||
|
||||
/*******************************************/
|
||||
/* NetworkManager additions */
|
||||
|
||||
int sd_dhcp6_client_set_ifname(sd_dhcp6_client *client, const char *ifname)
|
||||
{
|
||||
assert_return(client, -EINVAL);
|
||||
assert_return(ifname, -EINVAL);
|
||||
assert_return(strlen (ifname) < sizeof (client->ifname), -EINVAL);
|
||||
|
||||
strcpy(client->ifname, ifname);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -112,9 +112,11 @@ int dhcp6_lease_set_preference(sd_dhcp6_lease *lease, uint8_t preference) {
|
|||
}
|
||||
|
||||
int dhcp6_lease_get_preference(sd_dhcp6_lease *lease, uint8_t *preference) {
|
||||
assert_return(lease, -EINVAL);
|
||||
assert_return(preference, -EINVAL);
|
||||
|
||||
if (!lease)
|
||||
return -EINVAL;
|
||||
|
||||
*preference = lease->preference;
|
||||
|
||||
return 0;
|
||||
|
|
@ -146,10 +148,9 @@ int dhcp6_lease_get_iaid(sd_dhcp6_lease *lease, be32_t *iaid) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
int sd_dhcp6_lease_get_next_address(sd_dhcp6_lease *lease,
|
||||
struct in6_addr *addr,
|
||||
uint32_t *lifetime_preferred,
|
||||
uint32_t *lifetime_valid) {
|
||||
int sd_dhcp6_lease_get_address(sd_dhcp6_lease *lease, struct in6_addr *addr,
|
||||
uint32_t *lifetime_preferred,
|
||||
uint32_t *lifetime_valid) {
|
||||
assert_return(lease, -EINVAL);
|
||||
assert_return(addr, -EINVAL);
|
||||
assert_return(lifetime_preferred, -EINVAL);
|
||||
|
|
@ -169,22 +170,9 @@ int sd_dhcp6_lease_get_next_address(sd_dhcp6_lease *lease,
|
|||
return 0;
|
||||
}
|
||||
|
||||
int sd_dhcp6_lease_get_first_address(sd_dhcp6_lease *lease,
|
||||
struct in6_addr *addr,
|
||||
uint32_t *lifetime_preferred,
|
||||
uint32_t *lifetime_valid) {
|
||||
assert_return(lease, -EINVAL);
|
||||
assert_return(addr, -EINVAL);
|
||||
assert_return(lifetime_preferred, -EINVAL);
|
||||
assert_return(lifetime_valid, -EINVAL);
|
||||
|
||||
if (!lease->ia.addresses)
|
||||
return -ENOMSG;
|
||||
|
||||
lease->addr_iter = lease->ia.addresses;
|
||||
|
||||
return sd_dhcp6_lease_get_next_address(lease, addr, lifetime_preferred,
|
||||
lifetime_valid);
|
||||
void sd_dhcp6_lease_reset_address_iter(sd_dhcp6_lease *lease) {
|
||||
if (lease)
|
||||
lease->addr_iter = lease->ia.addresses;
|
||||
}
|
||||
|
||||
sd_dhcp6_lease *sd_dhcp6_lease_ref(sd_dhcp6_lease *lease) {
|
||||
|
|
@ -195,7 +183,7 @@ sd_dhcp6_lease *sd_dhcp6_lease_ref(sd_dhcp6_lease *lease) {
|
|||
}
|
||||
|
||||
sd_dhcp6_lease *sd_dhcp6_lease_unref(sd_dhcp6_lease *lease) {
|
||||
if (lease && REFCNT_DEC(lease->n_ref) <= 0) {
|
||||
if (lease && REFCNT_DEC(lease->n_ref) == 0) {
|
||||
free(lease->serverid);
|
||||
dhcp6_lease_free_ia(&lease->ia);
|
||||
|
||||
|
|
|
|||
235
src/dhcp-manager/systemd-dhcp/src/libsystemd/sd-id128/sd-id128.c
Normal file
235
src/dhcp-manager/systemd-dhcp/src/libsystemd/sd-id128/sd-id128.c
Normal file
|
|
@ -0,0 +1,235 @@
|
|||
/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
|
||||
|
||||
/***
|
||||
This file is part of systemd.
|
||||
|
||||
Copyright 2011 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 <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "util.h"
|
||||
#include "macro.h"
|
||||
#include "sd-id128.h"
|
||||
|
||||
#if 0 /* NM_IGNORED */
|
||||
_public_ char *sd_id128_to_string(sd_id128_t id, char s[33]) {
|
||||
unsigned n;
|
||||
|
||||
assert_return(s, NULL);
|
||||
|
||||
for (n = 0; n < 16; n++) {
|
||||
s[n*2] = hexchar(id.bytes[n] >> 4);
|
||||
s[n*2+1] = hexchar(id.bytes[n] & 0xF);
|
||||
}
|
||||
|
||||
s[32] = 0;
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
_public_ int sd_id128_from_string(const char s[], sd_id128_t *ret) {
|
||||
unsigned n, i;
|
||||
sd_id128_t t;
|
||||
bool is_guid = false;
|
||||
|
||||
assert_return(s, -EINVAL);
|
||||
assert_return(ret, -EINVAL);
|
||||
|
||||
for (n = 0, i = 0; n < 16;) {
|
||||
int a, b;
|
||||
|
||||
if (s[i] == '-') {
|
||||
/* Is this a GUID? Then be nice, and skip over
|
||||
* the dashes */
|
||||
|
||||
if (i == 8)
|
||||
is_guid = true;
|
||||
else if (i == 13 || i == 18 || i == 23) {
|
||||
if (!is_guid)
|
||||
return -EINVAL;
|
||||
} else
|
||||
return -EINVAL;
|
||||
|
||||
i++;
|
||||
continue;
|
||||
}
|
||||
|
||||
a = unhexchar(s[i++]);
|
||||
if (a < 0)
|
||||
return -EINVAL;
|
||||
|
||||
b = unhexchar(s[i++]);
|
||||
if (b < 0)
|
||||
return -EINVAL;
|
||||
|
||||
t.bytes[n++] = (a << 4) | b;
|
||||
}
|
||||
|
||||
if (i != (is_guid ? 36 : 32))
|
||||
return -EINVAL;
|
||||
|
||||
if (s[i] != 0)
|
||||
return -EINVAL;
|
||||
|
||||
*ret = t;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static sd_id128_t make_v4_uuid(sd_id128_t id) {
|
||||
/* Stolen from generate_random_uuid() of drivers/char/random.c
|
||||
* in the kernel sources */
|
||||
|
||||
/* Set UUID version to 4 --- truly random generation */
|
||||
id.bytes[6] = (id.bytes[6] & 0x0F) | 0x40;
|
||||
|
||||
/* Set the UUID variant to DCE */
|
||||
id.bytes[8] = (id.bytes[8] & 0x3F) | 0x80;
|
||||
|
||||
return id;
|
||||
}
|
||||
#endif
|
||||
|
||||
_public_ int sd_id128_get_machine(sd_id128_t *ret) {
|
||||
static thread_local sd_id128_t saved_machine_id;
|
||||
static thread_local bool saved_machine_id_valid = false;
|
||||
_cleanup_close_ int fd = -1;
|
||||
char buf[33];
|
||||
ssize_t k;
|
||||
unsigned j;
|
||||
sd_id128_t t;
|
||||
|
||||
assert_return(ret, -EINVAL);
|
||||
|
||||
if (saved_machine_id_valid) {
|
||||
*ret = saved_machine_id;
|
||||
return 0;
|
||||
}
|
||||
|
||||
fd = open("/etc/machine-id", O_RDONLY|O_CLOEXEC|O_NOCTTY);
|
||||
if (fd < 0)
|
||||
return -errno;
|
||||
|
||||
k = loop_read(fd, buf, 33, false);
|
||||
if (k < 0)
|
||||
return (int) k;
|
||||
|
||||
if (k != 33)
|
||||
return -EIO;
|
||||
|
||||
if (buf[32] !='\n')
|
||||
return -EIO;
|
||||
|
||||
for (j = 0; j < 16; j++) {
|
||||
int a, b;
|
||||
|
||||
a = unhexchar(buf[j*2]);
|
||||
b = unhexchar(buf[j*2+1]);
|
||||
|
||||
if (a < 0 || b < 0)
|
||||
return -EIO;
|
||||
|
||||
t.bytes[j] = a << 4 | b;
|
||||
}
|
||||
|
||||
saved_machine_id = t;
|
||||
saved_machine_id_valid = true;
|
||||
|
||||
*ret = t;
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if 0 /* NM_IGNORED */
|
||||
_public_ int sd_id128_get_boot(sd_id128_t *ret) {
|
||||
static thread_local sd_id128_t saved_boot_id;
|
||||
static thread_local bool saved_boot_id_valid = false;
|
||||
_cleanup_close_ int fd = -1;
|
||||
char buf[36];
|
||||
ssize_t k;
|
||||
unsigned j;
|
||||
sd_id128_t t;
|
||||
char *p;
|
||||
|
||||
assert_return(ret, -EINVAL);
|
||||
|
||||
if (saved_boot_id_valid) {
|
||||
*ret = saved_boot_id;
|
||||
return 0;
|
||||
}
|
||||
|
||||
fd = open("/proc/sys/kernel/random/boot_id", O_RDONLY|O_CLOEXEC|O_NOCTTY);
|
||||
if (fd < 0)
|
||||
return -errno;
|
||||
|
||||
k = loop_read(fd, buf, 36, false);
|
||||
if (k < 0)
|
||||
return (int) k;
|
||||
|
||||
if (k != 36)
|
||||
return -EIO;
|
||||
|
||||
for (j = 0, p = buf; j < 16; j++) {
|
||||
int a, b;
|
||||
|
||||
if (p >= buf + k - 1)
|
||||
return -EIO;
|
||||
|
||||
if (*p == '-') {
|
||||
p++;
|
||||
if (p >= buf + k - 1)
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
a = unhexchar(p[0]);
|
||||
b = unhexchar(p[1]);
|
||||
|
||||
if (a < 0 || b < 0)
|
||||
return -EIO;
|
||||
|
||||
t.bytes[j] = a << 4 | b;
|
||||
|
||||
p += 2;
|
||||
}
|
||||
|
||||
saved_boot_id = t;
|
||||
saved_boot_id_valid = true;
|
||||
|
||||
*ret = t;
|
||||
return 0;
|
||||
}
|
||||
|
||||
_public_ int sd_id128_randomize(sd_id128_t *ret) {
|
||||
sd_id128_t t;
|
||||
int r;
|
||||
|
||||
assert_return(ret, -EINVAL);
|
||||
|
||||
r = dev_urandom(&t, sizeof(t));
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
/* Turn this into a valid v4 UUID, to be nice. Note that we
|
||||
* only guarantee this for newly generated UUIDs, not for
|
||||
* pre-existing ones. */
|
||||
|
||||
*ret = make_v4_uuid(t);
|
||||
return 0;
|
||||
}
|
||||
#endif /* NM_IGNORED */
|
||||
|
|
@ -510,15 +510,17 @@ static int parse_env_file_push(
|
|||
va_list aq, *ap = userdata;
|
||||
|
||||
if (!utf8_is_valid(key)) {
|
||||
_cleanup_free_ char *p = utf8_escape_invalid(key);
|
||||
_cleanup_free_ char *p;
|
||||
|
||||
p = utf8_escape_invalid(key);
|
||||
log_error("%s:%u: invalid UTF-8 in key '%s', ignoring.", strna(filename), line, p);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (value && !utf8_is_valid(value)) {
|
||||
_cleanup_free_ char *p = utf8_escape_invalid(value);
|
||||
_cleanup_free_ char *p;
|
||||
|
||||
p = utf8_escape_invalid(value);
|
||||
log_error("%s:%u: invalid UTF-8 value for key %s: '%s', ignoring.", strna(filename), line, key, p);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -245,12 +245,25 @@ int in_addr_from_string_auto(const char *s, int *family, union in_addr_union *re
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
unsigned in_addr_netmask_to_prefixlen(const struct in_addr *addr) {
|
||||
unsigned char in_addr_netmask_to_prefixlen(const struct in_addr *addr) {
|
||||
assert(addr);
|
||||
|
||||
return 32 - u32ctz(be32toh(addr->s_addr));
|
||||
}
|
||||
|
||||
struct in_addr* in_addr_prefixlen_to_netmask(struct in_addr *addr, unsigned char prefixlen) {
|
||||
assert(addr);
|
||||
assert(prefixlen <= 32);
|
||||
|
||||
/* Shifting beyond 32 is not defined, handle this specially. */
|
||||
if (prefixlen == 0)
|
||||
addr->s_addr = 0;
|
||||
else
|
||||
addr->s_addr = htobe32((0xffffffff << (32 - prefixlen)) & 0xffffffff);
|
||||
|
||||
return addr;
|
||||
}
|
||||
|
||||
int in_addr_default_prefixlen(const struct in_addr *addr, unsigned char *prefixlen) {
|
||||
uint8_t msb_octet = *(uint8_t*) addr;
|
||||
|
||||
|
|
@ -286,9 +299,42 @@ int in_addr_default_subnet_mask(const struct in_addr *addr, struct in_addr *mask
|
|||
if (r < 0)
|
||||
return r;
|
||||
|
||||
assert(prefixlen > 0 && prefixlen < 32);
|
||||
|
||||
mask->s_addr = htobe32((0xffffffff << (32 - prefixlen)) & 0xffffffff);
|
||||
|
||||
in_addr_prefixlen_to_netmask(mask, prefixlen);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int in_addr_mask(int family, union in_addr_union *addr, unsigned char prefixlen) {
|
||||
assert(addr);
|
||||
|
||||
if (family == AF_INET) {
|
||||
struct in_addr mask;
|
||||
|
||||
if (!in_addr_prefixlen_to_netmask(&mask, prefixlen))
|
||||
return -EINVAL;
|
||||
|
||||
addr->in.s_addr &= mask.s_addr;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (family == AF_INET6) {
|
||||
unsigned i;
|
||||
|
||||
for (i = 0; i < 16; i++) {
|
||||
uint8_t mask;
|
||||
|
||||
if (prefixlen >= 8) {
|
||||
mask = 0xFF;
|
||||
prefixlen -= 8;
|
||||
} else {
|
||||
mask = 0xFF << (8 - prefixlen);
|
||||
prefixlen = 0;
|
||||
}
|
||||
|
||||
addr->in6.s6_addr[i] &= mask;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -EAFNOSUPPORT;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -41,11 +41,15 @@ int in_addr_prefix_next(int family, union in_addr_union *u, unsigned prefixlen);
|
|||
int in_addr_to_string(int family, const union in_addr_union *u, char **ret);
|
||||
int in_addr_from_string(int family, const char *s, union in_addr_union *ret);
|
||||
int in_addr_from_string_auto(const char *s, int *family, union in_addr_union *ret);
|
||||
unsigned in_addr_netmask_to_prefixlen(const struct in_addr *addr);
|
||||
unsigned char in_addr_netmask_to_prefixlen(const struct in_addr *addr);
|
||||
struct in_addr* in_addr_prefixlen_to_netmask(struct in_addr *addr, unsigned char prefixlen);
|
||||
int in_addr_default_prefixlen(const struct in_addr *addr, unsigned char *prefixlen);
|
||||
int in_addr_default_subnet_mask(const struct in_addr *addr, struct in_addr *mask);
|
||||
int in_addr_mask(int family, union in_addr_union *addr, unsigned char prefixlen);
|
||||
|
||||
static inline size_t FAMILY_ADDRESS_SIZE(int family) {
|
||||
assert(family == AF_INET || family == AF_INET6);
|
||||
return family == AF_INET6 ? 16 : 4;
|
||||
}
|
||||
|
||||
#define IN_ADDR_NULL ((union in_addr_union) {})
|
||||
|
|
|
|||
|
|
@ -57,6 +57,14 @@
|
|||
*_head = _item; \
|
||||
} while(false)
|
||||
|
||||
/* Append an item to the list */
|
||||
#define LIST_APPEND(name,head,item) \
|
||||
do { \
|
||||
typeof(*(head)) *_tail; \
|
||||
LIST_FIND_TAIL(name,head,_tail); \
|
||||
LIST_INSERT_AFTER(name,head,_tail,item); \
|
||||
} while(false)
|
||||
|
||||
/* Remove an item from the list */
|
||||
#define LIST_REMOVE(name,head,item) \
|
||||
do { \
|
||||
|
|
@ -132,6 +140,18 @@
|
|||
#define LIST_FOREACH_AFTER(name,i,p) \
|
||||
for ((i) = (p)->name##_next; (i); (i) = (i)->name##_next)
|
||||
|
||||
/* Iterate through all the members of the list p is included in, but skip over p */
|
||||
#define LIST_FOREACH_OTHERS(name,i,p) \
|
||||
for (({ \
|
||||
(i) = (p); \
|
||||
while ((i) && (i)->name##_prev) \
|
||||
(i) = (i)->name##_prev; \
|
||||
if ((i) == (p)) \
|
||||
(i) = (p)->name##_next; \
|
||||
}); \
|
||||
(i); \
|
||||
(i) = (i)->name##_next == (p) ? (p)->name##_next : (i)->name##_next)
|
||||
|
||||
/* Loop starting from p->next until p->prev.
|
||||
p can be adjusted meanwhile. */
|
||||
#define LIST_LOOP_BUT_ONE(name,i,head,p) \
|
||||
|
|
|
|||
214
src/dhcp-manager/systemd-dhcp/src/shared/log.h
Normal file
214
src/dhcp-manager/systemd-dhcp/src/shared/log.h
Normal file
|
|
@ -0,0 +1,214 @@
|
|||
/*-*- 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 <stdarg.h>
|
||||
#include <syslog.h>
|
||||
#include <sys/signalfd.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "macro.h"
|
||||
#include "sd-id128.h"
|
||||
|
||||
typedef enum LogTarget{
|
||||
LOG_TARGET_CONSOLE,
|
||||
LOG_TARGET_CONSOLE_PREFIXED,
|
||||
LOG_TARGET_KMSG,
|
||||
LOG_TARGET_JOURNAL,
|
||||
LOG_TARGET_JOURNAL_OR_KMSG,
|
||||
LOG_TARGET_SYSLOG,
|
||||
LOG_TARGET_SYSLOG_OR_KMSG,
|
||||
LOG_TARGET_AUTO, /* console if stderr is tty, JOURNAL_OR_KMSG otherwise */
|
||||
LOG_TARGET_SAFE, /* console if stderr is tty, KMSG otherwise */
|
||||
LOG_TARGET_NULL,
|
||||
_LOG_TARGET_MAX,
|
||||
_LOG_TARGET_INVALID = -1
|
||||
} LogTarget;
|
||||
|
||||
void log_set_target(LogTarget target);
|
||||
void log_set_max_level(int level);
|
||||
void log_set_facility(int facility);
|
||||
|
||||
int log_set_target_from_string(const char *e);
|
||||
int log_set_max_level_from_string(const char *e);
|
||||
|
||||
void log_show_color(bool b);
|
||||
bool log_get_show_color(void) _pure_;
|
||||
void log_show_location(bool b);
|
||||
bool log_get_show_location(void) _pure_;
|
||||
|
||||
int log_show_color_from_string(const char *e);
|
||||
int log_show_location_from_string(const char *e);
|
||||
|
||||
LogTarget log_get_target(void) _pure_;
|
||||
int log_get_max_level(void) _pure_;
|
||||
|
||||
int log_open(void);
|
||||
void log_close(void);
|
||||
void log_forget_fds(void);
|
||||
|
||||
void log_close_syslog(void);
|
||||
void log_close_journal(void);
|
||||
void log_close_kmsg(void);
|
||||
void log_close_console(void);
|
||||
|
||||
void log_parse_environment(void);
|
||||
|
||||
#if 0 /* NM_IGNORED */
|
||||
int log_internal(
|
||||
int level,
|
||||
int error,
|
||||
const char *file,
|
||||
int line,
|
||||
const char *func,
|
||||
const char *format, ...) _printf_(6,7);
|
||||
|
||||
int log_internalv(
|
||||
int level,
|
||||
int error,
|
||||
const char *file,
|
||||
int line,
|
||||
const char *func,
|
||||
const char *format,
|
||||
va_list ap) _printf_(6,0);
|
||||
|
||||
int log_object_internal(
|
||||
int level,
|
||||
int error,
|
||||
const char *file,
|
||||
int line,
|
||||
const char *func,
|
||||
const char *object_field,
|
||||
const char *object,
|
||||
const char *format, ...) _printf_(8,9);
|
||||
|
||||
int log_object_internalv(
|
||||
int level,
|
||||
int error,
|
||||
const char*file,
|
||||
int line,
|
||||
const char *func,
|
||||
const char *object_field,
|
||||
const char *object,
|
||||
const char *format,
|
||||
va_list ap) _printf_(8,0);
|
||||
|
||||
int log_struct_internal(
|
||||
int level,
|
||||
int error,
|
||||
const char *file,
|
||||
int line,
|
||||
const char *func,
|
||||
const char *format, ...) _printf_(6,0) _sentinel_;
|
||||
|
||||
int log_oom_internal(
|
||||
const char *file,
|
||||
int line,
|
||||
const char *func);
|
||||
|
||||
/* This modifies the buffer passed! */
|
||||
int log_dump_internal(
|
||||
int level,
|
||||
int error,
|
||||
const char *file,
|
||||
int line,
|
||||
const char *func,
|
||||
char *buffer);
|
||||
|
||||
/* Logging for various assertions */
|
||||
noreturn void log_assert_failed(
|
||||
const char *text,
|
||||
const char *file,
|
||||
int line,
|
||||
const char *func);
|
||||
|
||||
noreturn void log_assert_failed_unreachable(
|
||||
const char *text,
|
||||
const char *file,
|
||||
int line,
|
||||
const char *func);
|
||||
|
||||
void log_assert_failed_return(
|
||||
const char *text,
|
||||
const char *file,
|
||||
int line,
|
||||
const char *func);
|
||||
|
||||
/* Logging with level */
|
||||
#define log_full_errno(level, error, ...) \
|
||||
({ \
|
||||
int _level = (level), _e = (error); \
|
||||
(log_get_max_level() >= LOG_PRI(_level)) \
|
||||
? log_internal(_level, _e, __FILE__, __LINE__, __func__, __VA_ARGS__) \
|
||||
: -abs(_e); \
|
||||
})
|
||||
#endif /* NM_IGNORED */
|
||||
|
||||
#define log_full(level, ...) log_full_errno(level, 0, __VA_ARGS__)
|
||||
|
||||
/* Normal logging */
|
||||
#define log_debug(...) log_full(LOG_DEBUG, __VA_ARGS__)
|
||||
#define log_info(...) log_full(LOG_INFO, __VA_ARGS__)
|
||||
#define log_notice(...) log_full(LOG_NOTICE, __VA_ARGS__)
|
||||
#define log_warning(...) log_full(LOG_WARNING, __VA_ARGS__)
|
||||
#define log_error(...) log_full(LOG_ERR, __VA_ARGS__)
|
||||
#define log_emergency(...) log_full(getpid() == 1 ? LOG_EMERG : LOG_ERR, __VA_ARGS__)
|
||||
|
||||
/* Logging triggered by an errno-like error */
|
||||
#define log_debug_errno(error, ...) log_full_errno(LOG_DEBUG, error, __VA_ARGS__)
|
||||
#define log_info_errno(error, ...) log_full_errno(LOG_INFO, error, __VA_ARGS__)
|
||||
#define log_notice_errno(error, ...) log_full_errno(LOG_NOTICE, error, __VA_ARGS__)
|
||||
#define log_warning_errno(error, ...) log_full_errno(LOG_WARNING, error, __VA_ARGS__)
|
||||
#define log_error_errno(error, ...) log_full_errno(LOG_ERR, error, __VA_ARGS__)
|
||||
#define log_emergency_errno(error, ...) log_full_errno(getpid() == 1 ? LOG_EMERG : LOG_ERR, error, __VA_ARGS__)
|
||||
|
||||
#ifdef LOG_TRACE
|
||||
# define log_trace(...) log_debug(__VA_ARGS__)
|
||||
#else
|
||||
# define log_trace(...) do {} while(0)
|
||||
#endif
|
||||
|
||||
/* Structured logging */
|
||||
#define log_struct(level, ...) log_struct_internal(level, 0, __FILE__, __LINE__, __func__, __VA_ARGS__)
|
||||
#define log_struct_errno(level, error, ...) log_struct_internal(level, error, __FILE__, __LINE__, __func__, __VA_ARGS__)
|
||||
|
||||
/* This modifies the buffer passed! */
|
||||
#define log_dump(level, buffer) log_dump_internal(level, 0, __FILE__, __LINE__, __func__, buffer)
|
||||
|
||||
#define log_oom() log_oom_internal(__FILE__, __LINE__, __func__)
|
||||
|
||||
bool log_on_console(void) _pure_;
|
||||
|
||||
const char *log_target_to_string(LogTarget target) _const_;
|
||||
LogTarget log_target_from_string(const char *s) _pure_;
|
||||
|
||||
/* Helpers to prepare various fields for structured logging */
|
||||
#define LOG_MESSAGE(fmt, ...) "MESSAGE=" fmt, ##__VA_ARGS__
|
||||
#define LOG_MESSAGE_ID(x) "MESSAGE_ID=" SD_ID128_FORMAT_STR, SD_ID128_FORMAT_VAL(x)
|
||||
#define LOG_ERRNO(error) "ERRNO=%i", abs(error)
|
||||
|
||||
void log_received_signal(int level, const struct signalfd_siginfo *si);
|
||||
|
||||
void log_set_upgrade_syslog_to_journal(bool b);
|
||||
|
|
@ -69,6 +69,10 @@
|
|||
_Pragma("GCC diagnostic push"); \
|
||||
_Pragma("GCC diagnostic ignored \"-Wshadow\"")
|
||||
|
||||
#define DISABLE_WARNING_INCOMPATIBLE_POINTER_TYPES \
|
||||
_Pragma("GCC diagnostic push"); \
|
||||
_Pragma("GCC diagnostic ignored \"-Wincompatible-pointer-types\"")
|
||||
|
||||
#define REENABLE_WARNING \
|
||||
_Pragma("GCC diagnostic pop")
|
||||
|
||||
|
|
@ -97,15 +101,15 @@
|
|||
#error "Wut? Pointers are neither 4 nor 8 bytes long?"
|
||||
#endif
|
||||
|
||||
#define ALIGN_PTR(p) ((void*) ALIGN((unsigned long) p))
|
||||
#define ALIGN4_PTR(p) ((void*) ALIGN4((unsigned long) p))
|
||||
#define ALIGN8_PTR(p) ((void*) ALIGN8((unsigned long) p))
|
||||
#define ALIGN_PTR(p) ((void*) ALIGN((unsigned long) (p)))
|
||||
#define ALIGN4_PTR(p) ((void*) ALIGN4((unsigned long) (p)))
|
||||
#define ALIGN8_PTR(p) ((void*) ALIGN8((unsigned long) (p)))
|
||||
|
||||
static inline size_t ALIGN_TO(size_t l, size_t ali) {
|
||||
return ((l + ali - 1) & ~(ali - 1));
|
||||
}
|
||||
|
||||
#define ALIGN_TO_PTR(p, ali) ((void*) ALIGN_TO((unsigned long) p, ali))
|
||||
#define ALIGN_TO_PTR(p, ali) ((void*) ALIGN_TO((unsigned long) (p), (ali)))
|
||||
|
||||
/* align to next higher power-of-2 (except for: 0 => 0, overflow => 0) */
|
||||
static inline unsigned long ALIGN_POWER2(unsigned long u) {
|
||||
|
|
@ -199,6 +203,17 @@ static inline unsigned long ALIGN_POWER2(unsigned long u) {
|
|||
UNIQ_T(X,xq); \
|
||||
})
|
||||
|
||||
/* [(x + y - 1) / y] suffers from an integer overflow, even though the
|
||||
* computation should be possible in the given type. Therefore, we use
|
||||
* [x / y + !!(x % y)]. Note that on "Real CPUs" a division returns both the
|
||||
* quotient and the remainder, so both should be equally fast. */
|
||||
#define DIV_ROUND_UP(_x, _y) \
|
||||
__extension__ ({ \
|
||||
const typeof(_x) __x = (_x); \
|
||||
const typeof(_y) __y = (_y); \
|
||||
(__x / __y + !!(__x % __y)); \
|
||||
})
|
||||
|
||||
#define assert_se(expr) \
|
||||
do { \
|
||||
if (_unlikely_(!(expr))) \
|
||||
|
|
@ -229,7 +244,7 @@ static inline unsigned long ALIGN_POWER2(unsigned long u) {
|
|||
#else
|
||||
#define assert_cc(expr) \
|
||||
DISABLE_WARNING_DECLARATION_AFTER_STATEMENT; \
|
||||
struct CONCATENATE(_assert_struct_, __LINE__) { \
|
||||
struct CONCATENATE(_assert_struct_, __COUNTER__) { \
|
||||
char x[(expr) ? 0 : -1]; \
|
||||
}; \
|
||||
REENABLE_WARNING
|
||||
|
|
@ -266,6 +281,14 @@ 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 memzero(x,l) (memset((x), 0, (l)))
|
||||
#define zero(x) (memzero(&(x), sizeof(x)))
|
||||
|
||||
|
|
@ -362,7 +385,8 @@ do { \
|
|||
|
||||
/* 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. */
|
||||
* negative '-' prefix (hence works correctly on signed
|
||||
* types). Includes space for the trailing NUL. */
|
||||
#define DECIMAL_STR_MAX(type) \
|
||||
(2+(sizeof(type) <= 1 ? 3 : \
|
||||
sizeof(type) <= 2 ? 5 : \
|
||||
|
|
@ -386,7 +410,21 @@ do { \
|
|||
_found; \
|
||||
})
|
||||
|
||||
#if 0 /* NM_IGNORED */
|
||||
/* 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
|
||||
|
|
@ -394,13 +432,14 @@ do { \
|
|||
* Don't break on glibc < 2.16 that doesn't define __STDC_NO_THREADS__
|
||||
* see http://gcc.gnu.org/bugzilla/show_bug.cgi?id=53769
|
||||
*/
|
||||
#if __STDC_VERSION__ >= 201112L && !(defined(__STDC_NO_THREADS__) || (defined(__GNU_LIBRARY__) && __GLIBC__ == 2 && __GLIBC_MINOR__ < 16))
|
||||
#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L && !(defined(__STDC_NO_THREADS__) || (defined(__GNU_LIBRARY__) && __GLIBC__ == 2 && __GLIBC_MINOR__ < 16))
|
||||
#define thread_local _Thread_local
|
||||
#else
|
||||
#define thread_local __thread
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if 0 /* NM_IGNORED */
|
||||
/* Define C11 noreturn without <stdnoreturn.h> and even on older gcc
|
||||
* compiler versions */
|
||||
#ifndef noreturn
|
||||
|
|
@ -411,5 +450,16 @@ do { \
|
|||
#endif
|
||||
#endif
|
||||
|
||||
#include "log.h"
|
||||
#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) \
|
||||
static inline void func##p(type *p) { \
|
||||
if (*p) \
|
||||
func(*p); \
|
||||
} \
|
||||
struct __useless_struct_to_allow_trailing_semicolon__
|
||||
|
||||
#include "log.h"
|
||||
|
|
|
|||
694
src/dhcp-manager/systemd-dhcp/src/shared/path-util.c
Normal file
694
src/dhcp-manager/systemd-dhcp/src/shared/path-util.c
Normal file
|
|
@ -0,0 +1,694 @@
|
|||
/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
|
||||
|
||||
/***
|
||||
This file is part of systemd.
|
||||
|
||||
Copyright 2010-2012 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 <string.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/statvfs.h>
|
||||
|
||||
#include "macro.h"
|
||||
#include "util.h"
|
||||
#include "log.h"
|
||||
#include "strv.h"
|
||||
#endif /* NM_IGNORED */
|
||||
#include "path-util.h"
|
||||
#if 0 /* NM_IGNORED */
|
||||
#include "missing.h"
|
||||
|
||||
bool path_is_absolute(const char *p) {
|
||||
return p[0] == '/';
|
||||
}
|
||||
|
||||
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) {
|
||||
char **l;
|
||||
assert(p);
|
||||
|
||||
l = strv_split(p, ":");
|
||||
if (!l)
|
||||
return NULL;
|
||||
|
||||
if (!path_strv_make_absolute_cwd(l)) {
|
||||
strv_free(l);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return l;
|
||||
}
|
||||
|
||||
char *path_make_absolute(const char *p, const char *prefix) {
|
||||
assert(p);
|
||||
|
||||
/* Makes every item in the list an absolute path by prepending
|
||||
* the prefix, if specified and necessary */
|
||||
|
||||
if (path_is_absolute(p) || !prefix)
|
||||
return strdup(p);
|
||||
|
||||
return strjoin(prefix, "/", p, NULL);
|
||||
}
|
||||
|
||||
char *path_make_absolute_cwd(const char *p) {
|
||||
_cleanup_free_ char *cwd = NULL;
|
||||
|
||||
assert(p);
|
||||
|
||||
/* Similar to path_make_absolute(), but prefixes with the
|
||||
* current working directory. */
|
||||
|
||||
if (path_is_absolute(p))
|
||||
return strdup(p);
|
||||
|
||||
cwd = get_current_dir_name();
|
||||
if (!cwd)
|
||||
return NULL;
|
||||
|
||||
return strjoin(cwd, "/", p, NULL);
|
||||
}
|
||||
|
||||
int path_make_relative(const char *from_dir, const char *to_path, char **_r) {
|
||||
char *r, *p;
|
||||
unsigned n_parents;
|
||||
|
||||
assert(from_dir);
|
||||
assert(to_path);
|
||||
assert(_r);
|
||||
|
||||
/* Strips the common part, and adds ".." elements as necessary. */
|
||||
|
||||
if (!path_is_absolute(from_dir))
|
||||
return -EINVAL;
|
||||
|
||||
if (!path_is_absolute(to_path))
|
||||
return -EINVAL;
|
||||
|
||||
/* Skip the common part. */
|
||||
for (;;) {
|
||||
size_t a;
|
||||
size_t b;
|
||||
|
||||
from_dir += strspn(from_dir, "/");
|
||||
to_path += strspn(to_path, "/");
|
||||
|
||||
if (!*from_dir) {
|
||||
if (!*to_path)
|
||||
/* from_dir equals to_path. */
|
||||
r = strdup(".");
|
||||
else
|
||||
/* from_dir is a parent directory of to_path. */
|
||||
r = strdup(to_path);
|
||||
|
||||
if (!r)
|
||||
return -ENOMEM;
|
||||
|
||||
path_kill_slashes(r);
|
||||
|
||||
*_r = r;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!*to_path)
|
||||
break;
|
||||
|
||||
a = strcspn(from_dir, "/");
|
||||
b = strcspn(to_path, "/");
|
||||
|
||||
if (a != b)
|
||||
break;
|
||||
|
||||
if (memcmp(from_dir, to_path, a) != 0)
|
||||
break;
|
||||
|
||||
from_dir += a;
|
||||
to_path += b;
|
||||
}
|
||||
|
||||
/* If we're here, then "from_dir" has one or more elements that need to
|
||||
* be replaced with "..". */
|
||||
|
||||
/* Count the number of necessary ".." elements. */
|
||||
for (n_parents = 0;;) {
|
||||
from_dir += strspn(from_dir, "/");
|
||||
|
||||
if (!*from_dir)
|
||||
break;
|
||||
|
||||
from_dir += strcspn(from_dir, "/");
|
||||
n_parents++;
|
||||
}
|
||||
|
||||
r = malloc(n_parents * 3 + strlen(to_path) + 1);
|
||||
if (!r)
|
||||
return -ENOMEM;
|
||||
|
||||
for (p = r; n_parents > 0; n_parents--, p += 3)
|
||||
memcpy(p, "../", 3);
|
||||
|
||||
strcpy(p, to_path);
|
||||
path_kill_slashes(r);
|
||||
|
||||
*_r = r;
|
||||
return 0;
|
||||
}
|
||||
|
||||
char **path_strv_make_absolute_cwd(char **l) {
|
||||
char **s;
|
||||
|
||||
/* Goes through every item in the string list and makes it
|
||||
* absolute. This works in place and won't rollback any
|
||||
* changes on failure. */
|
||||
|
||||
STRV_FOREACH(s, l) {
|
||||
char *t;
|
||||
|
||||
t = path_make_absolute_cwd(*s);
|
||||
if (!t)
|
||||
return NULL;
|
||||
|
||||
free(*s);
|
||||
*s = t;
|
||||
}
|
||||
|
||||
return l;
|
||||
}
|
||||
|
||||
char **path_strv_resolve(char **l, const char *prefix) {
|
||||
char **s;
|
||||
unsigned k = 0;
|
||||
bool enomem = false;
|
||||
|
||||
if (strv_isempty(l))
|
||||
return l;
|
||||
|
||||
/* Goes through every item in the string list and canonicalize
|
||||
* the path. This works in place and won't rollback any
|
||||
* changes on failure. */
|
||||
|
||||
STRV_FOREACH(s, l) {
|
||||
char *t, *u;
|
||||
_cleanup_free_ char *orig = NULL;
|
||||
|
||||
if (!path_is_absolute(*s)) {
|
||||
free(*s);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (prefix) {
|
||||
orig = *s;
|
||||
t = strappend(prefix, orig);
|
||||
if (!t) {
|
||||
enomem = true;
|
||||
continue;
|
||||
}
|
||||
} else
|
||||
t = *s;
|
||||
|
||||
errno = 0;
|
||||
u = canonicalize_file_name(t);
|
||||
if (!u) {
|
||||
if (errno == ENOENT) {
|
||||
if (prefix) {
|
||||
u = orig;
|
||||
orig = NULL;
|
||||
free(t);
|
||||
} else
|
||||
u = t;
|
||||
} else {
|
||||
free(t);
|
||||
if (errno == ENOMEM || errno == 0)
|
||||
enomem = true;
|
||||
|
||||
continue;
|
||||
}
|
||||
} else if (prefix) {
|
||||
char *x;
|
||||
|
||||
free(t);
|
||||
x = path_startswith(u, prefix);
|
||||
if (x) {
|
||||
/* restore the slash if it was lost */
|
||||
if (!startswith(x, "/"))
|
||||
*(--x) = '/';
|
||||
|
||||
t = strdup(x);
|
||||
free(u);
|
||||
if (!t) {
|
||||
enomem = true;
|
||||
continue;
|
||||
}
|
||||
u = t;
|
||||
} else {
|
||||
/* canonicalized path goes outside of
|
||||
* prefix, keep the original path instead */
|
||||
free(u);
|
||||
u = orig;
|
||||
orig = NULL;
|
||||
}
|
||||
} else
|
||||
free(t);
|
||||
|
||||
l[k++] = u;
|
||||
}
|
||||
|
||||
l[k] = NULL;
|
||||
|
||||
if (enomem)
|
||||
return NULL;
|
||||
|
||||
return l;
|
||||
}
|
||||
|
||||
char **path_strv_resolve_uniq(char **l, const char *prefix) {
|
||||
|
||||
if (strv_isempty(l))
|
||||
return l;
|
||||
|
||||
if (!path_strv_resolve(l, prefix))
|
||||
return NULL;
|
||||
|
||||
return strv_uniq(l);
|
||||
}
|
||||
#endif /* NM_IGNORED */
|
||||
|
||||
char *path_kill_slashes(char *path) {
|
||||
char *f, *t;
|
||||
bool slash = false;
|
||||
|
||||
/* Removes redundant inner and trailing slashes. Modifies the
|
||||
* passed string in-place.
|
||||
*
|
||||
* ///foo///bar/ becomes /foo/bar
|
||||
*/
|
||||
|
||||
for (f = path, t = path; *f; f++) {
|
||||
|
||||
if (*f == '/') {
|
||||
slash = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (slash) {
|
||||
slash = false;
|
||||
*(t++) = '/';
|
||||
}
|
||||
|
||||
*(t++) = *f;
|
||||
}
|
||||
|
||||
/* Special rule, if we are talking of the root directory, a
|
||||
trailing slash is good */
|
||||
|
||||
if (t == path && slash)
|
||||
*(t++) = '/';
|
||||
|
||||
*t = 0;
|
||||
return path;
|
||||
}
|
||||
|
||||
#if 0 /* NM_IGNORED */
|
||||
char* path_startswith(const char *path, const char *prefix) {
|
||||
assert(path);
|
||||
assert(prefix);
|
||||
|
||||
if ((path[0] == '/') != (prefix[0] == '/'))
|
||||
return NULL;
|
||||
|
||||
for (;;) {
|
||||
size_t a, b;
|
||||
|
||||
path += strspn(path, "/");
|
||||
prefix += strspn(prefix, "/");
|
||||
|
||||
if (*prefix == 0)
|
||||
return (char*) path;
|
||||
|
||||
if (*path == 0)
|
||||
return NULL;
|
||||
|
||||
a = strcspn(path, "/");
|
||||
b = strcspn(prefix, "/");
|
||||
|
||||
if (a != b)
|
||||
return NULL;
|
||||
|
||||
if (memcmp(path, prefix, a) != 0)
|
||||
return NULL;
|
||||
|
||||
path += a;
|
||||
prefix += b;
|
||||
}
|
||||
}
|
||||
|
||||
bool path_equal(const char *a, const char *b) {
|
||||
assert(a);
|
||||
assert(b);
|
||||
|
||||
if ((a[0] == '/') != (b[0] == '/'))
|
||||
return false;
|
||||
|
||||
for (;;) {
|
||||
size_t j, k;
|
||||
|
||||
a += strspn(a, "/");
|
||||
b += strspn(b, "/");
|
||||
|
||||
if (*a == 0 && *b == 0)
|
||||
return true;
|
||||
|
||||
if (*a == 0 || *b == 0)
|
||||
return false;
|
||||
|
||||
j = strcspn(a, "/");
|
||||
k = strcspn(b, "/");
|
||||
|
||||
if (j != k)
|
||||
return false;
|
||||
|
||||
if (memcmp(a, b, j) != 0)
|
||||
return false;
|
||||
|
||||
a += j;
|
||||
b += k;
|
||||
}
|
||||
}
|
||||
|
||||
bool path_equal_or_files_same(const char *a, const char *b) {
|
||||
return path_equal(a, b) || files_same(a, b) > 0;
|
||||
}
|
||||
|
||||
char* path_join(const char *root, const char *path, const char *rest) {
|
||||
assert(path);
|
||||
|
||||
if (!isempty(root))
|
||||
return strjoin(root, endswith(root, "/") ? "" : "/",
|
||||
path[0] == '/' ? path+1 : path,
|
||||
rest ? (endswith(path, "/") ? "" : "/") : NULL,
|
||||
rest && rest[0] == '/' ? rest+1 : rest,
|
||||
NULL);
|
||||
else
|
||||
return strjoin(path,
|
||||
rest ? (endswith(path, "/") ? "" : "/") : NULL,
|
||||
rest && rest[0] == '/' ? rest+1 : rest,
|
||||
NULL);
|
||||
}
|
||||
|
||||
int path_is_mount_point(const char *t, bool allow_symlink) {
|
||||
|
||||
union file_handle_union h = FILE_HANDLE_INIT;
|
||||
int mount_id = -1, mount_id_parent = -1;
|
||||
_cleanup_free_ char *parent = NULL;
|
||||
struct stat a, b;
|
||||
int r;
|
||||
bool nosupp = false;
|
||||
|
||||
/* We are not actually interested in the file handles, but
|
||||
* name_to_handle_at() also passes us the mount ID, hence use
|
||||
* it but throw the handle away */
|
||||
|
||||
if (path_equal(t, "/"))
|
||||
return 1;
|
||||
|
||||
r = name_to_handle_at(AT_FDCWD, t, &h.handle, &mount_id, allow_symlink ? AT_SYMLINK_FOLLOW : 0);
|
||||
if (r < 0) {
|
||||
if (errno == ENOSYS)
|
||||
/* This kernel does not support name_to_handle_at()
|
||||
* fall back to the traditional stat() logic. */
|
||||
goto fallback;
|
||||
else if (errno == EOPNOTSUPP)
|
||||
/* This kernel or file system does not support
|
||||
* name_to_handle_at(), hence fallback to the
|
||||
* traditional stat() logic */
|
||||
nosupp = true;
|
||||
else if (errno == ENOENT)
|
||||
return 0;
|
||||
else
|
||||
return -errno;
|
||||
}
|
||||
|
||||
r = path_get_parent(t, &parent);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
h.handle.handle_bytes = MAX_HANDLE_SZ;
|
||||
r = name_to_handle_at(AT_FDCWD, parent, &h.handle, &mount_id_parent, AT_SYMLINK_FOLLOW);
|
||||
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;
|
||||
else
|
||||
/* The parent can't do name_to_handle_at() but
|
||||
* the directory we are interested in can?
|
||||
* Or the other way around?
|
||||
* If so, it must be a mount point. */
|
||||
return 1;
|
||||
else
|
||||
return -errno;
|
||||
else
|
||||
return mount_id != mount_id_parent;
|
||||
|
||||
fallback:
|
||||
if (allow_symlink)
|
||||
r = stat(t, &a);
|
||||
else
|
||||
r = lstat(t, &a);
|
||||
|
||||
if (r < 0) {
|
||||
if (errno == ENOENT)
|
||||
return 0;
|
||||
|
||||
return -errno;
|
||||
}
|
||||
|
||||
free(parent);
|
||||
parent = NULL;
|
||||
|
||||
r = path_get_parent(t, &parent);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = stat(parent, &b);
|
||||
if (r < 0)
|
||||
return -errno;
|
||||
|
||||
return a.st_dev != b.st_dev;
|
||||
}
|
||||
|
||||
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)
|
||||
return -errno;
|
||||
|
||||
if (filename) {
|
||||
char *p;
|
||||
|
||||
p = path_make_absolute_cwd(name);
|
||||
if (!p)
|
||||
return -ENOMEM;
|
||||
|
||||
*filename = p;
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
FOREACH_WORD_SEPARATOR(word, l, path, ":", state) {
|
||||
_cleanup_free_ char *p = NULL;
|
||||
|
||||
if (asprintf(&p, "%.*s/%s", (int) l, word, name) < 0)
|
||||
return -ENOMEM;
|
||||
|
||||
if (access(p, X_OK) < 0)
|
||||
continue;
|
||||
|
||||
if (filename) {
|
||||
*filename = path_kill_slashes(p);
|
||||
p = NULL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -ENOENT;
|
||||
}
|
||||
}
|
||||
|
||||
bool paths_check_timestamp(const char* const* paths, usec_t *timestamp, bool update) {
|
||||
bool changed = false;
|
||||
const char* const* i;
|
||||
|
||||
assert(timestamp);
|
||||
|
||||
if (paths == NULL)
|
||||
return false;
|
||||
|
||||
STRV_FOREACH(i, paths) {
|
||||
struct stat stats;
|
||||
usec_t u;
|
||||
|
||||
if (stat(*i, &stats) < 0)
|
||||
continue;
|
||||
|
||||
u = timespec_load(&stats.st_mtim);
|
||||
|
||||
/* first check */
|
||||
if (*timestamp >= u)
|
||||
continue;
|
||||
|
||||
log_debug("timestamp of '%s' changed", *i);
|
||||
|
||||
/* update timestamp */
|
||||
if (update) {
|
||||
*timestamp = u;
|
||||
changed = true;
|
||||
} else
|
||||
return true;
|
||||
}
|
||||
|
||||
return changed;
|
||||
}
|
||||
|
||||
int fsck_exists(const char *fstype) {
|
||||
_cleanup_free_ char *p = NULL, *d = NULL;
|
||||
const char *checker;
|
||||
int r;
|
||||
|
||||
checker = strjoina("fsck.", fstype);
|
||||
|
||||
r = find_binary(checker, true, &p);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
/* An fsck that is linked to /bin/true is a non-existent
|
||||
* 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;
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif /* NM_IGNORED */
|
||||
75
src/dhcp-manager/systemd-dhcp/src/shared/path-util.h
Normal file
75
src/dhcp-manager/systemd-dhcp/src/shared/path-util.h
Normal file
|
|
@ -0,0 +1,75 @@
|
|||
/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
|
||||
|
||||
#pragma once
|
||||
|
||||
/***
|
||||
This file is part of systemd.
|
||||
|
||||
Copyright 2010-2012 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 "macro.h"
|
||||
#include "time-util.h"
|
||||
|
||||
#define DEFAULT_PATH_NORMAL "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin"
|
||||
#define DEFAULT_PATH_SPLIT_USR DEFAULT_PATH_NORMAL ":/sbin:/bin"
|
||||
|
||||
#ifdef HAVE_SPLIT_USR
|
||||
# define DEFAULT_PATH DEFAULT_PATH_SPLIT_USR
|
||||
#else
|
||||
# define DEFAULT_PATH DEFAULT_PATH_NORMAL
|
||||
#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);
|
||||
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_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_;
|
||||
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);
|
||||
char** path_strv_resolve(char **l, const char *prefix);
|
||||
char** path_strv_resolve_uniq(char **l, const char *prefix);
|
||||
|
||||
int path_is_mount_point(const char *path, bool allow_symlink);
|
||||
int path_is_read_only_fs(const char *path);
|
||||
int path_is_os_tree(const char *path);
|
||||
|
||||
int find_binary(const char *name, bool local, char **filename);
|
||||
|
||||
bool paths_check_timestamp(const char* const* paths, usec_t *paths_ts_usec, bool update);
|
||||
|
||||
int fsck_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
|
||||
* directory. Excludes the specified directory itself */
|
||||
#define PATH_FOREACH_PREFIX(prefix, path) \
|
||||
for (char *_slash = ({ path_kill_slashes(strcpy(prefix, path)); streq(prefix, "/") ? NULL : strrchr(prefix, '/'); }); _slash && ((*_slash = 0), true); _slash = strrchr((prefix), '/'))
|
||||
|
||||
/* Same as PATH_FOREACH_PREFIX but also includes the specified path itself */
|
||||
#define PATH_FOREACH_PREFIX_MORE(prefix, path) \
|
||||
for (char *_slash = ({ path_kill_slashes(strcpy(prefix, path)); if (streq(prefix, "/")) prefix[0] = 0; strrchr(prefix, 0); }); _slash && ((*_slash = 0), true); _slash = strrchr((prefix), '/'))
|
||||
|
|
@ -27,7 +27,6 @@
|
|||
#include <netinet/in.h>
|
||||
#include <netinet/ether.h>
|
||||
#include <sys/un.h>
|
||||
#include <asm/types.h>
|
||||
#include <linux/netlink.h>
|
||||
#include <linux/if_packet.h>
|
||||
|
||||
|
|
|
|||
|
|
@ -21,7 +21,6 @@
|
|||
|
||||
#include "nm-sd-adapt.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdarg.h>
|
||||
#include <string.h>
|
||||
|
|
@ -71,7 +70,7 @@ char *strv_find_startswith(char **l, const char *name) {
|
|||
return NULL;
|
||||
}
|
||||
|
||||
void strv_free(char **l) {
|
||||
void strv_clear(char **l) {
|
||||
char **k;
|
||||
|
||||
if (!l)
|
||||
|
|
@ -80,6 +79,11 @@ void strv_free(char **l) {
|
|||
for (k = l; *k; k++)
|
||||
free(*k);
|
||||
|
||||
*l = NULL;
|
||||
}
|
||||
|
||||
void strv_free(char **l) {
|
||||
strv_clear(l);
|
||||
free(l);
|
||||
}
|
||||
|
||||
|
|
@ -392,7 +396,7 @@ int strv_push(char ***l, char *value) {
|
|||
|
||||
n = strv_length(*l);
|
||||
|
||||
/* increase and check for overflow */
|
||||
/* Increase and check for overflow */
|
||||
m = n + 2;
|
||||
if (m < n)
|
||||
return -ENOMEM;
|
||||
|
|
@ -408,6 +412,34 @@ int strv_push(char ***l, char *value) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
int strv_push_pair(char ***l, char *a, char *b) {
|
||||
char **c;
|
||||
unsigned n, m;
|
||||
|
||||
if (!a && !b)
|
||||
return 0;
|
||||
|
||||
n = strv_length(*l);
|
||||
|
||||
/* increase and check for overflow */
|
||||
m = n + !!a + !!b + 1;
|
||||
if (m < n)
|
||||
return -ENOMEM;
|
||||
|
||||
c = realloc_multiply(*l, sizeof(char*), m);
|
||||
if (!c)
|
||||
return -ENOMEM;
|
||||
|
||||
if (a)
|
||||
c[n++] = a;
|
||||
if (b)
|
||||
c[n++] = b;
|
||||
c[n] = NULL;
|
||||
|
||||
*l = c;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int strv_push_prepend(char ***l, char *value) {
|
||||
char **c;
|
||||
unsigned n, m, i;
|
||||
|
|
@ -448,6 +480,18 @@ int strv_consume(char ***l, char *value) {
|
|||
return r;
|
||||
}
|
||||
|
||||
int strv_consume_pair(char ***l, char *a, char *b) {
|
||||
int r;
|
||||
|
||||
r = strv_push_pair(l, a, b);
|
||||
if (r < 0) {
|
||||
free(a);
|
||||
free(b);
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
int strv_consume_prepend(char ***l, char *value) {
|
||||
int r;
|
||||
|
||||
|
|
@ -483,6 +527,16 @@ char **strv_uniq(char **l) {
|
|||
return l;
|
||||
}
|
||||
|
||||
bool strv_is_uniq(char **l) {
|
||||
char **i;
|
||||
|
||||
STRV_FOREACH(i, l)
|
||||
if (strv_find(i+1, *i))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
char **strv_remove(char **l, const char *s) {
|
||||
char **f, **t;
|
||||
|
||||
|
|
@ -591,6 +645,17 @@ char **strv_sort(char **l) {
|
|||
return l;
|
||||
}
|
||||
|
||||
bool strv_equal(char **a, char **b) {
|
||||
if (!a || !b)
|
||||
return a == b;
|
||||
|
||||
for ( ; *a || *b; ++a, ++b)
|
||||
if (!streq_ptr(*a, *b))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void strv_print(char **l) {
|
||||
char **s;
|
||||
|
||||
|
|
@ -612,3 +677,31 @@ int strv_extendf(char ***l, const char *format, ...) {
|
|||
|
||||
return strv_consume(l, x);
|
||||
}
|
||||
|
||||
char **strv_reverse(char **l) {
|
||||
unsigned n, i;
|
||||
|
||||
n = strv_length(l);
|
||||
if (n <= 1)
|
||||
return l;
|
||||
|
||||
for (i = 0; i < n / 2; i++) {
|
||||
char *t;
|
||||
|
||||
t = l[i];
|
||||
l[i] = l[n-1-i];
|
||||
l[n-1-i] = t;
|
||||
}
|
||||
|
||||
return l;
|
||||
}
|
||||
|
||||
bool strv_fnmatch(char* const* patterns, const char *s, int flags) {
|
||||
char* const* p;
|
||||
|
||||
STRV_FOREACH(p, patterns)
|
||||
if (fnmatch(*p, s, 0) == 0)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@
|
|||
|
||||
#include <stdarg.h>
|
||||
#include <stdbool.h>
|
||||
#include <fnmatch.h>
|
||||
|
||||
#include "util.h"
|
||||
|
||||
|
|
@ -36,6 +37,8 @@ void strv_free(char **l);
|
|||
DEFINE_TRIVIAL_CLEANUP_FUNC(char**, strv_free);
|
||||
#define _cleanup_strv_free_ _cleanup_(strv_freep)
|
||||
|
||||
void strv_clear(char **l);
|
||||
|
||||
char **strv_copy(char * const *l);
|
||||
unsigned strv_length(char * const *l) _pure_;
|
||||
|
||||
|
|
@ -44,12 +47,17 @@ 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);
|
||||
int strv_push(char ***l, char *value);
|
||||
int strv_push_pair(char ***l, char *a, char *b);
|
||||
int strv_push_prepend(char ***l, char *value);
|
||||
int strv_consume(char ***l, char *value);
|
||||
int strv_consume_pair(char ***l, char *a, char *b);
|
||||
int strv_consume_prepend(char ***l, char *value);
|
||||
|
||||
char **strv_remove(char **l, const char *s);
|
||||
char **strv_uniq(char **l);
|
||||
bool strv_is_uniq(char **l);
|
||||
|
||||
bool strv_equal(char **a, char **b);
|
||||
|
||||
#define strv_contains(l, s) (!!strv_find((l), (s)))
|
||||
|
||||
|
|
@ -137,3 +145,13 @@ void strv_print(char **l);
|
|||
_l ++; \
|
||||
_l[0]; \
|
||||
}))
|
||||
|
||||
char **strv_reverse(char **l);
|
||||
|
||||
bool strv_fnmatch(char* const* patterns, const char *s, int flags);
|
||||
|
||||
static inline bool strv_fnmatch_or_empty(char* const* patterns, const char *s, int flags) {
|
||||
assert(s);
|
||||
return strv_isempty(patterns) ||
|
||||
strv_fnmatch(patterns, s, flags);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -507,8 +507,9 @@ int parse_timestamp(const char *t, usec_t *usec) {
|
|||
return parse_sec(t + 1, usec);
|
||||
|
||||
else if (endswith(t, " ago")) {
|
||||
_cleanup_free_ char *z = strndup(t, strlen(t) - 4);
|
||||
_cleanup_free_ char *z;
|
||||
|
||||
z = strndup(t, strlen(t) - 4);
|
||||
if (!z)
|
||||
return -ENOMEM;
|
||||
|
||||
|
|
@ -518,8 +519,9 @@ int parse_timestamp(const char *t, usec_t *usec) {
|
|||
|
||||
goto finish;
|
||||
} else if (endswith(t, " left")) {
|
||||
_cleanup_free_ char *z = strndup(t, strlen(t) - 4);
|
||||
_cleanup_free_ char *z;
|
||||
|
||||
z = strndup(t, strlen(t) - 4);
|
||||
if (!z)
|
||||
return -ENOMEM;
|
||||
|
||||
|
|
@ -791,7 +793,7 @@ int parse_nsec(const char *t, nsec_t *nsec) {
|
|||
s = startswith(p, "infinity");
|
||||
if (s) {
|
||||
s += strspn(s, WHITESPACE);
|
||||
if (!*s != 0)
|
||||
if (*s != 0)
|
||||
return -EINVAL;
|
||||
|
||||
*nsec = NSEC_INFINITY;
|
||||
|
|
@ -970,7 +972,7 @@ bool timezone_is_valid(const char *name) {
|
|||
if (slash)
|
||||
return false;
|
||||
|
||||
t = strappenda("/usr/share/zoneinfo/", name);
|
||||
t = strjoina("/usr/share/zoneinfo/", name);
|
||||
if (stat(t, &st) < 0)
|
||||
return false;
|
||||
|
||||
|
|
@ -998,4 +1000,3 @@ clockid_t clock_boottime_or_monotonic(void) {
|
|||
|
||||
return clock;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -69,7 +69,7 @@ typedef struct dual_timestamp {
|
|||
|
||||
#define TIME_T_MAX (time_t)((1UL << ((sizeof(time_t) << 3) - 1)) - 1)
|
||||
|
||||
#define DUAL_TIMESTAMP_NULL ((struct dual_timestamp) { 0, 0 })
|
||||
#define DUAL_TIMESTAMP_NULL ((struct dual_timestamp) { 0ULL, 0ULL })
|
||||
|
||||
usec_t now(clockid_t clock);
|
||||
|
||||
|
|
@ -109,3 +109,5 @@ int get_timezones(char ***l);
|
|||
bool timezone_is_valid(const char *name);
|
||||
|
||||
clockid_t clock_boottime_or_monotonic(void);
|
||||
|
||||
#define xstrftime(buf, fmt, tm) assert_se(strftime(buf, ELEMENTSOF(buf), fmt, tm) > 0)
|
||||
|
|
|
|||
|
|
@ -144,19 +144,19 @@ int utf8_encoded_to_unichar(const char *str) {
|
|||
}
|
||||
|
||||
bool utf8_is_printable_newline(const char* str, size_t length, bool newline) {
|
||||
const uint8_t *p;
|
||||
const char *p;
|
||||
|
||||
assert(str);
|
||||
|
||||
for (p = (const uint8_t*) str; length;) {
|
||||
for (p = str; length;) {
|
||||
int encoded_len, val;
|
||||
|
||||
encoded_len = utf8_encoded_valid_unichar((const char *) p);
|
||||
encoded_len = utf8_encoded_valid_unichar(p);
|
||||
if (encoded_len < 0 ||
|
||||
(size_t) encoded_len > length)
|
||||
return false;
|
||||
|
||||
val = utf8_encoded_to_unichar((const char*) p);
|
||||
val = utf8_encoded_to_unichar(p);
|
||||
if (val < 0 ||
|
||||
is_unicode_control(val) ||
|
||||
(!newline && val == '\n'))
|
||||
|
|
@ -204,7 +204,46 @@ char *utf8_escape_invalid(const char *str) {
|
|||
s = mempcpy(s, str, len);
|
||||
str += len;
|
||||
} else {
|
||||
s = mempcpy(s, UTF8_REPLACEMENT_CHARACTER, strlen(UTF8_REPLACEMENT_CHARACTER));
|
||||
s = stpcpy(s, UTF8_REPLACEMENT_CHARACTER);
|
||||
str += 1;
|
||||
}
|
||||
}
|
||||
|
||||
*s = '\0';
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
char *utf8_escape_non_printable(const char *str) {
|
||||
char *p, *s;
|
||||
|
||||
assert(str);
|
||||
|
||||
p = s = malloc(strlen(str) * 4 + 1);
|
||||
if (!p)
|
||||
return NULL;
|
||||
|
||||
while (*str) {
|
||||
int len;
|
||||
|
||||
len = utf8_encoded_valid_unichar(str);
|
||||
if (len > 0) {
|
||||
if (utf8_is_printable(str, len)) {
|
||||
s = mempcpy(s, str, len);
|
||||
str += len;
|
||||
} else {
|
||||
while (len > 0) {
|
||||
*(s++) = '\\';
|
||||
*(s++) = 'x';
|
||||
*(s++) = hexchar((int) *str >> 4);
|
||||
*(s++) = hexchar((int) *str);
|
||||
|
||||
str += 1;
|
||||
len --;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
s = stpcpy(s, UTF8_REPLACEMENT_CHARACTER);
|
||||
str += 1;
|
||||
}
|
||||
}
|
||||
|
|
@ -226,39 +265,91 @@ char *ascii_is_valid(const char *str) {
|
|||
return (char*) str;
|
||||
}
|
||||
|
||||
char *utf16_to_utf8(const void *s, size_t length) {
|
||||
char *r;
|
||||
const uint8_t *f;
|
||||
uint8_t *t;
|
||||
/**
|
||||
* utf8_encode_unichar() - Encode single UCS-4 character as UTF-8
|
||||
* @out_utf8: output buffer of at least 4 bytes or NULL
|
||||
* @g: UCS-4 character to encode
|
||||
*
|
||||
* This encodes a single UCS-4 character as UTF-8 and writes it into @out_utf8.
|
||||
* The length of the character is returned. It is not zero-terminated! If the
|
||||
* output buffer is NULL, only the length is returned.
|
||||
*
|
||||
* Returns: The length in bytes that the UTF-8 representation does or would
|
||||
* occupy.
|
||||
*/
|
||||
size_t utf8_encode_unichar(char *out_utf8, uint32_t g) {
|
||||
if (g < (1 << 7)) {
|
||||
if (out_utf8)
|
||||
out_utf8[0] = g & 0x7f;
|
||||
return 1;
|
||||
} else if (g < (1 << 11)) {
|
||||
if (out_utf8) {
|
||||
out_utf8[0] = 0xc0 | ((g >> 6) & 0x1f);
|
||||
out_utf8[1] = 0x80 | (g & 0x3f);
|
||||
}
|
||||
return 2;
|
||||
} else if (g < (1 << 16)) {
|
||||
if (out_utf8) {
|
||||
out_utf8[0] = 0xe0 | ((g >> 12) & 0x0f);
|
||||
out_utf8[1] = 0x80 | ((g >> 6) & 0x3f);
|
||||
out_utf8[2] = 0x80 | (g & 0x3f);
|
||||
}
|
||||
return 3;
|
||||
} else if (g < (1 << 21)) {
|
||||
if (out_utf8) {
|
||||
out_utf8[0] = 0xf0 | ((g >> 18) & 0x07);
|
||||
out_utf8[1] = 0x80 | ((g >> 12) & 0x3f);
|
||||
out_utf8[2] = 0x80 | ((g >> 6) & 0x3f);
|
||||
out_utf8[3] = 0x80 | (g & 0x3f);
|
||||
}
|
||||
return 4;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
r = new(char, (length*3+1)/2 + 1);
|
||||
char *utf16_to_utf8(const void *s, size_t length) {
|
||||
const uint8_t *f;
|
||||
char *r, *t;
|
||||
|
||||
r = new(char, (length * 4 + 1) / 2 + 1);
|
||||
if (!r)
|
||||
return NULL;
|
||||
|
||||
t = (uint8_t*) r;
|
||||
f = s;
|
||||
t = r;
|
||||
|
||||
for (f = s; f < (const uint8_t*) s + length; f += 2) {
|
||||
uint16_t c;
|
||||
while (f < (const uint8_t*) s + length) {
|
||||
uint16_t w1, w2;
|
||||
|
||||
c = (f[1] << 8) | f[0];
|
||||
/* see RFC 2781 section 2.2 */
|
||||
|
||||
if (c == 0) {
|
||||
*t = 0;
|
||||
return r;
|
||||
} else if (c < 0x80) {
|
||||
*(t++) = (uint8_t) c;
|
||||
} else if (c < 0x800) {
|
||||
*(t++) = (uint8_t) (0xc0 | (c >> 6));
|
||||
*(t++) = (uint8_t) (0x80 | (c & 0x3f));
|
||||
} else {
|
||||
*(t++) = (uint8_t) (0xe0 | (c >> 12));
|
||||
*(t++) = (uint8_t) (0x80 | ((c >> 6) & 0x3f));
|
||||
*(t++) = (uint8_t) (0x80 | (c & 0x3f));
|
||||
w1 = f[1] << 8 | f[0];
|
||||
f += 2;
|
||||
|
||||
if (!utf16_is_surrogate(w1)) {
|
||||
t += utf8_encode_unichar(t, w1);
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if (utf16_is_trailing_surrogate(w1))
|
||||
continue;
|
||||
else if (f >= (const uint8_t*) s + length)
|
||||
break;
|
||||
|
||||
w2 = f[1] << 8 | f[0];
|
||||
f += 2;
|
||||
|
||||
if (!utf16_is_trailing_surrogate(w2)) {
|
||||
f -= 2;
|
||||
continue;
|
||||
}
|
||||
|
||||
t += utf8_encode_unichar(t, utf16_surrogate_pair_to_unichar(w1, w2));
|
||||
}
|
||||
|
||||
*t = 0;
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -31,14 +31,27 @@
|
|||
|
||||
const char *utf8_is_valid(const char *s) _pure_;
|
||||
char *ascii_is_valid(const char *s) _pure_;
|
||||
char *utf8_escape_invalid(const char *s);
|
||||
|
||||
bool utf8_is_printable_newline(const char* str, size_t length, bool newline) _pure_;
|
||||
_pure_ static inline bool utf8_is_printable(const char* str, size_t length) {
|
||||
return utf8_is_printable_newline(str, length, true);
|
||||
}
|
||||
#define utf8_is_printable(str, length) utf8_is_printable_newline(str, length, true)
|
||||
|
||||
char *utf8_escape_invalid(const char *s);
|
||||
char *utf8_escape_non_printable(const char *str);
|
||||
|
||||
size_t utf8_encode_unichar(char *out_utf8, uint32_t g);
|
||||
char *utf16_to_utf8(const void *s, size_t length);
|
||||
|
||||
int utf8_encoded_valid_unichar(const char *str);
|
||||
int utf8_encoded_to_unichar(const char *str);
|
||||
|
||||
static inline bool utf16_is_surrogate(uint16_t c) {
|
||||
return (0xd800 <= c && c <= 0xdfff);
|
||||
}
|
||||
|
||||
static inline bool utf16_is_trailing_surrogate(uint16_t c) {
|
||||
return (0xdc00 <= c && c <= 0xdfff);
|
||||
}
|
||||
|
||||
static inline uint32_t utf16_surrogate_pair_to_unichar(uint16_t lead, uint16_t trail) {
|
||||
return ((lead - 0xd800) << 10) + (trail - 0xdc00) + 0x10000;
|
||||
}
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -27,7 +27,6 @@
|
|||
#include <fcntl.h>
|
||||
#include <inttypes.h>
|
||||
#include <time.h>
|
||||
#include <sys/time.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdlib.h>
|
||||
|
|
@ -36,23 +35,24 @@
|
|||
#include <sched.h>
|
||||
#include <limits.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/stat.h>
|
||||
#include <dirent.h>
|
||||
#include <sys/resource.h>
|
||||
#include <stddef.h>
|
||||
#include <unistd.h>
|
||||
#include <locale.h>
|
||||
#include <mntent.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/inotify.h>
|
||||
|
||||
#if 0 /* NM_IGNORED */
|
||||
#if SIZEOF_PID_T == 4
|
||||
# define PID_FMT "%" PRIu32
|
||||
# define PID_PRI PRIi32
|
||||
#elif SIZEOF_PID_T == 2
|
||||
# define PID_FMT "%" PRIu16
|
||||
# define PID_PRI PRIi16
|
||||
#else
|
||||
# error Unknown pid_t size
|
||||
#endif
|
||||
#define PID_FMT "%" PID_PRI
|
||||
|
||||
#if SIZEOF_UID_T == 4
|
||||
# define UID_FMT "%" PRIu32
|
||||
|
|
@ -71,7 +71,7 @@
|
|||
#endif
|
||||
|
||||
#if SIZEOF_TIME_T == 8
|
||||
# define PRI_TIME PRIu64
|
||||
# define PRI_TIME PRIi64
|
||||
#elif SIZEOF_TIME_T == 4
|
||||
# define PRI_TIME PRIu32
|
||||
#else
|
||||
|
|
@ -118,7 +118,7 @@
|
|||
#define ANSI_HIGHLIGHT_OFF "\x1B[0m"
|
||||
#define ANSI_ERASE_TO_END_OF_LINE "\x1B[K"
|
||||
|
||||
size_t page_size(void);
|
||||
size_t page_size(void) _pure_;
|
||||
#define PAGE_ALIGN(l) ALIGN_TO((l), page_size())
|
||||
|
||||
#define streq(a,b) (strcmp((a),(b)) == 0)
|
||||
|
|
@ -148,6 +148,10 @@ static inline const char* true_false(bool b) {
|
|||
return b ? "true" : "false";
|
||||
}
|
||||
|
||||
static inline const char* one_zero(bool b) {
|
||||
return b ? "1" : "0";
|
||||
}
|
||||
|
||||
static inline const char* strempty(const char *s) {
|
||||
return s ? s : "";
|
||||
}
|
||||
|
|
@ -269,7 +273,6 @@ const char* split(const char **state, size_t *l, const char *separator, bool quo
|
|||
for ((state) = (s), (word) = split(&(state), &(length), (separator), (quoted)); (word); (word) = split(&(state), &(length), (separator), (quoted)))
|
||||
|
||||
pid_t get_parent_of_pid(pid_t pid, pid_t *ppid);
|
||||
int get_starttime_of_pid(pid_t pid, unsigned long long *st);
|
||||
|
||||
char *strappend(const char *s, const char *suffix);
|
||||
char *strnappend(const char *s, const char *suffix, size_t length);
|
||||
|
|
@ -301,6 +304,9 @@ int get_process_exe(pid_t pid, char **name);
|
|||
int get_process_uid(pid_t pid, uid_t *uid);
|
||||
int get_process_gid(pid_t pid, gid_t *gid);
|
||||
int get_process_capeff(pid_t pid, char **capeff);
|
||||
int get_process_cwd(pid_t pid, char **cwd);
|
||||
int get_process_root(pid_t pid, char **root);
|
||||
int get_process_environ(pid_t pid, char **environ);
|
||||
|
||||
char hexchar(int x) _const_;
|
||||
int unhexchar(char c) _const_;
|
||||
|
|
@ -321,7 +327,7 @@ 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 ignore_file(const char *filename) _pure_;
|
||||
bool hidden_file(const char *filename) _pure_;
|
||||
|
||||
bool chars_intersect(const char *a, const char *b) _pure_;
|
||||
|
||||
|
|
@ -346,26 +352,29 @@ static inline uint32_t random_u32(void) {
|
|||
}
|
||||
|
||||
/* For basic lookup tables with strictly enumerated entries */
|
||||
#define __DEFINE_STRING_TABLE_LOOKUP(name,type,scope) \
|
||||
#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]; \
|
||||
} \
|
||||
scope type name##_from_string(const char *s) { \
|
||||
type i; \
|
||||
if (!s) \
|
||||
return (type) -1; \
|
||||
for (i = 0; i < (type)ELEMENTSOF(name##_table); i++) \
|
||||
if (name##_table[i] && \
|
||||
streq(name##_table[i], s)) \
|
||||
return i; \
|
||||
return (type) -1; \
|
||||
} \
|
||||
}
|
||||
|
||||
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 inline 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_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) \
|
||||
|
|
@ -379,7 +388,7 @@ static inline uint32_t random_u32(void) {
|
|||
if (!s) \
|
||||
return log_oom(); \
|
||||
} else { \
|
||||
r = asprintf(&s, "%u", i); \
|
||||
r = asprintf(&s, "%i", i); \
|
||||
if (r < 0) \
|
||||
return log_oom(); \
|
||||
} \
|
||||
|
|
@ -429,7 +438,7 @@ int sigaction_many(const struct sigaction *sa, ...);
|
|||
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);
|
||||
ssize_t loop_write(int fd, const 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);
|
||||
|
||||
|
|
@ -457,6 +466,8 @@ int get_ctty(pid_t, dev_t *_devnr, char **r);
|
|||
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 is_fd_on_temporary_fs(int fd);
|
||||
|
||||
int rm_rf_children(int fd, bool only_dirs, bool honour_sticky, struct stat *root_dev);
|
||||
int rm_rf_children_dangerous(int fd, bool only_dirs, bool honour_sticky, struct stat *root_dev);
|
||||
int rm_rf(const char *path, bool only_dirs, bool delete_root, bool honour_sticky);
|
||||
|
|
@ -469,6 +480,8 @@ cpu_set_t* cpu_set_malloc(unsigned *ncpus);
|
|||
int status_vprintf(const char *status, bool ellipse, bool ephemeral, const char *format, va_list ap) _printf_(4,0);
|
||||
int status_printf(const char *status, bool ellipse, bool ephemeral, const char *format, ...) _printf_(4,5);
|
||||
|
||||
#define xsprintf(buf, fmt, ...) assert_se((size_t) snprintf(buf, ELEMENTSOF(buf), fmt, __VA_ARGS__) < ELEMENTSOF(buf))
|
||||
|
||||
int fd_columns(int fd);
|
||||
unsigned columns(void);
|
||||
int fd_lines(int fd);
|
||||
|
|
@ -516,7 +529,7 @@ char *unquote(const char *s, const char *quotes);
|
|||
char *normalize_env_assignment(const char *s);
|
||||
|
||||
int wait_for_terminate(pid_t pid, siginfo_t *status);
|
||||
int wait_for_terminate_and_warn(const char *name, pid_t pid);
|
||||
int wait_for_terminate_and_warn(const char *name, pid_t pid, bool check_exit_code);
|
||||
|
||||
noreturn void freeze(void);
|
||||
|
||||
|
|
@ -535,7 +548,7 @@ bool tty_is_console(const char *tty) _pure_;
|
|||
int vtnr_from_tty(const char *tty);
|
||||
const char *default_term_for_tty(const char *tty);
|
||||
|
||||
void execute_directory(const char *directory, DIR *_d, usec_t timeout, char *argv[]);
|
||||
void execute_directories(const char* const* directories, usec_t timeout, char *argv[]);
|
||||
|
||||
int kill_and_sigcont(pid_t pid, int sig);
|
||||
|
||||
|
|
@ -648,7 +661,10 @@ int setrlimit_closest(int resource, const struct rlimit *rlim);
|
|||
|
||||
int getenv_for_pid(pid_t pid, const char *field, char **_value);
|
||||
|
||||
bool is_valid_documentation_url(const char *url) _pure_;
|
||||
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);
|
||||
|
||||
|
|
@ -661,13 +677,6 @@ static inline void freep(void *p) {
|
|||
free(*(void**) p);
|
||||
}
|
||||
|
||||
#define DEFINE_TRIVIAL_CLEANUP_FUNC(type, func) \
|
||||
static inline void func##p(type *p) { \
|
||||
if (*p) \
|
||||
func(*p); \
|
||||
} \
|
||||
struct __useless_struct_to_allow_trailing_semicolon__
|
||||
|
||||
static inline void closep(int *fd) {
|
||||
safe_close(*fd);
|
||||
}
|
||||
|
|
@ -716,7 +725,7 @@ _alloc_(2, 3) static inline void *memdup_multiply(const void *p, size_t a, size_
|
|||
return memdup(p, a * b);
|
||||
}
|
||||
|
||||
bool filename_is_safe(const char *p) _pure_;
|
||||
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_;
|
||||
|
|
@ -732,6 +741,8 @@ void *xbsearch_r(const void *key, const void *base, size_t nmemb, size_t size,
|
|||
int (*compar) (const void *, const void *, void *),
|
||||
void *arg);
|
||||
|
||||
#define _(String) gettext (String)
|
||||
void init_gettext(void);
|
||||
bool is_locale_utf8(void);
|
||||
|
||||
typedef enum DrawSpecialChar {
|
||||
|
|
@ -773,10 +784,19 @@ int search_and_fopen_nulstr(const char *path, const char *mode, const char *root
|
|||
on_error; \
|
||||
} \
|
||||
break; \
|
||||
} else if (ignore_file((de)->d_name)) \
|
||||
} else if (hidden_file((de)->d_name)) \
|
||||
continue; \
|
||||
else
|
||||
|
||||
#define FOREACH_DIRENT_ALL(de, d, on_error) \
|
||||
for (errno = 0, de = readdir(d);; errno = 0, de = readdir(d)) \
|
||||
if (!de) { \
|
||||
if (errno > 0) { \
|
||||
on_error; \
|
||||
} \
|
||||
break; \
|
||||
} else
|
||||
|
||||
static inline void *mempset(void *s, int c, size_t n) {
|
||||
memset(s, c, n);
|
||||
return (uint8_t*)s + n;
|
||||
|
|
@ -841,7 +861,7 @@ static inline unsigned u32ctz(uint32_t n) {
|
|||
#endif
|
||||
}
|
||||
|
||||
static inline int log2i(int x) {
|
||||
static inline unsigned log2i(int x) {
|
||||
assert(x > 0);
|
||||
|
||||
return __SIZEOF_INT__ * 8 - __builtin_clz(x) - 1;
|
||||
|
|
@ -885,6 +905,7 @@ int unlink_noerrno(const char *path);
|
|||
(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_; \
|
||||
|
|
@ -901,19 +922,19 @@ int unlink_noerrno(const char *path);
|
|||
(void*)memset(_new_, 0, _size_); \
|
||||
})
|
||||
|
||||
#define strappenda(a, ...) \
|
||||
({ \
|
||||
int _len = strlen(a); \
|
||||
unsigned _i; \
|
||||
char *_d_, *_p_; \
|
||||
const char *_appendees_[] = { __VA_ARGS__ }; \
|
||||
for (_i = 0; _i < ELEMENTSOF(_appendees_); _i++) \
|
||||
_len += strlen(_appendees_[_i]); \
|
||||
_d_ = alloca(_len + 1); \
|
||||
_p_ = stpcpy(_d_, a); \
|
||||
for (_i = 0; _i < ELEMENTSOF(_appendees_); _i++) \
|
||||
_p_ = stpcpy(_p_, _appendees_[_i]); \
|
||||
_d_; \
|
||||
#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_; \
|
||||
})
|
||||
|
||||
#define procfs_file_alloca(pid, field) \
|
||||
|
|
@ -929,32 +950,6 @@ int unlink_noerrno(const char *path);
|
|||
_r_; \
|
||||
})
|
||||
|
||||
struct _locale_struct_ {
|
||||
locale_t saved_locale;
|
||||
locale_t new_locale;
|
||||
bool quit;
|
||||
};
|
||||
|
||||
static inline void _reset_locale_(struct _locale_struct_ *s) {
|
||||
PROTECT_ERRNO;
|
||||
if (s->saved_locale != (locale_t) 0)
|
||||
uselocale(s->saved_locale);
|
||||
if (s->new_locale != (locale_t) 0)
|
||||
freelocale(s->new_locale);
|
||||
}
|
||||
|
||||
#define RUN_WITH_LOCALE(mask, loc) \
|
||||
for (_cleanup_(_reset_locale_) struct _locale_struct_ _saved_locale_ = { (locale_t) 0, (locale_t) 0, false }; \
|
||||
({ \
|
||||
if (!_saved_locale_.quit) { \
|
||||
PROTECT_ERRNO; \
|
||||
_saved_locale_.new_locale = newlocale((mask), (loc), (locale_t) 0); \
|
||||
if (_saved_locale_.new_locale != (locale_t) 0) \
|
||||
_saved_locale_.saved_locale = uselocale(_saved_locale_.new_locale); \
|
||||
} \
|
||||
!_saved_locale_.quit; }) ; \
|
||||
_saved_locale_.quit = true)
|
||||
|
||||
bool id128_is_valid(const char *s) _pure_;
|
||||
|
||||
int split_pair(const char *s, const char *sep, char **l, char **r);
|
||||
|
|
@ -975,6 +970,7 @@ static inline void qsort_safe(void *base, size_t nmemb, size_t size,
|
|||
|
||||
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);
|
||||
|
||||
|
|
@ -1001,8 +997,6 @@ const char *personality_to_string(unsigned long);
|
|||
|
||||
uint64_t physical_memory(void);
|
||||
|
||||
char* mount_test_option(const char *haystack, const char *needle);
|
||||
|
||||
void hexdump(FILE *f, const void *p, size_t s);
|
||||
|
||||
#if 0 /* NM_IGNORED */
|
||||
|
|
@ -1010,6 +1004,7 @@ 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);
|
||||
|
|
@ -1020,8 +1015,9 @@ int bind_remount_recursive(const char *prefix, bool ro);
|
|||
|
||||
int fflush_and_check(FILE *f);
|
||||
|
||||
char *tempfn_xxxxxx(const char *p);
|
||||
char *tempfn_random(const char *p);
|
||||
int tempfn_xxxxxx(const char *p, char **ret);
|
||||
int tempfn_random(const char *p, char **ret);
|
||||
int tempfn_random_child(const char *p, char **ret);
|
||||
|
||||
bool is_localhost(const char *hostname);
|
||||
|
||||
|
|
@ -1036,3 +1032,61 @@ int unquote_many_words(const char **p, ...) _sentinel_;
|
|||
int free_and_strdup(char **p, const char *s);
|
||||
|
||||
int sethostname_idempotent(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, bool b, unsigned mask);
|
||||
int chattr_path(const char *p, bool b, unsigned mask);
|
||||
|
||||
int read_attr_fd(int fd, unsigned *ret);
|
||||
int read_attr_path(const char *p, unsigned *ret);
|
||||
|
||||
typedef struct LockFile {
|
||||
char *path;
|
||||
int fd;
|
||||
int operation;
|
||||
} LockFile;
|
||||
|
||||
int make_lock_file(const char *p, int operation, LockFile *ret);
|
||||
int make_lock_file_for(const char *p, int operation, LockFile *ret);
|
||||
void release_lock_file(LockFile *f);
|
||||
|
||||
#define _cleanup_release_lock_file_ _cleanup_(release_lock_file)
|
||||
|
||||
#define LOCK_FILE_INIT { .fd = -1, .path = NULL }
|
||||
|
||||
#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);
|
||||
|
|
|
|||
|
|
@ -35,6 +35,7 @@ enum {
|
|||
DHCP6_EVENT_RESEND_EXPIRE = 10,
|
||||
DHCP6_EVENT_RETRANS_MAX = 11,
|
||||
DHCP6_EVENT_IP_ACQUIRE = 12,
|
||||
DHCP6_EVENT_INFORMATION_REQUEST = 13,
|
||||
};
|
||||
|
||||
typedef struct sd_dhcp6_client sd_dhcp6_client;
|
||||
|
|
@ -49,7 +50,10 @@ 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_ifname(sd_dhcp6_client *client, const char *ifname);
|
||||
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_request_option(sd_dhcp6_client *client,
|
||||
uint16_t option);
|
||||
|
||||
|
|
|
|||
|
|
@ -29,14 +29,11 @@
|
|||
|
||||
typedef struct sd_dhcp6_lease sd_dhcp6_lease;
|
||||
|
||||
int sd_dhcp6_lease_get_first_address(sd_dhcp6_lease *lease,
|
||||
struct in6_addr *addr,
|
||||
uint32_t *lifetime_preferred,
|
||||
uint32_t *lifetime_valid);
|
||||
int sd_dhcp6_lease_get_next_address(sd_dhcp6_lease *lease,
|
||||
struct in6_addr *addr,
|
||||
uint32_t *lifetime_preferred,
|
||||
uint32_t *lifetime_valid);
|
||||
void sd_dhcp6_lease_reset_address_iter(sd_dhcp6_lease *lease);
|
||||
int sd_dhcp6_lease_get_address(sd_dhcp6_lease *lease,
|
||||
struct in6_addr *addr,
|
||||
uint32_t *lifetime_preferred,
|
||||
uint32_t *lifetime_valid);
|
||||
|
||||
sd_dhcp6_lease *sd_dhcp6_lease_ref(sd_dhcp6_lease *lease);
|
||||
sd_dhcp6_lease *sd_dhcp6_lease_unref(sd_dhcp6_lease *lease);
|
||||
|
|
|
|||
|
|
@ -62,7 +62,7 @@ int sd_id128_get_boot(sd_id128_t *ret);
|
|||
|
||||
/* Note that SD_ID128_FORMAT_VAL will evaluate the passed argument 16
|
||||
* times. It is hence not a good idea to call this macro with an
|
||||
* expensive function as paramater or an expression with side
|
||||
* expensive function as parameter or an expression with side
|
||||
* effects */
|
||||
|
||||
#define SD_ID128_FORMAT_STR "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x"
|
||||
|
|
@ -108,6 +108,10 @@ _sd_pure_ static inline int sd_id128_equal(sd_id128_t a, sd_id128_t b) {
|
|||
return memcmp(&a, &b, 16) == 0;
|
||||
}
|
||||
|
||||
_sd_pure_ static inline int sd_id128_is_null(sd_id128_t a) {
|
||||
return a.qwords[0] == 0 && a.qwords[1] == 0;
|
||||
}
|
||||
|
||||
#define SD_ID128_NULL ((const sd_id128_t) { .qwords = { 0, 0 }})
|
||||
|
||||
_SD_END_DECLARATIONS;
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue