]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/hostname/hostnamectl.c
networkd: allow trailing dot on fqdn in config file
[thirdparty/systemd.git] / src / hostname / hostnamectl.c
CommitLineData
dbc4fbae
LP
1/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3/***
4 This file is part of systemd.
5
6 Copyright 2012 Lennart Poettering
7
8 systemd is free software; you can redistribute it and/or modify it
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
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
16 Lesser General Public License for more details.
17
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
20***/
21
22#include <stdlib.h>
23#include <stdbool.h>
dbc4fbae 24#include <getopt.h>
a9cdc94f 25#include <locale.h>
dbc4fbae 26#include <string.h>
dbc4fbae 27
b028f3e4 28#include "sd-bus.h"
958b66ea
LP
29#include "sd-id128.h"
30#include "hostname-util.h"
b028f3e4
SP
31#include "bus-util.h"
32#include "bus-error.h"
dbc4fbae
LP
33#include "util.h"
34#include "spawn-polkit-agent.h"
35#include "build.h"
d9d93745 36#include "architecture.h"
dbc4fbae 37
dbc4fbae 38static bool arg_ask_password = true;
b028f3e4 39static BusTransport arg_transport = BUS_TRANSPORT_LOCAL;
7085053a 40static char *arg_host = NULL;
960787ae
ZJS
41static bool arg_transient = false;
42static bool arg_pretty = false;
43static bool arg_static = false;
dbc4fbae 44
46e65dcc
LP
45static void polkit_agent_open_if_enabled(void) {
46
47 /* Open the polkit agent as a child process if necessary */
48 if (!arg_ask_password)
49 return;
50
51 if (arg_transport != BUS_TRANSPORT_LOCAL)
52 return;
53
54 polkit_agent_open();
55}
56
dbc4fbae 57typedef struct StatusInfo {
b028f3e4
SP
58 char *hostname;
59 char *static_hostname;
60 char *pretty_hostname;
61 char *icon_name;
62 char *chassis;
799298d6 63 char *deployment;
41414fed 64 char *location;
fa4f8f9b
DH
65 char *kernel_name;
66 char *kernel_release;
3448456b
DH
67 char *os_pretty_name;
68 char *os_cpe_name;
e9a2e453
LP
69 char *virtualization;
70 char *architecture;
dbc4fbae
LP
71} StatusInfo;
72
73static void print_status_info(StatusInfo *i) {
39883f62 74 sd_id128_t mid = {}, bid = {};
dbc4fbae 75 int r;
dbc4fbae
LP
76
77 assert(i);
78
e9a2e453 79 printf(" Static hostname: %s\n", strna(i->static_hostname));
dbc4fbae 80
c0b21b96
LP
81 if (!isempty(i->pretty_hostname) &&
82 !streq_ptr(i->pretty_hostname, i->static_hostname))
e9a2e453 83 printf(" Pretty hostname: %s\n", i->pretty_hostname);
c0b21b96
LP
84
85 if (!isempty(i->hostname) &&
86 !streq_ptr(i->hostname, i->static_hostname))
e9a2e453 87 printf("Transient hostname: %s\n", i->hostname);
dbc4fbae 88
41414fed
LP
89 if (!isempty(i->icon_name))
90 printf(" Icon name: %s\n",
91 strna(i->icon_name));
92
93 if (!isempty(i->chassis))
94 printf(" Chassis: %s\n",
95 strna(i->chassis));
96
97 if (!isempty(i->deployment))
98 printf(" Deployment: %s\n", i->deployment);
99
100 if (!isempty(i->location))
101 printf(" Location: %s\n", i->location);
dbc4fbae
LP
102
103 r = sd_id128_get_machine(&mid);
104 if (r >= 0)
105 printf(" Machine ID: " SD_ID128_FORMAT_STR "\n", SD_ID128_FORMAT_VAL(mid));
106
107 r = sd_id128_get_boot(&bid);
108 if (r >= 0)
109 printf(" Boot ID: " SD_ID128_FORMAT_STR "\n", SD_ID128_FORMAT_VAL(bid));
110
e9a2e453
LP
111 if (!isempty(i->virtualization))
112 printf(" Virtualization: %s\n", i->virtualization);
fe29f9d2 113
3448456b
DH
114 if (!isempty(i->os_pretty_name))
115 printf(" Operating System: %s\n", i->os_pretty_name);
fe29f9d2 116
3448456b
DH
117 if (!isempty(i->os_cpe_name))
118 printf(" CPE OS Name: %s\n", i->os_cpe_name);
fe29f9d2 119
fa4f8f9b
DH
120 if (!isempty(i->kernel_name) && !isempty(i->kernel_release))
121 printf(" Kernel: %s %s\n", i->kernel_name, i->kernel_release);
e9a2e453
LP
122
123 if (!isempty(i->architecture))
124 printf(" Architecture: %s\n", i->architecture);
fe29f9d2 125
dbc4fbae
LP
126}
127
b028f3e4
SP
128static int show_one_name(sd_bus *bus, const char* attr) {
129 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
130 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
131 const char *s;
960787ae
ZJS
132 int r;
133
b028f3e4 134 r = sd_bus_get_property(
960787ae
ZJS
135 bus,
136 "org.freedesktop.hostname1",
137 "/org/freedesktop/hostname1",
b028f3e4
SP
138 "org.freedesktop.hostname1",
139 attr,
140 &error, &reply, "s");
141 if (r < 0) {
142 log_error("Could not get property: %s", bus_error_message(&error, -r));
960787ae 143 return r;
960787ae
ZJS
144 }
145
b028f3e4
SP
146 r = sd_bus_message_read(reply, "s", &s);
147 if (r < 0)
5b30bef8 148 return bus_log_parse_error(r);
960787ae 149
960787ae
ZJS
150 printf("%s\n", s);
151
152 return 0;
153}
154
b028f3e4 155static int show_all_names(sd_bus *bus) {
b92bea5d 156 StatusInfo info = {};
e9a2e453
LP
157
158 static const struct bus_properties_map hostname_map[] = {
41414fed
LP
159 { "Hostname", "s", NULL, offsetof(StatusInfo, hostname) },
160 { "StaticHostname", "s", NULL, offsetof(StatusInfo, static_hostname) },
161 { "PrettyHostname", "s", NULL, offsetof(StatusInfo, pretty_hostname) },
162 { "IconName", "s", NULL, offsetof(StatusInfo, icon_name) },
163 { "Chassis", "s", NULL, offsetof(StatusInfo, chassis) },
164 { "Deployment", "s", NULL, offsetof(StatusInfo, deployment) },
165 { "Location", "s", NULL, offsetof(StatusInfo, location) },
166 { "KernelName", "s", NULL, offsetof(StatusInfo, kernel_name) },
167 { "KernelRelease", "s", NULL, offsetof(StatusInfo, kernel_release) },
168 { "OperatingSystemPrettyName", "s", NULL, offsetof(StatusInfo, os_pretty_name) },
169 { "OperatingSystemCPEName", "s", NULL, offsetof(StatusInfo, os_cpe_name) },
b028f3e4
SP
170 {}
171 };
e9a2e453
LP
172
173 static const struct bus_properties_map manager_map[] = {
41414fed
LP
174 { "Virtualization", "s", NULL, offsetof(StatusInfo, virtualization) },
175 { "Architecture", "s", NULL, offsetof(StatusInfo, architecture) },
e9a2e453
LP
176 {}
177 };
178
b028f3e4 179 int r;
dbc4fbae 180
b028f3e4
SP
181 r = bus_map_all_properties(bus,
182 "org.freedesktop.hostname1",
183 "/org/freedesktop/hostname1",
e9a2e453 184 hostname_map,
9f6eb1cd 185 &info);
dbc4fbae 186 if (r < 0)
b028f3e4 187 goto fail;
dbc4fbae 188
e9a2e453
LP
189 bus_map_all_properties(bus,
190 "org.freedesktop.systemd1",
191 "/org/freedesktop/systemd1",
192 manager_map,
193 &info);
194
dbc4fbae 195 print_status_info(&info);
b028f3e4
SP
196
197fail:
198 free(info.hostname);
199 free(info.static_hostname);
200 free(info.pretty_hostname);
201 free(info.icon_name);
202 free(info.chassis);
799298d6 203 free(info.deployment);
41414fed 204 free(info.location);
fa4f8f9b
DH
205 free(info.kernel_name);
206 free(info.kernel_release);
3448456b
DH
207 free(info.os_pretty_name);
208 free(info.os_cpe_name);
e9a2e453
LP
209 free(info.virtualization);
210 free(info.architecture);
211
212 return r;
dbc4fbae
LP
213}
214
b028f3e4 215static int show_status(sd_bus *bus, char **args, unsigned n) {
960787ae
ZJS
216 assert(args);
217
218 if (arg_pretty || arg_static || arg_transient) {
219 const char *attr;
220
221 if (!!arg_static + !!arg_pretty + !!arg_transient > 1) {
222 log_error("Cannot query more than one name type at a time");
223 return -EINVAL;
224 }
225
226 attr = arg_pretty ? "PrettyHostname" :
227 arg_static ? "StaticHostname" : "Hostname";
228
229 return show_one_name(bus, attr);
230 } else
231 return show_all_names(bus);
232}
233
b028f3e4
SP
234static int set_simple_string(sd_bus *bus, const char *method, const char *value) {
235 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
b028f3e4
SP
236 int r = 0;
237
46e65dcc 238 polkit_agent_open_if_enabled();
b028f3e4
SP
239
240 r = sd_bus_call_method(
241 bus,
242 "org.freedesktop.hostname1",
243 "/org/freedesktop/hostname1",
244 "org.freedesktop.hostname1",
245 method,
246 &error, NULL,
247 "sb", value, arg_ask_password);
248 if (r < 0)
249 log_error("Could not set property: %s", bus_error_message(&error, -r));
250 return r;
251}
252
253static int set_hostname(sd_bus *bus, char **args, unsigned n) {
dbc4fbae
LP
254 _cleanup_free_ char *h = NULL;
255 const char *hostname = args[1];
256 int r;
257
258 assert(args);
259 assert(n == 2);
260
960787ae
ZJS
261 if (!arg_pretty && !arg_static && !arg_transient)
262 arg_pretty = arg_static = arg_transient = true;
263
264 if (arg_pretty) {
fda2c5d2
LP
265 const char *p;
266
267 /* If the passed hostname is already valid, then
268 * assume the user doesn't know anything about pretty
269 * hostnames, so let's unset the pretty hostname, and
270 * just set the passed hostname as static/dynamic
271 * hostname. */
272
e724b063
LP
273 h = strdup(hostname);
274 if (!h)
275 return log_oom();
276
277 hostname_cleanup(h, true);
278
960787ae 279 if (arg_static && streq(h, hostname))
fda2c5d2
LP
280 p = "";
281 else {
282 p = hostname;
e724b063 283 hostname = h;
fda2c5d2
LP
284 }
285
b028f3e4 286 r = set_simple_string(bus, "SetPrettyHostname", p);
dbc4fbae
LP
287 if (r < 0)
288 return r;
dbc4fbae
LP
289 }
290
960787ae 291 if (arg_static) {
b028f3e4 292 r = set_simple_string(bus, "SetStaticHostname", hostname);
dbc4fbae
LP
293 if (r < 0)
294 return r;
295 }
296
960787ae 297 if (arg_transient) {
b028f3e4 298 r = set_simple_string(bus, "SetHostname", hostname);
dbc4fbae
LP
299 if (r < 0)
300 return r;
301 }
302
303 return 0;
304}
305
b028f3e4 306static int set_icon_name(sd_bus *bus, char **args, unsigned n) {
dbc4fbae
LP
307 assert(args);
308 assert(n == 2);
309
b028f3e4 310 return set_simple_string(bus, "SetIconName", args[1]);
dbc4fbae
LP
311}
312
b028f3e4 313static int set_chassis(sd_bus *bus, char **args, unsigned n) {
7871c8e9
LP
314 assert(args);
315 assert(n == 2);
316
f20c84c1 317 return set_simple_string(bus, "SetChassis", args[1]);
7871c8e9
LP
318}
319
799298d6
JG
320static int set_deployment(sd_bus *bus, char **args, unsigned n) {
321 assert(args);
322 assert(n == 2);
323
324 return set_simple_string(bus, "SetDeployment", args[1]);
325}
326
41414fed
LP
327static int set_location(sd_bus *bus, char **args, unsigned n) {
328 assert(args);
329 assert(n == 2);
330
331 return set_simple_string(bus, "SetLocation", args[1]);
332}
333
601185b4 334static void help(void) {
7591abd4
LP
335 printf("%s [OPTIONS...] COMMAND ...\n\n"
336 "Query or change system hostname.\n\n"
dbc4fbae
LP
337 " -h --help Show this help\n"
338 " --version Show package version\n"
7591abd4 339 " --no-ask-password Do not prompt for password\n"
b028f3e4 340 " -H --host=[USER@]HOST Operate on remote host\n"
a86a47ce
LP
341 " -M --machine=CONTAINER Operate on local container\n"
342 " --transient Only set transient hostname\n"
343 " --static Only set static hostname\n"
344 " --pretty Only set pretty hostname\n\n"
dbc4fbae 345 "Commands:\n"
7591abd4
LP
346 " status Show current hostname settings\n"
347 " set-hostname NAME Set system hostname\n"
7871c8e9 348 " set-icon-name NAME Set icon name for host\n"
799298d6 349 " set-chassis NAME Set chassis type for host\n"
601185b4 350 " set-deployment NAME Set deployment environment for host\n"
41414fed 351 " set-location NAME Set location for host\n"
601185b4 352 , program_invocation_short_name);
dbc4fbae
LP
353}
354
355static int parse_argv(int argc, char *argv[]) {
356
357 enum {
358 ARG_VERSION = 0x100,
359 ARG_NO_ASK_PASSWORD,
960787ae
ZJS
360 ARG_TRANSIENT,
361 ARG_STATIC,
362 ARG_PRETTY
dbc4fbae
LP
363 };
364
365 static const struct option options[] = {
366 { "help", no_argument, NULL, 'h' },
367 { "version", no_argument, NULL, ARG_VERSION },
eb9da376
LP
368 { "transient", no_argument, NULL, ARG_TRANSIENT },
369 { "static", no_argument, NULL, ARG_STATIC },
370 { "pretty", no_argument, NULL, ARG_PRETTY },
dbc4fbae 371 { "host", required_argument, NULL, 'H' },
b028f3e4 372 { "machine", required_argument, NULL, 'M' },
dbc4fbae 373 { "no-ask-password", no_argument, NULL, ARG_NO_ASK_PASSWORD },
eb9da376 374 {}
dbc4fbae
LP
375 };
376
377 int c;
378
379 assert(argc >= 0);
380 assert(argv);
381
601185b4 382 while ((c = getopt_long(argc, argv, "hH:M:", options, NULL)) >= 0)
dbc4fbae
LP
383
384 switch (c) {
385
386 case 'h':
601185b4
ZJS
387 help();
388 return 0;
dbc4fbae
LP
389
390 case ARG_VERSION:
391 puts(PACKAGE_STRING);
dbc4fbae
LP
392 puts(SYSTEMD_FEATURES);
393 return 0;
394
b028f3e4
SP
395 case 'H':
396 arg_transport = BUS_TRANSPORT_REMOTE;
397 arg_host = optarg;
dbc4fbae
LP
398 break;
399
b028f3e4 400 case 'M':
de33fc62 401 arg_transport = BUS_TRANSPORT_MACHINE;
b028f3e4 402 arg_host = optarg;
dbc4fbae
LP
403 break;
404
960787ae
ZJS
405 case ARG_TRANSIENT:
406 arg_transient = true;
dbc4fbae
LP
407 break;
408
960787ae
ZJS
409 case ARG_PRETTY:
410 arg_pretty = true;
dbc4fbae
LP
411 break;
412
960787ae
ZJS
413 case ARG_STATIC:
414 arg_static = true;
dbc4fbae
LP
415 break;
416
59f432ea
LP
417 case ARG_NO_ASK_PASSWORD:
418 arg_ask_password = false;
419 break;
420
dbc4fbae
LP
421 case '?':
422 return -EINVAL;
423
424 default:
eb9da376 425 assert_not_reached("Unhandled option");
dbc4fbae 426 }
dbc4fbae 427
dbc4fbae
LP
428 return 1;
429}
430
b028f3e4 431static int hostnamectl_main(sd_bus *bus, int argc, char *argv[]) {
dbc4fbae
LP
432
433 static const struct {
434 const char* verb;
435 const enum {
436 MORE,
437 LESS,
438 EQUAL
439 } argc_cmp;
440 const int argc;
b028f3e4 441 int (* const dispatch)(sd_bus *bus, char **args, unsigned n);
dbc4fbae 442 } verbs[] = {
41414fed
LP
443 { "status", LESS, 1, show_status },
444 { "set-hostname", EQUAL, 2, set_hostname },
445 { "set-icon-name", EQUAL, 2, set_icon_name },
446 { "set-chassis", EQUAL, 2, set_chassis },
447 { "set-deployment", EQUAL, 2, set_deployment },
448 { "set-location", EQUAL, 2, set_location },
dbc4fbae
LP
449 };
450
451 int left;
452 unsigned i;
453
454 assert(argc >= 0);
455 assert(argv);
dbc4fbae
LP
456
457 left = argc - optind;
458
459 if (left <= 0)
460 /* Special rule: no arguments means "status" */
461 i = 0;
462 else {
463 if (streq(argv[optind], "help")) {
464 help();
465 return 0;
466 }
467
468 for (i = 0; i < ELEMENTSOF(verbs); i++)
469 if (streq(argv[optind], verbs[i].verb))
470 break;
471
472 if (i >= ELEMENTSOF(verbs)) {
473 log_error("Unknown operation %s", argv[optind]);
474 return -EINVAL;
475 }
476 }
477
478 switch (verbs[i].argc_cmp) {
479
480 case EQUAL:
481 if (left != verbs[i].argc) {
482 log_error("Invalid number of arguments.");
483 return -EINVAL;
484 }
485
486 break;
487
488 case MORE:
489 if (left < verbs[i].argc) {
490 log_error("Too few arguments.");
491 return -EINVAL;
492 }
493
494 break;
495
496 case LESS:
497 if (left > verbs[i].argc) {
498 log_error("Too many arguments.");
499 return -EINVAL;
500 }
501
502 break;
503
504 default:
505 assert_not_reached("Unknown comparison operator.");
506 }
507
dbc4fbae
LP
508 return verbs[i].dispatch(bus, argv + optind, left);
509}
510
511int main(int argc, char *argv[]) {
03976f7b 512 _cleanup_bus_flush_close_unref_ sd_bus *bus = NULL;
84f6181c 513 int r;
dbc4fbae 514
a9cdc94f 515 setlocale(LC_ALL, "");
dbc4fbae
LP
516 log_parse_environment();
517 log_open();
518
519 r = parse_argv(argc, argv);
b028f3e4 520 if (r <= 0)
dbc4fbae 521 goto finish;
b028f3e4
SP
522
523 r = bus_open_transport(arg_transport, arg_host, false, &bus);
524 if (r < 0) {
da927ba9 525 log_error_errno(r, "Failed to create bus connection: %m");
dbc4fbae
LP
526 goto finish;
527 }
528
b028f3e4 529 r = hostnamectl_main(bus, argc, argv);
dbc4fbae
LP
530
531finish:
5567fafb 532 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
dbc4fbae 533}