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