]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/hostname/hostnamectl.c
bus-util: add flags for bus_map_all_properties() (#8546)
[thirdparty/systemd.git] / src / hostname / hostnamectl.c
CommitLineData
53e1b683 1/* SPDX-License-Identifier: LGPL-2.1+ */
dbc4fbae
LP
2/***
3 This file is part of systemd.
4
5 Copyright 2012 Lennart Poettering
6
7 systemd is free software; you can redistribute it and/or modify it
8 under the terms of the GNU Lesser General Public License as published by
9 the Free Software Foundation; either version 2.1 of the License, or
10 (at your option) any later version.
11
12 systemd is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Lesser General Public License for more details.
16
17 You should have received a copy of the GNU Lesser General Public License
18 along with systemd; If not, see <http://www.gnu.org/licenses/>.
19***/
20
dbc4fbae 21#include <getopt.h>
a9cdc94f 22#include <locale.h>
3f6fd1ba
LP
23#include <stdbool.h>
24#include <stdlib.h>
dbc4fbae 25#include <string.h>
dbc4fbae 26
b028f3e4 27#include "sd-bus.h"
958b66ea 28#include "sd-id128.h"
3f6fd1ba 29
b5efdb8a 30#include "alloc-util.h"
3f6fd1ba 31#include "architecture.h"
b028f3e4 32#include "bus-error.h"
3f6fd1ba
LP
33#include "bus-util.h"
34#include "hostname-util.h"
dbc4fbae 35#include "spawn-polkit-agent.h"
3f6fd1ba 36#include "util.h"
f46bc484 37#include "verbs.h"
dbc4fbae 38
dbc4fbae 39static bool arg_ask_password = true;
b028f3e4 40static BusTransport arg_transport = BUS_TRANSPORT_LOCAL;
7085053a 41static char *arg_host = NULL;
960787ae
ZJS
42static bool arg_transient = false;
43static bool arg_pretty = false;
44static bool arg_static = false;
dbc4fbae 45
dbc4fbae 46typedef struct StatusInfo {
f37f8a61
YW
47 const char *hostname;
48 const char *static_hostname;
49 const char *pretty_hostname;
50 const char *icon_name;
51 const char *chassis;
52 const char *deployment;
53 const char *location;
54 const char *kernel_name;
55 const char *kernel_release;
56 const char *os_pretty_name;
57 const char *os_cpe_name;
58 const char *virtualization;
59 const char *architecture;
dbc4fbae
LP
60} StatusInfo;
61
62static void print_status_info(StatusInfo *i) {
39883f62 63 sd_id128_t mid = {}, bid = {};
dbc4fbae 64 int r;
dbc4fbae
LP
65
66 assert(i);
67
e9a2e453 68 printf(" Static hostname: %s\n", strna(i->static_hostname));
dbc4fbae 69
c0b21b96
LP
70 if (!isempty(i->pretty_hostname) &&
71 !streq_ptr(i->pretty_hostname, i->static_hostname))
e9a2e453 72 printf(" Pretty hostname: %s\n", i->pretty_hostname);
c0b21b96
LP
73
74 if (!isempty(i->hostname) &&
75 !streq_ptr(i->hostname, i->static_hostname))
e9a2e453 76 printf("Transient hostname: %s\n", i->hostname);
dbc4fbae 77
41414fed
LP
78 if (!isempty(i->icon_name))
79 printf(" Icon name: %s\n",
80 strna(i->icon_name));
81
82 if (!isempty(i->chassis))
83 printf(" Chassis: %s\n",
84 strna(i->chassis));
85
86 if (!isempty(i->deployment))
87 printf(" Deployment: %s\n", i->deployment);
88
89 if (!isempty(i->location))
90 printf(" Location: %s\n", i->location);
dbc4fbae
LP
91
92 r = sd_id128_get_machine(&mid);
93 if (r >= 0)
94 printf(" Machine ID: " SD_ID128_FORMAT_STR "\n", SD_ID128_FORMAT_VAL(mid));
95
96 r = sd_id128_get_boot(&bid);
97 if (r >= 0)
98 printf(" Boot ID: " SD_ID128_FORMAT_STR "\n", SD_ID128_FORMAT_VAL(bid));
99
e9a2e453
LP
100 if (!isempty(i->virtualization))
101 printf(" Virtualization: %s\n", i->virtualization);
fe29f9d2 102
3448456b
DH
103 if (!isempty(i->os_pretty_name))
104 printf(" Operating System: %s\n", i->os_pretty_name);
fe29f9d2 105
3448456b
DH
106 if (!isempty(i->os_cpe_name))
107 printf(" CPE OS Name: %s\n", i->os_cpe_name);
fe29f9d2 108
fa4f8f9b
DH
109 if (!isempty(i->kernel_name) && !isempty(i->kernel_release))
110 printf(" Kernel: %s %s\n", i->kernel_name, i->kernel_release);
e9a2e453
LP
111
112 if (!isempty(i->architecture))
113 printf(" Architecture: %s\n", i->architecture);
fe29f9d2 114
dbc4fbae
LP
115}
116
b028f3e4 117static int show_one_name(sd_bus *bus, const char* attr) {
4afd3348
LP
118 _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
119 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
b028f3e4 120 const char *s;
960787ae
ZJS
121 int r;
122
b028f3e4 123 r = sd_bus_get_property(
960787ae
ZJS
124 bus,
125 "org.freedesktop.hostname1",
126 "/org/freedesktop/hostname1",
b028f3e4
SP
127 "org.freedesktop.hostname1",
128 attr,
129 &error, &reply, "s");
f9e0eefc
LP
130 if (r < 0)
131 return log_error_errno(r, "Could not get property: %s", bus_error_message(&error, r));
960787ae 132
b028f3e4
SP
133 r = sd_bus_message_read(reply, "s", &s);
134 if (r < 0)
5b30bef8 135 return bus_log_parse_error(r);
960787ae 136
960787ae
ZJS
137 printf("%s\n", s);
138
139 return 0;
140}
141
f9e0eefc 142static int show_all_names(sd_bus *bus, sd_bus_error *error) {
b92bea5d 143 StatusInfo info = {};
e9a2e453
LP
144
145 static const struct bus_properties_map hostname_map[] = {
41414fed
LP
146 { "Hostname", "s", NULL, offsetof(StatusInfo, hostname) },
147 { "StaticHostname", "s", NULL, offsetof(StatusInfo, static_hostname) },
148 { "PrettyHostname", "s", NULL, offsetof(StatusInfo, pretty_hostname) },
149 { "IconName", "s", NULL, offsetof(StatusInfo, icon_name) },
150 { "Chassis", "s", NULL, offsetof(StatusInfo, chassis) },
151 { "Deployment", "s", NULL, offsetof(StatusInfo, deployment) },
152 { "Location", "s", NULL, offsetof(StatusInfo, location) },
153 { "KernelName", "s", NULL, offsetof(StatusInfo, kernel_name) },
154 { "KernelRelease", "s", NULL, offsetof(StatusInfo, kernel_release) },
155 { "OperatingSystemPrettyName", "s", NULL, offsetof(StatusInfo, os_pretty_name) },
156 { "OperatingSystemCPEName", "s", NULL, offsetof(StatusInfo, os_cpe_name) },
b028f3e4
SP
157 {}
158 };
e9a2e453
LP
159
160 static const struct bus_properties_map manager_map[] = {
41414fed
LP
161 { "Virtualization", "s", NULL, offsetof(StatusInfo, virtualization) },
162 { "Architecture", "s", NULL, offsetof(StatusInfo, architecture) },
e9a2e453
LP
163 {}
164 };
165
f37f8a61 166 _cleanup_(sd_bus_message_unrefp) sd_bus_message *host_message = NULL, *manager_message = NULL;
b028f3e4 167 int r;
dbc4fbae 168
b028f3e4
SP
169 r = bus_map_all_properties(bus,
170 "org.freedesktop.hostname1",
171 "/org/freedesktop/hostname1",
e9a2e453 172 hostname_map,
a7e4861c 173 0,
f9e0eefc 174 error,
f37f8a61 175 &host_message,
9f6eb1cd 176 &info);
dbc4fbae 177 if (r < 0)
f37f8a61 178 return r;
dbc4fbae 179
f37f8a61
YW
180 r = bus_map_all_properties(bus,
181 "org.freedesktop.systemd1",
182 "/org/freedesktop/systemd1",
183 manager_map,
a7e4861c 184 0,
f37f8a61
YW
185 error,
186 &manager_message,
187 &info);
e9a2e453 188
dbc4fbae 189 print_status_info(&info);
b028f3e4 190
e9a2e453 191 return r;
dbc4fbae
LP
192}
193
f46bc484
YW
194static int show_status(int argc, char **argv, void *userdata) {
195 sd_bus *bus = userdata;
f9e0eefc
LP
196 int r;
197
960787ae
ZJS
198 if (arg_pretty || arg_static || arg_transient) {
199 const char *attr;
200
201 if (!!arg_static + !!arg_pretty + !!arg_transient > 1) {
202 log_error("Cannot query more than one name type at a time");
203 return -EINVAL;
204 }
205
206 attr = arg_pretty ? "PrettyHostname" :
207 arg_static ? "StaticHostname" : "Hostname";
208
209 return show_one_name(bus, attr);
f9e0eefc
LP
210 } else {
211 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
212
213 r = show_all_names(bus, &error);
214 if (r < 0)
215 return log_error_errno(r, "Failed to query system properties: %s", bus_error_message(&error, r));
216
217 return 0;
218 }
960787ae
ZJS
219}
220
b028f3e4 221static int set_simple_string(sd_bus *bus, const char *method, const char *value) {
4afd3348 222 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
b028f3e4
SP
223 int r = 0;
224
8a4b13c5 225 polkit_agent_open_if_enabled(arg_transport, arg_ask_password);
b028f3e4
SP
226
227 r = sd_bus_call_method(
228 bus,
229 "org.freedesktop.hostname1",
230 "/org/freedesktop/hostname1",
231 "org.freedesktop.hostname1",
232 method,
233 &error, NULL,
234 "sb", value, arg_ask_password);
235 if (r < 0)
236 log_error("Could not set property: %s", bus_error_message(&error, -r));
237 return r;
238}
239
f46bc484 240static int set_hostname(int argc, char **argv, void *userdata) {
dbc4fbae 241 _cleanup_free_ char *h = NULL;
f46bc484
YW
242 const char *hostname = argv[1];
243 sd_bus *bus = userdata;
dbc4fbae
LP
244 int r;
245
960787ae
ZJS
246 if (!arg_pretty && !arg_static && !arg_transient)
247 arg_pretty = arg_static = arg_transient = true;
248
249 if (arg_pretty) {
fda2c5d2
LP
250 const char *p;
251
2ae0858e
LP
252 /* If the passed hostname is already valid, then assume the user doesn't know anything about pretty
253 * hostnames, so let's unset the pretty hostname, and just set the passed hostname as static/dynamic
fda2c5d2 254 * hostname. */
2ae0858e
LP
255 if (arg_static && hostname_is_valid(hostname, true))
256 p = ""; /* No pretty hostname (as it is redundant), just a static one */
257 else
258 p = hostname; /* Use the passed name as pretty hostname */
fda2c5d2 259
b028f3e4 260 r = set_simple_string(bus, "SetPrettyHostname", p);
dbc4fbae
LP
261 if (r < 0)
262 return r;
2ae0858e
LP
263
264 /* Now that we set the pretty hostname, let's clean up the parameter and use that as static
265 * hostname. If the hostname was already valid as static hostname, this will only chop off the trailing
266 * dot if there is one. If it was not valid, then it will be made fully valid by truncating, dropping
629ff674 267 * multiple dots, and dropping weird chars. Note that we clean the name up only if we also are
2ae0858e
LP
268 * supposed to set the pretty name. If the pretty name is not being set we assume the user knows what
269 * he does and pass the name as-is. */
270 h = strdup(hostname);
271 if (!h)
272 return log_oom();
273
274 hostname = hostname_cleanup(h); /* Use the cleaned up name as static hostname */
dbc4fbae
LP
275 }
276
960787ae 277 if (arg_static) {
b028f3e4 278 r = set_simple_string(bus, "SetStaticHostname", hostname);
dbc4fbae
LP
279 if (r < 0)
280 return r;
281 }
282
960787ae 283 if (arg_transient) {
b028f3e4 284 r = set_simple_string(bus, "SetHostname", hostname);
dbc4fbae
LP
285 if (r < 0)
286 return r;
287 }
288
289 return 0;
290}
291
f46bc484
YW
292static int set_icon_name(int argc, char **argv, void *userdata) {
293 return set_simple_string(userdata, "SetIconName", argv[1]);
dbc4fbae
LP
294}
295
f46bc484
YW
296static int set_chassis(int argc, char **argv, void *userdata) {
297 return set_simple_string(userdata, "SetChassis", argv[1]);
7871c8e9
LP
298}
299
f46bc484
YW
300static int set_deployment(int argc, char **argv, void *userdata) {
301 return set_simple_string(userdata, "SetDeployment", argv[1]);
799298d6
JG
302}
303
f46bc484
YW
304static int set_location(int argc, char **argv, void *userdata) {
305 return set_simple_string(userdata, "SetLocation", argv[1]);
41414fed
LP
306}
307
f46bc484 308static int help(void) {
7591abd4
LP
309 printf("%s [OPTIONS...] COMMAND ...\n\n"
310 "Query or change system hostname.\n\n"
dbc4fbae
LP
311 " -h --help Show this help\n"
312 " --version Show package version\n"
7591abd4 313 " --no-ask-password Do not prompt for password\n"
b028f3e4 314 " -H --host=[USER@]HOST Operate on remote host\n"
a86a47ce
LP
315 " -M --machine=CONTAINER Operate on local container\n"
316 " --transient Only set transient hostname\n"
317 " --static Only set static hostname\n"
318 " --pretty Only set pretty hostname\n\n"
dbc4fbae 319 "Commands:\n"
7591abd4
LP
320 " status Show current hostname settings\n"
321 " set-hostname NAME Set system hostname\n"
7871c8e9 322 " set-icon-name NAME Set icon name for host\n"
799298d6 323 " set-chassis NAME Set chassis type for host\n"
601185b4 324 " set-deployment NAME Set deployment environment for host\n"
41414fed 325 " set-location NAME Set location for host\n"
601185b4 326 , program_invocation_short_name);
f46bc484
YW
327
328 return 0;
329}
330
331static int verb_help(int argc, char **argv, void *userdata) {
332 return help();
dbc4fbae
LP
333}
334
335static int parse_argv(int argc, char *argv[]) {
336
337 enum {
338 ARG_VERSION = 0x100,
339 ARG_NO_ASK_PASSWORD,
960787ae
ZJS
340 ARG_TRANSIENT,
341 ARG_STATIC,
342 ARG_PRETTY
dbc4fbae
LP
343 };
344
345 static const struct option options[] = {
346 { "help", no_argument, NULL, 'h' },
347 { "version", no_argument, NULL, ARG_VERSION },
eb9da376
LP
348 { "transient", no_argument, NULL, ARG_TRANSIENT },
349 { "static", no_argument, NULL, ARG_STATIC },
350 { "pretty", no_argument, NULL, ARG_PRETTY },
dbc4fbae 351 { "host", required_argument, NULL, 'H' },
b028f3e4 352 { "machine", required_argument, NULL, 'M' },
dbc4fbae 353 { "no-ask-password", no_argument, NULL, ARG_NO_ASK_PASSWORD },
eb9da376 354 {}
dbc4fbae
LP
355 };
356
357 int c;
358
359 assert(argc >= 0);
360 assert(argv);
361
601185b4 362 while ((c = getopt_long(argc, argv, "hH:M:", options, NULL)) >= 0)
dbc4fbae
LP
363
364 switch (c) {
365
366 case 'h':
f46bc484 367 return help();
dbc4fbae
LP
368
369 case ARG_VERSION:
3f6fd1ba 370 return version();
dbc4fbae 371
b028f3e4
SP
372 case 'H':
373 arg_transport = BUS_TRANSPORT_REMOTE;
374 arg_host = optarg;
dbc4fbae
LP
375 break;
376
b028f3e4 377 case 'M':
de33fc62 378 arg_transport = BUS_TRANSPORT_MACHINE;
b028f3e4 379 arg_host = optarg;
dbc4fbae
LP
380 break;
381
960787ae
ZJS
382 case ARG_TRANSIENT:
383 arg_transient = true;
dbc4fbae
LP
384 break;
385
960787ae
ZJS
386 case ARG_PRETTY:
387 arg_pretty = true;
dbc4fbae
LP
388 break;
389
960787ae
ZJS
390 case ARG_STATIC:
391 arg_static = true;
dbc4fbae
LP
392 break;
393
59f432ea
LP
394 case ARG_NO_ASK_PASSWORD:
395 arg_ask_password = false;
396 break;
397
dbc4fbae
LP
398 case '?':
399 return -EINVAL;
400
401 default:
eb9da376 402 assert_not_reached("Unhandled option");
dbc4fbae 403 }
dbc4fbae 404
dbc4fbae
LP
405 return 1;
406}
407
b028f3e4 408static int hostnamectl_main(sd_bus *bus, int argc, char *argv[]) {
dbc4fbae 409
f46bc484
YW
410 static const Verb verbs[] = {
411 { "status", VERB_ANY, 1, VERB_DEFAULT, show_status },
412 { "set-hostname", 2, 2, 0, set_hostname },
413 { "set-icon-name", 2, 2, 0, set_icon_name },
414 { "set-chassis", 2, 2, 0, set_chassis },
415 { "set-deployment", 2, 2, 0, set_deployment },
416 { "set-location", 2, 2, 0, set_location },
417 { "help", VERB_ANY, VERB_ANY, 0, verb_help }, /* Not documented, but supported since it is created. */
418 {}
dbc4fbae
LP
419 };
420
f46bc484 421 return dispatch_verb(argc, argv, verbs, bus);
dbc4fbae
LP
422}
423
424int main(int argc, char *argv[]) {
4afd3348 425 _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
84f6181c 426 int r;
dbc4fbae 427
a9cdc94f 428 setlocale(LC_ALL, "");
dbc4fbae
LP
429 log_parse_environment();
430 log_open();
431
432 r = parse_argv(argc, argv);
b028f3e4 433 if (r <= 0)
dbc4fbae 434 goto finish;
b028f3e4 435
266f3e26 436 r = bus_connect_transport(arg_transport, arg_host, false, &bus);
b028f3e4 437 if (r < 0) {
da927ba9 438 log_error_errno(r, "Failed to create bus connection: %m");
dbc4fbae
LP
439 goto finish;
440 }
441
b028f3e4 442 r = hostnamectl_main(bus, argc, argv);
dbc4fbae
LP
443
444finish:
5567fafb 445 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
dbc4fbae 446}