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