]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/hostname/hostnamed.c
tree-wide: drop {} from one-line if blocks
[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 32#include "fileio-label.h"
66a4c743
LP
33#include "bus-util.h"
34#include "event-util.h"
d7b8eec7 35#include "selinux-util.h"
958b66ea 36#include "hostname-util.h"
91f9dcaf 37
799298d6
JG
38#define VALID_DEPLOYMENT_CHARS (DIGITS LETTERS "-.:")
39
7640a5de
LP
40enum {
41 PROP_HOSTNAME,
42 PROP_STATIC_HOSTNAME,
43 PROP_PRETTY_HOSTNAME,
44 PROP_ICON_NAME,
7871c8e9 45 PROP_CHASSIS,
799298d6 46 PROP_DEPLOYMENT,
ce0f1493 47 PROP_LOCATION,
f426cc5d
DH
48 PROP_KERNEL_NAME,
49 PROP_KERNEL_RELEASE,
9be3455f 50 PROP_KERNEL_VERSION,
44c32988
DH
51 PROP_OS_PRETTY_NAME,
52 PROP_OS_CPE_NAME,
7640a5de
LP
53 _PROP_MAX
54};
55
66a4c743
LP
56typedef struct Context {
57 char *data[_PROP_MAX];
58 Hashmap *polkit_registry;
59} Context;
ad740100 60
66a4c743 61static void context_reset(Context *c) {
7640a5de
LP
62 int p;
63
66a4c743
LP
64 assert(c);
65
7640a5de 66 for (p = 0; p < _PROP_MAX; p++) {
a1e58e8e 67 c->data[p] = mfree(c->data[p]);
7640a5de
LP
68 }
69}
70
36e34057 71static void context_free(Context *c) {
66a4c743
LP
72 assert(c);
73
74 context_reset(c);
36e34057 75 bus_verify_polkit_async_registry_free(c->polkit_registry);
66a4c743
LP
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
139e5336 98 r = read_hostname_config("/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);
ece174c5 116 if (r == -ENOENT)
5ae4d543
LP
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);
5ae4d543 121
44c32988
DH
122 if (r < 0 && r != -ENOENT)
123 return r;
124
7640a5de
LP
125 return 0;
126}
127
7871c8e9 128static bool valid_chassis(const char *chassis) {
7871c8e9
LP
129 assert(chassis);
130
131 return nulstr_contains(
132 "vm\0"
133 "container\0"
134 "desktop\0"
135 "laptop\0"
136 "server\0"
137 "tablet\0"
c49e59c1 138 "handset\0"
25fa306e
LP
139 "watch\0"
140 "embedded\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 155
75f86906 156 v = detect_virtualization();
7871c8e9 157
75f86906 158 if (VIRTUALIZATION_IS_VM(v))
7871c8e9 159 return "vm";
75f86906 160 if (VIRTUALIZATION_IS_CONTAINER(v))
7871c8e9
LP
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
f7340ab2 277 /* ... the transient host name, (ie: DHCP) comes next ... */
c779a442 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
605f81a8 289 if (sethostname_idempotent(hn) < 0)
7640a5de
LP
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
19070062 405static int method_set_hostname(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
19070062
LP
412 assert(m);
413 assert(c);
414
66a4c743
LP
415 r = sd_bus_message_read(m, "sb", &name, &interactive);
416 if (r < 0)
ebcf1f97 417 return r;
d200735e 418
66a4c743
LP
419 if (isempty(name))
420 name = c->data[PROP_STATIC_HOSTNAME];
7640a5de 421
66a4c743
LP
422 if (isempty(name))
423 name = "localhost";
7640a5de 424
8fb49443 425 if (!hostname_is_valid(name, false))
ebcf1f97 426 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid hostname '%s'", name);
7640a5de 427
66a4c743 428 if (streq_ptr(name, c->data[PROP_HOSTNAME]))
df2d202e 429 return sd_bus_reply_method_return(m, NULL);
7640a5de 430
c529695e
LP
431 r = bus_verify_polkit_async(
432 m,
433 CAP_SYS_ADMIN,
434 "org.freedesktop.hostname1.set-hostname",
403ed0e5 435 NULL,
c529695e
LP
436 interactive,
437 UID_INVALID,
438 &c->polkit_registry,
439 error);
66a4c743 440 if (r < 0)
ebcf1f97 441 return r;
66a4c743
LP
442 if (r == 0)
443 return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
7640a5de 444
66a4c743
LP
445 h = strdup(name);
446 if (!h)
ebcf1f97 447 return -ENOMEM;
7640a5de 448
66a4c743
LP
449 free(c->data[PROP_HOSTNAME]);
450 c->data[PROP_HOSTNAME] = h;
7640a5de 451
c779a442 452 r = context_update_kernel_hostname(c);
66a4c743 453 if (r < 0) {
da927ba9 454 log_error_errno(r, "Failed to set host name: %m");
ebcf1f97 455 return sd_bus_error_set_errnof(error, r, "Failed to set hostname: %s", strerror(-r));
66a4c743 456 }
7640a5de 457
66a4c743 458 log_info("Changed host name to '%s'", strna(c->data[PROP_HOSTNAME]));
7640a5de 459
19070062 460 (void) sd_bus_emit_properties_changed(sd_bus_message_get_bus(m), "/org/freedesktop/hostname1", "org.freedesktop.hostname1", "Hostname", NULL);
7640a5de 461
df2d202e 462 return sd_bus_reply_method_return(m, NULL);
66a4c743 463}
7640a5de 464
19070062 465static int method_set_static_hostname(sd_bus_message *m, void *userdata, sd_bus_error *error) {
66a4c743
LP
466 Context *c = userdata;
467 const char *name;
102d8f81 468 int interactive;
66a4c743 469 int r;
7640a5de 470
19070062
LP
471 assert(m);
472 assert(c);
473
66a4c743
LP
474 r = sd_bus_message_read(m, "sb", &name, &interactive);
475 if (r < 0)
ebcf1f97 476 return r;
7640a5de 477
66a4c743
LP
478 if (isempty(name))
479 name = NULL;
7640a5de 480
66a4c743 481 if (streq_ptr(name, c->data[PROP_STATIC_HOSTNAME]))
df2d202e 482 return sd_bus_reply_method_return(m, NULL);
7640a5de 483
c529695e
LP
484 r = bus_verify_polkit_async(
485 m,
486 CAP_SYS_ADMIN,
487 "org.freedesktop.hostname1.set-static-hostname",
403ed0e5 488 NULL,
c529695e
LP
489 interactive,
490 UID_INVALID,
491 &c->polkit_registry,
492 error);
66a4c743 493 if (r < 0)
ebcf1f97 494 return r;
66a4c743
LP
495 if (r == 0)
496 return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
7640a5de 497
66a4c743 498 if (isempty(name)) {
a1e58e8e 499 c->data[PROP_STATIC_HOSTNAME] = mfree(c->data[PROP_STATIC_HOSTNAME]);
66a4c743
LP
500 } else {
501 char *h;
7640a5de 502
8fb49443 503 if (!hostname_is_valid(name, false))
ebcf1f97 504 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid static hostname '%s'", name);
7640a5de 505
66a4c743
LP
506 h = strdup(name);
507 if (!h)
ebcf1f97 508 return -ENOMEM;
7640a5de 509
66a4c743
LP
510 free(c->data[PROP_STATIC_HOSTNAME]);
511 c->data[PROP_STATIC_HOSTNAME] = h;
512 }
7640a5de 513
c779a442
SW
514 r = context_update_kernel_hostname(c);
515 if (r < 0) {
da927ba9 516 log_error_errno(r, "Failed to set host name: %m");
c779a442
SW
517 return sd_bus_error_set_errnof(error, r, "Failed to set hostname: %s", strerror(-r));
518 }
519
66a4c743
LP
520 r = context_write_data_static_hostname(c);
521 if (r < 0) {
da927ba9 522 log_error_errno(r, "Failed to write static host name: %m");
ebcf1f97 523 return sd_bus_error_set_errnof(error, r, "Failed to set static hostname: %s", strerror(-r));
66a4c743 524 }
7640a5de 525
66a4c743 526 log_info("Changed static host name to '%s'", strna(c->data[PROP_STATIC_HOSTNAME]));
7640a5de 527
19070062 528 (void) sd_bus_emit_properties_changed(sd_bus_message_get_bus(m), "/org/freedesktop/hostname1", "org.freedesktop.hostname1", "StaticHostname", NULL);
7640a5de 529
df2d202e 530 return sd_bus_reply_method_return(m, NULL);
66a4c743 531}
7640a5de 532
19070062 533static int set_machine_info(Context *c, sd_bus_message *m, int prop, sd_bus_message_handler_t cb, sd_bus_error *error) {
102d8f81 534 int interactive;
66a4c743
LP
535 const char *name;
536 int r;
537
538 assert(c);
66a4c743
LP
539 assert(m);
540
541 r = sd_bus_message_read(m, "sb", &name, &interactive);
542 if (r < 0)
ebcf1f97 543 return r;
66a4c743
LP
544
545 if (isempty(name))
546 name = NULL;
547
548 if (streq_ptr(name, c->data[prop]))
df2d202e 549 return sd_bus_reply_method_return(m, NULL);
7640a5de 550
66a4c743
LP
551 /* Since the pretty hostname should always be changed at the
552 * same time as the static one, use the same policy action for
553 * both... */
554
c529695e
LP
555 r = bus_verify_polkit_async(
556 m,
557 CAP_SYS_ADMIN,
558 prop == PROP_PRETTY_HOSTNAME ? "org.freedesktop.hostname1.set-static-hostname" : "org.freedesktop.hostname1.set-machine-info",
403ed0e5 559 NULL,
c529695e
LP
560 interactive,
561 UID_INVALID,
562 &c->polkit_registry,
563 error);
66a4c743 564 if (r < 0)
ebcf1f97 565 return r;
66a4c743
LP
566 if (r == 0)
567 return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
568
569 if (isempty(name)) {
a1e58e8e 570 c->data[prop] = mfree(c->data[prop]);
66a4c743
LP
571 } else {
572 char *h;
573
574 /* The icon name might ultimately be used as file
575 * name, so better be safe than sorry */
576
ae6c3cc0 577 if (prop == PROP_ICON_NAME && !filename_is_valid(name))
ebcf1f97 578 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid icon name '%s'", name);
6294aa76 579 if (prop == PROP_PRETTY_HOSTNAME && string_has_cc(name, NULL))
ebcf1f97 580 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid pretty host name '%s'", name);
66a4c743 581 if (prop == PROP_CHASSIS && !valid_chassis(name))
ebcf1f97 582 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid chassis '%s'", name);
799298d6
JG
583 if (prop == PROP_DEPLOYMENT && !valid_deployment(name))
584 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid deployment '%s'", name);
ce0f1493
LP
585 if (prop == PROP_LOCATION && string_has_cc(name, NULL))
586 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid location '%s'", name);
66a4c743
LP
587
588 h = strdup(name);
589 if (!h)
ebcf1f97 590 return -ENOMEM;
66a4c743
LP
591
592 free(c->data[prop]);
593 c->data[prop] = h;
7640a5de
LP
594 }
595
f200e8bb 596 r = context_write_data_machine_info(c);
66a4c743 597 if (r < 0) {
da927ba9 598 log_error_errno(r, "Failed to write machine info: %m");
ebcf1f97 599 return sd_bus_error_set_errnof(error, r, "Failed to write machine info: %s", strerror(-r));
66a4c743 600 }
7640a5de 601
66a4c743
LP
602 log_info("Changed %s to '%s'",
603 prop == PROP_PRETTY_HOSTNAME ? "pretty host name" :
799298d6 604 prop == PROP_DEPLOYMENT ? "deployment" :
ce0f1493 605 prop == PROP_LOCATION ? "location" :
66a4c743 606 prop == PROP_CHASSIS ? "chassis" : "icon name", strna(c->data[prop]));
7640a5de 607
19070062
LP
608 (void) sd_bus_emit_properties_changed(
609 sd_bus_message_get_bus(m),
610 "/org/freedesktop/hostname1",
611 "org.freedesktop.hostname1",
612 prop == PROP_PRETTY_HOSTNAME ? "PrettyHostname" :
613 prop == PROP_DEPLOYMENT ? "Deployment" :
614 prop == PROP_LOCATION ? "Location" :
615 prop == PROP_CHASSIS ? "Chassis" : "IconName" , NULL);
7640a5de 616
df2d202e 617 return sd_bus_reply_method_return(m, NULL);
66a4c743 618}
7640a5de 619
19070062
LP
620static int method_set_pretty_hostname(sd_bus_message *m, void *userdata, sd_bus_error *error) {
621 return set_machine_info(userdata, m, PROP_PRETTY_HOSTNAME, method_set_pretty_hostname, error);
7640a5de
LP
622}
623
19070062
LP
624static int method_set_icon_name(sd_bus_message *m, void *userdata, sd_bus_error *error) {
625 return set_machine_info(userdata, m, PROP_ICON_NAME, method_set_icon_name, error);
66a4c743
LP
626}
627
19070062
LP
628static int method_set_chassis(sd_bus_message *m, void *userdata, sd_bus_error *error) {
629 return set_machine_info(userdata, m, PROP_CHASSIS, method_set_chassis, error);
66a4c743
LP
630}
631
19070062
LP
632static int method_set_deployment(sd_bus_message *m, void *userdata, sd_bus_error *error) {
633 return set_machine_info(userdata, m, PROP_DEPLOYMENT, method_set_deployment, error);
799298d6
JG
634}
635
19070062
LP
636static int method_set_location(sd_bus_message *m, void *userdata, sd_bus_error *error) {
637 return set_machine_info(userdata, m, PROP_LOCATION, method_set_location, error);
ce0f1493
LP
638}
639
66a4c743
LP
640static const sd_bus_vtable hostname_vtable[] = {
641 SD_BUS_VTABLE_START(0),
caffbef6 642 SD_BUS_PROPERTY("Hostname", "s", NULL, offsetof(Context, data) + sizeof(char*) * PROP_HOSTNAME, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
66a4c743
LP
643 SD_BUS_PROPERTY("StaticHostname", "s", NULL, offsetof(Context, data) + sizeof(char*) * PROP_STATIC_HOSTNAME, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
644 SD_BUS_PROPERTY("PrettyHostname", "s", NULL, offsetof(Context, data) + sizeof(char*) * PROP_PRETTY_HOSTNAME, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
645 SD_BUS_PROPERTY("IconName", "s", property_get_icon_name, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
646 SD_BUS_PROPERTY("Chassis", "s", property_get_chassis, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
ce0f1493
LP
647 SD_BUS_PROPERTY("Deployment", "s", NULL, offsetof(Context, data) + sizeof(char*) * PROP_DEPLOYMENT, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
648 SD_BUS_PROPERTY("Location", "s", NULL, offsetof(Context, data) + sizeof(char*) * PROP_LOCATION, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
f426cc5d
DH
649 SD_BUS_PROPERTY("KernelName", "s", NULL, offsetof(Context, data) + sizeof(char*) * PROP_KERNEL_NAME, SD_BUS_VTABLE_PROPERTY_CONST),
650 SD_BUS_PROPERTY("KernelRelease", "s", NULL, offsetof(Context, data) + sizeof(char*) * PROP_KERNEL_RELEASE, SD_BUS_VTABLE_PROPERTY_CONST),
9be3455f 651 SD_BUS_PROPERTY("KernelVersion", "s", NULL, offsetof(Context, data) + sizeof(char*) * PROP_KERNEL_VERSION, SD_BUS_VTABLE_PROPERTY_CONST),
44c32988
DH
652 SD_BUS_PROPERTY("OperatingSystemPrettyName", "s", NULL, offsetof(Context, data) + sizeof(char*) * PROP_OS_PRETTY_NAME, SD_BUS_VTABLE_PROPERTY_CONST),
653 SD_BUS_PROPERTY("OperatingSystemCPEName", "s", NULL, offsetof(Context, data) + sizeof(char*) * PROP_OS_CPE_NAME, SD_BUS_VTABLE_PROPERTY_CONST),
adacb957
LP
654 SD_BUS_METHOD("SetHostname", "sb", NULL, method_set_hostname, SD_BUS_VTABLE_UNPRIVILEGED),
655 SD_BUS_METHOD("SetStaticHostname", "sb", NULL, method_set_static_hostname, SD_BUS_VTABLE_UNPRIVILEGED),
656 SD_BUS_METHOD("SetPrettyHostname", "sb", NULL, method_set_pretty_hostname, SD_BUS_VTABLE_UNPRIVILEGED),
657 SD_BUS_METHOD("SetIconName", "sb", NULL, method_set_icon_name, SD_BUS_VTABLE_UNPRIVILEGED),
658 SD_BUS_METHOD("SetChassis", "sb", NULL, method_set_chassis, SD_BUS_VTABLE_UNPRIVILEGED),
799298d6 659 SD_BUS_METHOD("SetDeployment", "sb", NULL, method_set_deployment, SD_BUS_VTABLE_UNPRIVILEGED),
ce0f1493 660 SD_BUS_METHOD("SetLocation", "sb", NULL, method_set_location, SD_BUS_VTABLE_UNPRIVILEGED),
66a4c743
LP
661 SD_BUS_VTABLE_END,
662};
663
664static int connect_bus(Context *c, sd_event *event, sd_bus **_bus) {
03976f7b 665 _cleanup_bus_flush_close_unref_ sd_bus *bus = NULL;
7640a5de
LP
666 int r;
667
66a4c743
LP
668 assert(c);
669 assert(event);
d0baa06f
LP
670 assert(_bus);
671
76b54375 672 r = sd_bus_default_system(&bus);
23bbb0de
MS
673 if (r < 0)
674 return log_error_errno(r, "Failed to get system bus connection: %m");
d0baa06f 675
19befb2d 676 r = sd_bus_add_object_vtable(bus, NULL, "/org/freedesktop/hostname1", "org.freedesktop.hostname1", hostname_vtable, c);
23bbb0de
MS
677 if (r < 0)
678 return log_error_errno(r, "Failed to register object: %m");
d0baa06f 679
5bb658a1 680 r = sd_bus_request_name(bus, "org.freedesktop.hostname1", 0);
23bbb0de
MS
681 if (r < 0)
682 return log_error_errno(r, "Failed to register name: %m");
add10b5a 683
66a4c743 684 r = sd_bus_attach_event(bus, event, 0);
23bbb0de
MS
685 if (r < 0)
686 return log_error_errno(r, "Failed to attach bus to event loop: %m");
d0baa06f 687
66a4c743
LP
688 *_bus = bus;
689 bus = NULL;
d0baa06f 690
66a4c743 691 return 0;
d0baa06f
LP
692}
693
694int main(int argc, char *argv[]) {
66a4c743 695 Context context = {};
66a4c743 696 _cleanup_event_unref_ sd_event *event = NULL;
03976f7b 697 _cleanup_bus_flush_close_unref_ sd_bus *bus = NULL;
d0baa06f 698 int r;
d0baa06f 699
7640a5de
LP
700 log_set_target(LOG_TARGET_AUTO);
701 log_parse_environment();
702 log_open();
703
4c12626c 704 umask(0022);
cc56fafe 705 mac_selinux_init("/etc");
4c12626c 706
7640a5de
LP
707 if (argc != 1) {
708 log_error("This program takes no arguments.");
709 r = -EINVAL;
710 goto finish;
711 }
712
66a4c743
LP
713 if (argc != 1) {
714 log_error("This program takes no arguments.");
715 r = -EINVAL;
716 goto finish;
717 }
718
afc6adb5 719 r = sd_event_default(&event);
7640a5de 720 if (r < 0) {
da927ba9 721 log_error_errno(r, "Failed to allocate event loop: %m");
7640a5de
LP
722 goto finish;
723 }
724
cde93897
LP
725 sd_event_set_watchdog(event, true);
726
66a4c743 727 r = connect_bus(&context, event, &bus);
d0baa06f 728 if (r < 0)
7640a5de 729 goto finish;
7640a5de 730
66a4c743
LP
731 r = context_read_data(&context);
732 if (r < 0) {
da927ba9 733 log_error_errno(r, "Failed to read hostname and machine information: %m");
66a4c743
LP
734 goto finish;
735 }
ad740100 736
37224a5f 737 r = bus_event_loop_with_idle(event, bus, "org.freedesktop.hostname1", DEFAULT_EXIT_USEC, NULL, NULL);
66a4c743 738 if (r < 0) {
da927ba9 739 log_error_errno(r, "Failed to run event loop: %m");
66a4c743 740 goto finish;
ad740100 741 }
7640a5de 742
7640a5de 743finish:
36e34057 744 context_free(&context);
7640a5de 745
7640a5de
LP
746 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
747}