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