]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/hostname/hostnamed.c
journal/compress: improve xz compression performance
[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);
6294aa76 553 if (prop == PROP_PRETTY_HOSTNAME && string_has_cc(name, NULL))
ebcf1f97 554 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid pretty host name '%s'", name);
66a4c743 555 if (prop == PROP_CHASSIS && !valid_chassis(name))
ebcf1f97 556 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid chassis '%s'", name);
66a4c743
LP
557
558 h = strdup(name);
559 if (!h)
ebcf1f97 560 return -ENOMEM;
66a4c743
LP
561
562 free(c->data[prop]);
563 c->data[prop] = h;
7640a5de
LP
564 }
565
f200e8bb 566 r = context_write_data_machine_info(c);
66a4c743
LP
567 if (r < 0) {
568 log_error("Failed to write machine info: %s", strerror(-r));
ebcf1f97 569 return sd_bus_error_set_errnof(error, r, "Failed to write machine info: %s", strerror(-r));
66a4c743 570 }
7640a5de 571
66a4c743
LP
572 log_info("Changed %s to '%s'",
573 prop == PROP_PRETTY_HOSTNAME ? "pretty host name" :
574 prop == PROP_CHASSIS ? "chassis" : "icon name", strna(c->data[prop]));
7640a5de 575
66a4c743
LP
576 sd_bus_emit_properties_changed(bus, "/org/freedesktop/hostname1", "org.freedesktop.hostname1",
577 prop == PROP_PRETTY_HOSTNAME ? "PrettyHostname" :
578 prop == PROP_CHASSIS ? "Chassis" : "IconName", NULL);
7640a5de 579
df2d202e 580 return sd_bus_reply_method_return(m, NULL);
66a4c743 581}
7640a5de 582
ebcf1f97
LP
583static int method_set_pretty_hostname(sd_bus *bus, sd_bus_message *m, void *userdata, sd_bus_error *error) {
584 return set_machine_info(userdata, bus, m, PROP_PRETTY_HOSTNAME, method_set_pretty_hostname, error);
7640a5de
LP
585}
586
ebcf1f97
LP
587static int method_set_icon_name(sd_bus *bus, sd_bus_message *m, void *userdata, sd_bus_error *error) {
588 return set_machine_info(userdata, bus, m, PROP_ICON_NAME, method_set_icon_name, error);
66a4c743
LP
589}
590
ebcf1f97
LP
591static int method_set_chassis(sd_bus *bus, sd_bus_message *m, void *userdata, sd_bus_error *error) {
592 return set_machine_info(userdata, bus, m, PROP_CHASSIS, method_set_chassis, error);
66a4c743
LP
593}
594
595static const sd_bus_vtable hostname_vtable[] = {
596 SD_BUS_VTABLE_START(0),
597 SD_BUS_PROPERTY("Hostname", "s", NULL, offsetof(Context, data) + sizeof(char*) * PROP_HOSTNAME, 0),
598 SD_BUS_PROPERTY("StaticHostname", "s", NULL, offsetof(Context, data) + sizeof(char*) * PROP_STATIC_HOSTNAME, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
599 SD_BUS_PROPERTY("PrettyHostname", "s", NULL, offsetof(Context, data) + sizeof(char*) * PROP_PRETTY_HOSTNAME, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
600 SD_BUS_PROPERTY("IconName", "s", property_get_icon_name, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
601 SD_BUS_PROPERTY("Chassis", "s", property_get_chassis, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
f426cc5d
DH
602 SD_BUS_PROPERTY("KernelName", "s", NULL, offsetof(Context, data) + sizeof(char*) * PROP_KERNEL_NAME, SD_BUS_VTABLE_PROPERTY_CONST),
603 SD_BUS_PROPERTY("KernelRelease", "s", NULL, offsetof(Context, data) + sizeof(char*) * PROP_KERNEL_RELEASE, SD_BUS_VTABLE_PROPERTY_CONST),
9be3455f 604 SD_BUS_PROPERTY("KernelVersion", "s", NULL, offsetof(Context, data) + sizeof(char*) * PROP_KERNEL_VERSION, SD_BUS_VTABLE_PROPERTY_CONST),
44c32988
DH
605 SD_BUS_PROPERTY("OperatingSystemPrettyName", "s", NULL, offsetof(Context, data) + sizeof(char*) * PROP_OS_PRETTY_NAME, SD_BUS_VTABLE_PROPERTY_CONST),
606 SD_BUS_PROPERTY("OperatingSystemCPEName", "s", NULL, offsetof(Context, data) + sizeof(char*) * PROP_OS_CPE_NAME, SD_BUS_VTABLE_PROPERTY_CONST),
adacb957
LP
607 SD_BUS_METHOD("SetHostname", "sb", NULL, method_set_hostname, SD_BUS_VTABLE_UNPRIVILEGED),
608 SD_BUS_METHOD("SetStaticHostname", "sb", NULL, method_set_static_hostname, SD_BUS_VTABLE_UNPRIVILEGED),
609 SD_BUS_METHOD("SetPrettyHostname", "sb", NULL, method_set_pretty_hostname, SD_BUS_VTABLE_UNPRIVILEGED),
610 SD_BUS_METHOD("SetIconName", "sb", NULL, method_set_icon_name, SD_BUS_VTABLE_UNPRIVILEGED),
611 SD_BUS_METHOD("SetChassis", "sb", NULL, method_set_chassis, SD_BUS_VTABLE_UNPRIVILEGED),
66a4c743
LP
612 SD_BUS_VTABLE_END,
613};
614
615static int connect_bus(Context *c, sd_event *event, sd_bus **_bus) {
616 _cleanup_bus_unref_ sd_bus *bus = NULL;
7640a5de
LP
617 int r;
618
66a4c743
LP
619 assert(c);
620 assert(event);
d0baa06f
LP
621 assert(_bus);
622
76b54375 623 r = sd_bus_default_system(&bus);
66a4c743
LP
624 if (r < 0) {
625 log_error("Failed to get system bus connection: %s", strerror(-r));
626 return r;
d0baa06f
LP
627 }
628
19befb2d 629 r = sd_bus_add_object_vtable(bus, NULL, "/org/freedesktop/hostname1", "org.freedesktop.hostname1", hostname_vtable, c);
66a4c743
LP
630 if (r < 0) {
631 log_error("Failed to register object: %s", strerror(-r));
632 return r;
d0baa06f
LP
633 }
634
5bb658a1 635 r = sd_bus_request_name(bus, "org.freedesktop.hostname1", 0);
66a4c743
LP
636 if (r < 0) {
637 log_error("Failed to register name: %s", strerror(-r));
638 return r;
add10b5a
LP
639 }
640
66a4c743
LP
641 r = sd_bus_attach_event(bus, event, 0);
642 if (r < 0) {
643 log_error("Failed to attach bus to event loop: %s", strerror(-r));
644 return r;
645 }
d0baa06f 646
66a4c743
LP
647 *_bus = bus;
648 bus = NULL;
d0baa06f 649
66a4c743 650 return 0;
d0baa06f
LP
651}
652
653int main(int argc, char *argv[]) {
66a4c743
LP
654 Context context = {};
655
656 _cleanup_event_unref_ sd_event *event = NULL;
657 _cleanup_bus_unref_ sd_bus *bus = NULL;
d0baa06f 658 int r;
d0baa06f 659
7640a5de
LP
660 log_set_target(LOG_TARGET_AUTO);
661 log_parse_environment();
662 log_open();
663
4c12626c 664 umask(0022);
a5c32cff 665 label_init("/etc");
4c12626c 666
7640a5de
LP
667 if (argc != 1) {
668 log_error("This program takes no arguments.");
669 r = -EINVAL;
670 goto finish;
671 }
672
c2a14cf0
LP
673 if (!check_nss())
674 log_warning("Warning: nss-myhostname is not installed. Changing the local hostname might make it unresolveable. Please install nss-myhostname!");
675
66a4c743
LP
676 if (argc != 1) {
677 log_error("This program takes no arguments.");
678 r = -EINVAL;
679 goto finish;
680 }
681
afc6adb5 682 r = sd_event_default(&event);
7640a5de 683 if (r < 0) {
66a4c743 684 log_error("Failed to allocate event loop: %s", strerror(-r));
7640a5de
LP
685 goto finish;
686 }
687
cde93897
LP
688 sd_event_set_watchdog(event, true);
689
66a4c743 690 r = connect_bus(&context, event, &bus);
d0baa06f 691 if (r < 0)
7640a5de 692 goto finish;
7640a5de 693
66a4c743
LP
694 r = context_read_data(&context);
695 if (r < 0) {
3a3c71c1 696 log_error("Failed to read hostname and machine information: %s", strerror(-r));
66a4c743
LP
697 goto finish;
698 }
ad740100 699
37224a5f 700 r = bus_event_loop_with_idle(event, bus, "org.freedesktop.hostname1", DEFAULT_EXIT_USEC, NULL, NULL);
66a4c743
LP
701 if (r < 0) {
702 log_error("Failed to run event loop: %s", strerror(-r));
703 goto finish;
ad740100 704 }
7640a5de 705
7640a5de 706finish:
66a4c743 707 context_free(&context, bus);
7640a5de 708
7640a5de
LP
709 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
710}