]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/hostname/hostnamed.c
bus: always explicitly close bus from main programs
[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>
f426cc5d 25#include <sys/utsname.h>
7640a5de
LP
26
27#include "util.h"
28#include "strv.h"
ad740100 29#include "def.h"
b52aae1d 30#include "virt.h"
4d1a6904 31#include "env-util.h"
a5c32cff
HH
32#include "fileio-label.h"
33#include "label.h"
66a4c743
LP
34#include "bus-util.h"
35#include "event-util.h"
91f9dcaf 36
799298d6
JG
37#define VALID_DEPLOYMENT_CHARS (DIGITS LETTERS "-.:")
38
7640a5de
LP
39enum {
40 PROP_HOSTNAME,
41 PROP_STATIC_HOSTNAME,
42 PROP_PRETTY_HOSTNAME,
43 PROP_ICON_NAME,
7871c8e9 44 PROP_CHASSIS,
799298d6 45 PROP_DEPLOYMENT,
ce0f1493 46 PROP_LOCATION,
f426cc5d
DH
47 PROP_KERNEL_NAME,
48 PROP_KERNEL_RELEASE,
9be3455f 49 PROP_KERNEL_VERSION,
44c32988
DH
50 PROP_OS_PRETTY_NAME,
51 PROP_OS_CPE_NAME,
7640a5de
LP
52 _PROP_MAX
53};
54
66a4c743
LP
55typedef struct Context {
56 char *data[_PROP_MAX];
57 Hashmap *polkit_registry;
58} Context;
ad740100 59
66a4c743 60static void context_reset(Context *c) {
7640a5de
LP
61 int p;
62
66a4c743
LP
63 assert(c);
64
7640a5de 65 for (p = 0; p < _PROP_MAX; p++) {
66a4c743
LP
66 free(c->data[p]);
67 c->data[p] = NULL;
7640a5de
LP
68 }
69}
70
66a4c743
LP
71static void context_free(Context *c, sd_bus *bus) {
72 assert(c);
73
74 context_reset(c);
75 bus_verify_polkit_async_registry_free(bus, c->polkit_registry);
76}
77
78static int context_read_data(Context *c) {
7640a5de 79 int r;
f426cc5d 80 struct utsname u;
7640a5de 81
66a4c743
LP
82 assert(c);
83
84 context_reset(c);
7640a5de 85
f426cc5d
DH
86 assert_se(uname(&u) >= 0);
87 c->data[PROP_KERNEL_NAME] = strdup(u.sysname);
88 c->data[PROP_KERNEL_RELEASE] = strdup(u.release);
9be3455f
DH
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])
f426cc5d
DH
92 return -ENOMEM;
93
66a4c743
LP
94 c->data[PROP_HOSTNAME] = gethostname_malloc();
95 if (!c->data[PROP_HOSTNAME])
7640a5de
LP
96 return -ENOMEM;
97
66a4c743 98 r = read_one_line_file("/etc/hostname", &c->data[PROP_STATIC_HOSTNAME]);
7640a5de
LP
99 if (r < 0 && r != -ENOENT)
100 return r;
101
102 r = parse_env_file("/etc/machine-info", NEWLINE,
66a4c743
LP
103 "PRETTY_HOSTNAME", &c->data[PROP_PRETTY_HOSTNAME],
104 "ICON_NAME", &c->data[PROP_ICON_NAME],
105 "CHASSIS", &c->data[PROP_CHASSIS],
799298d6 106 "DEPLOYMENT", &c->data[PROP_DEPLOYMENT],
ce0f1493 107 "LOCATION", &c->data[PROP_LOCATION],
7640a5de
LP
108 NULL);
109 if (r < 0 && r != -ENOENT)
110 return r;
111
44c32988
DH
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);
5ae4d543
LP
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
44c32988
DH
123 if (r < 0 && r != -ENOENT)
124 return r;
125
7640a5de
LP
126 return 0;
127}
128
7871c8e9 129static bool valid_chassis(const char *chassis) {
7871c8e9
LP
130 assert(chassis);
131
132 return nulstr_contains(
133 "vm\0"
134 "container\0"
135 "desktop\0"
136 "laptop\0"
137 "server\0"
138 "tablet\0"
c49e59c1
LP
139 "handset\0"
140 "watch\0",
7871c8e9
LP
141 chassis);
142}
143
799298d6
JG
144static bool valid_deployment(const char *deployment) {
145 assert(deployment);
146
c2142cf1 147 return in_charset(deployment, VALID_DEPLOYMENT_CHARS);
799298d6
JG
148}
149
7871c8e9 150static const char* fallback_chassis(void) {
7640a5de
LP
151 int r;
152 char *type;
153 unsigned t;
248fab74 154 int v;
7871c8e9
LP
155
156 v = detect_virtualization(NULL);
157
158 if (v == VIRTUALIZATION_VM)
159 return "vm";
160 if (v == VIRTUALIZATION_CONTAINER)
161 return "container";
162
163 r = read_one_line_file("/sys/firmware/acpi/pm_profile", &type);
164 if (r < 0)
165 goto try_dmi;
166
167 r = safe_atou(type, &t);
168 free(type);
169 if (r < 0)
170 goto try_dmi;
171
172 /* We only list the really obvious cases here as the ACPI data
173 * is not really super reliable.
174 *
175 * See the ACPI 5.0 Spec Section 5.2.9.1 for details:
176 *
177 * http://www.acpi.info/DOWNLOADS/ACPIspec50.pdf
178 */
179
180 switch(t) {
181
182 case 1:
183 case 3:
184 case 6:
185 return "desktop";
186
187 case 2:
188 return "laptop";
7640a5de 189
7871c8e9
LP
190 case 4:
191 case 5:
192 case 7:
193 return "server";
7640a5de 194
7871c8e9
LP
195 case 8:
196 return "tablet";
197 }
198
199try_dmi:
7640a5de
LP
200 r = read_one_line_file("/sys/class/dmi/id/chassis_type", &type);
201 if (r < 0)
202 return NULL;
203
204 r = safe_atou(type, &t);
205 free(type);
7640a5de
LP
206 if (r < 0)
207 return NULL;
208
209 /* We only list the really obvious cases here. The DMI data is
210 unreliable enough, so let's not do any additional guesswork
41550d40
LP
211 on top of that.
212
213 See the SMBIOS Specification 2.7.1 section 7.4.1 for
214 details about the values listed here:
215
216 http://www.dmtf.org/sites/default/files/standards/documents/DSP0134_2.7.1.pdf
217 */
7640a5de
LP
218
219 switch (t) {
220
221 case 0x3:
222 case 0x4:
223 case 0x6:
224 case 0x7:
7871c8e9 225 return "desktop";
7640a5de 226
7871c8e9 227 case 0x8:
7640a5de
LP
228 case 0x9:
229 case 0xA:
230 case 0xE:
7871c8e9
LP
231 return "laptop";
232
233 case 0xB:
234 return "handset";
7640a5de
LP
235
236 case 0x11:
41550d40 237 case 0x1C:
7871c8e9 238 return "server";
7640a5de
LP
239 }
240
7640a5de
LP
241 return NULL;
242}
243
66a4c743 244static char* context_fallback_icon_name(Context *c) {
7871c8e9
LP
245 const char *chassis;
246
66a4c743
LP
247 assert(c);
248
249 if (!isempty(c->data[PROP_CHASSIS]))
250 return strappend("computer-", c->data[PROP_CHASSIS]);
7871c8e9
LP
251
252 chassis = fallback_chassis();
253 if (chassis)
254 return strappend("computer-", chassis);
255
256 return strdup("computer");
257}
258
799298d6 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 313 [PROP_ICON_NAME] = "ICON_NAME",
799298d6
JG
314 [PROP_CHASSIS] = "CHASSIS",
315 [PROP_DEPLOYMENT] = "DEPLOYMENT",
ce0f1493 316 [PROP_LOCATION] = "LOCATION",
7640a5de
LP
317 };
318
0ccad099 319 _cleanup_strv_free_ char **l = NULL;
7640a5de
LP
320 int r, p;
321
66a4c743
LP
322 assert(c);
323
717603e3 324 r = load_env_file(NULL, "/etc/machine-info", NULL, &l);
7640a5de
LP
325 if (r < 0 && r != -ENOENT)
326 return r;
327
ce0f1493 328 for (p = PROP_PRETTY_HOSTNAME; p <= PROP_LOCATION; p++) {
d77ab3f7
LP
329 _cleanup_free_ char *t = NULL;
330 char **u;
7640a5de
LP
331
332 assert(name[p]);
333
66a4c743 334 if (isempty(c->data[p])) {
f8440af5 335 strv_env_unset(l, name[p]);
7640a5de
LP
336 continue;
337 }
338
d77ab3f7
LP
339 t = strjoin(name[p], "=", c->data[p], NULL);
340 if (!t)
7640a5de 341 return -ENOMEM;
7640a5de
LP
342
343 u = strv_env_set(l, t);
7640a5de
LP
344 if (!u)
345 return -ENOMEM;
0ccad099
LP
346
347 strv_free(l);
7640a5de
LP
348 l = u;
349 }
350
351 if (strv_isempty(l)) {
7640a5de
LP
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);
799298d6
JG
558 if (prop == PROP_DEPLOYMENT && !valid_deployment(name))
559 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid deployment '%s'", name);
ce0f1493
LP
560 if (prop == PROP_LOCATION && string_has_cc(name, NULL))
561 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid location '%s'", name);
66a4c743
LP
562
563 h = strdup(name);
564 if (!h)
ebcf1f97 565 return -ENOMEM;
66a4c743
LP
566
567 free(c->data[prop]);
568 c->data[prop] = h;
7640a5de
LP
569 }
570
f200e8bb 571 r = context_write_data_machine_info(c);
66a4c743
LP
572 if (r < 0) {
573 log_error("Failed to write machine info: %s", strerror(-r));
ebcf1f97 574 return sd_bus_error_set_errnof(error, r, "Failed to write machine info: %s", strerror(-r));
66a4c743 575 }
7640a5de 576
66a4c743
LP
577 log_info("Changed %s to '%s'",
578 prop == PROP_PRETTY_HOSTNAME ? "pretty host name" :
799298d6 579 prop == PROP_DEPLOYMENT ? "deployment" :
ce0f1493 580 prop == PROP_LOCATION ? "location" :
66a4c743 581 prop == PROP_CHASSIS ? "chassis" : "icon name", strna(c->data[prop]));
7640a5de 582
66a4c743
LP
583 sd_bus_emit_properties_changed(bus, "/org/freedesktop/hostname1", "org.freedesktop.hostname1",
584 prop == PROP_PRETTY_HOSTNAME ? "PrettyHostname" :
799298d6 585 prop == PROP_DEPLOYMENT ? "Deployment" :
ce0f1493 586 prop == PROP_LOCATION ? "Location" :
799298d6 587 prop == PROP_CHASSIS ? "Chassis" : "IconName" , NULL);
7640a5de 588
df2d202e 589 return sd_bus_reply_method_return(m, NULL);
66a4c743 590}
7640a5de 591
ebcf1f97
LP
592static int method_set_pretty_hostname(sd_bus *bus, sd_bus_message *m, void *userdata, sd_bus_error *error) {
593 return set_machine_info(userdata, bus, m, PROP_PRETTY_HOSTNAME, method_set_pretty_hostname, error);
7640a5de
LP
594}
595
ebcf1f97
LP
596static int method_set_icon_name(sd_bus *bus, sd_bus_message *m, void *userdata, sd_bus_error *error) {
597 return set_machine_info(userdata, bus, m, PROP_ICON_NAME, method_set_icon_name, error);
66a4c743
LP
598}
599
ebcf1f97
LP
600static int method_set_chassis(sd_bus *bus, sd_bus_message *m, void *userdata, sd_bus_error *error) {
601 return set_machine_info(userdata, bus, m, PROP_CHASSIS, method_set_chassis, error);
66a4c743
LP
602}
603
799298d6
JG
604static int method_set_deployment(sd_bus *bus, sd_bus_message *m, void *userdata, sd_bus_error *error) {
605 return set_machine_info(userdata, bus, m, PROP_DEPLOYMENT, method_set_deployment, error);
606}
607
ce0f1493
LP
608static int method_set_location(sd_bus *bus, sd_bus_message *m, void *userdata, sd_bus_error *error) {
609 return set_machine_info(userdata, bus, m, PROP_LOCATION, method_set_location, error);
610}
611
66a4c743
LP
612static const sd_bus_vtable hostname_vtable[] = {
613 SD_BUS_VTABLE_START(0),
614 SD_BUS_PROPERTY("Hostname", "s", NULL, offsetof(Context, data) + sizeof(char*) * PROP_HOSTNAME, 0),
615 SD_BUS_PROPERTY("StaticHostname", "s", NULL, offsetof(Context, data) + sizeof(char*) * PROP_STATIC_HOSTNAME, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
616 SD_BUS_PROPERTY("PrettyHostname", "s", NULL, offsetof(Context, data) + sizeof(char*) * PROP_PRETTY_HOSTNAME, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
617 SD_BUS_PROPERTY("IconName", "s", property_get_icon_name, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
618 SD_BUS_PROPERTY("Chassis", "s", property_get_chassis, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
ce0f1493
LP
619 SD_BUS_PROPERTY("Deployment", "s", NULL, offsetof(Context, data) + sizeof(char*) * PROP_DEPLOYMENT, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
620 SD_BUS_PROPERTY("Location", "s", NULL, offsetof(Context, data) + sizeof(char*) * PROP_LOCATION, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
f426cc5d
DH
621 SD_BUS_PROPERTY("KernelName", "s", NULL, offsetof(Context, data) + sizeof(char*) * PROP_KERNEL_NAME, SD_BUS_VTABLE_PROPERTY_CONST),
622 SD_BUS_PROPERTY("KernelRelease", "s", NULL, offsetof(Context, data) + sizeof(char*) * PROP_KERNEL_RELEASE, SD_BUS_VTABLE_PROPERTY_CONST),
9be3455f 623 SD_BUS_PROPERTY("KernelVersion", "s", NULL, offsetof(Context, data) + sizeof(char*) * PROP_KERNEL_VERSION, SD_BUS_VTABLE_PROPERTY_CONST),
44c32988
DH
624 SD_BUS_PROPERTY("OperatingSystemPrettyName", "s", NULL, offsetof(Context, data) + sizeof(char*) * PROP_OS_PRETTY_NAME, SD_BUS_VTABLE_PROPERTY_CONST),
625 SD_BUS_PROPERTY("OperatingSystemCPEName", "s", NULL, offsetof(Context, data) + sizeof(char*) * PROP_OS_CPE_NAME, SD_BUS_VTABLE_PROPERTY_CONST),
adacb957
LP
626 SD_BUS_METHOD("SetHostname", "sb", NULL, method_set_hostname, SD_BUS_VTABLE_UNPRIVILEGED),
627 SD_BUS_METHOD("SetStaticHostname", "sb", NULL, method_set_static_hostname, SD_BUS_VTABLE_UNPRIVILEGED),
628 SD_BUS_METHOD("SetPrettyHostname", "sb", NULL, method_set_pretty_hostname, SD_BUS_VTABLE_UNPRIVILEGED),
629 SD_BUS_METHOD("SetIconName", "sb", NULL, method_set_icon_name, SD_BUS_VTABLE_UNPRIVILEGED),
630 SD_BUS_METHOD("SetChassis", "sb", NULL, method_set_chassis, SD_BUS_VTABLE_UNPRIVILEGED),
799298d6 631 SD_BUS_METHOD("SetDeployment", "sb", NULL, method_set_deployment, SD_BUS_VTABLE_UNPRIVILEGED),
ce0f1493 632 SD_BUS_METHOD("SetLocation", "sb", NULL, method_set_location, SD_BUS_VTABLE_UNPRIVILEGED),
66a4c743
LP
633 SD_BUS_VTABLE_END,
634};
635
636static int connect_bus(Context *c, sd_event *event, sd_bus **_bus) {
24996861 637 _cleanup_bus_close_unref_ sd_bus *bus = NULL;
7640a5de
LP
638 int r;
639
66a4c743
LP
640 assert(c);
641 assert(event);
d0baa06f
LP
642 assert(_bus);
643
76b54375 644 r = sd_bus_default_system(&bus);
66a4c743
LP
645 if (r < 0) {
646 log_error("Failed to get system bus connection: %s", strerror(-r));
647 return r;
d0baa06f
LP
648 }
649
19befb2d 650 r = sd_bus_add_object_vtable(bus, NULL, "/org/freedesktop/hostname1", "org.freedesktop.hostname1", hostname_vtable, c);
66a4c743
LP
651 if (r < 0) {
652 log_error("Failed to register object: %s", strerror(-r));
653 return r;
d0baa06f
LP
654 }
655
5bb658a1 656 r = sd_bus_request_name(bus, "org.freedesktop.hostname1", 0);
66a4c743
LP
657 if (r < 0) {
658 log_error("Failed to register name: %s", strerror(-r));
659 return r;
add10b5a
LP
660 }
661
66a4c743
LP
662 r = sd_bus_attach_event(bus, event, 0);
663 if (r < 0) {
664 log_error("Failed to attach bus to event loop: %s", strerror(-r));
665 return r;
666 }
d0baa06f 667
66a4c743
LP
668 *_bus = bus;
669 bus = NULL;
d0baa06f 670
66a4c743 671 return 0;
d0baa06f
LP
672}
673
674int main(int argc, char *argv[]) {
66a4c743 675 Context context = {};
66a4c743 676 _cleanup_event_unref_ sd_event *event = NULL;
24996861 677 _cleanup_bus_close_unref_ sd_bus *bus = NULL;
d0baa06f 678 int r;
d0baa06f 679
7640a5de
LP
680 log_set_target(LOG_TARGET_AUTO);
681 log_parse_environment();
682 log_open();
683
4c12626c 684 umask(0022);
a5c32cff 685 label_init("/etc");
4c12626c 686
7640a5de
LP
687 if (argc != 1) {
688 log_error("This program takes no arguments.");
689 r = -EINVAL;
690 goto finish;
691 }
692
66a4c743
LP
693 if (argc != 1) {
694 log_error("This program takes no arguments.");
695 r = -EINVAL;
696 goto finish;
697 }
698
afc6adb5 699 r = sd_event_default(&event);
7640a5de 700 if (r < 0) {
66a4c743 701 log_error("Failed to allocate event loop: %s", strerror(-r));
7640a5de
LP
702 goto finish;
703 }
704
cde93897
LP
705 sd_event_set_watchdog(event, true);
706
66a4c743 707 r = connect_bus(&context, event, &bus);
d0baa06f 708 if (r < 0)
7640a5de 709 goto finish;
7640a5de 710
66a4c743
LP
711 r = context_read_data(&context);
712 if (r < 0) {
3a3c71c1 713 log_error("Failed to read hostname and machine information: %s", strerror(-r));
66a4c743
LP
714 goto finish;
715 }
ad740100 716
37224a5f 717 r = bus_event_loop_with_idle(event, bus, "org.freedesktop.hostname1", DEFAULT_EXIT_USEC, NULL, NULL);
66a4c743
LP
718 if (r < 0) {
719 log_error("Failed to run event loop: %s", strerror(-r));
720 goto finish;
ad740100 721 }
7640a5de 722
7640a5de 723finish:
66a4c743 724 context_free(&context, bus);
7640a5de 725
7640a5de
LP
726 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
727}