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