hostname: Allow comments in /etc/hostname
The hostname(1) tool allows comments in /etc/hostname. Introduce a new read_hostname_config() in hostname-util which reads a hostname configuration file like /etc/hostname, strips out comments, whitespace, and cleans the hostname. Use it in hostname-setup.c and hostnamed and remove duplicated code. Update hostname manpage. Add tests. https://launchpad.net/bugs/1053048
This commit is contained in:
parent
e861098bf2
commit
139e533628
|
@ -57,11 +57,12 @@
|
||||||
name of the local system that is set during boot using the
|
name of the local system that is set during boot using the
|
||||||
<citerefentry><refentrytitle>sethostname</refentrytitle><manvolnum>2</manvolnum></citerefentry>
|
<citerefentry><refentrytitle>sethostname</refentrytitle><manvolnum>2</manvolnum></citerefentry>
|
||||||
system call. It should contain a single newline-terminated
|
system call. It should contain a single newline-terminated
|
||||||
hostname string. The hostname may be a free-form string up to 64
|
hostname string. Comments (lines starting with a `#') are ignored.
|
||||||
characters in length; however, it is recommended that it consists
|
The hostname may be a free-form string up to 64 characters in length;
|
||||||
only of 7-bit ASCII lower-case characters and no spaces or dots,
|
however, it is recommended that it consists only of 7-bit ASCII lower-case
|
||||||
and limits itself to the format allowed for DNS domain name
|
characters and no spaces or dots, and limits itself to the format allowed
|
||||||
labels, even though this is not a strict requirement.</para>
|
for DNS domain name labels, even though this is not a strict
|
||||||
|
requirement.</para>
|
||||||
|
|
||||||
<para>Depending on the operating system, other configuration files
|
<para>Depending on the operating system, other configuration files
|
||||||
might be checked for configuration of the hostname as well,
|
might be checked for configuration of the hostname as well,
|
||||||
|
|
|
@ -30,35 +30,13 @@
|
||||||
#include "hostname-util.h"
|
#include "hostname-util.h"
|
||||||
#include "hostname-setup.h"
|
#include "hostname-setup.h"
|
||||||
|
|
||||||
static int read_and_strip_hostname(const char *path, char **hn) {
|
|
||||||
char *s;
|
|
||||||
int r;
|
|
||||||
|
|
||||||
assert(path);
|
|
||||||
assert(hn);
|
|
||||||
|
|
||||||
r = read_one_line_file(path, &s);
|
|
||||||
if (r < 0)
|
|
||||||
return r;
|
|
||||||
|
|
||||||
hostname_cleanup(s, false);
|
|
||||||
|
|
||||||
if (isempty(s)) {
|
|
||||||
free(s);
|
|
||||||
return -ENOENT;
|
|
||||||
}
|
|
||||||
|
|
||||||
*hn = s;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int hostname_setup(void) {
|
int hostname_setup(void) {
|
||||||
int r;
|
int r;
|
||||||
_cleanup_free_ char *b = NULL;
|
_cleanup_free_ char *b = NULL;
|
||||||
const char *hn;
|
const char *hn;
|
||||||
bool enoent = false;
|
bool enoent = false;
|
||||||
|
|
||||||
r = read_and_strip_hostname("/etc/hostname", &b);
|
r = read_hostname_config("/etc/hostname", &b);
|
||||||
if (r < 0) {
|
if (r < 0) {
|
||||||
if (r == -ENOENT)
|
if (r == -ENOENT)
|
||||||
enoent = true;
|
enoent = true;
|
||||||
|
|
|
@ -96,7 +96,7 @@ static int context_read_data(Context *c) {
|
||||||
if (!c->data[PROP_HOSTNAME])
|
if (!c->data[PROP_HOSTNAME])
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
r = read_one_line_file("/etc/hostname", &c->data[PROP_STATIC_HOSTNAME]);
|
r = read_hostname_config("/etc/hostname", &c->data[PROP_STATIC_HOSTNAME]);
|
||||||
if (r < 0 && r != -ENOENT)
|
if (r < 0 && r != -ENOENT)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
|
|
|
@ -158,3 +158,36 @@ int sethostname_idempotent(const char *s) {
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int read_hostname_config(const char *path, char **hostname) {
|
||||||
|
_cleanup_fclose_ FILE *f = NULL;
|
||||||
|
char l[LINE_MAX];
|
||||||
|
char *name = NULL;
|
||||||
|
|
||||||
|
assert(path);
|
||||||
|
assert(hostname);
|
||||||
|
|
||||||
|
f = fopen(path, "re");
|
||||||
|
if (!f)
|
||||||
|
return -errno;
|
||||||
|
|
||||||
|
/* may have comments, ignore them */
|
||||||
|
FOREACH_LINE(l, f, return -errno) {
|
||||||
|
truncate_nl(l);
|
||||||
|
if (l[0] != '\0' && l[0] != '#') {
|
||||||
|
/* found line with value */
|
||||||
|
name = hostname_cleanup(l, false);
|
||||||
|
name = strdup(name);
|
||||||
|
if (!name)
|
||||||
|
return -ENOMEM;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!name)
|
||||||
|
/* no non-empty line found */
|
||||||
|
return -ENOENT;
|
||||||
|
|
||||||
|
*hostname = name;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
|
@ -35,3 +35,5 @@ char* hostname_cleanup(char *s, bool lowercase);
|
||||||
bool is_localhost(const char *hostname);
|
bool is_localhost(const char *hostname);
|
||||||
|
|
||||||
int sethostname_idempotent(const char *s);
|
int sethostname_idempotent(const char *s);
|
||||||
|
|
||||||
|
int read_hostname_config(const char *path, char **hostname);
|
||||||
|
|
|
@ -549,6 +549,52 @@ static void test_hostname_is_valid(void) {
|
||||||
assert_se(!hostname_is_valid("xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"));
|
assert_se(!hostname_is_valid("xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void test_read_hostname_config(void) {
|
||||||
|
char path[] = "/tmp/hostname.XXXXXX";
|
||||||
|
char *hostname;
|
||||||
|
int fd;
|
||||||
|
|
||||||
|
fd = mkostemp_safe(path, O_RDWR|O_CLOEXEC);
|
||||||
|
assert(fd > 0);
|
||||||
|
close(fd);
|
||||||
|
|
||||||
|
/* simple hostname */
|
||||||
|
write_string_file(path, "foo");
|
||||||
|
assert_se(read_hostname_config(path, &hostname) == 0);
|
||||||
|
assert_se(streq(hostname, "foo"));
|
||||||
|
free(hostname);
|
||||||
|
|
||||||
|
/* with comment */
|
||||||
|
write_string_file(path, "# comment\nfoo");
|
||||||
|
assert_se(read_hostname_config(path, &hostname) == 0);
|
||||||
|
assert_se(streq(hostname, "foo"));
|
||||||
|
free(hostname);
|
||||||
|
|
||||||
|
/* with comment and extra whitespace */
|
||||||
|
write_string_file(path, "# comment\n\n foo ");
|
||||||
|
assert_se(read_hostname_config(path, &hostname) == 0);
|
||||||
|
assert_se(streq(hostname, "foo"));
|
||||||
|
free(hostname);
|
||||||
|
|
||||||
|
/* cleans up name */
|
||||||
|
write_string_file(path, "!foo/bar.com");
|
||||||
|
assert_se(read_hostname_config(path, &hostname) == 0);
|
||||||
|
assert_se(streq(hostname, "foobar.com"));
|
||||||
|
free(hostname);
|
||||||
|
|
||||||
|
/* no value set */
|
||||||
|
hostname = (char*) 0x1234;
|
||||||
|
write_string_file(path, "# nothing here\n");
|
||||||
|
assert_se(read_hostname_config(path, &hostname) == -ENOENT);
|
||||||
|
assert_se(hostname == (char*) 0x1234); /* does not touch argument on error */
|
||||||
|
|
||||||
|
/* nonexisting file */
|
||||||
|
assert_se(read_hostname_config("/non/existing", &hostname) == -ENOENT);
|
||||||
|
assert_se(hostname == (char*) 0x1234); /* does not touch argument on error */
|
||||||
|
|
||||||
|
unlink(path);
|
||||||
|
}
|
||||||
|
|
||||||
static void test_u64log2(void) {
|
static void test_u64log2(void) {
|
||||||
assert_se(u64log2(0) == 0);
|
assert_se(u64log2(0) == 0);
|
||||||
assert_se(u64log2(8) == 3);
|
assert_se(u64log2(8) == 3);
|
||||||
|
@ -1481,6 +1527,7 @@ int main(int argc, char *argv[]) {
|
||||||
test_foreach_word_quoted();
|
test_foreach_word_quoted();
|
||||||
test_memdup_multiply();
|
test_memdup_multiply();
|
||||||
test_hostname_is_valid();
|
test_hostname_is_valid();
|
||||||
|
test_read_hostname_config();
|
||||||
test_u64log2();
|
test_u64log2();
|
||||||
test_protect_errno();
|
test_protect_errno();
|
||||||
test_parse_size();
|
test_parse_size();
|
||||||
|
|
Loading…
Reference in New Issue