]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/hostname/hostnamed.c
nss-myhostname: simplify array building a bit
[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>
c2a14cf0 25#include <dlfcn.h>
f426cc5d 26#include <sys/utsname.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,
f426cc5d
DH
47 PROP_KERNEL_NAME,
48 PROP_KERNEL_RELEASE,
9be3455f 49 PROP_KERNEL_VERSION,
44c32988
DH
50 PROP_OS_PRETTY_NAME,
51 PROP_OS_CPE_NAME,
7640a5de
LP
52 _PROP_MAX
53};
54
66a4c743
LP
55typedef struct Context {
56 char *data[_PROP_MAX];
57 Hashmap *polkit_registry;
58} Context;
ad740100 59
66a4c743 60static void context_reset(Context *c) {
7640a5de
LP
61 int p;
62
66a4c743
LP
63 assert(c);
64
7640a5de 65 for (p = 0; p < _PROP_MAX; p++) {
66a4c743
LP
66 free(c->data[p]);
67 c->data[p] = NULL;
7640a5de
LP
68 }
69}
70
66a4c743
LP
71static void context_free(Context *c, sd_bus *bus) {
72 assert(c);
73
74 context_reset(c);
75 bus_verify_polkit_async_registry_free(bus, c->polkit_registry);
76}
77
78static int context_read_data(Context *c) {
7640a5de 79 int r;
f426cc5d 80 struct utsname u;
7640a5de 81
66a4c743
LP
82 assert(c);
83
84 context_reset(c);
7640a5de 85
f426cc5d
DH
86 assert_se(uname(&u) >= 0);
87 c->data[PROP_KERNEL_NAME] = strdup(u.sysname);
88 c->data[PROP_KERNEL_RELEASE] = strdup(u.release);
9be3455f
DH
89 c->data[PROP_KERNEL_VERSION] = strdup(u.version);
90 if (!c->data[PROP_KERNEL_NAME] || !c->data[PROP_KERNEL_RELEASE] ||
91 !c->data[PROP_KERNEL_VERSION])
f426cc5d
DH
92 return -ENOMEM;
93
66a4c743
LP
94 c->data[PROP_HOSTNAME] = gethostname_malloc();
95 if (!c->data[PROP_HOSTNAME])
7640a5de
LP
96 return -ENOMEM;
97
66a4c743 98 r = read_one_line_file("/etc/hostname", &c->data[PROP_STATIC_HOSTNAME]);
7640a5de
LP
99 if (r < 0 && r != -ENOENT)
100 return r;
101
102 r = parse_env_file("/etc/machine-info", NEWLINE,
66a4c743
LP
103 "PRETTY_HOSTNAME", &c->data[PROP_PRETTY_HOSTNAME],
104 "ICON_NAME", &c->data[PROP_ICON_NAME],
105 "CHASSIS", &c->data[PROP_CHASSIS],
799298d6 106 "DEPLOYMENT", &c->data[PROP_DEPLOYMENT],
7640a5de
LP
107 NULL);
108 if (r < 0 && r != -ENOENT)
109 return r;
110
44c32988
DH
111 r = parse_env_file("/etc/os-release", NEWLINE,
112 "PRETTY_NAME", &c->data[PROP_OS_PRETTY_NAME],
113 "CPE_NAME", &c->data[PROP_OS_CPE_NAME],
114 NULL);
5ae4d543
LP
115 if (r == -ENOENT) {
116 r = parse_env_file("/usr/lib/os-release", NEWLINE,
117 "PRETTY_NAME", &c->data[PROP_OS_PRETTY_NAME],
118 "CPE_NAME", &c->data[PROP_OS_CPE_NAME],
119 NULL);
120 }
121
44c32988
DH
122 if (r < 0 && r != -ENOENT)
123 return r;
124
7640a5de
LP
125 return 0;
126}
127
c2a14cf0 128static bool check_nss(void) {
c2a14cf0
LP
129 void *dl;
130
7871c8e9
LP
131 dl = dlopen("libnss_myhostname.so.2", RTLD_LAZY);
132 if (dl) {
c2a14cf0
LP
133 dlclose(dl);
134 return true;
135 }
136
137 return false;
138}
139
7871c8e9 140static bool valid_chassis(const char *chassis) {
7871c8e9
LP
141 assert(chassis);
142
143 return nulstr_contains(
144 "vm\0"
145 "container\0"
146 "desktop\0"
147 "laptop\0"
148 "server\0"
149 "tablet\0"
c49e59c1
LP
150 "handset\0"
151 "watch\0",
7871c8e9
LP
152 chassis);
153}
154
799298d6
JG
155static bool valid_deployment(const char *deployment) {
156 assert(deployment);
157
158 return strspn(deployment, VALID_DEPLOYMENT_CHARS) == strlen(deployment);
159}
160
7871c8e9 161static const char* fallback_chassis(void) {
7640a5de
LP
162 int r;
163 char *type;
164 unsigned t;
248fab74 165 int v;
7871c8e9
LP
166
167 v = detect_virtualization(NULL);
168
169 if (v == VIRTUALIZATION_VM)
170 return "vm";
171 if (v == VIRTUALIZATION_CONTAINER)
172 return "container";
173
174 r = read_one_line_file("/sys/firmware/acpi/pm_profile", &type);
175 if (r < 0)
176 goto try_dmi;
177
178 r = safe_atou(type, &t);
179 free(type);
180 if (r < 0)
181 goto try_dmi;
182
183 /* We only list the really obvious cases here as the ACPI data
184 * is not really super reliable.
185 *
186 * See the ACPI 5.0 Spec Section 5.2.9.1 for details:
187 *
188 * http://www.acpi.info/DOWNLOADS/ACPIspec50.pdf
189 */
190
191 switch(t) {
192
193 case 1:
194 case 3:
195 case 6:
196 return "desktop";
197
198 case 2:
199 return "laptop";
7640a5de 200
7871c8e9
LP
201 case 4:
202 case 5:
203 case 7:
204 return "server";
7640a5de 205
7871c8e9
LP
206 case 8:
207 return "tablet";
208 }
209
210try_dmi:
7640a5de
LP
211 r = read_one_line_file("/sys/class/dmi/id/chassis_type", &type);
212 if (r < 0)
213 return NULL;
214
215 r = safe_atou(type, &t);
216 free(type);
7640a5de
LP
217 if (r < 0)
218 return NULL;
219
220 /* We only list the really obvious cases here. The DMI data is
221 unreliable enough, so let's not do any additional guesswork
41550d40
LP
222 on top of that.
223
224 See the SMBIOS Specification 2.7.1 section 7.4.1 for
225 details about the values listed here:
226
227 http://www.dmtf.org/sites/default/files/standards/documents/DSP0134_2.7.1.pdf
228 */
7640a5de
LP
229
230 switch (t) {
231
232 case 0x3:
233 case 0x4:
234 case 0x6:
235 case 0x7:
7871c8e9 236 return "desktop";
7640a5de 237
7871c8e9 238 case 0x8:
7640a5de
LP
239 case 0x9:
240 case 0xA:
241 case 0xE:
7871c8e9
LP
242 return "laptop";
243
244 case 0xB:
245 return "handset";
7640a5de
LP
246
247 case 0x11:
41550d40 248 case 0x1C:
7871c8e9 249 return "server";
7640a5de
LP
250 }
251
7640a5de
LP
252 return NULL;
253}
254
66a4c743 255static char* context_fallback_icon_name(Context *c) {
7871c8e9
LP
256 const char *chassis;
257
66a4c743
LP
258 assert(c);
259
260 if (!isempty(c->data[PROP_CHASSIS]))
261 return strappend("computer-", c->data[PROP_CHASSIS]);
7871c8e9
LP
262
263 chassis = fallback_chassis();
264 if (chassis)
265 return strappend("computer-", chassis);
266
267 return strdup("computer");
268}
269
799298d6 270
c779a442 271static bool hostname_is_useful(const char *hn) {
fecc80c1 272 return !isempty(hn) && !is_localhost(hn);
c779a442
SW
273}
274
275static int context_update_kernel_hostname(Context *c) {
276 const char *static_hn;
7640a5de
LP
277 const char *hn;
278
66a4c743
LP
279 assert(c);
280
c779a442
SW
281 static_hn = c->data[PROP_STATIC_HOSTNAME];
282
283 /* /etc/hostname with something other than "localhost"
284 * has the highest preference ... */
285 if (hostname_is_useful(static_hn))
286 hn = static_hn;
287
288 /* ... the transient host name, (ie: DHCP) comes next ...*/
289 else if (!isempty(c->data[PROP_HOSTNAME]))
66a4c743 290 hn = c->data[PROP_HOSTNAME];
7640a5de 291
c779a442
SW
292 /* ... fallback to static "localhost.*" ignored above ... */
293 else if (!isempty(static_hn))
294 hn = static_hn;
295
296 /* ... and the ultimate fallback */
297 else
298 hn = "localhost";
299
7640a5de
LP
300 if (sethostname(hn, strlen(hn)) < 0)
301 return -errno;
302
303 return 0;
304}
305
66a4c743 306static int context_write_data_static_hostname(Context *c) {
7640a5de 307
66a4c743
LP
308 assert(c);
309
310 if (isempty(c->data[PROP_STATIC_HOSTNAME])) {
7640a5de
LP
311
312 if (unlink("/etc/hostname") < 0)
313 return errno == ENOENT ? 0 : -errno;
314
315 return 0;
316 }
66a4c743 317 return write_string_file_atomic_label("/etc/hostname", c->data[PROP_STATIC_HOSTNAME]);
7640a5de
LP
318}
319
f200e8bb 320static int context_write_data_machine_info(Context *c) {
4f34ed54 321
7640a5de
LP
322 static const char * const name[_PROP_MAX] = {
323 [PROP_PRETTY_HOSTNAME] = "PRETTY_HOSTNAME",
7871c8e9 324 [PROP_ICON_NAME] = "ICON_NAME",
799298d6
JG
325 [PROP_CHASSIS] = "CHASSIS",
326 [PROP_DEPLOYMENT] = "DEPLOYMENT",
7640a5de
LP
327 };
328
0ccad099 329 _cleanup_strv_free_ char **l = NULL;
7640a5de
LP
330 int r, p;
331
66a4c743
LP
332 assert(c);
333
717603e3 334 r = load_env_file(NULL, "/etc/machine-info", NULL, &l);
7640a5de
LP
335 if (r < 0 && r != -ENOENT)
336 return r;
337
799298d6 338 for (p = PROP_PRETTY_HOSTNAME; p <= PROP_DEPLOYMENT; p++) {
d77ab3f7
LP
339 _cleanup_free_ char *t = NULL;
340 char **u;
7640a5de
LP
341
342 assert(name[p]);
343
66a4c743 344 if (isempty(c->data[p])) {
f8440af5 345 strv_env_unset(l, name[p]);
7640a5de
LP
346 continue;
347 }
348
d77ab3f7
LP
349 t = strjoin(name[p], "=", c->data[p], NULL);
350 if (!t)
7640a5de 351 return -ENOMEM;
7640a5de
LP
352
353 u = strv_env_set(l, t);
7640a5de
LP
354 if (!u)
355 return -ENOMEM;
0ccad099
LP
356
357 strv_free(l);
7640a5de
LP
358 l = u;
359 }
360
361 if (strv_isempty(l)) {
7640a5de
LP
362 if (unlink("/etc/machine-info") < 0)
363 return errno == ENOENT ? 0 : -errno;
364
365 return 0;
366 }
367
0ccad099 368 return write_env_file_label("/etc/machine-info", l);
7640a5de
LP
369}
370
66a4c743
LP
371static int property_get_icon_name(
372 sd_bus *bus,
373 const char *path,
374 const char *interface,
375 const char *property,
376 sd_bus_message *reply,
ebcf1f97
LP
377 void *userdata,
378 sd_bus_error *error) {
7640a5de 379
66a4c743
LP
380 _cleanup_free_ char *n = NULL;
381 Context *c = userdata;
382 const char *name;
7640a5de 383
66a4c743
LP
384 if (isempty(c->data[PROP_ICON_NAME]))
385 name = n = context_fallback_icon_name(c);
7640a5de 386 else
66a4c743
LP
387 name = c->data[PROP_ICON_NAME];
388
389 if (!name)
390 return -ENOMEM;
7640a5de 391
ebcf1f97 392 return sd_bus_message_append(reply, "s", name);
7640a5de
LP
393}
394
66a4c743
LP
395static int property_get_chassis(
396 sd_bus *bus,
397 const char *path,
398 const char *interface,
399 const char *property,
400 sd_bus_message *reply,
ebcf1f97
LP
401 void *userdata,
402 sd_bus_error *error) {
7871c8e9 403
66a4c743
LP
404 Context *c = userdata;
405 const char *name;
7871c8e9 406
66a4c743 407 if (isempty(c->data[PROP_CHASSIS]))
7871c8e9
LP
408 name = fallback_chassis();
409 else
66a4c743 410 name = c->data[PROP_CHASSIS];
7871c8e9 411
ebcf1f97 412 return sd_bus_message_append(reply, "s", name);
7871c8e9
LP
413}
414
799298d6
JG
415static int property_get_deployment(
416 sd_bus *bus,
417 const char *path,
418 const char *interface,
419 const char *property,
420 sd_bus_message *reply,
421 void *userdata,
422 sd_bus_error *error) {
423
424 Context *c = userdata;
425 const char *name;
426
427 name = c->data[PROP_DEPLOYMENT];
428
429 return sd_bus_message_append(reply, "s", name);
430}
431
ebcf1f97 432static int method_set_hostname(sd_bus *bus, sd_bus_message *m, void *userdata, sd_bus_error *error) {
66a4c743
LP
433 Context *c = userdata;
434 const char *name;
102d8f81 435 int interactive;
66a4c743
LP
436 char *h;
437 int r;
d200735e 438
66a4c743
LP
439 r = sd_bus_message_read(m, "sb", &name, &interactive);
440 if (r < 0)
ebcf1f97 441 return r;
d200735e 442
66a4c743
LP
443 if (isempty(name))
444 name = c->data[PROP_STATIC_HOSTNAME];
7640a5de 445
66a4c743
LP
446 if (isempty(name))
447 name = "localhost";
7640a5de 448
66a4c743 449 if (!hostname_is_valid(name))
ebcf1f97 450 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid hostname '%s'", name);
7640a5de 451
66a4c743 452 if (streq_ptr(name, c->data[PROP_HOSTNAME]))
df2d202e 453 return sd_bus_reply_method_return(m, NULL);
7640a5de 454
ebcf1f97 455 r = bus_verify_polkit_async(bus, &c->polkit_registry, m, "org.freedesktop.hostname1.set-hostname", interactive, error, method_set_hostname, c);
66a4c743 456 if (r < 0)
ebcf1f97 457 return r;
66a4c743
LP
458 if (r == 0)
459 return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
7640a5de 460
66a4c743
LP
461 h = strdup(name);
462 if (!h)
ebcf1f97 463 return -ENOMEM;
7640a5de 464
66a4c743
LP
465 free(c->data[PROP_HOSTNAME]);
466 c->data[PROP_HOSTNAME] = h;
7640a5de 467
c779a442 468 r = context_update_kernel_hostname(c);
66a4c743
LP
469 if (r < 0) {
470 log_error("Failed to set host name: %s", strerror(-r));
ebcf1f97 471 return sd_bus_error_set_errnof(error, r, "Failed to set hostname: %s", strerror(-r));
66a4c743 472 }
7640a5de 473
66a4c743 474 log_info("Changed host name to '%s'", strna(c->data[PROP_HOSTNAME]));
7640a5de 475
66a4c743 476 sd_bus_emit_properties_changed(bus, "/org/freedesktop/hostname1", "org.freedesktop.hostname1", "Hostname", NULL);
7640a5de 477
df2d202e 478 return sd_bus_reply_method_return(m, NULL);
66a4c743 479}
7640a5de 480
ebcf1f97 481static int method_set_static_hostname(sd_bus *bus, sd_bus_message *m, void *userdata, sd_bus_error *error) {
66a4c743
LP
482 Context *c = userdata;
483 const char *name;
102d8f81 484 int interactive;
66a4c743 485 int r;
7640a5de 486
66a4c743
LP
487 r = sd_bus_message_read(m, "sb", &name, &interactive);
488 if (r < 0)
ebcf1f97 489 return r;
7640a5de 490
66a4c743
LP
491 if (isempty(name))
492 name = NULL;
7640a5de 493
66a4c743 494 if (streq_ptr(name, c->data[PROP_STATIC_HOSTNAME]))
df2d202e 495 return sd_bus_reply_method_return(m, NULL);
7640a5de 496
ebcf1f97 497 r = bus_verify_polkit_async(bus, &c->polkit_registry, m, "org.freedesktop.hostname1.set-static-hostname", interactive, error, method_set_static_hostname, c);
66a4c743 498 if (r < 0)
ebcf1f97 499 return r;
66a4c743
LP
500 if (r == 0)
501 return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
7640a5de 502
66a4c743
LP
503 if (isempty(name)) {
504 free(c->data[PROP_STATIC_HOSTNAME]);
505 c->data[PROP_STATIC_HOSTNAME] = NULL;
506 } else {
507 char *h;
7640a5de 508
66a4c743 509 if (!hostname_is_valid(name))
ebcf1f97 510 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid static hostname '%s'", name);
7640a5de 511
66a4c743
LP
512 h = strdup(name);
513 if (!h)
ebcf1f97 514 return -ENOMEM;
7640a5de 515
66a4c743
LP
516 free(c->data[PROP_STATIC_HOSTNAME]);
517 c->data[PROP_STATIC_HOSTNAME] = h;
518 }
7640a5de 519
c779a442
SW
520 r = context_update_kernel_hostname(c);
521 if (r < 0) {
522 log_error("Failed to set host name: %s", strerror(-r));
523 return sd_bus_error_set_errnof(error, r, "Failed to set hostname: %s", strerror(-r));
524 }
525
66a4c743
LP
526 r = context_write_data_static_hostname(c);
527 if (r < 0) {
528 log_error("Failed to write static host name: %s", strerror(-r));
ebcf1f97 529 return sd_bus_error_set_errnof(error, r, "Failed to set static hostname: %s", strerror(-r));
66a4c743 530 }
7640a5de 531
66a4c743 532 log_info("Changed static host name to '%s'", strna(c->data[PROP_STATIC_HOSTNAME]));
7640a5de 533
66a4c743 534 sd_bus_emit_properties_changed(bus, "/org/freedesktop/hostname1", "org.freedesktop.hostname1", "StaticHostname", NULL);
7640a5de 535
df2d202e 536 return sd_bus_reply_method_return(m, NULL);
66a4c743 537}
7640a5de 538
ebcf1f97 539static 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 540 int interactive;
66a4c743
LP
541 const char *name;
542 int r;
543
544 assert(c);
545 assert(bus);
546 assert(m);
547
548 r = sd_bus_message_read(m, "sb", &name, &interactive);
549 if (r < 0)
ebcf1f97 550 return r;
66a4c743
LP
551
552 if (isempty(name))
553 name = NULL;
554
555 if (streq_ptr(name, c->data[prop]))
df2d202e 556 return sd_bus_reply_method_return(m, NULL);
7640a5de 557
66a4c743
LP
558 /* Since the pretty hostname should always be changed at the
559 * same time as the static one, use the same policy action for
560 * both... */
561
562 r = bus_verify_polkit_async(bus, &c->polkit_registry, m, prop == PROP_PRETTY_HOSTNAME ?
563 "org.freedesktop.hostname1.set-static-hostname" :
ebcf1f97 564 "org.freedesktop.hostname1.set-machine-info", interactive, error, cb, c);
66a4c743 565 if (r < 0)
ebcf1f97 566 return r;
66a4c743
LP
567 if (r == 0)
568 return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
569
570 if (isempty(name)) {
571 free(c->data[prop]);
572 c->data[prop] = NULL;
573 } else {
574 char *h;
575
576 /* The icon name might ultimately be used as file
577 * name, so better be safe than sorry */
578
579 if (prop == PROP_ICON_NAME && !filename_is_safe(name))
ebcf1f97 580 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid icon name '%s'", name);
6294aa76 581 if (prop == PROP_PRETTY_HOSTNAME && string_has_cc(name, NULL))
ebcf1f97 582 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid pretty host name '%s'", name);
66a4c743 583 if (prop == PROP_CHASSIS && !valid_chassis(name))
ebcf1f97 584 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid chassis '%s'", name);
799298d6
JG
585 if (prop == PROP_DEPLOYMENT && !valid_deployment(name))
586 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid deployment '%s'", name);
66a4c743
LP
587
588 h = strdup(name);
589 if (!h)
ebcf1f97 590 return -ENOMEM;
66a4c743
LP
591
592 free(c->data[prop]);
593 c->data[prop] = h;
7640a5de
LP
594 }
595
f200e8bb 596 r = context_write_data_machine_info(c);
66a4c743
LP
597 if (r < 0) {
598 log_error("Failed to write machine info: %s", strerror(-r));
ebcf1f97 599 return sd_bus_error_set_errnof(error, r, "Failed to write machine info: %s", strerror(-r));
66a4c743 600 }
7640a5de 601
66a4c743
LP
602 log_info("Changed %s to '%s'",
603 prop == PROP_PRETTY_HOSTNAME ? "pretty host name" :
799298d6 604 prop == PROP_DEPLOYMENT ? "deployment" :
66a4c743 605 prop == PROP_CHASSIS ? "chassis" : "icon name", strna(c->data[prop]));
7640a5de 606
66a4c743
LP
607 sd_bus_emit_properties_changed(bus, "/org/freedesktop/hostname1", "org.freedesktop.hostname1",
608 prop == PROP_PRETTY_HOSTNAME ? "PrettyHostname" :
799298d6
JG
609 prop == PROP_DEPLOYMENT ? "Deployment" :
610 prop == PROP_CHASSIS ? "Chassis" : "IconName" , NULL);
7640a5de 611
df2d202e 612 return sd_bus_reply_method_return(m, NULL);
66a4c743 613}
7640a5de 614
ebcf1f97
LP
615static int method_set_pretty_hostname(sd_bus *bus, sd_bus_message *m, void *userdata, sd_bus_error *error) {
616 return set_machine_info(userdata, bus, m, PROP_PRETTY_HOSTNAME, method_set_pretty_hostname, error);
7640a5de
LP
617}
618
ebcf1f97
LP
619static int method_set_icon_name(sd_bus *bus, sd_bus_message *m, void *userdata, sd_bus_error *error) {
620 return set_machine_info(userdata, bus, m, PROP_ICON_NAME, method_set_icon_name, error);
66a4c743
LP
621}
622
ebcf1f97
LP
623static int method_set_chassis(sd_bus *bus, sd_bus_message *m, void *userdata, sd_bus_error *error) {
624 return set_machine_info(userdata, bus, m, PROP_CHASSIS, method_set_chassis, error);
66a4c743
LP
625}
626
799298d6
JG
627static int method_set_deployment(sd_bus *bus, sd_bus_message *m, void *userdata, sd_bus_error *error) {
628 return set_machine_info(userdata, bus, m, PROP_DEPLOYMENT, method_set_deployment, error);
629}
630
66a4c743
LP
631static const sd_bus_vtable hostname_vtable[] = {
632 SD_BUS_VTABLE_START(0),
633 SD_BUS_PROPERTY("Hostname", "s", NULL, offsetof(Context, data) + sizeof(char*) * PROP_HOSTNAME, 0),
634 SD_BUS_PROPERTY("StaticHostname", "s", NULL, offsetof(Context, data) + sizeof(char*) * PROP_STATIC_HOSTNAME, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
635 SD_BUS_PROPERTY("PrettyHostname", "s", NULL, offsetof(Context, data) + sizeof(char*) * PROP_PRETTY_HOSTNAME, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
636 SD_BUS_PROPERTY("IconName", "s", property_get_icon_name, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
637 SD_BUS_PROPERTY("Chassis", "s", property_get_chassis, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
799298d6 638 SD_BUS_PROPERTY("Deployment", "s", property_get_deployment, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
f426cc5d
DH
639 SD_BUS_PROPERTY("KernelName", "s", NULL, offsetof(Context, data) + sizeof(char*) * PROP_KERNEL_NAME, SD_BUS_VTABLE_PROPERTY_CONST),
640 SD_BUS_PROPERTY("KernelRelease", "s", NULL, offsetof(Context, data) + sizeof(char*) * PROP_KERNEL_RELEASE, SD_BUS_VTABLE_PROPERTY_CONST),
9be3455f 641 SD_BUS_PROPERTY("KernelVersion", "s", NULL, offsetof(Context, data) + sizeof(char*) * PROP_KERNEL_VERSION, SD_BUS_VTABLE_PROPERTY_CONST),
44c32988
DH
642 SD_BUS_PROPERTY("OperatingSystemPrettyName", "s", NULL, offsetof(Context, data) + sizeof(char*) * PROP_OS_PRETTY_NAME, SD_BUS_VTABLE_PROPERTY_CONST),
643 SD_BUS_PROPERTY("OperatingSystemCPEName", "s", NULL, offsetof(Context, data) + sizeof(char*) * PROP_OS_CPE_NAME, SD_BUS_VTABLE_PROPERTY_CONST),
adacb957
LP
644 SD_BUS_METHOD("SetHostname", "sb", NULL, method_set_hostname, SD_BUS_VTABLE_UNPRIVILEGED),
645 SD_BUS_METHOD("SetStaticHostname", "sb", NULL, method_set_static_hostname, SD_BUS_VTABLE_UNPRIVILEGED),
646 SD_BUS_METHOD("SetPrettyHostname", "sb", NULL, method_set_pretty_hostname, SD_BUS_VTABLE_UNPRIVILEGED),
647 SD_BUS_METHOD("SetIconName", "sb", NULL, method_set_icon_name, SD_BUS_VTABLE_UNPRIVILEGED),
648 SD_BUS_METHOD("SetChassis", "sb", NULL, method_set_chassis, SD_BUS_VTABLE_UNPRIVILEGED),
799298d6 649 SD_BUS_METHOD("SetDeployment", "sb", NULL, method_set_deployment, SD_BUS_VTABLE_UNPRIVILEGED),
66a4c743
LP
650 SD_BUS_VTABLE_END,
651};
652
653static int connect_bus(Context *c, sd_event *event, sd_bus **_bus) {
654 _cleanup_bus_unref_ sd_bus *bus = NULL;
7640a5de
LP
655 int r;
656
66a4c743
LP
657 assert(c);
658 assert(event);
d0baa06f
LP
659 assert(_bus);
660
76b54375 661 r = sd_bus_default_system(&bus);
66a4c743
LP
662 if (r < 0) {
663 log_error("Failed to get system bus connection: %s", strerror(-r));
664 return r;
d0baa06f
LP
665 }
666
19befb2d 667 r = sd_bus_add_object_vtable(bus, NULL, "/org/freedesktop/hostname1", "org.freedesktop.hostname1", hostname_vtable, c);
66a4c743
LP
668 if (r < 0) {
669 log_error("Failed to register object: %s", strerror(-r));
670 return r;
d0baa06f
LP
671 }
672
5bb658a1 673 r = sd_bus_request_name(bus, "org.freedesktop.hostname1", 0);
66a4c743
LP
674 if (r < 0) {
675 log_error("Failed to register name: %s", strerror(-r));
676 return r;
add10b5a
LP
677 }
678
66a4c743
LP
679 r = sd_bus_attach_event(bus, event, 0);
680 if (r < 0) {
681 log_error("Failed to attach bus to event loop: %s", strerror(-r));
682 return r;
683 }
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
LP
692 Context context = {};
693
694 _cleanup_event_unref_ sd_event *event = NULL;
695 _cleanup_bus_unref_ sd_bus *bus = NULL;
d0baa06f 696 int r;
d0baa06f 697
7640a5de
LP
698 log_set_target(LOG_TARGET_AUTO);
699 log_parse_environment();
700 log_open();
701
4c12626c 702 umask(0022);
a5c32cff 703 label_init("/etc");
4c12626c 704
7640a5de
LP
705 if (argc != 1) {
706 log_error("This program takes no arguments.");
707 r = -EINVAL;
708 goto finish;
709 }
710
c2a14cf0
LP
711 if (!check_nss())
712 log_warning("Warning: nss-myhostname is not installed. Changing the local hostname might make it unresolveable. Please install nss-myhostname!");
713
66a4c743
LP
714 if (argc != 1) {
715 log_error("This program takes no arguments.");
716 r = -EINVAL;
717 goto finish;
718 }
719
afc6adb5 720 r = sd_event_default(&event);
7640a5de 721 if (r < 0) {
66a4c743 722 log_error("Failed to allocate event loop: %s", strerror(-r));
7640a5de
LP
723 goto finish;
724 }
725
cde93897
LP
726 sd_event_set_watchdog(event, true);
727
66a4c743 728 r = connect_bus(&context, event, &bus);
d0baa06f 729 if (r < 0)
7640a5de 730 goto finish;
7640a5de 731
66a4c743
LP
732 r = context_read_data(&context);
733 if (r < 0) {
3a3c71c1 734 log_error("Failed to read hostname and machine information: %s", strerror(-r));
66a4c743
LP
735 goto finish;
736 }
ad740100 737
37224a5f 738 r = bus_event_loop_with_idle(event, bus, "org.freedesktop.hostname1", DEFAULT_EXIT_USEC, NULL, NULL);
66a4c743
LP
739 if (r < 0) {
740 log_error("Failed to run event loop: %s", strerror(-r));
741 goto finish;
ad740100 742 }
7640a5de 743
7640a5de 744finish:
66a4c743 745 context_free(&context, bus);
7640a5de 746
7640a5de
LP
747 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
748}