]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/hostname/hostnamed.c
sd-bus: introduce sd_bus_slot objects encapsulating callbacks or vtables attached...
[thirdparty/systemd.git] / src / hostname / hostnamed.c
CommitLineData
7640a5de
LP
1/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3/***
4 This file is part of systemd.
5
41550d40 6 Copyright 2011 Lennart Poettering
7640a5de
LP
7
8 systemd is free software; you can redistribute it and/or modify it
5430f7f2
LP
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
7640a5de
LP
11 (at your option) any later version.
12
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
5430f7f2 16 Lesser General Public License for more details.
7640a5de 17
5430f7f2 18 You should have received a copy of the GNU Lesser General Public License
7640a5de
LP
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
20***/
21
7640a5de
LP
22#include <errno.h>
23#include <string.h>
24#include <unistd.h>
c2a14cf0 25#include <dlfcn.h>
f426cc5d 26#include <sys/utsname.h>
7640a5de
LP
27
28#include "util.h"
29#include "strv.h"
ad740100 30#include "def.h"
b52aae1d 31#include "virt.h"
4d1a6904 32#include "env-util.h"
a5c32cff
HH
33#include "fileio-label.h"
34#include "label.h"
66a4c743
LP
35#include "bus-util.h"
36#include "event-util.h"
91f9dcaf 37
7640a5de
LP
38enum {
39 PROP_HOSTNAME,
40 PROP_STATIC_HOSTNAME,
41 PROP_PRETTY_HOSTNAME,
42 PROP_ICON_NAME,
7871c8e9 43 PROP_CHASSIS,
f426cc5d
DH
44 PROP_KERNEL_NAME,
45 PROP_KERNEL_RELEASE,
44c32988
DH
46 PROP_OS_PRETTY_NAME,
47 PROP_OS_CPE_NAME,
7640a5de
LP
48 _PROP_MAX
49};
50
66a4c743
LP
51typedef struct Context {
52 char *data[_PROP_MAX];
53 Hashmap *polkit_registry;
54} Context;
ad740100 55
66a4c743 56static void context_reset(Context *c) {
7640a5de
LP
57 int p;
58
66a4c743
LP
59 assert(c);
60
7640a5de 61 for (p = 0; p < _PROP_MAX; p++) {
66a4c743
LP
62 free(c->data[p]);
63 c->data[p] = NULL;
7640a5de
LP
64 }
65}
66
66a4c743
LP
67static void context_free(Context *c, sd_bus *bus) {
68 assert(c);
69
70 context_reset(c);
71 bus_verify_polkit_async_registry_free(bus, c->polkit_registry);
72}
73
74static int context_read_data(Context *c) {
7640a5de 75 int r;
f426cc5d 76 struct utsname u;
7640a5de 77
66a4c743
LP
78 assert(c);
79
80 context_reset(c);
7640a5de 81
f426cc5d
DH
82 assert_se(uname(&u) >= 0);
83 c->data[PROP_KERNEL_NAME] = strdup(u.sysname);
84 c->data[PROP_KERNEL_RELEASE] = strdup(u.release);
85 if (!c->data[PROP_KERNEL_NAME] || !c->data[PROP_KERNEL_RELEASE])
86 return -ENOMEM;
87
66a4c743
LP
88 c->data[PROP_HOSTNAME] = gethostname_malloc();
89 if (!c->data[PROP_HOSTNAME])
7640a5de
LP
90 return -ENOMEM;
91
66a4c743 92 r = read_one_line_file("/etc/hostname", &c->data[PROP_STATIC_HOSTNAME]);
7640a5de
LP
93 if (r < 0 && r != -ENOENT)
94 return r;
95
96 r = parse_env_file("/etc/machine-info", NEWLINE,
66a4c743
LP
97 "PRETTY_HOSTNAME", &c->data[PROP_PRETTY_HOSTNAME],
98 "ICON_NAME", &c->data[PROP_ICON_NAME],
99 "CHASSIS", &c->data[PROP_CHASSIS],
7640a5de
LP
100 NULL);
101 if (r < 0 && r != -ENOENT)
102 return r;
103
44c32988
DH
104 r = parse_env_file("/etc/os-release", NEWLINE,
105 "PRETTY_NAME", &c->data[PROP_OS_PRETTY_NAME],
106 "CPE_NAME", &c->data[PROP_OS_CPE_NAME],
107 NULL);
108 if (r < 0 && r != -ENOENT)
109 return r;
110
7640a5de
LP
111 return 0;
112}
113
c2a14cf0 114static bool check_nss(void) {
c2a14cf0
LP
115 void *dl;
116
7871c8e9
LP
117 dl = dlopen("libnss_myhostname.so.2", RTLD_LAZY);
118 if (dl) {
c2a14cf0
LP
119 dlclose(dl);
120 return true;
121 }
122
123 return false;
124}
125
7871c8e9 126static bool valid_chassis(const char *chassis) {
7640a5de 127
7871c8e9
LP
128 assert(chassis);
129
130 return nulstr_contains(
131 "vm\0"
132 "container\0"
133 "desktop\0"
134 "laptop\0"
135 "server\0"
136 "tablet\0"
137 "handset\0",
138 chassis);
139}
140
141static const char* fallback_chassis(void) {
7640a5de
LP
142 int r;
143 char *type;
144 unsigned t;
248fab74 145 int v;
7871c8e9
LP
146
147 v = detect_virtualization(NULL);
148
149 if (v == VIRTUALIZATION_VM)
150 return "vm";
151 if (v == VIRTUALIZATION_CONTAINER)
152 return "container";
153
154 r = read_one_line_file("/sys/firmware/acpi/pm_profile", &type);
155 if (r < 0)
156 goto try_dmi;
157
158 r = safe_atou(type, &t);
159 free(type);
160 if (r < 0)
161 goto try_dmi;
162
163 /* We only list the really obvious cases here as the ACPI data
164 * is not really super reliable.
165 *
166 * See the ACPI 5.0 Spec Section 5.2.9.1 for details:
167 *
168 * http://www.acpi.info/DOWNLOADS/ACPIspec50.pdf
169 */
170
171 switch(t) {
172
173 case 1:
174 case 3:
175 case 6:
176 return "desktop";
177
178 case 2:
179 return "laptop";
7640a5de 180
7871c8e9
LP
181 case 4:
182 case 5:
183 case 7:
184 return "server";
7640a5de 185
7871c8e9
LP
186 case 8:
187 return "tablet";
188 }
189
190try_dmi:
7640a5de
LP
191 r = read_one_line_file("/sys/class/dmi/id/chassis_type", &type);
192 if (r < 0)
193 return NULL;
194
195 r = safe_atou(type, &t);
196 free(type);
7640a5de
LP
197 if (r < 0)
198 return NULL;
199
200 /* We only list the really obvious cases here. The DMI data is
201 unreliable enough, so let's not do any additional guesswork
41550d40
LP
202 on top of that.
203
204 See the SMBIOS Specification 2.7.1 section 7.4.1 for
205 details about the values listed here:
206
207 http://www.dmtf.org/sites/default/files/standards/documents/DSP0134_2.7.1.pdf
208 */
7640a5de
LP
209
210 switch (t) {
211
212 case 0x3:
213 case 0x4:
214 case 0x6:
215 case 0x7:
7871c8e9 216 return "desktop";
7640a5de 217
7871c8e9 218 case 0x8:
7640a5de
LP
219 case 0x9:
220 case 0xA:
221 case 0xE:
7871c8e9
LP
222 return "laptop";
223
224 case 0xB:
225 return "handset";
7640a5de
LP
226
227 case 0x11:
41550d40 228 case 0x1C:
7871c8e9 229 return "server";
7640a5de
LP
230 }
231
7640a5de
LP
232 return NULL;
233}
234
66a4c743 235static char* context_fallback_icon_name(Context *c) {
7871c8e9
LP
236 const char *chassis;
237
66a4c743
LP
238 assert(c);
239
240 if (!isempty(c->data[PROP_CHASSIS]))
241 return strappend("computer-", c->data[PROP_CHASSIS]);
7871c8e9
LP
242
243 chassis = fallback_chassis();
244 if (chassis)
245 return strappend("computer-", chassis);
246
247 return strdup("computer");
248}
249
66a4c743 250static int context_write_data_hostname(Context *c) {
7640a5de
LP
251 const char *hn;
252
66a4c743
LP
253 assert(c);
254
255 if (isempty(c->data[PROP_HOSTNAME]))
7640a5de
LP
256 hn = "localhost";
257 else
66a4c743 258 hn = c->data[PROP_HOSTNAME];
7640a5de
LP
259
260 if (sethostname(hn, strlen(hn)) < 0)
261 return -errno;
262
263 return 0;
264}
265
66a4c743 266static int context_write_data_static_hostname(Context *c) {
7640a5de 267
66a4c743
LP
268 assert(c);
269
270 if (isempty(c->data[PROP_STATIC_HOSTNAME])) {
7640a5de
LP
271
272 if (unlink("/etc/hostname") < 0)
273 return errno == ENOENT ? 0 : -errno;
274
275 return 0;
276 }
66a4c743 277 return write_string_file_atomic_label("/etc/hostname", c->data[PROP_STATIC_HOSTNAME]);
7640a5de
LP
278}
279
f200e8bb 280static int context_write_data_machine_info(Context *c) {
4f34ed54 281
7640a5de
LP
282 static const char * const name[_PROP_MAX] = {
283 [PROP_PRETTY_HOSTNAME] = "PRETTY_HOSTNAME",
7871c8e9
LP
284 [PROP_ICON_NAME] = "ICON_NAME",
285 [PROP_CHASSIS] = "CHASSIS"
7640a5de
LP
286 };
287
0ccad099 288 _cleanup_strv_free_ char **l = NULL;
7640a5de
LP
289 int r, p;
290
66a4c743
LP
291 assert(c);
292
f73141d7 293 r = load_env_file("/etc/machine-info", NULL, &l);
7640a5de
LP
294 if (r < 0 && r != -ENOENT)
295 return r;
296
f200e8bb 297 for (p = PROP_PRETTY_HOSTNAME; p <= PROP_CHASSIS; p++) {
7640a5de
LP
298 char *t, **u;
299
300 assert(name[p]);
301
66a4c743 302 if (isempty(c->data[p])) {
f8440af5 303 strv_env_unset(l, name[p]);
7640a5de
LP
304 continue;
305 }
306
0ccad099 307 if (asprintf(&t, "%s=%s", name[p], strempty(c->data[p])) < 0)
7640a5de 308 return -ENOMEM;
7640a5de
LP
309
310 u = strv_env_set(l, t);
311 free(t);
7640a5de
LP
312
313 if (!u)
314 return -ENOMEM;
0ccad099
LP
315
316 strv_free(l);
7640a5de
LP
317 l = u;
318 }
319
320 if (strv_isempty(l)) {
321
322 if (unlink("/etc/machine-info") < 0)
323 return errno == ENOENT ? 0 : -errno;
324
325 return 0;
326 }
327
0ccad099 328 return write_env_file_label("/etc/machine-info", l);
7640a5de
LP
329}
330
66a4c743
LP
331static int property_get_icon_name(
332 sd_bus *bus,
333 const char *path,
334 const char *interface,
335 const char *property,
336 sd_bus_message *reply,
ebcf1f97
LP
337 void *userdata,
338 sd_bus_error *error) {
7640a5de 339
66a4c743
LP
340 _cleanup_free_ char *n = NULL;
341 Context *c = userdata;
342 const char *name;
7640a5de 343
66a4c743
LP
344 if (isempty(c->data[PROP_ICON_NAME]))
345 name = n = context_fallback_icon_name(c);
7640a5de 346 else
66a4c743
LP
347 name = c->data[PROP_ICON_NAME];
348
349 if (!name)
350 return -ENOMEM;
7640a5de 351
ebcf1f97 352 return sd_bus_message_append(reply, "s", name);
7640a5de
LP
353}
354
66a4c743
LP
355static int property_get_chassis(
356 sd_bus *bus,
357 const char *path,
358 const char *interface,
359 const char *property,
360 sd_bus_message *reply,
ebcf1f97
LP
361 void *userdata,
362 sd_bus_error *error) {
7871c8e9 363
66a4c743
LP
364 Context *c = userdata;
365 const char *name;
7871c8e9 366
66a4c743 367 if (isempty(c->data[PROP_CHASSIS]))
7871c8e9
LP
368 name = fallback_chassis();
369 else
66a4c743 370 name = c->data[PROP_CHASSIS];
7871c8e9 371
ebcf1f97 372 return sd_bus_message_append(reply, "s", name);
7871c8e9
LP
373}
374
ebcf1f97 375static int method_set_hostname(sd_bus *bus, sd_bus_message *m, void *userdata, sd_bus_error *error) {
66a4c743
LP
376 Context *c = userdata;
377 const char *name;
102d8f81 378 int interactive;
66a4c743
LP
379 char *h;
380 int r;
d200735e 381
66a4c743
LP
382 r = sd_bus_message_read(m, "sb", &name, &interactive);
383 if (r < 0)
ebcf1f97 384 return r;
d200735e 385
66a4c743
LP
386 if (isempty(name))
387 name = c->data[PROP_STATIC_HOSTNAME];
7640a5de 388
66a4c743
LP
389 if (isempty(name))
390 name = "localhost";
7640a5de 391
66a4c743 392 if (!hostname_is_valid(name))
ebcf1f97 393 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid hostname '%s'", name);
7640a5de 394
66a4c743 395 if (streq_ptr(name, c->data[PROP_HOSTNAME]))
df2d202e 396 return sd_bus_reply_method_return(m, NULL);
7640a5de 397
ebcf1f97 398 r = bus_verify_polkit_async(bus, &c->polkit_registry, m, "org.freedesktop.hostname1.set-hostname", interactive, error, method_set_hostname, c);
66a4c743 399 if (r < 0)
ebcf1f97 400 return r;
66a4c743
LP
401 if (r == 0)
402 return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
7640a5de 403
66a4c743
LP
404 h = strdup(name);
405 if (!h)
ebcf1f97 406 return -ENOMEM;
7640a5de 407
66a4c743
LP
408 free(c->data[PROP_HOSTNAME]);
409 c->data[PROP_HOSTNAME] = h;
7640a5de 410
66a4c743
LP
411 r = context_write_data_hostname(c);
412 if (r < 0) {
413 log_error("Failed to set host name: %s", strerror(-r));
ebcf1f97 414 return sd_bus_error_set_errnof(error, r, "Failed to set hostname: %s", strerror(-r));
66a4c743 415 }
7640a5de 416
66a4c743 417 log_info("Changed host name to '%s'", strna(c->data[PROP_HOSTNAME]));
7640a5de 418
66a4c743 419 sd_bus_emit_properties_changed(bus, "/org/freedesktop/hostname1", "org.freedesktop.hostname1", "Hostname", NULL);
7640a5de 420
df2d202e 421 return sd_bus_reply_method_return(m, NULL);
66a4c743 422}
7640a5de 423
ebcf1f97 424static int method_set_static_hostname(sd_bus *bus, sd_bus_message *m, void *userdata, sd_bus_error *error) {
66a4c743
LP
425 Context *c = userdata;
426 const char *name;
102d8f81 427 int interactive;
66a4c743 428 int r;
7640a5de 429
66a4c743
LP
430 r = sd_bus_message_read(m, "sb", &name, &interactive);
431 if (r < 0)
ebcf1f97 432 return r;
7640a5de 433
66a4c743
LP
434 if (isempty(name))
435 name = NULL;
7640a5de 436
66a4c743 437 if (streq_ptr(name, c->data[PROP_STATIC_HOSTNAME]))
df2d202e 438 return sd_bus_reply_method_return(m, NULL);
7640a5de 439
ebcf1f97 440 r = bus_verify_polkit_async(bus, &c->polkit_registry, m, "org.freedesktop.hostname1.set-static-hostname", interactive, error, method_set_static_hostname, c);
66a4c743 441 if (r < 0)
ebcf1f97 442 return r;
66a4c743
LP
443 if (r == 0)
444 return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
7640a5de 445
66a4c743
LP
446 if (isempty(name)) {
447 free(c->data[PROP_STATIC_HOSTNAME]);
448 c->data[PROP_STATIC_HOSTNAME] = NULL;
449 } else {
450 char *h;
7640a5de 451
66a4c743 452 if (!hostname_is_valid(name))
ebcf1f97 453 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid static hostname '%s'", name);
7640a5de 454
66a4c743
LP
455 h = strdup(name);
456 if (!h)
ebcf1f97 457 return -ENOMEM;
7640a5de 458
66a4c743
LP
459 free(c->data[PROP_STATIC_HOSTNAME]);
460 c->data[PROP_STATIC_HOSTNAME] = h;
461 }
7640a5de 462
66a4c743
LP
463 r = context_write_data_static_hostname(c);
464 if (r < 0) {
465 log_error("Failed to write static host name: %s", strerror(-r));
ebcf1f97 466 return sd_bus_error_set_errnof(error, r, "Failed to set static hostname: %s", strerror(-r));
66a4c743 467 }
7640a5de 468
66a4c743 469 log_info("Changed static host name to '%s'", strna(c->data[PROP_STATIC_HOSTNAME]));
7640a5de 470
66a4c743 471 sd_bus_emit_properties_changed(bus, "/org/freedesktop/hostname1", "org.freedesktop.hostname1", "StaticHostname", NULL);
7640a5de 472
df2d202e 473 return sd_bus_reply_method_return(m, NULL);
66a4c743 474}
7640a5de 475
ebcf1f97 476static int set_machine_info(Context *c, sd_bus *bus, sd_bus_message *m, int prop, sd_bus_message_handler_t cb, sd_bus_error *error) {
102d8f81 477 int interactive;
66a4c743
LP
478 const char *name;
479 int r;
480
481 assert(c);
482 assert(bus);
483 assert(m);
484
485 r = sd_bus_message_read(m, "sb", &name, &interactive);
486 if (r < 0)
ebcf1f97 487 return r;
66a4c743
LP
488
489 if (isempty(name))
490 name = NULL;
491
492 if (streq_ptr(name, c->data[prop]))
df2d202e 493 return sd_bus_reply_method_return(m, NULL);
7640a5de 494
66a4c743
LP
495 /* Since the pretty hostname should always be changed at the
496 * same time as the static one, use the same policy action for
497 * both... */
498
499 r = bus_verify_polkit_async(bus, &c->polkit_registry, m, prop == PROP_PRETTY_HOSTNAME ?
500 "org.freedesktop.hostname1.set-static-hostname" :
ebcf1f97 501 "org.freedesktop.hostname1.set-machine-info", interactive, error, cb, c);
66a4c743 502 if (r < 0)
ebcf1f97 503 return r;
66a4c743
LP
504 if (r == 0)
505 return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
506
507 if (isempty(name)) {
508 free(c->data[prop]);
509 c->data[prop] = NULL;
510 } else {
511 char *h;
512
513 /* The icon name might ultimately be used as file
514 * name, so better be safe than sorry */
515
516 if (prop == PROP_ICON_NAME && !filename_is_safe(name))
ebcf1f97 517 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid icon name '%s'", name);
66a4c743
LP
518 if (prop == PROP_PRETTY_HOSTNAME &&
519 (string_has_cc(name) || chars_intersect(name, "\t")))
ebcf1f97 520 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid pretty host name '%s'", name);
66a4c743 521 if (prop == PROP_CHASSIS && !valid_chassis(name))
ebcf1f97 522 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid chassis '%s'", name);
66a4c743
LP
523
524 h = strdup(name);
525 if (!h)
ebcf1f97 526 return -ENOMEM;
66a4c743
LP
527
528 free(c->data[prop]);
529 c->data[prop] = h;
7640a5de
LP
530 }
531
f200e8bb 532 r = context_write_data_machine_info(c);
66a4c743
LP
533 if (r < 0) {
534 log_error("Failed to write machine info: %s", strerror(-r));
ebcf1f97 535 return sd_bus_error_set_errnof(error, r, "Failed to write machine info: %s", strerror(-r));
66a4c743 536 }
7640a5de 537
66a4c743
LP
538 log_info("Changed %s to '%s'",
539 prop == PROP_PRETTY_HOSTNAME ? "pretty host name" :
540 prop == PROP_CHASSIS ? "chassis" : "icon name", strna(c->data[prop]));
7640a5de 541
66a4c743
LP
542 sd_bus_emit_properties_changed(bus, "/org/freedesktop/hostname1", "org.freedesktop.hostname1",
543 prop == PROP_PRETTY_HOSTNAME ? "PrettyHostname" :
544 prop == PROP_CHASSIS ? "Chassis" : "IconName", NULL);
7640a5de 545
df2d202e 546 return sd_bus_reply_method_return(m, NULL);
66a4c743 547}
7640a5de 548
ebcf1f97
LP
549static int method_set_pretty_hostname(sd_bus *bus, sd_bus_message *m, void *userdata, sd_bus_error *error) {
550 return set_machine_info(userdata, bus, m, PROP_PRETTY_HOSTNAME, method_set_pretty_hostname, error);
7640a5de
LP
551}
552
ebcf1f97
LP
553static int method_set_icon_name(sd_bus *bus, sd_bus_message *m, void *userdata, sd_bus_error *error) {
554 return set_machine_info(userdata, bus, m, PROP_ICON_NAME, method_set_icon_name, error);
66a4c743
LP
555}
556
ebcf1f97
LP
557static int method_set_chassis(sd_bus *bus, sd_bus_message *m, void *userdata, sd_bus_error *error) {
558 return set_machine_info(userdata, bus, m, PROP_CHASSIS, method_set_chassis, error);
66a4c743
LP
559}
560
561static const sd_bus_vtable hostname_vtable[] = {
562 SD_BUS_VTABLE_START(0),
563 SD_BUS_PROPERTY("Hostname", "s", NULL, offsetof(Context, data) + sizeof(char*) * PROP_HOSTNAME, 0),
564 SD_BUS_PROPERTY("StaticHostname", "s", NULL, offsetof(Context, data) + sizeof(char*) * PROP_STATIC_HOSTNAME, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
565 SD_BUS_PROPERTY("PrettyHostname", "s", NULL, offsetof(Context, data) + sizeof(char*) * PROP_PRETTY_HOSTNAME, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
566 SD_BUS_PROPERTY("IconName", "s", property_get_icon_name, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
567 SD_BUS_PROPERTY("Chassis", "s", property_get_chassis, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
f426cc5d
DH
568 SD_BUS_PROPERTY("KernelName", "s", NULL, offsetof(Context, data) + sizeof(char*) * PROP_KERNEL_NAME, SD_BUS_VTABLE_PROPERTY_CONST),
569 SD_BUS_PROPERTY("KernelRelease", "s", NULL, offsetof(Context, data) + sizeof(char*) * PROP_KERNEL_RELEASE, SD_BUS_VTABLE_PROPERTY_CONST),
44c32988
DH
570 SD_BUS_PROPERTY("OperatingSystemPrettyName", "s", NULL, offsetof(Context, data) + sizeof(char*) * PROP_OS_PRETTY_NAME, SD_BUS_VTABLE_PROPERTY_CONST),
571 SD_BUS_PROPERTY("OperatingSystemCPEName", "s", NULL, offsetof(Context, data) + sizeof(char*) * PROP_OS_CPE_NAME, SD_BUS_VTABLE_PROPERTY_CONST),
adacb957
LP
572 SD_BUS_METHOD("SetHostname", "sb", NULL, method_set_hostname, SD_BUS_VTABLE_UNPRIVILEGED),
573 SD_BUS_METHOD("SetStaticHostname", "sb", NULL, method_set_static_hostname, SD_BUS_VTABLE_UNPRIVILEGED),
574 SD_BUS_METHOD("SetPrettyHostname", "sb", NULL, method_set_pretty_hostname, SD_BUS_VTABLE_UNPRIVILEGED),
575 SD_BUS_METHOD("SetIconName", "sb", NULL, method_set_icon_name, SD_BUS_VTABLE_UNPRIVILEGED),
576 SD_BUS_METHOD("SetChassis", "sb", NULL, method_set_chassis, SD_BUS_VTABLE_UNPRIVILEGED),
66a4c743
LP
577 SD_BUS_VTABLE_END,
578};
579
580static int connect_bus(Context *c, sd_event *event, sd_bus **_bus) {
581 _cleanup_bus_unref_ sd_bus *bus = NULL;
7640a5de
LP
582 int r;
583
66a4c743
LP
584 assert(c);
585 assert(event);
d0baa06f
LP
586 assert(_bus);
587
76b54375 588 r = sd_bus_default_system(&bus);
66a4c743
LP
589 if (r < 0) {
590 log_error("Failed to get system bus connection: %s", strerror(-r));
591 return r;
d0baa06f
LP
592 }
593
19befb2d 594 r = sd_bus_add_object_vtable(bus, NULL, "/org/freedesktop/hostname1", "org.freedesktop.hostname1", hostname_vtable, c);
66a4c743
LP
595 if (r < 0) {
596 log_error("Failed to register object: %s", strerror(-r));
597 return r;
d0baa06f
LP
598 }
599
5bb658a1 600 r = sd_bus_request_name(bus, "org.freedesktop.hostname1", 0);
66a4c743
LP
601 if (r < 0) {
602 log_error("Failed to register name: %s", strerror(-r));
603 return r;
add10b5a
LP
604 }
605
66a4c743
LP
606 r = sd_bus_attach_event(bus, event, 0);
607 if (r < 0) {
608 log_error("Failed to attach bus to event loop: %s", strerror(-r));
609 return r;
610 }
d0baa06f 611
66a4c743
LP
612 *_bus = bus;
613 bus = NULL;
d0baa06f 614
66a4c743 615 return 0;
d0baa06f
LP
616}
617
618int main(int argc, char *argv[]) {
66a4c743
LP
619 Context context = {};
620
621 _cleanup_event_unref_ sd_event *event = NULL;
622 _cleanup_bus_unref_ sd_bus *bus = NULL;
d0baa06f 623 int r;
d0baa06f 624
7640a5de
LP
625 log_set_target(LOG_TARGET_AUTO);
626 log_parse_environment();
627 log_open();
628
4c12626c 629 umask(0022);
a5c32cff 630 label_init("/etc");
4c12626c 631
7640a5de
LP
632 if (argc != 1) {
633 log_error("This program takes no arguments.");
634 r = -EINVAL;
635 goto finish;
636 }
637
c2a14cf0
LP
638 if (!check_nss())
639 log_warning("Warning: nss-myhostname is not installed. Changing the local hostname might make it unresolveable. Please install nss-myhostname!");
640
66a4c743
LP
641 if (argc != 1) {
642 log_error("This program takes no arguments.");
643 r = -EINVAL;
644 goto finish;
645 }
646
afc6adb5 647 r = sd_event_default(&event);
7640a5de 648 if (r < 0) {
66a4c743 649 log_error("Failed to allocate event loop: %s", strerror(-r));
7640a5de
LP
650 goto finish;
651 }
652
cde93897
LP
653 sd_event_set_watchdog(event, true);
654
66a4c743 655 r = connect_bus(&context, event, &bus);
d0baa06f 656 if (r < 0)
7640a5de 657 goto finish;
7640a5de 658
66a4c743
LP
659 r = context_read_data(&context);
660 if (r < 0) {
3a3c71c1 661 log_error("Failed to read hostname and machine information: %s", strerror(-r));
66a4c743
LP
662 goto finish;
663 }
ad740100 664
37224a5f 665 r = bus_event_loop_with_idle(event, bus, "org.freedesktop.hostname1", DEFAULT_EXIT_USEC, NULL, NULL);
66a4c743
LP
666 if (r < 0) {
667 log_error("Failed to run event loop: %s", strerror(-r));
668 goto finish;
ad740100 669 }
7640a5de 670
7640a5de 671finish:
66a4c743 672 context_free(&context, bus);
7640a5de 673
7640a5de
LP
674 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
675}