]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/hostname/hostnamed.c
shell-completion,man: beef up chassis completions and description
[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"
c49e59c1
LP
147 "handset\0"
148 "watch\0",
7871c8e9
LP
149 chassis);
150}
151
152static const char* fallback_chassis(void) {
7640a5de
LP
153 int r;
154 char *type;
155 unsigned t;
248fab74 156 int v;
7871c8e9
LP
157
158 v = detect_virtualization(NULL);
159
160 if (v == VIRTUALIZATION_VM)
161 return "vm";
162 if (v == VIRTUALIZATION_CONTAINER)
163 return "container";
164
165 r = read_one_line_file("/sys/firmware/acpi/pm_profile", &type);
166 if (r < 0)
167 goto try_dmi;
168
169 r = safe_atou(type, &t);
170 free(type);
171 if (r < 0)
172 goto try_dmi;
173
174 /* We only list the really obvious cases here as the ACPI data
175 * is not really super reliable.
176 *
177 * See the ACPI 5.0 Spec Section 5.2.9.1 for details:
178 *
179 * http://www.acpi.info/DOWNLOADS/ACPIspec50.pdf
180 */
181
182 switch(t) {
183
184 case 1:
185 case 3:
186 case 6:
187 return "desktop";
188
189 case 2:
190 return "laptop";
7640a5de 191
7871c8e9
LP
192 case 4:
193 case 5:
194 case 7:
195 return "server";
7640a5de 196
7871c8e9
LP
197 case 8:
198 return "tablet";
199 }
200
201try_dmi:
7640a5de
LP
202 r = read_one_line_file("/sys/class/dmi/id/chassis_type", &type);
203 if (r < 0)
204 return NULL;
205
206 r = safe_atou(type, &t);
207 free(type);
7640a5de
LP
208 if (r < 0)
209 return NULL;
210
211 /* We only list the really obvious cases here. The DMI data is
212 unreliable enough, so let's not do any additional guesswork
41550d40
LP
213 on top of that.
214
215 See the SMBIOS Specification 2.7.1 section 7.4.1 for
216 details about the values listed here:
217
218 http://www.dmtf.org/sites/default/files/standards/documents/DSP0134_2.7.1.pdf
219 */
7640a5de
LP
220
221 switch (t) {
222
223 case 0x3:
224 case 0x4:
225 case 0x6:
226 case 0x7:
7871c8e9 227 return "desktop";
7640a5de 228
7871c8e9 229 case 0x8:
7640a5de
LP
230 case 0x9:
231 case 0xA:
232 case 0xE:
7871c8e9
LP
233 return "laptop";
234
235 case 0xB:
236 return "handset";
7640a5de
LP
237
238 case 0x11:
41550d40 239 case 0x1C:
7871c8e9 240 return "server";
7640a5de
LP
241 }
242
7640a5de
LP
243 return NULL;
244}
245
66a4c743 246static char* context_fallback_icon_name(Context *c) {
7871c8e9
LP
247 const char *chassis;
248
66a4c743
LP
249 assert(c);
250
251 if (!isempty(c->data[PROP_CHASSIS]))
252 return strappend("computer-", c->data[PROP_CHASSIS]);
7871c8e9
LP
253
254 chassis = fallback_chassis();
255 if (chassis)
256 return strappend("computer-", chassis);
257
258 return strdup("computer");
259}
260
c779a442 261static bool hostname_is_useful(const char *hn) {
fecc80c1 262 return !isempty(hn) && !is_localhost(hn);
c779a442
SW
263}
264
265static int context_update_kernel_hostname(Context *c) {
266 const char *static_hn;
7640a5de
LP
267 const char *hn;
268
66a4c743
LP
269 assert(c);
270
c779a442
SW
271 static_hn = c->data[PROP_STATIC_HOSTNAME];
272
273 /* /etc/hostname with something other than "localhost"
274 * has the highest preference ... */
275 if (hostname_is_useful(static_hn))
276 hn = static_hn;
277
278 /* ... the transient host name, (ie: DHCP) comes next ...*/
279 else if (!isempty(c->data[PROP_HOSTNAME]))
66a4c743 280 hn = c->data[PROP_HOSTNAME];
7640a5de 281
c779a442
SW
282 /* ... fallback to static "localhost.*" ignored above ... */
283 else if (!isempty(static_hn))
284 hn = static_hn;
285
286 /* ... and the ultimate fallback */
287 else
288 hn = "localhost";
289
7640a5de
LP
290 if (sethostname(hn, strlen(hn)) < 0)
291 return -errno;
292
293 return 0;
294}
295
66a4c743 296static int context_write_data_static_hostname(Context *c) {
7640a5de 297
66a4c743
LP
298 assert(c);
299
300 if (isempty(c->data[PROP_STATIC_HOSTNAME])) {
7640a5de
LP
301
302 if (unlink("/etc/hostname") < 0)
303 return errno == ENOENT ? 0 : -errno;
304
305 return 0;
306 }
66a4c743 307 return write_string_file_atomic_label("/etc/hostname", c->data[PROP_STATIC_HOSTNAME]);
7640a5de
LP
308}
309
f200e8bb 310static int context_write_data_machine_info(Context *c) {
4f34ed54 311
7640a5de
LP
312 static const char * const name[_PROP_MAX] = {
313 [PROP_PRETTY_HOSTNAME] = "PRETTY_HOSTNAME",
7871c8e9
LP
314 [PROP_ICON_NAME] = "ICON_NAME",
315 [PROP_CHASSIS] = "CHASSIS"
7640a5de
LP
316 };
317
0ccad099 318 _cleanup_strv_free_ char **l = NULL;
7640a5de
LP
319 int r, p;
320
66a4c743
LP
321 assert(c);
322
717603e3 323 r = load_env_file(NULL, "/etc/machine-info", NULL, &l);
7640a5de
LP
324 if (r < 0 && r != -ENOENT)
325 return r;
326
f200e8bb 327 for (p = PROP_PRETTY_HOSTNAME; p <= PROP_CHASSIS; p++) {
7640a5de
LP
328 char *t, **u;
329
330 assert(name[p]);
331
66a4c743 332 if (isempty(c->data[p])) {
f8440af5 333 strv_env_unset(l, name[p]);
7640a5de
LP
334 continue;
335 }
336
0ccad099 337 if (asprintf(&t, "%s=%s", name[p], strempty(c->data[p])) < 0)
7640a5de 338 return -ENOMEM;
7640a5de
LP
339
340 u = strv_env_set(l, t);
341 free(t);
7640a5de
LP
342
343 if (!u)
344 return -ENOMEM;
0ccad099
LP
345
346 strv_free(l);
7640a5de
LP
347 l = u;
348 }
349
350 if (strv_isempty(l)) {
351
352 if (unlink("/etc/machine-info") < 0)
353 return errno == ENOENT ? 0 : -errno;
354
355 return 0;
356 }
357
0ccad099 358 return write_env_file_label("/etc/machine-info", l);
7640a5de
LP
359}
360
66a4c743
LP
361static int property_get_icon_name(
362 sd_bus *bus,
363 const char *path,
364 const char *interface,
365 const char *property,
366 sd_bus_message *reply,
ebcf1f97
LP
367 void *userdata,
368 sd_bus_error *error) {
7640a5de 369
66a4c743
LP
370 _cleanup_free_ char *n = NULL;
371 Context *c = userdata;
372 const char *name;
7640a5de 373
66a4c743
LP
374 if (isempty(c->data[PROP_ICON_NAME]))
375 name = n = context_fallback_icon_name(c);
7640a5de 376 else
66a4c743
LP
377 name = c->data[PROP_ICON_NAME];
378
379 if (!name)
380 return -ENOMEM;
7640a5de 381
ebcf1f97 382 return sd_bus_message_append(reply, "s", name);
7640a5de
LP
383}
384
66a4c743
LP
385static int property_get_chassis(
386 sd_bus *bus,
387 const char *path,
388 const char *interface,
389 const char *property,
390 sd_bus_message *reply,
ebcf1f97
LP
391 void *userdata,
392 sd_bus_error *error) {
7871c8e9 393
66a4c743
LP
394 Context *c = userdata;
395 const char *name;
7871c8e9 396
66a4c743 397 if (isempty(c->data[PROP_CHASSIS]))
7871c8e9
LP
398 name = fallback_chassis();
399 else
66a4c743 400 name = c->data[PROP_CHASSIS];
7871c8e9 401
ebcf1f97 402 return sd_bus_message_append(reply, "s", name);
7871c8e9
LP
403}
404
ebcf1f97 405static int method_set_hostname(sd_bus *bus, sd_bus_message *m, void *userdata, sd_bus_error *error) {
66a4c743
LP
406 Context *c = userdata;
407 const char *name;
102d8f81 408 int interactive;
66a4c743
LP
409 char *h;
410 int r;
d200735e 411
66a4c743
LP
412 r = sd_bus_message_read(m, "sb", &name, &interactive);
413 if (r < 0)
ebcf1f97 414 return r;
d200735e 415
66a4c743
LP
416 if (isempty(name))
417 name = c->data[PROP_STATIC_HOSTNAME];
7640a5de 418
66a4c743
LP
419 if (isempty(name))
420 name = "localhost";
7640a5de 421
66a4c743 422 if (!hostname_is_valid(name))
ebcf1f97 423 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid hostname '%s'", name);
7640a5de 424
66a4c743 425 if (streq_ptr(name, c->data[PROP_HOSTNAME]))
df2d202e 426 return sd_bus_reply_method_return(m, NULL);
7640a5de 427
ebcf1f97 428 r = bus_verify_polkit_async(bus, &c->polkit_registry, m, "org.freedesktop.hostname1.set-hostname", interactive, error, method_set_hostname, c);
66a4c743 429 if (r < 0)
ebcf1f97 430 return r;
66a4c743
LP
431 if (r == 0)
432 return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
7640a5de 433
66a4c743
LP
434 h = strdup(name);
435 if (!h)
ebcf1f97 436 return -ENOMEM;
7640a5de 437
66a4c743
LP
438 free(c->data[PROP_HOSTNAME]);
439 c->data[PROP_HOSTNAME] = h;
7640a5de 440
c779a442 441 r = context_update_kernel_hostname(c);
66a4c743
LP
442 if (r < 0) {
443 log_error("Failed to set host name: %s", strerror(-r));
ebcf1f97 444 return sd_bus_error_set_errnof(error, r, "Failed to set hostname: %s", strerror(-r));
66a4c743 445 }
7640a5de 446
66a4c743 447 log_info("Changed host name to '%s'", strna(c->data[PROP_HOSTNAME]));
7640a5de 448
66a4c743 449 sd_bus_emit_properties_changed(bus, "/org/freedesktop/hostname1", "org.freedesktop.hostname1", "Hostname", NULL);
7640a5de 450
df2d202e 451 return sd_bus_reply_method_return(m, NULL);
66a4c743 452}
7640a5de 453
ebcf1f97 454static int method_set_static_hostname(sd_bus *bus, sd_bus_message *m, void *userdata, sd_bus_error *error) {
66a4c743
LP
455 Context *c = userdata;
456 const char *name;
102d8f81 457 int interactive;
66a4c743 458 int r;
7640a5de 459
66a4c743
LP
460 r = sd_bus_message_read(m, "sb", &name, &interactive);
461 if (r < 0)
ebcf1f97 462 return r;
7640a5de 463
66a4c743
LP
464 if (isempty(name))
465 name = NULL;
7640a5de 466
66a4c743 467 if (streq_ptr(name, c->data[PROP_STATIC_HOSTNAME]))
df2d202e 468 return sd_bus_reply_method_return(m, NULL);
7640a5de 469
ebcf1f97 470 r = bus_verify_polkit_async(bus, &c->polkit_registry, m, "org.freedesktop.hostname1.set-static-hostname", interactive, error, method_set_static_hostname, c);
66a4c743 471 if (r < 0)
ebcf1f97 472 return r;
66a4c743
LP
473 if (r == 0)
474 return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
7640a5de 475
66a4c743
LP
476 if (isempty(name)) {
477 free(c->data[PROP_STATIC_HOSTNAME]);
478 c->data[PROP_STATIC_HOSTNAME] = NULL;
479 } else {
480 char *h;
7640a5de 481
66a4c743 482 if (!hostname_is_valid(name))
ebcf1f97 483 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid static hostname '%s'", name);
7640a5de 484
66a4c743
LP
485 h = strdup(name);
486 if (!h)
ebcf1f97 487 return -ENOMEM;
7640a5de 488
66a4c743
LP
489 free(c->data[PROP_STATIC_HOSTNAME]);
490 c->data[PROP_STATIC_HOSTNAME] = h;
491 }
7640a5de 492
c779a442
SW
493 r = context_update_kernel_hostname(c);
494 if (r < 0) {
495 log_error("Failed to set host name: %s", strerror(-r));
496 return sd_bus_error_set_errnof(error, r, "Failed to set hostname: %s", strerror(-r));
497 }
498
66a4c743
LP
499 r = context_write_data_static_hostname(c);
500 if (r < 0) {
501 log_error("Failed to write static host name: %s", strerror(-r));
ebcf1f97 502 return sd_bus_error_set_errnof(error, r, "Failed to set static hostname: %s", strerror(-r));
66a4c743 503 }
7640a5de 504
66a4c743 505 log_info("Changed static host name to '%s'", strna(c->data[PROP_STATIC_HOSTNAME]));
7640a5de 506
66a4c743 507 sd_bus_emit_properties_changed(bus, "/org/freedesktop/hostname1", "org.freedesktop.hostname1", "StaticHostname", NULL);
7640a5de 508
df2d202e 509 return sd_bus_reply_method_return(m, NULL);
66a4c743 510}
7640a5de 511
ebcf1f97 512static 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 513 int interactive;
66a4c743
LP
514 const char *name;
515 int r;
516
517 assert(c);
518 assert(bus);
519 assert(m);
520
521 r = sd_bus_message_read(m, "sb", &name, &interactive);
522 if (r < 0)
ebcf1f97 523 return r;
66a4c743
LP
524
525 if (isempty(name))
526 name = NULL;
527
528 if (streq_ptr(name, c->data[prop]))
df2d202e 529 return sd_bus_reply_method_return(m, NULL);
7640a5de 530
66a4c743
LP
531 /* Since the pretty hostname should always be changed at the
532 * same time as the static one, use the same policy action for
533 * both... */
534
535 r = bus_verify_polkit_async(bus, &c->polkit_registry, m, prop == PROP_PRETTY_HOSTNAME ?
536 "org.freedesktop.hostname1.set-static-hostname" :
ebcf1f97 537 "org.freedesktop.hostname1.set-machine-info", interactive, error, cb, c);
66a4c743 538 if (r < 0)
ebcf1f97 539 return r;
66a4c743
LP
540 if (r == 0)
541 return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
542
543 if (isempty(name)) {
544 free(c->data[prop]);
545 c->data[prop] = NULL;
546 } else {
547 char *h;
548
549 /* The icon name might ultimately be used as file
550 * name, so better be safe than sorry */
551
552 if (prop == PROP_ICON_NAME && !filename_is_safe(name))
ebcf1f97 553 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid icon name '%s'", name);
6294aa76 554 if (prop == PROP_PRETTY_HOSTNAME && string_has_cc(name, NULL))
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}