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