]> git.proxmox.com Git - systemd.git/blame - src/hostname/hostnamed.c
Imported Upstream version 218
[systemd.git] / src / hostname / hostnamed.c
CommitLineData
663996b3
MS
1/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3/***
4 This file is part of systemd.
5
6 Copyright 2011 Lennart Poettering
7
8 systemd is free software; you can redistribute it and/or modify it
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
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
16 Lesser General Public License for more details.
17
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
20***/
21
663996b3
MS
22#include <errno.h>
23#include <string.h>
24#include <unistd.h>
60f067b4 25#include <sys/utsname.h>
5eef597e 26#include <sys/capability.h>
663996b3
MS
27
28#include "util.h"
29#include "strv.h"
663996b3
MS
30#include "def.h"
31#include "virt.h"
32#include "env-util.h"
33#include "fileio-label.h"
34#include "label.h"
60f067b4
JS
35#include "bus-util.h"
36#include "event-util.h"
663996b3 37
5eef597e
MP
38#define VALID_DEPLOYMENT_CHARS (DIGITS LETTERS "-.:")
39
663996b3
MS
40enum {
41 PROP_HOSTNAME,
42 PROP_STATIC_HOSTNAME,
43 PROP_PRETTY_HOSTNAME,
44 PROP_ICON_NAME,
45 PROP_CHASSIS,
5eef597e
MP
46 PROP_DEPLOYMENT,
47 PROP_LOCATION,
60f067b4
JS
48 PROP_KERNEL_NAME,
49 PROP_KERNEL_RELEASE,
50 PROP_KERNEL_VERSION,
51 PROP_OS_PRETTY_NAME,
52 PROP_OS_CPE_NAME,
663996b3
MS
53 _PROP_MAX
54};
55
60f067b4
JS
56typedef struct Context {
57 char *data[_PROP_MAX];
58 Hashmap *polkit_registry;
59} Context;
663996b3 60
60f067b4 61static void context_reset(Context *c) {
663996b3
MS
62 int p;
63
60f067b4
JS
64 assert(c);
65
663996b3 66 for (p = 0; p < _PROP_MAX; p++) {
60f067b4
JS
67 free(c->data[p]);
68 c->data[p] = NULL;
663996b3
MS
69 }
70}
71
5eef597e 72static void context_free(Context *c) {
60f067b4
JS
73 assert(c);
74
75 context_reset(c);
5eef597e 76 bus_verify_polkit_async_registry_free(c->polkit_registry);
60f067b4
JS
77}
78
79static int context_read_data(Context *c) {
663996b3 80 int r;
60f067b4 81 struct utsname u;
663996b3 82
60f067b4 83 assert(c);
663996b3 84
60f067b4
JS
85 context_reset(c);
86
87 assert_se(uname(&u) >= 0);
88 c->data[PROP_KERNEL_NAME] = strdup(u.sysname);
89 c->data[PROP_KERNEL_RELEASE] = strdup(u.release);
90 c->data[PROP_KERNEL_VERSION] = strdup(u.version);
91 if (!c->data[PROP_KERNEL_NAME] || !c->data[PROP_KERNEL_RELEASE] ||
92 !c->data[PROP_KERNEL_VERSION])
93 return -ENOMEM;
94
95 c->data[PROP_HOSTNAME] = gethostname_malloc();
96 if (!c->data[PROP_HOSTNAME])
663996b3
MS
97 return -ENOMEM;
98
60f067b4 99 r = read_one_line_file("/etc/hostname", &c->data[PROP_STATIC_HOSTNAME]);
663996b3
MS
100 if (r < 0 && r != -ENOENT)
101 return r;
102
103 r = parse_env_file("/etc/machine-info", NEWLINE,
60f067b4
JS
104 "PRETTY_HOSTNAME", &c->data[PROP_PRETTY_HOSTNAME],
105 "ICON_NAME", &c->data[PROP_ICON_NAME],
106 "CHASSIS", &c->data[PROP_CHASSIS],
5eef597e
MP
107 "DEPLOYMENT", &c->data[PROP_DEPLOYMENT],
108 "LOCATION", &c->data[PROP_LOCATION],
60f067b4
JS
109 NULL);
110 if (r < 0 && r != -ENOENT)
111 return r;
112
113 r = parse_env_file("/etc/os-release", NEWLINE,
114 "PRETTY_NAME", &c->data[PROP_OS_PRETTY_NAME],
115 "CPE_NAME", &c->data[PROP_OS_CPE_NAME],
663996b3 116 NULL);
e842803a
MB
117 if (r == -ENOENT) {
118 r = parse_env_file("/usr/lib/os-release", NEWLINE,
119 "PRETTY_NAME", &c->data[PROP_OS_PRETTY_NAME],
120 "CPE_NAME", &c->data[PROP_OS_CPE_NAME],
121 NULL);
122 }
123
663996b3
MS
124 if (r < 0 && r != -ENOENT)
125 return r;
126
127 return 0;
128}
129
663996b3 130static bool valid_chassis(const char *chassis) {
663996b3
MS
131 assert(chassis);
132
133 return nulstr_contains(
134 "vm\0"
135 "container\0"
136 "desktop\0"
137 "laptop\0"
138 "server\0"
139 "tablet\0"
5eef597e 140 "handset\0"
f47781d8
MP
141 "watch\0"
142 "embedded\0",
663996b3
MS
143 chassis);
144}
145
5eef597e
MP
146static bool valid_deployment(const char *deployment) {
147 assert(deployment);
148
149 return in_charset(deployment, VALID_DEPLOYMENT_CHARS);
150}
151
663996b3
MS
152static const char* fallback_chassis(void) {
153 int r;
154 char *type;
155 unsigned t;
60f067b4 156 int v;
663996b3
MS
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";
191
192 case 4:
193 case 5:
194 case 7:
195 return "server";
196
197 case 8:
198 return "tablet";
199 }
200
201try_dmi:
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);
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
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 */
220
221 switch (t) {
222
223 case 0x3:
224 case 0x4:
225 case 0x6:
226 case 0x7:
227 return "desktop";
228
229 case 0x8:
230 case 0x9:
231 case 0xA:
232 case 0xE:
233 return "laptop";
234
235 case 0xB:
236 return "handset";
237
238 case 0x11:
239 case 0x1C:
240 return "server";
241 }
242
243 return NULL;
244}
245
60f067b4 246static char* context_fallback_icon_name(Context *c) {
663996b3
MS
247 const char *chassis;
248
60f067b4
JS
249 assert(c);
250
251 if (!isempty(c->data[PROP_CHASSIS]))
252 return strappend("computer-", c->data[PROP_CHASSIS]);
663996b3
MS
253
254 chassis = fallback_chassis();
255 if (chassis)
256 return strappend("computer-", chassis);
257
258 return strdup("computer");
259}
260
5eef597e 261
60f067b4 262static bool hostname_is_useful(const char *hn) {
e842803a 263 return !isempty(hn) && !is_localhost(hn);
60f067b4
JS
264}
265
266static int context_update_kernel_hostname(Context *c) {
267 const char *static_hn;
663996b3
MS
268 const char *hn;
269
60f067b4
JS
270 assert(c);
271
272 static_hn = c->data[PROP_STATIC_HOSTNAME];
273
274 /* /etc/hostname with something other than "localhost"
275 * has the highest preference ... */
276 if (hostname_is_useful(static_hn))
277 hn = static_hn;
278
279 /* ... the transient host name, (ie: DHCP) comes next ...*/
280 else if (!isempty(c->data[PROP_HOSTNAME]))
281 hn = c->data[PROP_HOSTNAME];
282
283 /* ... fallback to static "localhost.*" ignored above ... */
284 else if (!isempty(static_hn))
285 hn = static_hn;
286
287 /* ... and the ultimate fallback */
663996b3 288 else
60f067b4 289 hn = "localhost";
663996b3 290
5eef597e 291 if (sethostname_idempotent(hn) < 0)
663996b3
MS
292 return -errno;
293
294 return 0;
295}
296
60f067b4
JS
297static int context_write_data_static_hostname(Context *c) {
298
299 assert(c);
663996b3 300
60f067b4 301 if (isempty(c->data[PROP_STATIC_HOSTNAME])) {
663996b3
MS
302
303 if (unlink("/etc/hostname") < 0)
304 return errno == ENOENT ? 0 : -errno;
305
306 return 0;
307 }
60f067b4 308 return write_string_file_atomic_label("/etc/hostname", c->data[PROP_STATIC_HOSTNAME]);
663996b3
MS
309}
310
60f067b4 311static int context_write_data_machine_info(Context *c) {
663996b3
MS
312
313 static const char * const name[_PROP_MAX] = {
314 [PROP_PRETTY_HOSTNAME] = "PRETTY_HOSTNAME",
315 [PROP_ICON_NAME] = "ICON_NAME",
5eef597e
MP
316 [PROP_CHASSIS] = "CHASSIS",
317 [PROP_DEPLOYMENT] = "DEPLOYMENT",
318 [PROP_LOCATION] = "LOCATION",
663996b3
MS
319 };
320
60f067b4 321 _cleanup_strv_free_ char **l = NULL;
663996b3
MS
322 int r, p;
323
60f067b4
JS
324 assert(c);
325
e842803a 326 r = load_env_file(NULL, "/etc/machine-info", NULL, &l);
663996b3
MS
327 if (r < 0 && r != -ENOENT)
328 return r;
329
5eef597e
MP
330 for (p = PROP_PRETTY_HOSTNAME; p <= PROP_LOCATION; p++) {
331 _cleanup_free_ char *t = NULL;
332 char **u;
663996b3
MS
333
334 assert(name[p]);
335
60f067b4 336 if (isempty(c->data[p])) {
663996b3
MS
337 strv_env_unset(l, name[p]);
338 continue;
339 }
340
5eef597e
MP
341 t = strjoin(name[p], "=", c->data[p], NULL);
342 if (!t)
663996b3 343 return -ENOMEM;
663996b3
MS
344
345 u = strv_env_set(l, t);
663996b3
MS
346 if (!u)
347 return -ENOMEM;
60f067b4
JS
348
349 strv_free(l);
663996b3
MS
350 l = u;
351 }
352
353 if (strv_isempty(l)) {
663996b3
MS
354 if (unlink("/etc/machine-info") < 0)
355 return errno == ENOENT ? 0 : -errno;
356
357 return 0;
358 }
359
60f067b4 360 return write_env_file_label("/etc/machine-info", l);
663996b3
MS
361}
362
60f067b4
JS
363static int property_get_icon_name(
364 sd_bus *bus,
365 const char *path,
366 const char *interface,
367 const char *property,
368 sd_bus_message *reply,
369 void *userdata,
370 sd_bus_error *error) {
663996b3 371
60f067b4
JS
372 _cleanup_free_ char *n = NULL;
373 Context *c = userdata;
374 const char *name;
663996b3 375
60f067b4
JS
376 if (isempty(c->data[PROP_ICON_NAME]))
377 name = n = context_fallback_icon_name(c);
663996b3 378 else
60f067b4 379 name = c->data[PROP_ICON_NAME];
663996b3 380
60f067b4
JS
381 if (!name)
382 return -ENOMEM;
383
384 return sd_bus_message_append(reply, "s", name);
663996b3
MS
385}
386
60f067b4
JS
387static int property_get_chassis(
388 sd_bus *bus,
389 const char *path,
390 const char *interface,
391 const char *property,
392 sd_bus_message *reply,
393 void *userdata,
394 sd_bus_error *error) {
663996b3 395
60f067b4
JS
396 Context *c = userdata;
397 const char *name;
663996b3 398
60f067b4 399 if (isempty(c->data[PROP_CHASSIS]))
663996b3
MS
400 name = fallback_chassis();
401 else
60f067b4 402 name = c->data[PROP_CHASSIS];
663996b3 403
60f067b4 404 return sd_bus_message_append(reply, "s", name);
663996b3
MS
405}
406
60f067b4
JS
407static int method_set_hostname(sd_bus *bus, sd_bus_message *m, void *userdata, sd_bus_error *error) {
408 Context *c = userdata;
409 const char *name;
410 int interactive;
411 char *h;
412 int r;
663996b3 413
60f067b4
JS
414 r = sd_bus_message_read(m, "sb", &name, &interactive);
415 if (r < 0)
416 return r;
663996b3 417
60f067b4
JS
418 if (isempty(name))
419 name = c->data[PROP_STATIC_HOSTNAME];
663996b3 420
60f067b4
JS
421 if (isempty(name))
422 name = "localhost";
663996b3 423
60f067b4
JS
424 if (!hostname_is_valid(name))
425 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid hostname '%s'", name);
426
427 if (streq_ptr(name, c->data[PROP_HOSTNAME]))
428 return sd_bus_reply_method_return(m, NULL);
663996b3 429
5eef597e 430 r = bus_verify_polkit_async(m, CAP_SYS_ADMIN, "org.freedesktop.hostname1.set-hostname", interactive, &c->polkit_registry, error);
60f067b4
JS
431 if (r < 0)
432 return r;
433 if (r == 0)
434 return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
435
436 h = strdup(name);
437 if (!h)
438 return -ENOMEM;
439
440 free(c->data[PROP_HOSTNAME]);
441 c->data[PROP_HOSTNAME] = h;
442
443 r = context_update_kernel_hostname(c);
444 if (r < 0) {
f47781d8 445 log_error_errno(r, "Failed to set host name: %m");
60f067b4
JS
446 return sd_bus_error_set_errnof(error, r, "Failed to set hostname: %s", strerror(-r));
447 }
663996b3 448
60f067b4 449 log_info("Changed host name to '%s'", strna(c->data[PROP_HOSTNAME]));
663996b3 450
60f067b4 451 sd_bus_emit_properties_changed(bus, "/org/freedesktop/hostname1", "org.freedesktop.hostname1", "Hostname", NULL);
663996b3 452
60f067b4
JS
453 return sd_bus_reply_method_return(m, NULL);
454}
455
456static int method_set_static_hostname(sd_bus *bus, sd_bus_message *m, void *userdata, sd_bus_error *error) {
457 Context *c = userdata;
458 const char *name;
459 int interactive;
460 int r;
663996b3 461
60f067b4
JS
462 r = sd_bus_message_read(m, "sb", &name, &interactive);
463 if (r < 0)
464 return r;
663996b3 465
60f067b4
JS
466 if (isempty(name))
467 name = NULL;
468
469 if (streq_ptr(name, c->data[PROP_STATIC_HOSTNAME]))
470 return sd_bus_reply_method_return(m, NULL);
471
5eef597e 472 r = bus_verify_polkit_async(m, CAP_SYS_ADMIN, "org.freedesktop.hostname1.set-static-hostname", interactive, &c->polkit_registry, error);
60f067b4
JS
473 if (r < 0)
474 return r;
475 if (r == 0)
476 return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
477
478 if (isempty(name)) {
479 free(c->data[PROP_STATIC_HOSTNAME]);
480 c->data[PROP_STATIC_HOSTNAME] = NULL;
481 } else {
482 char *h;
663996b3
MS
483
484 if (!hostname_is_valid(name))
60f067b4 485 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid static hostname '%s'", name);
663996b3 486
60f067b4
JS
487 h = strdup(name);
488 if (!h)
489 return -ENOMEM;
663996b3 490
60f067b4
JS
491 free(c->data[PROP_STATIC_HOSTNAME]);
492 c->data[PROP_STATIC_HOSTNAME] = h;
493 }
663996b3 494
60f067b4
JS
495 r = context_update_kernel_hostname(c);
496 if (r < 0) {
f47781d8 497 log_error_errno(r, "Failed to set host name: %m");
60f067b4
JS
498 return sd_bus_error_set_errnof(error, r, "Failed to set hostname: %s", strerror(-r));
499 }
663996b3 500
60f067b4
JS
501 r = context_write_data_static_hostname(c);
502 if (r < 0) {
f47781d8 503 log_error_errno(r, "Failed to write static host name: %m");
60f067b4
JS
504 return sd_bus_error_set_errnof(error, r, "Failed to set static hostname: %s", strerror(-r));
505 }
663996b3 506
60f067b4 507 log_info("Changed static host name to '%s'", strna(c->data[PROP_STATIC_HOSTNAME]));
663996b3 508
60f067b4 509 sd_bus_emit_properties_changed(bus, "/org/freedesktop/hostname1", "org.freedesktop.hostname1", "StaticHostname", NULL);
663996b3 510
60f067b4
JS
511 return sd_bus_reply_method_return(m, NULL);
512}
663996b3 513
60f067b4
JS
514static 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) {
515 int interactive;
516 const char *name;
517 int r;
663996b3 518
60f067b4
JS
519 assert(c);
520 assert(bus);
521 assert(m);
663996b3 522
60f067b4
JS
523 r = sd_bus_message_read(m, "sb", &name, &interactive);
524 if (r < 0)
525 return r;
663996b3 526
60f067b4
JS
527 if (isempty(name))
528 name = NULL;
663996b3 529
60f067b4
JS
530 if (streq_ptr(name, c->data[prop]))
531 return sd_bus_reply_method_return(m, NULL);
663996b3 532
60f067b4
JS
533 /* Since the pretty hostname should always be changed at the
534 * same time as the static one, use the same policy action for
535 * both... */
663996b3 536
5eef597e
MP
537 r = bus_verify_polkit_async(m, CAP_SYS_ADMIN,
538 prop == PROP_PRETTY_HOSTNAME ?
539 "org.freedesktop.hostname1.set-static-hostname" :
540 "org.freedesktop.hostname1.set-machine-info", interactive, &c->polkit_registry, error);
60f067b4
JS
541 if (r < 0)
542 return r;
543 if (r == 0)
544 return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
545
546 if (isempty(name)) {
547 free(c->data[prop]);
548 c->data[prop] = NULL;
549 } else {
550 char *h;
551
552 /* The icon name might ultimately be used as file
553 * name, so better be safe than sorry */
554
555 if (prop == PROP_ICON_NAME && !filename_is_safe(name))
556 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid icon name '%s'", name);
5eef597e 557 if (prop == PROP_PRETTY_HOSTNAME && string_has_cc(name, NULL))
60f067b4
JS
558 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid pretty host name '%s'", name);
559 if (prop == PROP_CHASSIS && !valid_chassis(name))
560 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid chassis '%s'", name);
5eef597e
MP
561 if (prop == PROP_DEPLOYMENT && !valid_deployment(name))
562 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid deployment '%s'", name);
563 if (prop == PROP_LOCATION && string_has_cc(name, NULL))
564 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid location '%s'", name);
60f067b4
JS
565
566 h = strdup(name);
567 if (!h)
568 return -ENOMEM;
663996b3 569
60f067b4
JS
570 free(c->data[prop]);
571 c->data[prop] = h;
572 }
663996b3 573
60f067b4
JS
574 r = context_write_data_machine_info(c);
575 if (r < 0) {
f47781d8 576 log_error_errno(r, "Failed to write machine info: %m");
60f067b4 577 return sd_bus_error_set_errnof(error, r, "Failed to write machine info: %s", strerror(-r));
663996b3
MS
578 }
579
60f067b4
JS
580 log_info("Changed %s to '%s'",
581 prop == PROP_PRETTY_HOSTNAME ? "pretty host name" :
5eef597e
MP
582 prop == PROP_DEPLOYMENT ? "deployment" :
583 prop == PROP_LOCATION ? "location" :
60f067b4 584 prop == PROP_CHASSIS ? "chassis" : "icon name", strna(c->data[prop]));
663996b3 585
60f067b4
JS
586 sd_bus_emit_properties_changed(bus, "/org/freedesktop/hostname1", "org.freedesktop.hostname1",
587 prop == PROP_PRETTY_HOSTNAME ? "PrettyHostname" :
5eef597e
MP
588 prop == PROP_DEPLOYMENT ? "Deployment" :
589 prop == PROP_LOCATION ? "Location" :
590 prop == PROP_CHASSIS ? "Chassis" : "IconName" , NULL);
60f067b4
JS
591
592 return sd_bus_reply_method_return(m, NULL);
593}
663996b3 594
60f067b4
JS
595static int method_set_pretty_hostname(sd_bus *bus, sd_bus_message *m, void *userdata, sd_bus_error *error) {
596 return set_machine_info(userdata, bus, m, PROP_PRETTY_HOSTNAME, method_set_pretty_hostname, error);
597}
663996b3 598
60f067b4
JS
599static int method_set_icon_name(sd_bus *bus, sd_bus_message *m, void *userdata, sd_bus_error *error) {
600 return set_machine_info(userdata, bus, m, PROP_ICON_NAME, method_set_icon_name, error);
601}
663996b3 602
60f067b4
JS
603static int method_set_chassis(sd_bus *bus, sd_bus_message *m, void *userdata, sd_bus_error *error) {
604 return set_machine_info(userdata, bus, m, PROP_CHASSIS, method_set_chassis, error);
663996b3
MS
605}
606
5eef597e
MP
607static int method_set_deployment(sd_bus *bus, sd_bus_message *m, void *userdata, sd_bus_error *error) {
608 return set_machine_info(userdata, bus, m, PROP_DEPLOYMENT, method_set_deployment, error);
609}
610
611static int method_set_location(sd_bus *bus, sd_bus_message *m, void *userdata, sd_bus_error *error) {
612 return set_machine_info(userdata, bus, m, PROP_LOCATION, method_set_location, error);
613}
614
60f067b4
JS
615static const sd_bus_vtable hostname_vtable[] = {
616 SD_BUS_VTABLE_START(0),
5eef597e 617 SD_BUS_PROPERTY("Hostname", "s", NULL, offsetof(Context, data) + sizeof(char*) * PROP_HOSTNAME, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
60f067b4
JS
618 SD_BUS_PROPERTY("StaticHostname", "s", NULL, offsetof(Context, data) + sizeof(char*) * PROP_STATIC_HOSTNAME, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
619 SD_BUS_PROPERTY("PrettyHostname", "s", NULL, offsetof(Context, data) + sizeof(char*) * PROP_PRETTY_HOSTNAME, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
620 SD_BUS_PROPERTY("IconName", "s", property_get_icon_name, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
621 SD_BUS_PROPERTY("Chassis", "s", property_get_chassis, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
5eef597e
MP
622 SD_BUS_PROPERTY("Deployment", "s", NULL, offsetof(Context, data) + sizeof(char*) * PROP_DEPLOYMENT, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
623 SD_BUS_PROPERTY("Location", "s", NULL, offsetof(Context, data) + sizeof(char*) * PROP_LOCATION, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
60f067b4
JS
624 SD_BUS_PROPERTY("KernelName", "s", NULL, offsetof(Context, data) + sizeof(char*) * PROP_KERNEL_NAME, SD_BUS_VTABLE_PROPERTY_CONST),
625 SD_BUS_PROPERTY("KernelRelease", "s", NULL, offsetof(Context, data) + sizeof(char*) * PROP_KERNEL_RELEASE, SD_BUS_VTABLE_PROPERTY_CONST),
626 SD_BUS_PROPERTY("KernelVersion", "s", NULL, offsetof(Context, data) + sizeof(char*) * PROP_KERNEL_VERSION, SD_BUS_VTABLE_PROPERTY_CONST),
627 SD_BUS_PROPERTY("OperatingSystemPrettyName", "s", NULL, offsetof(Context, data) + sizeof(char*) * PROP_OS_PRETTY_NAME, SD_BUS_VTABLE_PROPERTY_CONST),
628 SD_BUS_PROPERTY("OperatingSystemCPEName", "s", NULL, offsetof(Context, data) + sizeof(char*) * PROP_OS_CPE_NAME, SD_BUS_VTABLE_PROPERTY_CONST),
629 SD_BUS_METHOD("SetHostname", "sb", NULL, method_set_hostname, SD_BUS_VTABLE_UNPRIVILEGED),
630 SD_BUS_METHOD("SetStaticHostname", "sb", NULL, method_set_static_hostname, SD_BUS_VTABLE_UNPRIVILEGED),
631 SD_BUS_METHOD("SetPrettyHostname", "sb", NULL, method_set_pretty_hostname, SD_BUS_VTABLE_UNPRIVILEGED),
632 SD_BUS_METHOD("SetIconName", "sb", NULL, method_set_icon_name, SD_BUS_VTABLE_UNPRIVILEGED),
633 SD_BUS_METHOD("SetChassis", "sb", NULL, method_set_chassis, SD_BUS_VTABLE_UNPRIVILEGED),
5eef597e
MP
634 SD_BUS_METHOD("SetDeployment", "sb", NULL, method_set_deployment, SD_BUS_VTABLE_UNPRIVILEGED),
635 SD_BUS_METHOD("SetLocation", "sb", NULL, method_set_location, SD_BUS_VTABLE_UNPRIVILEGED),
60f067b4
JS
636 SD_BUS_VTABLE_END,
637};
638
639static int connect_bus(Context *c, sd_event *event, sd_bus **_bus) {
5eef597e 640 _cleanup_bus_close_unref_ sd_bus *bus = NULL;
663996b3
MS
641 int r;
642
60f067b4
JS
643 assert(c);
644 assert(event);
663996b3
MS
645 assert(_bus);
646
60f067b4 647 r = sd_bus_default_system(&bus);
f47781d8
MP
648 if (r < 0)
649 return log_error_errno(r, "Failed to get system bus connection: %m");
663996b3 650
60f067b4 651 r = sd_bus_add_object_vtable(bus, NULL, "/org/freedesktop/hostname1", "org.freedesktop.hostname1", hostname_vtable, c);
f47781d8
MP
652 if (r < 0)
653 return log_error_errno(r, "Failed to register object: %m");
663996b3 654
60f067b4 655 r = sd_bus_request_name(bus, "org.freedesktop.hostname1", 0);
f47781d8
MP
656 if (r < 0)
657 return log_error_errno(r, "Failed to register name: %m");
663996b3 658
60f067b4 659 r = sd_bus_attach_event(bus, event, 0);
f47781d8
MP
660 if (r < 0)
661 return log_error_errno(r, "Failed to attach bus to event loop: %m");
663996b3 662
60f067b4
JS
663 *_bus = bus;
664 bus = NULL;
663996b3
MS
665
666 return 0;
663996b3
MS
667}
668
669int main(int argc, char *argv[]) {
60f067b4 670 Context context = {};
60f067b4 671 _cleanup_event_unref_ sd_event *event = NULL;
5eef597e 672 _cleanup_bus_close_unref_ sd_bus *bus = NULL;
663996b3 673 int r;
663996b3
MS
674
675 log_set_target(LOG_TARGET_AUTO);
676 log_parse_environment();
677 log_open();
678
679 umask(0022);
5eef597e 680 mac_selinux_init("/etc");
663996b3 681
663996b3
MS
682 if (argc != 1) {
683 log_error("This program takes no arguments.");
684 r = -EINVAL;
685 goto finish;
686 }
687
60f067b4
JS
688 if (argc != 1) {
689 log_error("This program takes no arguments.");
690 r = -EINVAL;
663996b3
MS
691 goto finish;
692 }
693
60f067b4
JS
694 r = sd_event_default(&event);
695 if (r < 0) {
f47781d8 696 log_error_errno(r, "Failed to allocate event loop: %m");
663996b3 697 goto finish;
60f067b4 698 }
663996b3 699
60f067b4 700 sd_event_set_watchdog(event, true);
663996b3 701
60f067b4
JS
702 r = connect_bus(&context, event, &bus);
703 if (r < 0)
704 goto finish;
663996b3 705
60f067b4
JS
706 r = context_read_data(&context);
707 if (r < 0) {
f47781d8 708 log_error_errno(r, "Failed to read hostname and machine information: %m");
60f067b4 709 goto finish;
663996b3
MS
710 }
711
60f067b4
JS
712 r = bus_event_loop_with_idle(event, bus, "org.freedesktop.hostname1", DEFAULT_EXIT_USEC, NULL, NULL);
713 if (r < 0) {
f47781d8 714 log_error_errno(r, "Failed to run event loop: %m");
60f067b4
JS
715 goto finish;
716 }
663996b3
MS
717
718finish:
5eef597e 719 context_free(&context);
663996b3
MS
720
721 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
722}