
This is a direct dump from systemd git. ====== SYSTEMD_DIR=../systemd COMMIT=25f9288e31a586460c13d49edea9edafdca2a972 ( cd "$SYSTEMD_DIR" git checkout "$COMMIT" git reset --hard git clean -fdx ) git ls-files -z :/src/systemd/src/ \ :/shared/systemd/src/ \ :/shared/nm-utils/unaligned.h | \ xargs -0 rm -f nm_copy_sd_shared() { mkdir -p "./shared/systemd/$(dirname "$1")" cp "$SYSTEMD_DIR/$1" "./shared/systemd/$1" } nm_copy_sd_core() { mkdir -p "./src/systemd/$(dirname "$1")" cp "$SYSTEMD_DIR/$1" "./src/systemd/$1" } nm_copy_sd_nmutils() { mkdir -p "./shared/nm-utils/" cp "$SYSTEMD_DIR/$1" "./shared/nm-utils/${1##*/}" } nm_copy_sd_core "src/libsystemd-network/arp-util.c" nm_copy_sd_core "src/libsystemd-network/arp-util.h" nm_copy_sd_core "src/libsystemd-network/dhcp-identifier.c" nm_copy_sd_core "src/libsystemd-network/dhcp-identifier.h" nm_copy_sd_core "src/libsystemd-network/dhcp-internal.h" nm_copy_sd_core "src/libsystemd-network/dhcp-lease-internal.h" nm_copy_sd_core "src/libsystemd-network/dhcp-network.c" nm_copy_sd_core "src/libsystemd-network/dhcp-option.c" nm_copy_sd_core "src/libsystemd-network/dhcp-packet.c" nm_copy_sd_core "src/libsystemd-network/dhcp-protocol.h" nm_copy_sd_core "src/libsystemd-network/dhcp6-internal.h" nm_copy_sd_core "src/libsystemd-network/dhcp6-lease-internal.h" nm_copy_sd_core "src/libsystemd-network/dhcp6-network.c" nm_copy_sd_core "src/libsystemd-network/dhcp6-option.c" nm_copy_sd_core "src/libsystemd-network/dhcp6-protocol.h" nm_copy_sd_core "src/libsystemd-network/lldp-internal.h" nm_copy_sd_core "src/libsystemd-network/lldp-neighbor.c" nm_copy_sd_core "src/libsystemd-network/lldp-neighbor.h" nm_copy_sd_core "src/libsystemd-network/lldp-network.c" nm_copy_sd_core "src/libsystemd-network/lldp-network.h" nm_copy_sd_core "src/libsystemd-network/network-internal.c" nm_copy_sd_core "src/libsystemd-network/network-internal.h" nm_copy_sd_core "src/libsystemd-network/sd-dhcp-client.c" nm_copy_sd_core "src/libsystemd-network/sd-dhcp-lease.c" nm_copy_sd_core "src/libsystemd-network/sd-dhcp6-client.c" nm_copy_sd_core "src/libsystemd-network/sd-dhcp6-lease.c" nm_copy_sd_core "src/libsystemd-network/sd-ipv4acd.c" nm_copy_sd_core "src/libsystemd-network/sd-ipv4ll.c" nm_copy_sd_core "src/libsystemd-network/sd-lldp.c" nm_copy_sd_core "src/libsystemd/sd-event/event-source.h" nm_copy_sd_core "src/libsystemd/sd-event/event-util.c" nm_copy_sd_core "src/libsystemd/sd-event/event-util.h" nm_copy_sd_core "src/libsystemd/sd-event/sd-event.c" nm_copy_sd_core "src/libsystemd/sd-id128/id128-util.c" nm_copy_sd_core "src/libsystemd/sd-id128/id128-util.h" nm_copy_sd_core "src/libsystemd/sd-id128/sd-id128.c" nm_copy_sd_core "src/systemd/_sd-common.h" nm_copy_sd_core "src/systemd/sd-dhcp-client.h" nm_copy_sd_core "src/systemd/sd-dhcp-lease.h" nm_copy_sd_core "src/systemd/sd-dhcp-option.h" nm_copy_sd_core "src/systemd/sd-dhcp6-client.h" nm_copy_sd_core "src/systemd/sd-dhcp6-lease.h" nm_copy_sd_core "src/systemd/sd-event.h" nm_copy_sd_core "src/systemd/sd-id128.h" nm_copy_sd_core "src/systemd/sd-ipv4acd.h" nm_copy_sd_core "src/systemd/sd-ipv4ll.h" nm_copy_sd_core "src/systemd/sd-lldp.h" nm_copy_sd_core "src/systemd/sd-ndisc.h" nm_copy_sd_nmutils "src/basic/unaligned.h" nm_copy_sd_shared "src/basic/alloc-util.c" nm_copy_sd_shared "src/basic/alloc-util.h" nm_copy_sd_shared "src/basic/async.h" nm_copy_sd_shared "src/basic/env-file.c" nm_copy_sd_shared "src/basic/env-file.h" nm_copy_sd_shared "src/basic/env-util.c" nm_copy_sd_shared "src/basic/env-util.h" nm_copy_sd_shared "src/basic/errno-util.h" nm_copy_sd_shared "src/basic/escape.c" nm_copy_sd_shared "src/basic/escape.h" nm_copy_sd_shared "src/basic/ether-addr-util.c" nm_copy_sd_shared "src/basic/ether-addr-util.h" nm_copy_sd_shared "src/basic/extract-word.c" nm_copy_sd_shared "src/basic/extract-word.h" nm_copy_sd_shared "src/basic/fd-util.c" nm_copy_sd_shared "src/basic/fd-util.h" nm_copy_sd_shared "src/basic/fileio.c" nm_copy_sd_shared "src/basic/fileio.h" nm_copy_sd_shared "src/basic/format-util.c" nm_copy_sd_shared "src/basic/format-util.h" nm_copy_sd_shared "src/basic/fs-util.c" nm_copy_sd_shared "src/basic/fs-util.h" nm_copy_sd_shared "src/basic/hash-funcs.c" nm_copy_sd_shared "src/basic/hash-funcs.h" nm_copy_sd_shared "src/basic/hashmap.c" nm_copy_sd_shared "src/basic/hashmap.h" nm_copy_sd_shared "src/basic/hexdecoct.c" nm_copy_sd_shared "src/basic/hexdecoct.h" nm_copy_sd_shared "src/basic/hostname-util.c" nm_copy_sd_shared "src/basic/hostname-util.h" nm_copy_sd_shared "src/basic/in-addr-util.c" nm_copy_sd_shared "src/basic/in-addr-util.h" nm_copy_sd_shared "src/basic/io-util.c" nm_copy_sd_shared "src/basic/io-util.h" nm_copy_sd_shared "src/basic/list.h" nm_copy_sd_shared "src/basic/log.h" nm_copy_sd_shared "src/basic/macro.h" nm_copy_sd_shared "src/basic/memory-util.c" nm_copy_sd_shared "src/basic/memory-util.h" nm_copy_sd_shared "src/basic/mempool.c" nm_copy_sd_shared "src/basic/mempool.h" nm_copy_sd_shared "src/basic/missing_fcntl.h" nm_copy_sd_shared "src/basic/missing_random.h" nm_copy_sd_shared "src/basic/missing_socket.h" nm_copy_sd_shared "src/basic/missing_stat.h" nm_copy_sd_shared "src/basic/missing_type.h" nm_copy_sd_shared "src/basic/parse-util.c" nm_copy_sd_shared "src/basic/parse-util.h" nm_copy_sd_shared "src/basic/path-util.c" nm_copy_sd_shared "src/basic/path-util.h" nm_copy_sd_shared "src/basic/prioq.c" nm_copy_sd_shared "src/basic/prioq.h" nm_copy_sd_shared "src/basic/process-util.c" nm_copy_sd_shared "src/basic/process-util.h" nm_copy_sd_shared "src/basic/random-util.c" nm_copy_sd_shared "src/basic/random-util.h" nm_copy_sd_shared "src/basic/set.h" nm_copy_sd_shared "src/basic/signal-util.h" nm_copy_sd_shared "src/basic/siphash24.h" nm_copy_sd_shared "src/basic/socket-util.c" nm_copy_sd_shared "src/basic/socket-util.h" nm_copy_sd_shared "src/basic/sort-util.h" nm_copy_sd_shared "src/basic/sparse-endian.h" nm_copy_sd_shared "src/basic/stat-util.c" nm_copy_sd_shared "src/basic/stat-util.h" nm_copy_sd_shared "src/basic/stdio-util.h" nm_copy_sd_shared "src/basic/string-table.c" nm_copy_sd_shared "src/basic/string-table.h" nm_copy_sd_shared "src/basic/string-util.c" nm_copy_sd_shared "src/basic/string-util.h" nm_copy_sd_shared "src/basic/strv.c" nm_copy_sd_shared "src/basic/strv.h" nm_copy_sd_shared "src/basic/strxcpyx.c" nm_copy_sd_shared "src/basic/strxcpyx.h" nm_copy_sd_shared "src/basic/time-util.c" nm_copy_sd_shared "src/basic/time-util.h" nm_copy_sd_shared "src/basic/tmpfile-util.c" nm_copy_sd_shared "src/basic/tmpfile-util.h" nm_copy_sd_shared "src/basic/umask-util.h" nm_copy_sd_shared "src/basic/utf8.c" nm_copy_sd_shared "src/basic/utf8.h" nm_copy_sd_shared "src/basic/util.c" nm_copy_sd_shared "src/basic/util.h" nm_copy_sd_shared "src/shared/dns-domain.c" nm_copy_sd_shared "src/shared/dns-domain.h"
308 lines
8.2 KiB
C
308 lines
8.2 KiB
C
/* SPDX-License-Identifier: LGPL-2.1+ */
|
|
|
|
#include <errno.h>
|
|
#include <limits.h>
|
|
#include <stdio.h>
|
|
#include <sys/utsname.h>
|
|
#include <unistd.h>
|
|
|
|
#include "alloc-util.h"
|
|
#include "fd-util.h"
|
|
#include "fileio.h"
|
|
#include "hostname-util.h"
|
|
#include "macro.h"
|
|
#include "string-util.h"
|
|
|
|
bool hostname_is_set(void) {
|
|
struct utsname u;
|
|
|
|
assert_se(uname(&u) >= 0);
|
|
|
|
if (isempty(u.nodename))
|
|
return false;
|
|
|
|
/* This is the built-in kernel default host name */
|
|
if (streq(u.nodename, "(none)"))
|
|
return false;
|
|
|
|
return true;
|
|
}
|
|
|
|
char* gethostname_malloc(void) {
|
|
struct utsname u;
|
|
|
|
/* This call tries to return something useful, either the actual hostname
|
|
* or it makes something up. The only reason it might fail is OOM.
|
|
* It might even return "localhost" if that's set. */
|
|
|
|
assert_se(uname(&u) >= 0);
|
|
|
|
if (isempty(u.nodename) || streq(u.nodename, "(none)"))
|
|
return strdup(FALLBACK_HOSTNAME);
|
|
|
|
return strdup(u.nodename);
|
|
}
|
|
|
|
int gethostname_strict(char **ret) {
|
|
struct utsname u;
|
|
char *k;
|
|
|
|
/* This call will rather fail than make up a name. It will not return "localhost" either. */
|
|
|
|
assert_se(uname(&u) >= 0);
|
|
|
|
if (isempty(u.nodename))
|
|
return -ENXIO;
|
|
|
|
if (streq(u.nodename, "(none)"))
|
|
return -ENXIO;
|
|
|
|
if (is_localhost(u.nodename))
|
|
return -ENXIO;
|
|
|
|
k = strdup(u.nodename);
|
|
if (!k)
|
|
return -ENOMEM;
|
|
|
|
*ret = k;
|
|
return 0;
|
|
}
|
|
|
|
bool valid_ldh_char(char c) {
|
|
return
|
|
(c >= 'a' && c <= 'z') ||
|
|
(c >= 'A' && c <= 'Z') ||
|
|
(c >= '0' && c <= '9') ||
|
|
c == '-';
|
|
}
|
|
|
|
/**
|
|
* Check if s looks like a valid host name or FQDN. This does not do
|
|
* full DNS validation, but only checks if the name is composed of
|
|
* allowed characters and the length is not above the maximum allowed
|
|
* by Linux (c.f. dns_name_is_valid()). Trailing dot is allowed if
|
|
* allow_trailing_dot is true and at least two components are present
|
|
* in the name. Note that due to the restricted charset and length
|
|
* this call is substantially more conservative than
|
|
* dns_name_is_valid().
|
|
*/
|
|
bool hostname_is_valid(const char *s, bool allow_trailing_dot) {
|
|
unsigned n_dots = 0;
|
|
const char *p;
|
|
bool dot, hyphen;
|
|
|
|
if (isempty(s))
|
|
return false;
|
|
|
|
/* Doesn't accept empty hostnames, hostnames with
|
|
* leading dots, and hostnames with multiple dots in a
|
|
* sequence. Also ensures that the length stays below
|
|
* HOST_NAME_MAX. */
|
|
|
|
for (p = s, dot = hyphen = true; *p; p++)
|
|
if (*p == '.') {
|
|
if (dot || hyphen)
|
|
return false;
|
|
|
|
dot = true;
|
|
hyphen = false;
|
|
n_dots++;
|
|
|
|
} else if (*p == '-') {
|
|
if (dot)
|
|
return false;
|
|
|
|
dot = false;
|
|
hyphen = true;
|
|
|
|
} else {
|
|
if (!valid_ldh_char(*p))
|
|
return false;
|
|
|
|
dot = false;
|
|
hyphen = false;
|
|
}
|
|
|
|
if (dot && (n_dots < 2 || !allow_trailing_dot))
|
|
return false;
|
|
if (hyphen)
|
|
return false;
|
|
|
|
if (p-s > HOST_NAME_MAX) /* Note that HOST_NAME_MAX is 64 on
|
|
* Linux, but DNS allows domain names
|
|
* up to 255 characters */
|
|
return false;
|
|
|
|
return true;
|
|
}
|
|
|
|
char* hostname_cleanup(char *s) {
|
|
char *p, *d;
|
|
bool dot, hyphen;
|
|
|
|
assert(s);
|
|
|
|
for (p = s, d = s, dot = hyphen = true; *p && d - s < HOST_NAME_MAX; p++)
|
|
if (*p == '.') {
|
|
if (dot || hyphen)
|
|
continue;
|
|
|
|
*(d++) = '.';
|
|
dot = true;
|
|
hyphen = false;
|
|
|
|
} else if (*p == '-') {
|
|
if (dot)
|
|
continue;
|
|
|
|
*(d++) = '-';
|
|
dot = false;
|
|
hyphen = true;
|
|
|
|
} else if (valid_ldh_char(*p)) {
|
|
*(d++) = *p;
|
|
dot = false;
|
|
hyphen = false;
|
|
}
|
|
|
|
if (d > s && IN_SET(d[-1], '-', '.'))
|
|
/* The dot can occur at most once, but we might have multiple
|
|
* hyphens, hence the loop */
|
|
d--;
|
|
*d = 0;
|
|
|
|
return s;
|
|
}
|
|
|
|
bool is_localhost(const char *hostname) {
|
|
assert(hostname);
|
|
|
|
/* This tries to identify local host and domain names
|
|
* described in RFC6761 plus the redhatism of localdomain */
|
|
|
|
return strcaseeq(hostname, "localhost") ||
|
|
strcaseeq(hostname, "localhost.") ||
|
|
strcaseeq(hostname, "localhost.localdomain") ||
|
|
strcaseeq(hostname, "localhost.localdomain.") ||
|
|
endswith_no_case(hostname, ".localhost") ||
|
|
endswith_no_case(hostname, ".localhost.") ||
|
|
endswith_no_case(hostname, ".localhost.localdomain") ||
|
|
endswith_no_case(hostname, ".localhost.localdomain.");
|
|
}
|
|
|
|
bool is_gateway_hostname(const char *hostname) {
|
|
assert(hostname);
|
|
|
|
/* This tries to identify the valid syntaxes for the our
|
|
* synthetic "gateway" host. */
|
|
|
|
return
|
|
strcaseeq(hostname, "_gateway") || strcaseeq(hostname, "_gateway.")
|
|
#if ENABLE_COMPAT_GATEWAY_HOSTNAME
|
|
|| strcaseeq(hostname, "gateway") || strcaseeq(hostname, "gateway.")
|
|
#endif
|
|
;
|
|
}
|
|
|
|
int sethostname_idempotent(const char *s) {
|
|
char buf[HOST_NAME_MAX + 1] = {};
|
|
|
|
assert(s);
|
|
|
|
if (gethostname(buf, sizeof(buf)) < 0)
|
|
return -errno;
|
|
|
|
if (streq(buf, s))
|
|
return 0;
|
|
|
|
if (sethostname(s, strlen(s)) < 0)
|
|
return -errno;
|
|
|
|
return 1;
|
|
}
|
|
|
|
int shorten_overlong(const char *s, char **ret) {
|
|
char *h, *p;
|
|
|
|
/* Shorten an overlong name to HOST_NAME_MAX or to the first dot,
|
|
* whatever comes earlier. */
|
|
|
|
assert(s);
|
|
|
|
h = strdup(s);
|
|
if (!h)
|
|
return -ENOMEM;
|
|
|
|
if (hostname_is_valid(h, false)) {
|
|
*ret = h;
|
|
return 0;
|
|
}
|
|
|
|
p = strchr(h, '.');
|
|
if (p)
|
|
*p = 0;
|
|
|
|
strshorten(h, HOST_NAME_MAX);
|
|
|
|
if (!hostname_is_valid(h, false)) {
|
|
free(h);
|
|
return -EDOM;
|
|
}
|
|
|
|
*ret = h;
|
|
return 1;
|
|
}
|
|
|
|
int read_etc_hostname_stream(FILE *f, char **ret) {
|
|
int r;
|
|
|
|
assert(f);
|
|
assert(ret);
|
|
|
|
for (;;) {
|
|
_cleanup_free_ char *line = NULL;
|
|
char *p;
|
|
|
|
r = read_line(f, LONG_LINE_MAX, &line);
|
|
if (r < 0)
|
|
return r;
|
|
if (r == 0) /* EOF without any hostname? the file is empty, let's treat that exactly like no file at all: ENOENT */
|
|
return -ENOENT;
|
|
|
|
p = strstrip(line);
|
|
|
|
/* File may have empty lines or comments, ignore them */
|
|
if (!IN_SET(*p, '\0', '#')) {
|
|
char *copy;
|
|
|
|
hostname_cleanup(p); /* normalize the hostname */
|
|
|
|
if (!hostname_is_valid(p, true)) /* check that the hostname we return is valid */
|
|
return -EBADMSG;
|
|
|
|
copy = strdup(p);
|
|
if (!copy)
|
|
return -ENOMEM;
|
|
|
|
*ret = copy;
|
|
return 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
int read_etc_hostname(const char *path, char **ret) {
|
|
_cleanup_fclose_ FILE *f = NULL;
|
|
|
|
assert(ret);
|
|
|
|
if (!path)
|
|
path = "/etc/hostname";
|
|
|
|
f = fopen(path, "re");
|
|
if (!f)
|
|
return -errno;
|
|
|
|
return read_etc_hostname_stream(f, ret);
|
|
|
|
}
|