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