]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/hostname/hostnamed.c
sd-bus: drop bus parameter from message callback prototype
[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"
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
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
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 139 "handset\0"
25fa306e
LP
140 "watch\0"
141 "embedded\0",
7871c8e9
LP
142 chassis);
143}
144
799298d6
JG
145static bool valid_deployment(const char *deployment) {
146 assert(deployment);
147
c2142cf1 148 return in_charset(deployment, VALID_DEPLOYMENT_CHARS);
799298d6
JG
149}
150
7871c8e9 151static const char* fallback_chassis(void) {
7640a5de
LP
152 int r;
153 char *type;
154 unsigned t;
248fab74 155 int v;
7871c8e9
LP
156
157 v = detect_virtualization(NULL);
158
159 if (v == VIRTUALIZATION_VM)
160 return "vm";
161 if (v == VIRTUALIZATION_CONTAINER)
162 return "container";
163
164 r = read_one_line_file("/sys/firmware/acpi/pm_profile", &type);
165 if (r < 0)
166 goto try_dmi;
167
168 r = safe_atou(type, &t);
169 free(type);
170 if (r < 0)
171 goto try_dmi;
172
173 /* We only list the really obvious cases here as the ACPI data
174 * is not really super reliable.
175 *
176 * See the ACPI 5.0 Spec Section 5.2.9.1 for details:
177 *
178 * http://www.acpi.info/DOWNLOADS/ACPIspec50.pdf
179 */
180
181 switch(t) {
182
183 case 1:
184 case 3:
185 case 6:
186 return "desktop";
187
188 case 2:
189 return "laptop";
7640a5de 190
7871c8e9
LP
191 case 4:
192 case 5:
193 case 7:
194 return "server";
7640a5de 195
7871c8e9
LP
196 case 8:
197 return "tablet";
198 }
199
200try_dmi:
7640a5de
LP
201 r = read_one_line_file("/sys/class/dmi/id/chassis_type", &type);
202 if (r < 0)
203 return NULL;
204
205 r = safe_atou(type, &t);
206 free(type);
7640a5de
LP
207 if (r < 0)
208 return NULL;
209
210 /* We only list the really obvious cases here. The DMI data is
211 unreliable enough, so let's not do any additional guesswork
41550d40
LP
212 on top of that.
213
214 See the SMBIOS Specification 2.7.1 section 7.4.1 for
215 details about the values listed here:
216
217 http://www.dmtf.org/sites/default/files/standards/documents/DSP0134_2.7.1.pdf
218 */
7640a5de
LP
219
220 switch (t) {
221
222 case 0x3:
223 case 0x4:
224 case 0x6:
225 case 0x7:
7871c8e9 226 return "desktop";
7640a5de 227
7871c8e9 228 case 0x8:
7640a5de
LP
229 case 0x9:
230 case 0xA:
231 case 0xE:
7871c8e9
LP
232 return "laptop";
233
234 case 0xB:
235 return "handset";
7640a5de
LP
236
237 case 0x11:
41550d40 238 case 0x1C:
7871c8e9 239 return "server";
7640a5de
LP
240 }
241
7640a5de
LP
242 return NULL;
243}
244
66a4c743 245static char* context_fallback_icon_name(Context *c) {
7871c8e9
LP
246 const char *chassis;
247
66a4c743
LP
248 assert(c);
249
250 if (!isempty(c->data[PROP_CHASSIS]))
251 return strappend("computer-", c->data[PROP_CHASSIS]);
7871c8e9
LP
252
253 chassis = fallback_chassis();
254 if (chassis)
255 return strappend("computer-", chassis);
256
257 return strdup("computer");
258}
259
799298d6 260
c779a442 261static bool hostname_is_useful(const char *hn) {
fecc80c1 262 return !isempty(hn) && !is_localhost(hn);
c779a442
SW
263}
264
265static int context_update_kernel_hostname(Context *c) {
266 const char *static_hn;
7640a5de
LP
267 const char *hn;
268
66a4c743
LP
269 assert(c);
270
c779a442
SW
271 static_hn = c->data[PROP_STATIC_HOSTNAME];
272
273 /* /etc/hostname with something other than "localhost"
274 * has the highest preference ... */
275 if (hostname_is_useful(static_hn))
276 hn = static_hn;
277
f7340ab2 278 /* ... the transient host name, (ie: DHCP) comes next ... */
c779a442 279 else if (!isempty(c->data[PROP_HOSTNAME]))
66a4c743 280 hn = c->data[PROP_HOSTNAME];
7640a5de 281
c779a442
SW
282 /* ... fallback to static "localhost.*" ignored above ... */
283 else if (!isempty(static_hn))
284 hn = static_hn;
285
286 /* ... and the ultimate fallback */
287 else
288 hn = "localhost";
289
605f81a8 290 if (sethostname_idempotent(hn) < 0)
7640a5de
LP
291 return -errno;
292
293 return 0;
294}
295
66a4c743 296static int context_write_data_static_hostname(Context *c) {
7640a5de 297
66a4c743
LP
298 assert(c);
299
300 if (isempty(c->data[PROP_STATIC_HOSTNAME])) {
7640a5de
LP
301
302 if (unlink("/etc/hostname") < 0)
303 return errno == ENOENT ? 0 : -errno;
304
305 return 0;
306 }
66a4c743 307 return write_string_file_atomic_label("/etc/hostname", c->data[PROP_STATIC_HOSTNAME]);
7640a5de
LP
308}
309
f200e8bb 310static int context_write_data_machine_info(Context *c) {
4f34ed54 311
7640a5de
LP
312 static const char * const name[_PROP_MAX] = {
313 [PROP_PRETTY_HOSTNAME] = "PRETTY_HOSTNAME",
7871c8e9 314 [PROP_ICON_NAME] = "ICON_NAME",
799298d6
JG
315 [PROP_CHASSIS] = "CHASSIS",
316 [PROP_DEPLOYMENT] = "DEPLOYMENT",
ce0f1493 317 [PROP_LOCATION] = "LOCATION",
7640a5de
LP
318 };
319
0ccad099 320 _cleanup_strv_free_ char **l = NULL;
7640a5de
LP
321 int r, p;
322
66a4c743
LP
323 assert(c);
324
717603e3 325 r = load_env_file(NULL, "/etc/machine-info", NULL, &l);
7640a5de
LP
326 if (r < 0 && r != -ENOENT)
327 return r;
328
ce0f1493 329 for (p = PROP_PRETTY_HOSTNAME; p <= PROP_LOCATION; p++) {
d77ab3f7
LP
330 _cleanup_free_ char *t = NULL;
331 char **u;
7640a5de
LP
332
333 assert(name[p]);
334
66a4c743 335 if (isempty(c->data[p])) {
f8440af5 336 strv_env_unset(l, name[p]);
7640a5de
LP
337 continue;
338 }
339
d77ab3f7
LP
340 t = strjoin(name[p], "=", c->data[p], NULL);
341 if (!t)
7640a5de 342 return -ENOMEM;
7640a5de
LP
343
344 u = strv_env_set(l, t);
7640a5de
LP
345 if (!u)
346 return -ENOMEM;
0ccad099
LP
347
348 strv_free(l);
7640a5de
LP
349 l = u;
350 }
351
352 if (strv_isempty(l)) {
7640a5de
LP
353 if (unlink("/etc/machine-info") < 0)
354 return errno == ENOENT ? 0 : -errno;
355
356 return 0;
357 }
358
0ccad099 359 return write_env_file_label("/etc/machine-info", l);
7640a5de
LP
360}
361
66a4c743
LP
362static int property_get_icon_name(
363 sd_bus *bus,
364 const char *path,
365 const char *interface,
366 const char *property,
367 sd_bus_message *reply,
ebcf1f97
LP
368 void *userdata,
369 sd_bus_error *error) {
7640a5de 370
66a4c743
LP
371 _cleanup_free_ char *n = NULL;
372 Context *c = userdata;
373 const char *name;
7640a5de 374
66a4c743
LP
375 if (isempty(c->data[PROP_ICON_NAME]))
376 name = n = context_fallback_icon_name(c);
7640a5de 377 else
66a4c743
LP
378 name = c->data[PROP_ICON_NAME];
379
380 if (!name)
381 return -ENOMEM;
7640a5de 382
ebcf1f97 383 return sd_bus_message_append(reply, "s", name);
7640a5de
LP
384}
385
66a4c743
LP
386static int property_get_chassis(
387 sd_bus *bus,
388 const char *path,
389 const char *interface,
390 const char *property,
391 sd_bus_message *reply,
ebcf1f97
LP
392 void *userdata,
393 sd_bus_error *error) {
7871c8e9 394
66a4c743
LP
395 Context *c = userdata;
396 const char *name;
7871c8e9 397
66a4c743 398 if (isempty(c->data[PROP_CHASSIS]))
7871c8e9
LP
399 name = fallback_chassis();
400 else
66a4c743 401 name = c->data[PROP_CHASSIS];
7871c8e9 402
ebcf1f97 403 return sd_bus_message_append(reply, "s", name);
7871c8e9
LP
404}
405
19070062 406static int method_set_hostname(sd_bus_message *m, void *userdata, sd_bus_error *error) {
66a4c743
LP
407 Context *c = userdata;
408 const char *name;
102d8f81 409 int interactive;
66a4c743
LP
410 char *h;
411 int r;
d200735e 412
19070062
LP
413 assert(m);
414 assert(c);
415
66a4c743
LP
416 r = sd_bus_message_read(m, "sb", &name, &interactive);
417 if (r < 0)
ebcf1f97 418 return r;
d200735e 419
66a4c743
LP
420 if (isempty(name))
421 name = c->data[PROP_STATIC_HOSTNAME];
7640a5de 422
66a4c743
LP
423 if (isempty(name))
424 name = "localhost";
7640a5de 425
66a4c743 426 if (!hostname_is_valid(name))
ebcf1f97 427 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid hostname '%s'", name);
7640a5de 428
66a4c743 429 if (streq_ptr(name, c->data[PROP_HOSTNAME]))
df2d202e 430 return sd_bus_reply_method_return(m, NULL);
7640a5de 431
c529695e
LP
432 r = bus_verify_polkit_async(
433 m,
434 CAP_SYS_ADMIN,
435 "org.freedesktop.hostname1.set-hostname",
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",
488 interactive,
489 UID_INVALID,
490 &c->polkit_registry,
491 error);
66a4c743 492 if (r < 0)
ebcf1f97 493 return r;
66a4c743
LP
494 if (r == 0)
495 return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
7640a5de 496
66a4c743
LP
497 if (isempty(name)) {
498 free(c->data[PROP_STATIC_HOSTNAME]);
499 c->data[PROP_STATIC_HOSTNAME] = NULL;
500 } else {
501 char *h;
7640a5de 502
66a4c743 503 if (!hostname_is_valid(name))
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",
559 interactive,
560 UID_INVALID,
561 &c->polkit_registry,
562 error);
66a4c743 563 if (r < 0)
ebcf1f97 564 return r;
66a4c743
LP
565 if (r == 0)
566 return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
567
568 if (isempty(name)) {
569 free(c->data[prop]);
570 c->data[prop] = NULL;
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) {
24996861 665 _cleanup_bus_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;
24996861 697 _cleanup_bus_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}