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"
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;
78 static void print_status_info(StatusInfo *i) {
79 sd_id128_t mid = {}, bid = {};
84 printf(" Static hostname: %s\n", strna(i->static_hostname));
86 if (!isempty(i->pretty_hostname) &&
87 !streq_ptr(i->pretty_hostname, i->static_hostname))
88 printf(" Pretty hostname: %s\n", i->pretty_hostname);
90 if (!isempty(i->hostname) &&
91 !streq_ptr(i->hostname, i->static_hostname))
92 printf("Transient hostname: %s\n", i->hostname);
94 printf(" Icon name: %s\n"
99 r = sd_id128_get_machine(&mid);
101 printf(" Machine ID: " SD_ID128_FORMAT_STR "\n", SD_ID128_FORMAT_VAL(mid));
103 r = sd_id128_get_boot(&bid);
105 printf(" Boot ID: " SD_ID128_FORMAT_STR "\n", SD_ID128_FORMAT_VAL(bid));
107 if (!isempty(i->virtualization))
108 printf(" Virtualization: %s\n", i->virtualization);
110 if (!isempty(i->os_pretty_name))
111 printf(" Operating System: %s\n", i->os_pretty_name);
113 if (!isempty(i->os_cpe_name))
114 printf(" CPE OS Name: %s\n", i->os_cpe_name);
116 if (!isempty(i->kernel_name) && !isempty(i->kernel_release))
117 printf(" Kernel: %s %s\n", i->kernel_name, i->kernel_release);
119 if (!isempty(i->architecture))
120 printf(" Architecture: %s\n", i->architecture);
124 static 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;
130 r = sd_bus_get_property(
132 "org.freedesktop.hostname1",
133 "/org/freedesktop/hostname1",
134 "org.freedesktop.hostname1",
136 &error, &reply, "s");
138 log_error("Could not get property: %s", bus_error_message(&error, -r));
142 r = sd_bus_message_read(reply, "s", &s);
144 return bus_log_parse_error(r);
151 static int show_all_names(sd_bus *bus) {
152 StatusInfo info = {};
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) },
167 static const struct bus_properties_map manager_map[] = {
168 { "Virtualization", "s", NULL, offsetof(StatusInfo, virtualization) },
169 { "Architecture", "s", NULL, offsetof(StatusInfo, architecture) },
175 r = bus_map_all_properties(bus,
176 "org.freedesktop.hostname1",
177 "/org/freedesktop/hostname1",
183 bus_map_all_properties(bus,
184 "org.freedesktop.systemd1",
185 "/org/freedesktop/systemd1",
189 print_status_info(&info);
193 free(info.static_hostname);
194 free(info.pretty_hostname);
195 free(info.icon_name);
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);
207 static int show_status(sd_bus *bus, char **args, unsigned n) {
210 if (arg_pretty || arg_static || arg_transient) {
213 if (!!arg_static + !!arg_pretty + !!arg_transient > 1) {
214 log_error("Cannot query more than one name type at a time");
218 attr = arg_pretty ? "PrettyHostname" :
219 arg_static ? "StaticHostname" : "Hostname";
221 return show_one_name(bus, attr);
223 return show_all_names(bus);
226 static 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;
230 polkit_agent_open_if_enabled();
232 r = sd_bus_call_method(
234 "org.freedesktop.hostname1",
235 "/org/freedesktop/hostname1",
236 "org.freedesktop.hostname1",
239 "sb", value, arg_ask_password);
241 log_error("Could not set property: %s", bus_error_message(&error, -r));
245 static int set_hostname(sd_bus *bus, char **args, unsigned n) {
246 _cleanup_free_ char *h = NULL;
247 const char *hostname = args[1];
253 if (!arg_pretty && !arg_static && !arg_transient)
254 arg_pretty = arg_static = arg_transient = true;
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
265 h = strdup(hostname);
269 hostname_cleanup(h, true);
271 if (arg_static && streq(h, hostname))
278 r = set_simple_string(bus, "SetPrettyHostname", p);
284 r = set_simple_string(bus, "SetStaticHostname", hostname);
290 r = set_simple_string(bus, "SetHostname", hostname);
298 static int set_icon_name(sd_bus *bus, char **args, unsigned n) {
302 return set_simple_string(bus, "SetIconName", args[1]);
305 static int set_chassis(sd_bus *bus, char **args, unsigned n) {
309 return set_simple_string(bus, "SetChassis", args[1]);
312 static int help(void) {
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"
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"
321 " --transient Only set transient hostname\n"
322 " --static Only set static hostname\n"
323 " --pretty Only set pretty hostname\n\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);
334 static int parse_argv(int argc, char *argv[]) {
344 static const struct option options[] = {
345 { "help", no_argument, NULL, 'h' },
346 { "version", no_argument, NULL, ARG_VERSION },
347 { "transient", no_argument, NULL, ARG_TRANSIENT },
348 { "static", no_argument, NULL, ARG_STATIC },
349 { "pretty", no_argument, NULL, ARG_PRETTY },
350 { "host", required_argument, NULL, 'H' },
351 { "machine", required_argument, NULL, 'M' },
352 { "no-ask-password", no_argument, NULL, ARG_NO_ASK_PASSWORD },
361 while ((c = getopt_long(argc, argv, "hH:M:", options, NULL)) >= 0) {
369 puts(PACKAGE_STRING);
370 puts(SYSTEMD_FEATURES);
374 arg_transport = BUS_TRANSPORT_REMOTE;
379 arg_transport = BUS_TRANSPORT_CONTAINER;
384 arg_transient = true;
395 case ARG_NO_ASK_PASSWORD:
396 arg_ask_password = false;
403 assert_not_reached("Unhandled option");
410 static int hostnamectl_main(sd_bus *bus, int argc, char *argv[]) {
412 static const struct {
420 int (* const dispatch)(sd_bus *bus, char **args, unsigned n);
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 },
434 left = argc - optind;
437 /* Special rule: no arguments means "status" */
440 if (streq(argv[optind], "help")) {
445 for (i = 0; i < ELEMENTSOF(verbs); i++)
446 if (streq(argv[optind], verbs[i].verb))
449 if (i >= ELEMENTSOF(verbs)) {
450 log_error("Unknown operation %s", argv[optind]);
455 switch (verbs[i].argc_cmp) {
458 if (left != verbs[i].argc) {
459 log_error("Invalid number of arguments.");
466 if (left < verbs[i].argc) {
467 log_error("Too few arguments.");
474 if (left > verbs[i].argc) {
475 log_error("Too many arguments.");
482 assert_not_reached("Unknown comparison operator.");
485 return verbs[i].dispatch(bus, argv + optind, left);
488 int main(int argc, char *argv[]) {
489 _cleanup_bus_unref_ sd_bus *bus = NULL;
492 setlocale(LC_ALL, "");
493 log_parse_environment();
496 r = parse_argv(argc, argv);
500 r = bus_open_transport(arg_transport, arg_host, false, &bus);
502 log_error("Failed to create bus connection: %s", strerror(-r));
506 r = hostnamectl_main(bus, argc, argv);
509 return r < 0 ? EXIT_FAILURE : r;