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