1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
4 This file is part of systemd.
6 Copyright 2012 Lennart Poettering
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.
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.
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/>.
28 #include <sys/timex.h>
29 #include <sys/utsname.h>
34 #include "bus-error.h"
36 #include "spawn-polkit-agent.h"
38 #include "clock-util.h"
42 #include "architecture.h"
45 static bool arg_ask_password = true;
46 static BusTransport arg_transport = BUS_TRANSPORT_LOCAL;
47 static char *arg_host = NULL;
48 static bool arg_transient = false;
49 static bool arg_pretty = false;
50 static bool arg_static = false;
52 static void polkit_agent_open_if_enabled(void) {
54 /* Open the polkit agent as a child process if necessary */
55 if (!arg_ask_password)
58 if (arg_transport != BUS_TRANSPORT_LOCAL)
64 typedef struct StatusInfo {
66 char *static_hostname;
67 char *pretty_hostname;
80 static void print_status_info(StatusInfo *i) {
81 sd_id128_t mid = {}, bid = {};
86 printf(" Static hostname: %s\n", strna(i->static_hostname));
88 if (!isempty(i->pretty_hostname) &&
89 !streq_ptr(i->pretty_hostname, i->static_hostname))
90 printf(" Pretty hostname: %s\n", i->pretty_hostname);
92 if (!isempty(i->hostname) &&
93 !streq_ptr(i->hostname, i->static_hostname))
94 printf("Transient hostname: %s\n", i->hostname);
96 if (!isempty(i->icon_name))
97 printf(" Icon name: %s\n",
100 if (!isempty(i->chassis))
101 printf(" Chassis: %s\n",
104 if (!isempty(i->deployment))
105 printf(" Deployment: %s\n", i->deployment);
107 if (!isempty(i->location))
108 printf(" Location: %s\n", i->location);
110 r = sd_id128_get_machine(&mid);
112 printf(" Machine ID: " SD_ID128_FORMAT_STR "\n", SD_ID128_FORMAT_VAL(mid));
114 r = sd_id128_get_boot(&bid);
116 printf(" Boot ID: " SD_ID128_FORMAT_STR "\n", SD_ID128_FORMAT_VAL(bid));
118 if (!isempty(i->virtualization))
119 printf(" Virtualization: %s\n", i->virtualization);
121 if (!isempty(i->os_pretty_name))
122 printf(" Operating System: %s\n", i->os_pretty_name);
124 if (!isempty(i->os_cpe_name))
125 printf(" CPE OS Name: %s\n", i->os_cpe_name);
127 if (!isempty(i->kernel_name) && !isempty(i->kernel_release))
128 printf(" Kernel: %s %s\n", i->kernel_name, i->kernel_release);
130 if (!isempty(i->architecture))
131 printf(" Architecture: %s\n", i->architecture);
135 static int show_one_name(sd_bus *bus, const char* attr) {
136 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
137 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
141 r = sd_bus_get_property(
143 "org.freedesktop.hostname1",
144 "/org/freedesktop/hostname1",
145 "org.freedesktop.hostname1",
147 &error, &reply, "s");
149 log_error("Could not get property: %s", bus_error_message(&error, -r));
153 r = sd_bus_message_read(reply, "s", &s);
155 return bus_log_parse_error(r);
162 static int show_all_names(sd_bus *bus) {
163 StatusInfo info = {};
165 static const struct bus_properties_map hostname_map[] = {
166 { "Hostname", "s", NULL, offsetof(StatusInfo, hostname) },
167 { "StaticHostname", "s", NULL, offsetof(StatusInfo, static_hostname) },
168 { "PrettyHostname", "s", NULL, offsetof(StatusInfo, pretty_hostname) },
169 { "IconName", "s", NULL, offsetof(StatusInfo, icon_name) },
170 { "Chassis", "s", NULL, offsetof(StatusInfo, chassis) },
171 { "Deployment", "s", NULL, offsetof(StatusInfo, deployment) },
172 { "Location", "s", NULL, offsetof(StatusInfo, location) },
173 { "KernelName", "s", NULL, offsetof(StatusInfo, kernel_name) },
174 { "KernelRelease", "s", NULL, offsetof(StatusInfo, kernel_release) },
175 { "OperatingSystemPrettyName", "s", NULL, offsetof(StatusInfo, os_pretty_name) },
176 { "OperatingSystemCPEName", "s", NULL, offsetof(StatusInfo, os_cpe_name) },
180 static const struct bus_properties_map manager_map[] = {
181 { "Virtualization", "s", NULL, offsetof(StatusInfo, virtualization) },
182 { "Architecture", "s", NULL, offsetof(StatusInfo, architecture) },
188 r = bus_map_all_properties(bus,
189 "org.freedesktop.hostname1",
190 "/org/freedesktop/hostname1",
196 bus_map_all_properties(bus,
197 "org.freedesktop.systemd1",
198 "/org/freedesktop/systemd1",
202 print_status_info(&info);
206 free(info.static_hostname);
207 free(info.pretty_hostname);
208 free(info.icon_name);
210 free(info.deployment);
212 free(info.kernel_name);
213 free(info.kernel_release);
214 free(info.os_pretty_name);
215 free(info.os_cpe_name);
216 free(info.virtualization);
217 free(info.architecture);
222 static int show_status(sd_bus *bus, char **args, unsigned n) {
225 if (arg_pretty || arg_static || arg_transient) {
228 if (!!arg_static + !!arg_pretty + !!arg_transient > 1) {
229 log_error("Cannot query more than one name type at a time");
233 attr = arg_pretty ? "PrettyHostname" :
234 arg_static ? "StaticHostname" : "Hostname";
236 return show_one_name(bus, attr);
238 return show_all_names(bus);
241 static int set_simple_string(sd_bus *bus, const char *method, const char *value) {
242 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
245 polkit_agent_open_if_enabled();
247 r = sd_bus_call_method(
249 "org.freedesktop.hostname1",
250 "/org/freedesktop/hostname1",
251 "org.freedesktop.hostname1",
254 "sb", value, arg_ask_password);
256 log_error("Could not set property: %s", bus_error_message(&error, -r));
260 static int set_hostname(sd_bus *bus, char **args, unsigned n) {
261 _cleanup_free_ char *h = NULL;
262 const char *hostname = args[1];
268 if (!arg_pretty && !arg_static && !arg_transient)
269 arg_pretty = arg_static = arg_transient = true;
274 /* If the passed hostname is already valid, then
275 * assume the user doesn't know anything about pretty
276 * hostnames, so let's unset the pretty hostname, and
277 * just set the passed hostname as static/dynamic
280 h = strdup(hostname);
284 hostname_cleanup(h, true);
286 if (arg_static && streq(h, hostname))
293 r = set_simple_string(bus, "SetPrettyHostname", p);
299 r = set_simple_string(bus, "SetStaticHostname", hostname);
305 r = set_simple_string(bus, "SetHostname", hostname);
313 static int set_icon_name(sd_bus *bus, char **args, unsigned n) {
317 return set_simple_string(bus, "SetIconName", args[1]);
320 static int set_chassis(sd_bus *bus, char **args, unsigned n) {
324 return set_simple_string(bus, "SetChassis", args[1]);
327 static int set_deployment(sd_bus *bus, char **args, unsigned n) {
331 return set_simple_string(bus, "SetDeployment", args[1]);
334 static int set_location(sd_bus *bus, char **args, unsigned n) {
338 return set_simple_string(bus, "SetLocation", args[1]);
341 static void help(void) {
342 printf("%s [OPTIONS...] COMMAND ...\n\n"
343 "Query or change system hostname.\n\n"
344 " -h --help Show this help\n"
345 " --version Show package version\n"
346 " --no-ask-password Do not prompt for password\n"
347 " -H --host=[USER@]HOST Operate on remote host\n"
348 " -M --machine=CONTAINER Operate on local container\n"
349 " --transient Only set transient hostname\n"
350 " --static Only set static hostname\n"
351 " --pretty Only set pretty hostname\n\n"
353 " status Show current hostname settings\n"
354 " set-hostname NAME Set system hostname\n"
355 " set-icon-name NAME Set icon name for host\n"
356 " set-chassis NAME Set chassis type for host\n"
357 " set-deployment NAME Set deployment environment for host\n"
358 " set-location NAME Set location for host\n"
359 , program_invocation_short_name);
362 static int parse_argv(int argc, char *argv[]) {
372 static const struct option options[] = {
373 { "help", no_argument, NULL, 'h' },
374 { "version", no_argument, NULL, ARG_VERSION },
375 { "transient", no_argument, NULL, ARG_TRANSIENT },
376 { "static", no_argument, NULL, ARG_STATIC },
377 { "pretty", no_argument, NULL, ARG_PRETTY },
378 { "host", required_argument, NULL, 'H' },
379 { "machine", required_argument, NULL, 'M' },
380 { "no-ask-password", no_argument, NULL, ARG_NO_ASK_PASSWORD },
389 while ((c = getopt_long(argc, argv, "hH:M:", options, NULL)) >= 0)
398 puts(PACKAGE_STRING);
399 puts(SYSTEMD_FEATURES);
403 arg_transport = BUS_TRANSPORT_REMOTE;
408 arg_transport = BUS_TRANSPORT_CONTAINER;
413 arg_transient = true;
424 case ARG_NO_ASK_PASSWORD:
425 arg_ask_password = false;
432 assert_not_reached("Unhandled option");
438 static int hostnamectl_main(sd_bus *bus, int argc, char *argv[]) {
440 static const struct {
448 int (* const dispatch)(sd_bus *bus, char **args, unsigned n);
450 { "status", LESS, 1, show_status },
451 { "set-hostname", EQUAL, 2, set_hostname },
452 { "set-icon-name", EQUAL, 2, set_icon_name },
453 { "set-chassis", EQUAL, 2, set_chassis },
454 { "set-deployment", EQUAL, 2, set_deployment },
455 { "set-location", EQUAL, 2, set_location },
464 left = argc - optind;
467 /* Special rule: no arguments means "status" */
470 if (streq(argv[optind], "help")) {
475 for (i = 0; i < ELEMENTSOF(verbs); i++)
476 if (streq(argv[optind], verbs[i].verb))
479 if (i >= ELEMENTSOF(verbs)) {
480 log_error("Unknown operation %s", argv[optind]);
485 switch (verbs[i].argc_cmp) {
488 if (left != verbs[i].argc) {
489 log_error("Invalid number of arguments.");
496 if (left < verbs[i].argc) {
497 log_error("Too few arguments.");
504 if (left > verbs[i].argc) {
505 log_error("Too many arguments.");
512 assert_not_reached("Unknown comparison operator.");
515 return verbs[i].dispatch(bus, argv + optind, left);
518 int main(int argc, char *argv[]) {
519 _cleanup_bus_close_unref_ sd_bus *bus = NULL;
522 setlocale(LC_ALL, "");
523 log_parse_environment();
526 r = parse_argv(argc, argv);
530 r = bus_open_transport(arg_transport, arg_host, false, &bus);
532 log_error_errno(r, "Failed to create bus connection: %m");
536 r = hostnamectl_main(bus, argc, argv);
539 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;