]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/hostname/hostnamed.c
update TODO
[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>
def9a7aa 26#include <sys/capability.h>
7640a5de
LP
27
28#include "util.h"
29#include "strv.h"
ad740100 30#include "def.h"
b52aae1d 31#include "virt.h"
4d1a6904 32#include "env-util.h"
a5c32cff
HH
33#include "fileio-label.h"
34#include "label.h"
66a4c743
LP
35#include "bus-util.h"
36#include "event-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
LP
140 "handset\0"
141 "watch\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
278 /* ... the transient host name, (ie: DHCP) comes next ...*/
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
ebcf1f97 406static int method_set_hostname(sd_bus *bus, 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
66a4c743
LP
413 r = sd_bus_message_read(m, "sb", &name, &interactive);
414 if (r < 0)
ebcf1f97 415 return r;
d200735e 416
66a4c743
LP
417 if (isempty(name))
418 name = c->data[PROP_STATIC_HOSTNAME];
7640a5de 419
66a4c743
LP
420 if (isempty(name))
421 name = "localhost";
7640a5de 422
66a4c743 423 if (!hostname_is_valid(name))
ebcf1f97 424 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid hostname '%s'", name);
7640a5de 425
66a4c743 426 if (streq_ptr(name, c->data[PROP_HOSTNAME]))
df2d202e 427 return sd_bus_reply_method_return(m, NULL);
7640a5de 428
f3885791 429 r = bus_verify_polkit_async(m, CAP_SYS_ADMIN, "org.freedesktop.hostname1.set-hostname", interactive, &c->polkit_registry, error);
66a4c743 430 if (r < 0)
ebcf1f97 431 return r;
66a4c743
LP
432 if (r == 0)
433 return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
7640a5de 434
66a4c743
LP
435 h = strdup(name);
436 if (!h)
ebcf1f97 437 return -ENOMEM;
7640a5de 438
66a4c743
LP
439 free(c->data[PROP_HOSTNAME]);
440 c->data[PROP_HOSTNAME] = h;
7640a5de 441
c779a442 442 r = context_update_kernel_hostname(c);
66a4c743
LP
443 if (r < 0) {
444 log_error("Failed to set host name: %s", strerror(-r));
ebcf1f97 445 return sd_bus_error_set_errnof(error, r, "Failed to set hostname: %s", strerror(-r));
66a4c743 446 }
7640a5de 447
66a4c743 448 log_info("Changed host name to '%s'", strna(c->data[PROP_HOSTNAME]));
7640a5de 449
66a4c743 450 sd_bus_emit_properties_changed(bus, "/org/freedesktop/hostname1", "org.freedesktop.hostname1", "Hostname", NULL);
7640a5de 451
df2d202e 452 return sd_bus_reply_method_return(m, NULL);
66a4c743 453}
7640a5de 454
ebcf1f97 455static int method_set_static_hostname(sd_bus *bus, sd_bus_message *m, void *userdata, sd_bus_error *error) {
66a4c743
LP
456 Context *c = userdata;
457 const char *name;
102d8f81 458 int interactive;
66a4c743 459 int r;
7640a5de 460
66a4c743
LP
461 r = sd_bus_message_read(m, "sb", &name, &interactive);
462 if (r < 0)
ebcf1f97 463 return r;
7640a5de 464
66a4c743
LP
465 if (isempty(name))
466 name = NULL;
7640a5de 467
66a4c743 468 if (streq_ptr(name, c->data[PROP_STATIC_HOSTNAME]))
df2d202e 469 return sd_bus_reply_method_return(m, NULL);
7640a5de 470
f3885791 471 r = bus_verify_polkit_async(m, CAP_SYS_ADMIN, "org.freedesktop.hostname1.set-static-hostname", interactive, &c->polkit_registry, error);
66a4c743 472 if (r < 0)
ebcf1f97 473 return r;
66a4c743
LP
474 if (r == 0)
475 return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
7640a5de 476
66a4c743
LP
477 if (isempty(name)) {
478 free(c->data[PROP_STATIC_HOSTNAME]);
479 c->data[PROP_STATIC_HOSTNAME] = NULL;
480 } else {
481 char *h;
7640a5de 482
66a4c743 483 if (!hostname_is_valid(name))
ebcf1f97 484 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid static hostname '%s'", name);
7640a5de 485
66a4c743
LP
486 h = strdup(name);
487 if (!h)
ebcf1f97 488 return -ENOMEM;
7640a5de 489
66a4c743
LP
490 free(c->data[PROP_STATIC_HOSTNAME]);
491 c->data[PROP_STATIC_HOSTNAME] = h;
492 }
7640a5de 493
c779a442
SW
494 r = context_update_kernel_hostname(c);
495 if (r < 0) {
496 log_error("Failed to set host name: %s", strerror(-r));
497 return sd_bus_error_set_errnof(error, r, "Failed to set hostname: %s", strerror(-r));
498 }
499
66a4c743
LP
500 r = context_write_data_static_hostname(c);
501 if (r < 0) {
502 log_error("Failed to write static host name: %s", strerror(-r));
ebcf1f97 503 return sd_bus_error_set_errnof(error, r, "Failed to set static hostname: %s", strerror(-r));
66a4c743 504 }
7640a5de 505
66a4c743 506 log_info("Changed static host name to '%s'", strna(c->data[PROP_STATIC_HOSTNAME]));
7640a5de 507
66a4c743 508 sd_bus_emit_properties_changed(bus, "/org/freedesktop/hostname1", "org.freedesktop.hostname1", "StaticHostname", NULL);
7640a5de 509
df2d202e 510 return sd_bus_reply_method_return(m, NULL);
66a4c743 511}
7640a5de 512
ebcf1f97 513static int set_machine_info(Context *c, sd_bus *bus, sd_bus_message *m, int prop, sd_bus_message_handler_t cb, sd_bus_error *error) {
102d8f81 514 int interactive;
66a4c743
LP
515 const char *name;
516 int r;
517
518 assert(c);
519 assert(bus);
520 assert(m);
521
522 r = sd_bus_message_read(m, "sb", &name, &interactive);
523 if (r < 0)
ebcf1f97 524 return r;
66a4c743
LP
525
526 if (isempty(name))
527 name = NULL;
528
529 if (streq_ptr(name, c->data[prop]))
df2d202e 530 return sd_bus_reply_method_return(m, NULL);
7640a5de 531
66a4c743
LP
532 /* Since the pretty hostname should always be changed at the
533 * same time as the static one, use the same policy action for
534 * both... */
535
f3885791 536 r = bus_verify_polkit_async(m, CAP_SYS_ADMIN,
def9a7aa
LP
537 prop == PROP_PRETTY_HOSTNAME ?
538 "org.freedesktop.hostname1.set-static-hostname" :
f3885791 539 "org.freedesktop.hostname1.set-machine-info", interactive, &c->polkit_registry, error);
66a4c743 540 if (r < 0)
ebcf1f97 541 return r;
66a4c743
LP
542 if (r == 0)
543 return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
544
545 if (isempty(name)) {
546 free(c->data[prop]);
547 c->data[prop] = NULL;
548 } else {
549 char *h;
550
551 /* The icon name might ultimately be used as file
552 * name, so better be safe than sorry */
553
554 if (prop == PROP_ICON_NAME && !filename_is_safe(name))
ebcf1f97 555 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid icon name '%s'", name);
6294aa76 556 if (prop == PROP_PRETTY_HOSTNAME && string_has_cc(name, NULL))
ebcf1f97 557 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid pretty host name '%s'", name);
66a4c743 558 if (prop == PROP_CHASSIS && !valid_chassis(name))
ebcf1f97 559 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid chassis '%s'", name);
799298d6
JG
560 if (prop == PROP_DEPLOYMENT && !valid_deployment(name))
561 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid deployment '%s'", name);
ce0f1493
LP
562 if (prop == PROP_LOCATION && string_has_cc(name, NULL))
563 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid location '%s'", name);
66a4c743
LP
564
565 h = strdup(name);
566 if (!h)
ebcf1f97 567 return -ENOMEM;
66a4c743
LP
568
569 free(c->data[prop]);
570 c->data[prop] = h;
7640a5de
LP
571 }
572
f200e8bb 573 r = context_write_data_machine_info(c);
66a4c743
LP
574 if (r < 0) {
575 log_error("Failed to write machine info: %s", strerror(-r));
ebcf1f97 576 return sd_bus_error_set_errnof(error, r, "Failed to write machine info: %s", strerror(-r));
66a4c743 577 }
7640a5de 578
66a4c743
LP
579 log_info("Changed %s to '%s'",
580 prop == PROP_PRETTY_HOSTNAME ? "pretty host name" :
799298d6 581 prop == PROP_DEPLOYMENT ? "deployment" :
ce0f1493 582 prop == PROP_LOCATION ? "location" :
66a4c743 583 prop == PROP_CHASSIS ? "chassis" : "icon name", strna(c->data[prop]));
7640a5de 584
66a4c743
LP
585 sd_bus_emit_properties_changed(bus, "/org/freedesktop/hostname1", "org.freedesktop.hostname1",
586 prop == PROP_PRETTY_HOSTNAME ? "PrettyHostname" :
799298d6 587 prop == PROP_DEPLOYMENT ? "Deployment" :
ce0f1493 588 prop == PROP_LOCATION ? "Location" :
799298d6 589 prop == PROP_CHASSIS ? "Chassis" : "IconName" , NULL);
7640a5de 590
df2d202e 591 return sd_bus_reply_method_return(m, NULL);
66a4c743 592}
7640a5de 593
ebcf1f97
LP
594static int method_set_pretty_hostname(sd_bus *bus, sd_bus_message *m, void *userdata, sd_bus_error *error) {
595 return set_machine_info(userdata, bus, m, PROP_PRETTY_HOSTNAME, method_set_pretty_hostname, error);
7640a5de
LP
596}
597
ebcf1f97
LP
598static int method_set_icon_name(sd_bus *bus, sd_bus_message *m, void *userdata, sd_bus_error *error) {
599 return set_machine_info(userdata, bus, m, PROP_ICON_NAME, method_set_icon_name, error);
66a4c743
LP
600}
601
ebcf1f97
LP
602static int method_set_chassis(sd_bus *bus, sd_bus_message *m, void *userdata, sd_bus_error *error) {
603 return set_machine_info(userdata, bus, m, PROP_CHASSIS, method_set_chassis, error);
66a4c743
LP
604}
605
799298d6
JG
606static int method_set_deployment(sd_bus *bus, sd_bus_message *m, void *userdata, sd_bus_error *error) {
607 return set_machine_info(userdata, bus, m, PROP_DEPLOYMENT, method_set_deployment, error);
608}
609
ce0f1493
LP
610static int method_set_location(sd_bus *bus, sd_bus_message *m, void *userdata, sd_bus_error *error) {
611 return set_machine_info(userdata, bus, m, PROP_LOCATION, method_set_location, error);
612}
613
66a4c743
LP
614static const sd_bus_vtable hostname_vtable[] = {
615 SD_BUS_VTABLE_START(0),
caffbef6 616 SD_BUS_PROPERTY("Hostname", "s", NULL, offsetof(Context, data) + sizeof(char*) * PROP_HOSTNAME, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
66a4c743
LP
617 SD_BUS_PROPERTY("StaticHostname", "s", NULL, offsetof(Context, data) + sizeof(char*) * PROP_STATIC_HOSTNAME, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
618 SD_BUS_PROPERTY("PrettyHostname", "s", NULL, offsetof(Context, data) + sizeof(char*) * PROP_PRETTY_HOSTNAME, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
619 SD_BUS_PROPERTY("IconName", "s", property_get_icon_name, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
620 SD_BUS_PROPERTY("Chassis", "s", property_get_chassis, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
ce0f1493
LP
621 SD_BUS_PROPERTY("Deployment", "s", NULL, offsetof(Context, data) + sizeof(char*) * PROP_DEPLOYMENT, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
622 SD_BUS_PROPERTY("Location", "s", NULL, offsetof(Context, data) + sizeof(char*) * PROP_LOCATION, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
f426cc5d
DH
623 SD_BUS_PROPERTY("KernelName", "s", NULL, offsetof(Context, data) + sizeof(char*) * PROP_KERNEL_NAME, SD_BUS_VTABLE_PROPERTY_CONST),
624 SD_BUS_PROPERTY("KernelRelease", "s", NULL, offsetof(Context, data) + sizeof(char*) * PROP_KERNEL_RELEASE, SD_BUS_VTABLE_PROPERTY_CONST),
9be3455f 625 SD_BUS_PROPERTY("KernelVersion", "s", NULL, offsetof(Context, data) + sizeof(char*) * PROP_KERNEL_VERSION, SD_BUS_VTABLE_PROPERTY_CONST),
44c32988
DH
626 SD_BUS_PROPERTY("OperatingSystemPrettyName", "s", NULL, offsetof(Context, data) + sizeof(char*) * PROP_OS_PRETTY_NAME, SD_BUS_VTABLE_PROPERTY_CONST),
627 SD_BUS_PROPERTY("OperatingSystemCPEName", "s", NULL, offsetof(Context, data) + sizeof(char*) * PROP_OS_CPE_NAME, SD_BUS_VTABLE_PROPERTY_CONST),
adacb957
LP
628 SD_BUS_METHOD("SetHostname", "sb", NULL, method_set_hostname, SD_BUS_VTABLE_UNPRIVILEGED),
629 SD_BUS_METHOD("SetStaticHostname", "sb", NULL, method_set_static_hostname, SD_BUS_VTABLE_UNPRIVILEGED),
630 SD_BUS_METHOD("SetPrettyHostname", "sb", NULL, method_set_pretty_hostname, SD_BUS_VTABLE_UNPRIVILEGED),
631 SD_BUS_METHOD("SetIconName", "sb", NULL, method_set_icon_name, SD_BUS_VTABLE_UNPRIVILEGED),
632 SD_BUS_METHOD("SetChassis", "sb", NULL, method_set_chassis, SD_BUS_VTABLE_UNPRIVILEGED),
799298d6 633 SD_BUS_METHOD("SetDeployment", "sb", NULL, method_set_deployment, SD_BUS_VTABLE_UNPRIVILEGED),
ce0f1493 634 SD_BUS_METHOD("SetLocation", "sb", NULL, method_set_location, SD_BUS_VTABLE_UNPRIVILEGED),
66a4c743
LP
635 SD_BUS_VTABLE_END,
636};
637
638static int connect_bus(Context *c, sd_event *event, sd_bus **_bus) {
24996861 639 _cleanup_bus_close_unref_ sd_bus *bus = NULL;
7640a5de
LP
640 int r;
641
66a4c743
LP
642 assert(c);
643 assert(event);
d0baa06f
LP
644 assert(_bus);
645
76b54375 646 r = sd_bus_default_system(&bus);
66a4c743
LP
647 if (r < 0) {
648 log_error("Failed to get system bus connection: %s", strerror(-r));
649 return r;
d0baa06f
LP
650 }
651
19befb2d 652 r = sd_bus_add_object_vtable(bus, NULL, "/org/freedesktop/hostname1", "org.freedesktop.hostname1", hostname_vtable, c);
66a4c743
LP
653 if (r < 0) {
654 log_error("Failed to register object: %s", strerror(-r));
655 return r;
d0baa06f
LP
656 }
657
5bb658a1 658 r = sd_bus_request_name(bus, "org.freedesktop.hostname1", 0);
66a4c743
LP
659 if (r < 0) {
660 log_error("Failed to register name: %s", strerror(-r));
661 return r;
add10b5a
LP
662 }
663
66a4c743
LP
664 r = sd_bus_attach_event(bus, event, 0);
665 if (r < 0) {
666 log_error("Failed to attach bus to event loop: %s", strerror(-r));
667 return r;
668 }
d0baa06f 669
66a4c743
LP
670 *_bus = bus;
671 bus = NULL;
d0baa06f 672
66a4c743 673 return 0;
d0baa06f
LP
674}
675
676int main(int argc, char *argv[]) {
66a4c743 677 Context context = {};
66a4c743 678 _cleanup_event_unref_ sd_event *event = NULL;
24996861 679 _cleanup_bus_close_unref_ sd_bus *bus = NULL;
d0baa06f 680 int r;
d0baa06f 681
7640a5de
LP
682 log_set_target(LOG_TARGET_AUTO);
683 log_parse_environment();
684 log_open();
685
4c12626c 686 umask(0022);
cc56fafe 687 mac_selinux_init("/etc");
4c12626c 688
7640a5de
LP
689 if (argc != 1) {
690 log_error("This program takes no arguments.");
691 r = -EINVAL;
692 goto finish;
693 }
694
66a4c743
LP
695 if (argc != 1) {
696 log_error("This program takes no arguments.");
697 r = -EINVAL;
698 goto finish;
699 }
700
afc6adb5 701 r = sd_event_default(&event);
7640a5de 702 if (r < 0) {
66a4c743 703 log_error("Failed to allocate event loop: %s", strerror(-r));
7640a5de
LP
704 goto finish;
705 }
706
cde93897
LP
707 sd_event_set_watchdog(event, true);
708
66a4c743 709 r = connect_bus(&context, event, &bus);
d0baa06f 710 if (r < 0)
7640a5de 711 goto finish;
7640a5de 712
66a4c743
LP
713 r = context_read_data(&context);
714 if (r < 0) {
3a3c71c1 715 log_error("Failed to read hostname and machine information: %s", strerror(-r));
66a4c743
LP
716 goto finish;
717 }
ad740100 718
37224a5f 719 r = bus_event_loop_with_idle(event, bus, "org.freedesktop.hostname1", DEFAULT_EXIT_USEC, NULL, NULL);
66a4c743
LP
720 if (r < 0) {
721 log_error("Failed to run event loop: %s", strerror(-r));
722 goto finish;
ad740100 723 }
7640a5de 724
7640a5de 725finish:
36e34057 726 context_free(&context);
7640a5de 727
7640a5de
LP
728 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
729}