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