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