hostnamed.c revision 9bcbce4201afada1c0ad8ada0cbfbbf58a52a6a7
641d1f99b8c4c5427a1fedcb4740586a130ac6cfRonny Chevalier/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
641d1f99b8c4c5427a1fedcb4740586a130ac6cfRonny Chevalier
641d1f99b8c4c5427a1fedcb4740586a130ac6cfRonny Chevalier/***
641d1f99b8c4c5427a1fedcb4740586a130ac6cfRonny Chevalier This file is part of systemd.
641d1f99b8c4c5427a1fedcb4740586a130ac6cfRonny Chevalier
641d1f99b8c4c5427a1fedcb4740586a130ac6cfRonny Chevalier Copyright 2011 Lennart Poettering
641d1f99b8c4c5427a1fedcb4740586a130ac6cfRonny Chevalier
641d1f99b8c4c5427a1fedcb4740586a130ac6cfRonny Chevalier systemd is free software; you can redistribute it and/or modify it
641d1f99b8c4c5427a1fedcb4740586a130ac6cfRonny Chevalier under the terms of the GNU Lesser General Public License as published by
641d1f99b8c4c5427a1fedcb4740586a130ac6cfRonny Chevalier the Free Software Foundation; either version 2.1 of the License, or
641d1f99b8c4c5427a1fedcb4740586a130ac6cfRonny Chevalier (at your option) any later version.
641d1f99b8c4c5427a1fedcb4740586a130ac6cfRonny Chevalier
641d1f99b8c4c5427a1fedcb4740586a130ac6cfRonny Chevalier systemd is distributed in the hope that it will be useful, but
641d1f99b8c4c5427a1fedcb4740586a130ac6cfRonny Chevalier WITHOUT ANY WARRANTY; without even the implied warranty of
641d1f99b8c4c5427a1fedcb4740586a130ac6cfRonny Chevalier MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
641d1f99b8c4c5427a1fedcb4740586a130ac6cfRonny Chevalier Lesser General Public License for more details.
641d1f99b8c4c5427a1fedcb4740586a130ac6cfRonny Chevalier
641d1f99b8c4c5427a1fedcb4740586a130ac6cfRonny Chevalier You should have received a copy of the GNU Lesser General Public License
641d1f99b8c4c5427a1fedcb4740586a130ac6cfRonny Chevalier along with systemd; If not, see <http://www.gnu.org/licenses/>.
641d1f99b8c4c5427a1fedcb4740586a130ac6cfRonny Chevalier***/
641d1f99b8c4c5427a1fedcb4740586a130ac6cfRonny Chevalier
641d1f99b8c4c5427a1fedcb4740586a130ac6cfRonny Chevalier#include <errno.h>
641d1f99b8c4c5427a1fedcb4740586a130ac6cfRonny Chevalier#include <string.h>
07630cea1f3a845c09309f197ac7c4f11edd3b62Lennart Poettering#include <unistd.h>
641d1f99b8c4c5427a1fedcb4740586a130ac6cfRonny Chevalier#include <dlfcn.h>
07630cea1f3a845c09309f197ac7c4f11edd3b62Lennart Poettering
07630cea1f3a845c09309f197ac7c4f11edd3b62Lennart Poettering#include "util.h"
07630cea1f3a845c09309f197ac7c4f11edd3b62Lennart Poettering#include "strv.h"
641d1f99b8c4c5427a1fedcb4740586a130ac6cfRonny Chevalier#include "def.h"
641d1f99b8c4c5427a1fedcb4740586a130ac6cfRonny Chevalier#include "virt.h"
641d1f99b8c4c5427a1fedcb4740586a130ac6cfRonny Chevalier#include "env-util.h"
641d1f99b8c4c5427a1fedcb4740586a130ac6cfRonny Chevalier#include "fileio-label.h"
641d1f99b8c4c5427a1fedcb4740586a130ac6cfRonny Chevalier#include "label.h"
641d1f99b8c4c5427a1fedcb4740586a130ac6cfRonny Chevalier#include "bus-util.h"
641d1f99b8c4c5427a1fedcb4740586a130ac6cfRonny Chevalier#include "event-util.h"
641d1f99b8c4c5427a1fedcb4740586a130ac6cfRonny Chevalier
641d1f99b8c4c5427a1fedcb4740586a130ac6cfRonny Chevalierenum {
641d1f99b8c4c5427a1fedcb4740586a130ac6cfRonny Chevalier PROP_HOSTNAME,
641d1f99b8c4c5427a1fedcb4740586a130ac6cfRonny Chevalier PROP_STATIC_HOSTNAME,
641d1f99b8c4c5427a1fedcb4740586a130ac6cfRonny Chevalier PROP_PRETTY_HOSTNAME,
641d1f99b8c4c5427a1fedcb4740586a130ac6cfRonny Chevalier PROP_ICON_NAME,
641d1f99b8c4c5427a1fedcb4740586a130ac6cfRonny Chevalier PROP_CHASSIS,
641d1f99b8c4c5427a1fedcb4740586a130ac6cfRonny Chevalier _PROP_MAX
641d1f99b8c4c5427a1fedcb4740586a130ac6cfRonny Chevalier};
641d1f99b8c4c5427a1fedcb4740586a130ac6cfRonny Chevalier
641d1f99b8c4c5427a1fedcb4740586a130ac6cfRonny Chevaliertypedef struct Context {
4c1fc3e404d648c70bd2f50ac50aeac6ece8872eDaniel Mack char *data[_PROP_MAX];
641d1f99b8c4c5427a1fedcb4740586a130ac6cfRonny Chevalier Hashmap *polkit_registry;
f2068bcce01db31cdc9422f44185f3b49c04d2ceLennart Poettering} Context;
641d1f99b8c4c5427a1fedcb4740586a130ac6cfRonny Chevalier
641d1f99b8c4c5427a1fedcb4740586a130ac6cfRonny Chevalierstatic void context_reset(Context *c) {
641d1f99b8c4c5427a1fedcb4740586a130ac6cfRonny Chevalier int p;
cda134ab1eac84f874aacf8e885a07112a7fd5ceLennart Poettering
641d1f99b8c4c5427a1fedcb4740586a130ac6cfRonny Chevalier assert(c);
641d1f99b8c4c5427a1fedcb4740586a130ac6cfRonny Chevalier
641d1f99b8c4c5427a1fedcb4740586a130ac6cfRonny Chevalier for (p = 0; p < _PROP_MAX; p++) {
641d1f99b8c4c5427a1fedcb4740586a130ac6cfRonny Chevalier free(c->data[p]);
641d1f99b8c4c5427a1fedcb4740586a130ac6cfRonny Chevalier c->data[p] = NULL;
cda134ab1eac84f874aacf8e885a07112a7fd5ceLennart Poettering }
cda134ab1eac84f874aacf8e885a07112a7fd5ceLennart Poettering}
cda134ab1eac84f874aacf8e885a07112a7fd5ceLennart Poettering
cda134ab1eac84f874aacf8e885a07112a7fd5ceLennart Poetteringstatic void context_free(Context *c, sd_bus *bus) {
cda134ab1eac84f874aacf8e885a07112a7fd5ceLennart Poettering assert(c);
cda134ab1eac84f874aacf8e885a07112a7fd5ceLennart Poettering
cda134ab1eac84f874aacf8e885a07112a7fd5ceLennart Poettering context_reset(c);
cda134ab1eac84f874aacf8e885a07112a7fd5ceLennart Poettering bus_verify_polkit_async_registry_free(bus, c->polkit_registry);
cda134ab1eac84f874aacf8e885a07112a7fd5ceLennart Poettering}
cda134ab1eac84f874aacf8e885a07112a7fd5ceLennart Poettering
cda134ab1eac84f874aacf8e885a07112a7fd5ceLennart Poetteringstatic int context_read_data(Context *c) {
cda134ab1eac84f874aacf8e885a07112a7fd5ceLennart Poettering int r;
4c1fc3e404d648c70bd2f50ac50aeac6ece8872eDaniel Mack
7430ec6ac08f2c0416d9f806964c46b30f3862b2Lennart Poettering assert(c);
7430ec6ac08f2c0416d9f806964c46b30f3862b2Lennart Poettering
cda134ab1eac84f874aacf8e885a07112a7fd5ceLennart Poettering context_reset(c);
cda134ab1eac84f874aacf8e885a07112a7fd5ceLennart Poettering
cda134ab1eac84f874aacf8e885a07112a7fd5ceLennart Poettering c->data[PROP_HOSTNAME] = gethostname_malloc();
cda134ab1eac84f874aacf8e885a07112a7fd5ceLennart Poettering if (!c->data[PROP_HOSTNAME])
cda134ab1eac84f874aacf8e885a07112a7fd5ceLennart Poettering return -ENOMEM;
cda134ab1eac84f874aacf8e885a07112a7fd5ceLennart Poettering
cda134ab1eac84f874aacf8e885a07112a7fd5ceLennart Poettering r = read_one_line_file("/etc/hostname", &c->data[PROP_STATIC_HOSTNAME]);
cda134ab1eac84f874aacf8e885a07112a7fd5ceLennart Poettering if (r < 0 && r != -ENOENT)
cda134ab1eac84f874aacf8e885a07112a7fd5ceLennart Poettering return r;
641d1f99b8c4c5427a1fedcb4740586a130ac6cfRonny Chevalier
641d1f99b8c4c5427a1fedcb4740586a130ac6cfRonny Chevalier r = parse_env_file("/etc/machine-info", NEWLINE,
641d1f99b8c4c5427a1fedcb4740586a130ac6cfRonny Chevalier "PRETTY_HOSTNAME", &c->data[PROP_PRETTY_HOSTNAME],
641d1f99b8c4c5427a1fedcb4740586a130ac6cfRonny Chevalier "ICON_NAME", &c->data[PROP_ICON_NAME],
641d1f99b8c4c5427a1fedcb4740586a130ac6cfRonny Chevalier "CHASSIS", &c->data[PROP_CHASSIS],
641d1f99b8c4c5427a1fedcb4740586a130ac6cfRonny Chevalier NULL);
641d1f99b8c4c5427a1fedcb4740586a130ac6cfRonny Chevalier if (r < 0 && r != -ENOENT)
641d1f99b8c4c5427a1fedcb4740586a130ac6cfRonny Chevalier return r;
c6878637502b1717a110a9a7e8bba32a8583fcdfLennart Poettering
c6878637502b1717a110a9a7e8bba32a8583fcdfLennart Poettering return 0;
641d1f99b8c4c5427a1fedcb4740586a130ac6cfRonny Chevalier}
641d1f99b8c4c5427a1fedcb4740586a130ac6cfRonny Chevalier
63c372cb9df3bee01e3bf8cd7f96f336bddda846Lennart Poetteringstatic bool check_nss(void) {
641d1f99b8c4c5427a1fedcb4740586a130ac6cfRonny Chevalier void *dl;
641d1f99b8c4c5427a1fedcb4740586a130ac6cfRonny Chevalier
4c1fc3e404d648c70bd2f50ac50aeac6ece8872eDaniel Mack dl = dlopen("libnss_myhostname.so.2", RTLD_LAZY);
641d1f99b8c4c5427a1fedcb4740586a130ac6cfRonny Chevalier if (dl) {
641d1f99b8c4c5427a1fedcb4740586a130ac6cfRonny Chevalier dlclose(dl);
641d1f99b8c4c5427a1fedcb4740586a130ac6cfRonny Chevalier return true;
63c372cb9df3bee01e3bf8cd7f96f336bddda846Lennart Poettering }
63c372cb9df3bee01e3bf8cd7f96f336bddda846Lennart Poettering
641d1f99b8c4c5427a1fedcb4740586a130ac6cfRonny Chevalier return false;
641d1f99b8c4c5427a1fedcb4740586a130ac6cfRonny Chevalier}
641d1f99b8c4c5427a1fedcb4740586a130ac6cfRonny Chevalier
641d1f99b8c4c5427a1fedcb4740586a130ac6cfRonny Chevalierstatic bool valid_chassis(const char *chassis) {
641d1f99b8c4c5427a1fedcb4740586a130ac6cfRonny Chevalier
641d1f99b8c4c5427a1fedcb4740586a130ac6cfRonny Chevalier assert(chassis);
641d1f99b8c4c5427a1fedcb4740586a130ac6cfRonny Chevalier
641d1f99b8c4c5427a1fedcb4740586a130ac6cfRonny Chevalier return nulstr_contains(
641d1f99b8c4c5427a1fedcb4740586a130ac6cfRonny Chevalier "vm\0"
641d1f99b8c4c5427a1fedcb4740586a130ac6cfRonny Chevalier "container\0"
63c372cb9df3bee01e3bf8cd7f96f336bddda846Lennart Poettering "desktop\0"
641d1f99b8c4c5427a1fedcb4740586a130ac6cfRonny Chevalier "laptop\0"
641d1f99b8c4c5427a1fedcb4740586a130ac6cfRonny Chevalier "server\0"
641d1f99b8c4c5427a1fedcb4740586a130ac6cfRonny Chevalier "tablet\0"
641d1f99b8c4c5427a1fedcb4740586a130ac6cfRonny Chevalier "handset\0",
641d1f99b8c4c5427a1fedcb4740586a130ac6cfRonny Chevalier chassis);
641d1f99b8c4c5427a1fedcb4740586a130ac6cfRonny Chevalier}
641d1f99b8c4c5427a1fedcb4740586a130ac6cfRonny Chevalier
641d1f99b8c4c5427a1fedcb4740586a130ac6cfRonny Chevalierstatic const char* fallback_chassis(void) {
63c372cb9df3bee01e3bf8cd7f96f336bddda846Lennart Poettering int r;
63c372cb9df3bee01e3bf8cd7f96f336bddda846Lennart Poettering char *type;
641d1f99b8c4c5427a1fedcb4740586a130ac6cfRonny Chevalier unsigned t;
641d1f99b8c4c5427a1fedcb4740586a130ac6cfRonny Chevalier Virtualization v;
641d1f99b8c4c5427a1fedcb4740586a130ac6cfRonny Chevalier
641d1f99b8c4c5427a1fedcb4740586a130ac6cfRonny Chevalier v = detect_virtualization(NULL);
641d1f99b8c4c5427a1fedcb4740586a130ac6cfRonny Chevalier
641d1f99b8c4c5427a1fedcb4740586a130ac6cfRonny Chevalier if (v == VIRTUALIZATION_VM)
641d1f99b8c4c5427a1fedcb4740586a130ac6cfRonny Chevalier return "vm";
641d1f99b8c4c5427a1fedcb4740586a130ac6cfRonny Chevalier if (v == VIRTUALIZATION_CONTAINER)
c6878637502b1717a110a9a7e8bba32a8583fcdfLennart Poettering return "container";
c6878637502b1717a110a9a7e8bba32a8583fcdfLennart Poettering
641d1f99b8c4c5427a1fedcb4740586a130ac6cfRonny Chevalier r = read_one_line_file("/sys/firmware/acpi/pm_profile", &type);
641d1f99b8c4c5427a1fedcb4740586a130ac6cfRonny Chevalier if (r < 0)
ad5ecc113821fbfa33f6fd43cdaee9c538cdff78Zbigniew Jędrzejewski-Szmek goto try_dmi;
ad5ecc113821fbfa33f6fd43cdaee9c538cdff78Zbigniew Jędrzejewski-Szmek
ad5ecc113821fbfa33f6fd43cdaee9c538cdff78Zbigniew Jędrzejewski-Szmek r = safe_atou(type, &t);
ad5ecc113821fbfa33f6fd43cdaee9c538cdff78Zbigniew Jędrzejewski-Szmek free(type);
ad5ecc113821fbfa33f6fd43cdaee9c538cdff78Zbigniew Jędrzejewski-Szmek if (r < 0)
ad5ecc113821fbfa33f6fd43cdaee9c538cdff78Zbigniew Jędrzejewski-Szmek goto try_dmi;
4f36d4004c407c16508001a20450c5f14f7d4d31Dimitri John Ledkov
4f36d4004c407c16508001a20450c5f14f7d4d31Dimitri John Ledkov /* We only list the really obvious cases here as the ACPI data
4f36d4004c407c16508001a20450c5f14f7d4d31Dimitri John Ledkov * is not really super reliable.
ad5ecc113821fbfa33f6fd43cdaee9c538cdff78Zbigniew Jędrzejewski-Szmek *
ad5ecc113821fbfa33f6fd43cdaee9c538cdff78Zbigniew Jędrzejewski-Szmek * See the ACPI 5.0 Spec Section 5.2.9.1 for details:
ad5ecc113821fbfa33f6fd43cdaee9c538cdff78Zbigniew Jędrzejewski-Szmek *
ad5ecc113821fbfa33f6fd43cdaee9c538cdff78Zbigniew Jędrzejewski-Szmek * http://www.acpi.info/DOWNLOADS/ACPIspec50.pdf
59f448cf15f94bc5ebfd5b254de6f2441d02fbecLennart Poettering */
ad5ecc113821fbfa33f6fd43cdaee9c538cdff78Zbigniew Jędrzejewski-Szmek
ad5ecc113821fbfa33f6fd43cdaee9c538cdff78Zbigniew Jędrzejewski-Szmek switch(t) {
ad5ecc113821fbfa33f6fd43cdaee9c538cdff78Zbigniew Jędrzejewski-Szmek
ad5ecc113821fbfa33f6fd43cdaee9c538cdff78Zbigniew Jędrzejewski-Szmek case 1:
ad5ecc113821fbfa33f6fd43cdaee9c538cdff78Zbigniew Jędrzejewski-Szmek case 3:
ad5ecc113821fbfa33f6fd43cdaee9c538cdff78Zbigniew Jędrzejewski-Szmek case 6:
ad5ecc113821fbfa33f6fd43cdaee9c538cdff78Zbigniew Jędrzejewski-Szmek return "desktop";
ad5ecc113821fbfa33f6fd43cdaee9c538cdff78Zbigniew Jędrzejewski-Szmek
ad5ecc113821fbfa33f6fd43cdaee9c538cdff78Zbigniew Jędrzejewski-Szmek case 2:
ad5ecc113821fbfa33f6fd43cdaee9c538cdff78Zbigniew Jędrzejewski-Szmek return "laptop";
ad5ecc113821fbfa33f6fd43cdaee9c538cdff78Zbigniew Jędrzejewski-Szmek
ad5ecc113821fbfa33f6fd43cdaee9c538cdff78Zbigniew Jędrzejewski-Szmek case 4:
ad5ecc113821fbfa33f6fd43cdaee9c538cdff78Zbigniew Jędrzejewski-Szmek case 5:
ad5ecc113821fbfa33f6fd43cdaee9c538cdff78Zbigniew Jędrzejewski-Szmek case 7:
ad5ecc113821fbfa33f6fd43cdaee9c538cdff78Zbigniew Jędrzejewski-Szmek return "server";
ad5ecc113821fbfa33f6fd43cdaee9c538cdff78Zbigniew Jędrzejewski-Szmek
ad5ecc113821fbfa33f6fd43cdaee9c538cdff78Zbigniew Jędrzejewski-Szmek case 8:
ad5ecc113821fbfa33f6fd43cdaee9c538cdff78Zbigniew Jędrzejewski-Szmek return "tablet";
ad5ecc113821fbfa33f6fd43cdaee9c538cdff78Zbigniew Jędrzejewski-Szmek }
ad5ecc113821fbfa33f6fd43cdaee9c538cdff78Zbigniew Jędrzejewski-Szmek
ad5ecc113821fbfa33f6fd43cdaee9c538cdff78Zbigniew Jędrzejewski-Szmektry_dmi:
ad5ecc113821fbfa33f6fd43cdaee9c538cdff78Zbigniew Jędrzejewski-Szmek r = read_one_line_file("/sys/class/dmi/id/chassis_type", &type);
641d1f99b8c4c5427a1fedcb4740586a130ac6cfRonny Chevalier if (r < 0)
641d1f99b8c4c5427a1fedcb4740586a130ac6cfRonny Chevalier return NULL;
cda134ab1eac84f874aacf8e885a07112a7fd5ceLennart Poettering
641d1f99b8c4c5427a1fedcb4740586a130ac6cfRonny Chevalier r = safe_atou(type, &t);
ad5ecc113821fbfa33f6fd43cdaee9c538cdff78Zbigniew Jędrzejewski-Szmek free(type);
641d1f99b8c4c5427a1fedcb4740586a130ac6cfRonny Chevalier if (r < 0)
641d1f99b8c4c5427a1fedcb4740586a130ac6cfRonny Chevalier return NULL;
641d1f99b8c4c5427a1fedcb4740586a130ac6cfRonny Chevalier
/* We only list the really obvious cases here. The DMI data is
unreliable enough, so let's not do any additional guesswork
on top of that.
See the SMBIOS Specification 2.7.1 section 7.4.1 for
details about the values listed here:
http://www.dmtf.org/sites/default/files/standards/documents/DSP0134_2.7.1.pdf
*/
switch (t) {
case 0x3:
case 0x4:
case 0x6:
case 0x7:
return "desktop";
case 0x8:
case 0x9:
case 0xA:
case 0xE:
return "laptop";
case 0xB:
return "handset";
case 0x11:
case 0x1C:
return "server";
}
return NULL;
}
static char* context_fallback_icon_name(Context *c) {
const char *chassis;
assert(c);
if (!isempty(c->data[PROP_CHASSIS]))
return strappend("computer-", c->data[PROP_CHASSIS]);
chassis = fallback_chassis();
if (chassis)
return strappend("computer-", chassis);
return strdup("computer");
}
static int context_write_data_hostname(Context *c) {
const char *hn;
assert(c);
if (isempty(c->data[PROP_HOSTNAME]))
hn = "localhost";
else
hn = c->data[PROP_HOSTNAME];
if (sethostname(hn, strlen(hn)) < 0)
return -errno;
return 0;
}
static int context_write_data_static_hostname(Context *c) {
assert(c);
if (isempty(c->data[PROP_STATIC_HOSTNAME])) {
if (unlink("/etc/hostname") < 0)
return errno == ENOENT ? 0 : -errno;
return 0;
}
return write_string_file_atomic_label("/etc/hostname", c->data[PROP_STATIC_HOSTNAME]);
}
static int context_write_data_other(Context *c) {
static const char * const name[_PROP_MAX] = {
[PROP_PRETTY_HOSTNAME] = "PRETTY_HOSTNAME",
[PROP_ICON_NAME] = "ICON_NAME",
[PROP_CHASSIS] = "CHASSIS"
};
char **l = NULL;
int r, p;
assert(c);
r = load_env_file("/etc/machine-info", NULL, &l);
if (r < 0 && r != -ENOENT)
return r;
for (p = 2; p < _PROP_MAX; p++) {
char *t, **u;
assert(name[p]);
if (isempty(c->data[p])) {
strv_env_unset(l, name[p]);
continue;
}
if (asprintf(&t, "%s=%s", name[p], strempty(c->data[p])) < 0) {
strv_free(l);
return -ENOMEM;
}
u = strv_env_set(l, t);
free(t);
strv_free(l);
if (!u)
return -ENOMEM;
l = u;
}
if (strv_isempty(l)) {
if (unlink("/etc/machine-info") < 0)
return errno == ENOENT ? 0 : -errno;
return 0;
}
r = write_env_file_label("/etc/machine-info", l);
strv_free(l);
return r;
}
static int property_get_icon_name(
sd_bus *bus,
const char *path,
const char *interface,
const char *property,
sd_bus_message *reply,
sd_bus_error *error,
void *userdata) {
_cleanup_free_ char *n = NULL;
Context *c = userdata;
const char *name;
int r;
if (isempty(c->data[PROP_ICON_NAME]))
name = n = context_fallback_icon_name(c);
else
name = c->data[PROP_ICON_NAME];
if (!name)
return -ENOMEM;
r = sd_bus_message_append(reply, "s", name);
if (r < 0)
return r;
return 1;
}
static int property_get_chassis(
sd_bus *bus,
const char *path,
const char *interface,
const char *property,
sd_bus_message *reply,
sd_bus_error *error,
void *userdata) {
Context *c = userdata;
const char *name;
int r;
if (isempty(c->data[PROP_CHASSIS]))
name = fallback_chassis();
else
name = c->data[PROP_CHASSIS];
r = sd_bus_message_append(reply, "s", name);
if (r < 0)
return r;
return 1;
}
static int method_set_hostname(sd_bus *bus, sd_bus_message *m, void *userdata) {
_cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
Context *c = userdata;
const char *name;
unsigned interactive;
char *h;
int r;
r = sd_bus_message_read(m, "sb", &name, &interactive);
if (r < 0)
return sd_bus_reply_method_errno(bus, m, r, NULL);
if (isempty(name))
name = c->data[PROP_STATIC_HOSTNAME];
if (isempty(name))
name = "localhost";
if (!hostname_is_valid(name))
return sd_bus_reply_method_errorf(bus, m, SD_BUS_ERROR_INVALID_ARGS, "Invalid hostname '%s'", name);
if (streq_ptr(name, c->data[PROP_HOSTNAME]))
return sd_bus_reply_method_return(bus, m, NULL);
r = bus_verify_polkit_async(bus, &c->polkit_registry, m, "org.freedesktop.hostname1.set-hostname", interactive, &error, method_set_hostname, c);
if (r < 0)
return sd_bus_reply_method_errno(bus, m, r, &error);
if (r == 0)
return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
h = strdup(name);
if (!h)
return log_oom();
free(c->data[PROP_HOSTNAME]);
c->data[PROP_HOSTNAME] = h;
r = context_write_data_hostname(c);
if (r < 0) {
log_error("Failed to set host name: %s", strerror(-r));
return sd_bus_reply_method_errnof(bus, m, r, "Failed to set hostname: %s", strerror(-r));
}
log_info("Changed host name to '%s'", strna(c->data[PROP_HOSTNAME]));
sd_bus_emit_properties_changed(bus, "/org/freedesktop/hostname1", "org.freedesktop.hostname1", "Hostname", NULL);
return sd_bus_reply_method_return(bus, m, NULL);
}
static int method_set_static_hostname(sd_bus *bus, sd_bus_message *m, void *userdata) {
_cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
Context *c = userdata;
const char *name;
unsigned interactive;
int r;
r = sd_bus_message_read(m, "sb", &name, &interactive);
if (r < 0)
return sd_bus_reply_method_errno(bus, m, r, NULL);
if (isempty(name))
name = NULL;
if (streq_ptr(name, c->data[PROP_STATIC_HOSTNAME]))
return sd_bus_reply_method_return(bus, m, NULL);
r = bus_verify_polkit_async(bus, &c->polkit_registry, m, "org.freedesktop.hostname1.set-static-hostname", interactive, &error, method_set_static_hostname, c);
if (r < 0)
return sd_bus_reply_method_errno(bus, m, r, &error);
if (r == 0)
return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
if (isempty(name)) {
free(c->data[PROP_STATIC_HOSTNAME]);
c->data[PROP_STATIC_HOSTNAME] = NULL;
} else {
char *h;
if (!hostname_is_valid(name))
return sd_bus_reply_method_errorf(bus, m, SD_BUS_ERROR_INVALID_ARGS, "Invalid static hostname '%s'", name);
h = strdup(name);
if (!h)
return log_oom();
free(c->data[PROP_STATIC_HOSTNAME]);
c->data[PROP_STATIC_HOSTNAME] = h;
}
r = context_write_data_static_hostname(c);
if (r < 0) {
log_error("Failed to write static host name: %s", strerror(-r));
return sd_bus_reply_method_errnof(bus, m, r, "Failed to set static hostname: %s", strerror(-r));
}
log_info("Changed static host name to '%s'", strna(c->data[PROP_STATIC_HOSTNAME]));
sd_bus_emit_properties_changed(bus, "/org/freedesktop/hostname1", "org.freedesktop.hostname1", "StaticHostname", NULL);
return sd_bus_reply_method_return(bus, m, NULL);
}
static int set_machine_info(Context *c, sd_bus *bus, sd_bus_message *m, int prop, sd_bus_message_handler_t cb) {
_cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
unsigned interactive;
const char *name;
int r;
assert(c);
assert(bus);
assert(m);
r = sd_bus_message_read(m, "sb", &name, &interactive);
if (r < 0)
return sd_bus_reply_method_errno(bus, m, r, NULL);
if (isempty(name))
name = NULL;
if (streq_ptr(name, c->data[prop]))
return sd_bus_reply_method_return(bus, m, NULL);
/* Since the pretty hostname should always be changed at the
* same time as the static one, use the same policy action for
* both... */
r = bus_verify_polkit_async(bus, &c->polkit_registry, m, prop == PROP_PRETTY_HOSTNAME ?
"org.freedesktop.hostname1.set-static-hostname" :
"org.freedesktop.hostname1.set-machine-info", interactive, &error, cb, c);
if (r < 0)
return sd_bus_reply_method_errno(bus, m, r, &error);
if (r == 0)
return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
if (isempty(name)) {
free(c->data[prop]);
c->data[prop] = NULL;
} else {
char *h;
/* The icon name might ultimately be used as file
* name, so better be safe than sorry */
if (prop == PROP_ICON_NAME && !filename_is_safe(name))
return sd_bus_reply_method_errorf(bus, m, SD_BUS_ERROR_INVALID_ARGS, "Invalid icon name '%s'", name);
if (prop == PROP_PRETTY_HOSTNAME &&
(string_has_cc(name) || chars_intersect(name, "\t")))
return sd_bus_reply_method_errorf(bus, m, SD_BUS_ERROR_INVALID_ARGS, "Invalid pretty host name '%s'", name);
if (prop == PROP_CHASSIS && !valid_chassis(name))
return sd_bus_reply_method_errorf(bus, m, SD_BUS_ERROR_INVALID_ARGS, "Invalid chassis '%s'", name);
h = strdup(name);
if (!h)
return log_oom();
free(c->data[prop]);
c->data[prop] = h;
}
r = context_write_data_other(c);
if (r < 0) {
log_error("Failed to write machine info: %s", strerror(-r));
return sd_bus_reply_method_errnof(bus, m, r, "Failed to write machine info: %s", strerror(-r));
}
log_info("Changed %s to '%s'",
prop == PROP_PRETTY_HOSTNAME ? "pretty host name" :
prop == PROP_CHASSIS ? "chassis" : "icon name", strna(c->data[prop]));
sd_bus_emit_properties_changed(bus, "/org/freedesktop/hostname1", "org.freedesktop.hostname1",
prop == PROP_PRETTY_HOSTNAME ? "PrettyHostname" :
prop == PROP_CHASSIS ? "Chassis" : "IconName", NULL);
return sd_bus_reply_method_return(bus, m, NULL);
}
static int method_set_pretty_hostname(sd_bus *bus, sd_bus_message *m, void *userdata) {
return set_machine_info(userdata, bus, m, PROP_PRETTY_HOSTNAME, method_set_pretty_hostname);
}
static int method_set_icon_name(sd_bus *bus, sd_bus_message *m, void *userdata) {
return set_machine_info(userdata, bus, m, PROP_ICON_NAME, method_set_icon_name);
}
static int method_set_chassis(sd_bus *bus, sd_bus_message *m, void *userdata) {
return set_machine_info(userdata, bus, m, PROP_CHASSIS, method_set_chassis);
}
static const sd_bus_vtable hostname_vtable[] = {
SD_BUS_VTABLE_START(0),
SD_BUS_PROPERTY("Hostname", "s", NULL, offsetof(Context, data) + sizeof(char*) * PROP_HOSTNAME, 0),
SD_BUS_PROPERTY("StaticHostname", "s", NULL, offsetof(Context, data) + sizeof(char*) * PROP_STATIC_HOSTNAME, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
SD_BUS_PROPERTY("PrettyHostname", "s", NULL, offsetof(Context, data) + sizeof(char*) * PROP_PRETTY_HOSTNAME, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
SD_BUS_PROPERTY("IconName", "s", property_get_icon_name, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
SD_BUS_PROPERTY("Chassis", "s", property_get_chassis, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
SD_BUS_METHOD("SetHostname", "sb", NULL, method_set_hostname, 0),
SD_BUS_METHOD("SetStaticHostname", "sb", NULL, method_set_static_hostname, 0),
SD_BUS_METHOD("SetPrettyHostname", "sb", NULL, method_set_pretty_hostname, 0),
SD_BUS_METHOD("SetIconName", "sb", NULL, method_set_icon_name, 0),
SD_BUS_METHOD("SetChassis", "sb", NULL, method_set_chassis, 0),
SD_BUS_VTABLE_END,
};
static int connect_bus(Context *c, sd_event *event, sd_bus **_bus) {
_cleanup_bus_unref_ sd_bus *bus = NULL;
int r;
assert(c);
assert(event);
assert(_bus);
r = sd_bus_open_system(&bus);
if (r < 0) {
log_error("Failed to get system bus connection: %s", strerror(-r));
return r;
}
r = sd_bus_add_object_vtable(bus, "/org/freedesktop/hostname1", "org.freedesktop.hostname1", hostname_vtable, c);
if (r < 0) {
log_error("Failed to register object: %s", strerror(-r));
return r;
}
r = sd_bus_request_name(bus, "org.freedesktop.hostname1", SD_BUS_NAME_DO_NOT_QUEUE);
if (r < 0) {
log_error("Failed to register name: %s", strerror(-r));
return r;
}
if (r != SD_BUS_NAME_PRIMARY_OWNER) {
log_error("Failed to acquire name.");
return -EEXIST;
}
r = sd_bus_attach_event(bus, event, 0);
if (r < 0) {
log_error("Failed to attach bus to event loop: %s", strerror(-r));
return r;
}
*_bus = bus;
bus = NULL;
return 0;
}
int main(int argc, char *argv[]) {
Context context = {};
_cleanup_event_unref_ sd_event *event = NULL;
_cleanup_bus_unref_ sd_bus *bus = NULL;
int r;
log_set_target(LOG_TARGET_AUTO);
log_parse_environment();
log_open();
umask(0022);
label_init("/etc");
if (argc != 1) {
log_error("This program takes no arguments.");
r = -EINVAL;
goto finish;
}
if (!check_nss())
log_warning("Warning: nss-myhostname is not installed. Changing the local hostname might make it unresolveable. Please install nss-myhostname!");
if (argc != 1) {
log_error("This program takes no arguments.");
r = -EINVAL;
goto finish;
}
r = sd_event_new(&event);
if (r < 0) {
log_error("Failed to allocate event loop: %s", strerror(-r));
goto finish;
}
r = connect_bus(&context, event, &bus);
if (r < 0)
goto finish;
r = context_read_data(&context);
if (r < 0) {
log_error("Failed to read timezone data: %s", strerror(-r));
goto finish;
}
r = bus_event_loop_with_idle(event, bus, "org.freedesktop.hostname1", DEFAULT_EXIT_USEC);
if (r < 0) {
log_error("Failed to run event loop: %s", strerror(-r));
goto finish;
}
r = 0;
finish:
context_free(&context, bus);
return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
}