]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/hostname/hostnamectl.c
hostname-util: get rid of unused parameter of hostname_cleanup()
[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 254 _cleanup_free_ char *h = NULL;
17eb9a9d 255 char *hostname = args[1];
dbc4fbae
LP
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
17eb9a9d 273 if (arg_static && hostname_is_valid(hostname, true)) {
fda2c5d2 274 p = "";
17eb9a9d 275 /* maybe get rid of trailing dot */
ae691c1d 276 hostname = hostname_cleanup(hostname);
17eb9a9d
ZJS
277 } else {
278 p = h = strdup(hostname);
279 if (!p)
280 return log_oom();
281
ae691c1d 282 hostname_cleanup(hostname);
fda2c5d2
LP
283 }
284
b028f3e4 285 r = set_simple_string(bus, "SetPrettyHostname", p);
dbc4fbae
LP
286 if (r < 0)
287 return r;
dbc4fbae
LP
288 }
289
960787ae 290 if (arg_static) {
b028f3e4 291 r = set_simple_string(bus, "SetStaticHostname", hostname);
dbc4fbae
LP
292 if (r < 0)
293 return r;
294 }
295
960787ae 296 if (arg_transient) {
b028f3e4 297 r = set_simple_string(bus, "SetHostname", hostname);
dbc4fbae
LP
298 if (r < 0)
299 return r;
300 }
301
302 return 0;
303}
304
b028f3e4 305static int set_icon_name(sd_bus *bus, char **args, unsigned n) {
dbc4fbae
LP
306 assert(args);
307 assert(n == 2);
308
b028f3e4 309 return set_simple_string(bus, "SetIconName", args[1]);
dbc4fbae
LP
310}
311
b028f3e4 312static int set_chassis(sd_bus *bus, char **args, unsigned n) {
7871c8e9
LP
313 assert(args);
314 assert(n == 2);
315
f20c84c1 316 return set_simple_string(bus, "SetChassis", args[1]);
7871c8e9
LP
317}
318
799298d6
JG
319static int set_deployment(sd_bus *bus, char **args, unsigned n) {
320 assert(args);
321 assert(n == 2);
322
323 return set_simple_string(bus, "SetDeployment", args[1]);
324}
325
41414fed
LP
326static int set_location(sd_bus *bus, char **args, unsigned n) {
327 assert(args);
328 assert(n == 2);
329
330 return set_simple_string(bus, "SetLocation", args[1]);
331}
332
601185b4 333static void help(void) {
7591abd4
LP
334 printf("%s [OPTIONS...] COMMAND ...\n\n"
335 "Query or change system hostname.\n\n"
dbc4fbae
LP
336 " -h --help Show this help\n"
337 " --version Show package version\n"
7591abd4 338 " --no-ask-password Do not prompt for password\n"
b028f3e4 339 " -H --host=[USER@]HOST Operate on remote host\n"
a86a47ce
LP
340 " -M --machine=CONTAINER Operate on local container\n"
341 " --transient Only set transient hostname\n"
342 " --static Only set static hostname\n"
343 " --pretty Only set pretty hostname\n\n"
dbc4fbae 344 "Commands:\n"
7591abd4
LP
345 " status Show current hostname settings\n"
346 " set-hostname NAME Set system hostname\n"
7871c8e9 347 " set-icon-name NAME Set icon name for host\n"
799298d6 348 " set-chassis NAME Set chassis type for host\n"
601185b4 349 " set-deployment NAME Set deployment environment for host\n"
41414fed 350 " set-location NAME Set location for host\n"
601185b4 351 , program_invocation_short_name);
dbc4fbae
LP
352}
353
354static int parse_argv(int argc, char *argv[]) {
355
356 enum {
357 ARG_VERSION = 0x100,
358 ARG_NO_ASK_PASSWORD,
960787ae
ZJS
359 ARG_TRANSIENT,
360 ARG_STATIC,
361 ARG_PRETTY
dbc4fbae
LP
362 };
363
364 static const struct option options[] = {
365 { "help", no_argument, NULL, 'h' },
366 { "version", no_argument, NULL, ARG_VERSION },
eb9da376
LP
367 { "transient", no_argument, NULL, ARG_TRANSIENT },
368 { "static", no_argument, NULL, ARG_STATIC },
369 { "pretty", no_argument, NULL, ARG_PRETTY },
dbc4fbae 370 { "host", required_argument, NULL, 'H' },
b028f3e4 371 { "machine", required_argument, NULL, 'M' },
dbc4fbae 372 { "no-ask-password", no_argument, NULL, ARG_NO_ASK_PASSWORD },
eb9da376 373 {}
dbc4fbae
LP
374 };
375
376 int c;
377
378 assert(argc >= 0);
379 assert(argv);
380
601185b4 381 while ((c = getopt_long(argc, argv, "hH:M:", options, NULL)) >= 0)
dbc4fbae
LP
382
383 switch (c) {
384
385 case 'h':
601185b4
ZJS
386 help();
387 return 0;
dbc4fbae
LP
388
389 case ARG_VERSION:
390 puts(PACKAGE_STRING);
dbc4fbae
LP
391 puts(SYSTEMD_FEATURES);
392 return 0;
393
b028f3e4
SP
394 case 'H':
395 arg_transport = BUS_TRANSPORT_REMOTE;
396 arg_host = optarg;
dbc4fbae
LP
397 break;
398
b028f3e4 399 case 'M':
de33fc62 400 arg_transport = BUS_TRANSPORT_MACHINE;
b028f3e4 401 arg_host = optarg;
dbc4fbae
LP
402 break;
403
960787ae
ZJS
404 case ARG_TRANSIENT:
405 arg_transient = true;
dbc4fbae
LP
406 break;
407
960787ae
ZJS
408 case ARG_PRETTY:
409 arg_pretty = true;
dbc4fbae
LP
410 break;
411
960787ae
ZJS
412 case ARG_STATIC:
413 arg_static = true;
dbc4fbae
LP
414 break;
415
59f432ea
LP
416 case ARG_NO_ASK_PASSWORD:
417 arg_ask_password = false;
418 break;
419
dbc4fbae
LP
420 case '?':
421 return -EINVAL;
422
423 default:
eb9da376 424 assert_not_reached("Unhandled option");
dbc4fbae 425 }
dbc4fbae 426
dbc4fbae
LP
427 return 1;
428}
429
b028f3e4 430static int hostnamectl_main(sd_bus *bus, int argc, char *argv[]) {
dbc4fbae
LP
431
432 static const struct {
433 const char* verb;
434 const enum {
435 MORE,
436 LESS,
437 EQUAL
438 } argc_cmp;
439 const int argc;
b028f3e4 440 int (* const dispatch)(sd_bus *bus, char **args, unsigned n);
dbc4fbae 441 } verbs[] = {
41414fed
LP
442 { "status", LESS, 1, show_status },
443 { "set-hostname", EQUAL, 2, set_hostname },
444 { "set-icon-name", EQUAL, 2, set_icon_name },
445 { "set-chassis", EQUAL, 2, set_chassis },
446 { "set-deployment", EQUAL, 2, set_deployment },
447 { "set-location", EQUAL, 2, set_location },
dbc4fbae
LP
448 };
449
450 int left;
451 unsigned i;
452
453 assert(argc >= 0);
454 assert(argv);
dbc4fbae
LP
455
456 left = argc - optind;
457
458 if (left <= 0)
459 /* Special rule: no arguments means "status" */
460 i = 0;
461 else {
462 if (streq(argv[optind], "help")) {
463 help();
464 return 0;
465 }
466
467 for (i = 0; i < ELEMENTSOF(verbs); i++)
468 if (streq(argv[optind], verbs[i].verb))
469 break;
470
471 if (i >= ELEMENTSOF(verbs)) {
472 log_error("Unknown operation %s", argv[optind]);
473 return -EINVAL;
474 }
475 }
476
477 switch (verbs[i].argc_cmp) {
478
479 case EQUAL:
480 if (left != verbs[i].argc) {
481 log_error("Invalid number of arguments.");
482 return -EINVAL;
483 }
484
485 break;
486
487 case MORE:
488 if (left < verbs[i].argc) {
489 log_error("Too few arguments.");
490 return -EINVAL;
491 }
492
493 break;
494
495 case LESS:
496 if (left > verbs[i].argc) {
497 log_error("Too many arguments.");
498 return -EINVAL;
499 }
500
501 break;
502
503 default:
504 assert_not_reached("Unknown comparison operator.");
505 }
506
dbc4fbae
LP
507 return verbs[i].dispatch(bus, argv + optind, left);
508}
509
510int main(int argc, char *argv[]) {
03976f7b 511 _cleanup_bus_flush_close_unref_ sd_bus *bus = NULL;
84f6181c 512 int r;
dbc4fbae 513
a9cdc94f 514 setlocale(LC_ALL, "");
dbc4fbae
LP
515 log_parse_environment();
516 log_open();
517
518 r = parse_argv(argc, argv);
b028f3e4 519 if (r <= 0)
dbc4fbae 520 goto finish;
b028f3e4
SP
521
522 r = bus_open_transport(arg_transport, arg_host, false, &bus);
523 if (r < 0) {
da927ba9 524 log_error_errno(r, "Failed to create bus connection: %m");
dbc4fbae
LP
525 goto finish;
526 }
527
b028f3e4 528 r = hostnamectl_main(bus, argc, argv);
dbc4fbae
LP
529
530finish:
5567fafb 531 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
dbc4fbae 532}