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:
Martin Pitt 2015-05-19 07:49:56 +02:00 committed by Lennart Poettering
parent e861098bf2
commit 139e533628
6 changed files with 90 additions and 29 deletions

View File

@ -57,11 +57,12 @@
name of the local system that is set during boot using the
<citerefentry><refentrytitle>sethostname</refentrytitle><manvolnum>2</manvolnum></citerefentry>
system call. It should contain a single newline-terminated
hostname string. The hostname may be a free-form string up to 64
characters in length; however, it is recommended that it consists
only of 7-bit ASCII lower-case characters and no spaces or dots,
and limits itself to the format allowed for DNS domain name
labels, even though this is not a strict requirement.</para>
hostname string. Comments (lines starting with a `#') are ignored.
The hostname may be a free-form string up to 64 characters in length;
however, it is recommended that it consists only of 7-bit ASCII lower-case
characters and no spaces or dots, and limits itself to the format allowed
for DNS domain name labels, even though this is not a strict
requirement.</para>
<para>Depending on the operating system, other configuration files
might be checked for configuration of the hostname as well,

View File

@ -30,35 +30,13 @@
#include "hostname-util.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 r;
_cleanup_free_ char *b = NULL;
const char *hn;
bool enoent = false;
r = read_and_strip_hostname("/etc/hostname", &b);
r = read_hostname_config("/etc/hostname", &b);
if (r < 0) {
if (r == -ENOENT)
enoent = true;

View File

@ -96,7 +96,7 @@ static int context_read_data(Context *c) {
if (!c->data[PROP_HOSTNAME])
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)
return r;

View File

@ -158,3 +158,36 @@ int sethostname_idempotent(const char *s) {
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;
}

View File

@ -35,3 +35,5 @@ char* hostname_cleanup(char *s, bool lowercase);
bool is_localhost(const char *hostname);
int sethostname_idempotent(const char *s);
int read_hostname_config(const char *path, char **hostname);

View File

@ -549,6 +549,52 @@ static void test_hostname_is_valid(void) {
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) {
assert_se(u64log2(0) == 0);
assert_se(u64log2(8) == 3);
@ -1481,6 +1527,7 @@ int main(int argc, char *argv[]) {
test_foreach_word_quoted();
test_memdup_multiply();
test_hostname_is_valid();
test_read_hostname_config();
test_u64log2();
test_protect_errno();
test_parse_size();