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