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;
76 static void print_status_info(StatusInfo *i) {
77 sd_id128_t mid = {}, bid = {};
83 printf(" Static hostname: %s\n", strna(i->static_hostname));
85 if (!isempty(i->pretty_hostname) &&
86 !streq_ptr(i->pretty_hostname, i->static_hostname))
87 printf(" Pretty hostname: %s\n", i->pretty_hostname);
89 if (!isempty(i->hostname) &&
90 !streq_ptr(i->hostname, i->static_hostname))
91 printf("Transient hostname: %s\n", i->hostname);
93 printf(" Icon name: %s\n"
98 r = sd_id128_get_machine(&mid);
100 printf(" Machine ID: " SD_ID128_FORMAT_STR "\n", SD_ID128_FORMAT_VAL(mid));
102 r = sd_id128_get_boot(&bid);
104 printf(" Boot ID: " SD_ID128_FORMAT_STR "\n", SD_ID128_FORMAT_VAL(bid));
106 if (!isempty(i->virtualization))
107 printf(" Virtualization: %s\n", i->virtualization);
109 if (!isempty(i->os_pretty_name))
110 printf(" Operating System: %s\n", i->os_pretty_name);
112 if (!isempty(i->os_cpe_name))
113 printf(" CPE OS Name: %s\n", i->os_cpe_name);
115 assert_se(uname(&u) >= 0);
116 printf(" Kernel: %s %s\n", u.sysname, u.release);
118 if (!isempty(i->architecture))
119 printf(" Architecture: %s\n", i->architecture);
123 static int show_one_name(sd_bus *bus, const char* attr) {
124 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
125 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
129 r = sd_bus_get_property(
131 "org.freedesktop.hostname1",
132 "/org/freedesktop/hostname1",
133 "org.freedesktop.hostname1",
135 &error, &reply, "s");
137 log_error("Could not get property: %s", bus_error_message(&error, -r));
141 r = sd_bus_message_read(reply, "s", &s);
143 return bus_log_parse_error(r);
150 static int show_all_names(sd_bus *bus) {
151 StatusInfo info = {};
153 static const struct bus_properties_map hostname_map[] = {
154 { "Hostname", "s", NULL, offsetof(StatusInfo, hostname) },
155 { "StaticHostname", "s", NULL, offsetof(StatusInfo, static_hostname) },
156 { "PrettyHostname", "s", NULL, offsetof(StatusInfo, pretty_hostname) },
157 { "IconName", "s", NULL, offsetof(StatusInfo, icon_name) },
158 { "Chassis", "s", NULL, offsetof(StatusInfo, chassis) },
159 { "OperatingSystemPrettyName", "s", NULL, offsetof(StatusInfo, os_pretty_name) },
160 { "OperatingSystemCPEName", "s", NULL, offsetof(StatusInfo, os_cpe_name) },
164 static const struct bus_properties_map manager_map[] = {
165 { "Virtualization", "s", NULL, offsetof(StatusInfo, virtualization) },
166 { "Architecture", "s", NULL, offsetof(StatusInfo, architecture) },
172 r = bus_map_all_properties(bus,
173 "org.freedesktop.hostname1",
174 "/org/freedesktop/hostname1",
180 bus_map_all_properties(bus,
181 "org.freedesktop.systemd1",
182 "/org/freedesktop/systemd1",
186 print_status_info(&info);
190 free(info.static_hostname);
191 free(info.pretty_hostname);
192 free(info.icon_name);
194 free(info.os_pretty_name);
195 free(info.os_cpe_name);
196 free(info.virtualization);
197 free(info.architecture);
202 static int show_status(sd_bus *bus, char **args, unsigned n) {
205 if (arg_pretty || arg_static || arg_transient) {
208 if (!!arg_static + !!arg_pretty + !!arg_transient > 1) {
209 log_error("Cannot query more than one name type at a time");
213 attr = arg_pretty ? "PrettyHostname" :
214 arg_static ? "StaticHostname" : "Hostname";
216 return show_one_name(bus, attr);
218 return show_all_names(bus);
221 static int set_simple_string(sd_bus *bus, const char *method, const char *value) {
222 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
225 polkit_agent_open_if_enabled();
227 r = sd_bus_call_method(
229 "org.freedesktop.hostname1",
230 "/org/freedesktop/hostname1",
231 "org.freedesktop.hostname1",
234 "sb", value, arg_ask_password);
236 log_error("Could not set property: %s", bus_error_message(&error, -r));
240 static int set_hostname(sd_bus *bus, char **args, unsigned n) {
241 _cleanup_free_ char *h = NULL;
242 const char *hostname = args[1];
248 if (!arg_pretty && !arg_static && !arg_transient)
249 arg_pretty = arg_static = arg_transient = true;
254 /* If the passed hostname is already valid, then
255 * assume the user doesn't know anything about pretty
256 * hostnames, so let's unset the pretty hostname, and
257 * just set the passed hostname as static/dynamic
260 h = strdup(hostname);
264 hostname_cleanup(h, true);
266 if (arg_static && streq(h, hostname))
273 r = set_simple_string(bus, "SetPrettyHostname", p);
279 r = set_simple_string(bus, "SetStaticHostname", hostname);
285 r = set_simple_string(bus, "SetHostname", hostname);
293 static int set_icon_name(sd_bus *bus, char **args, unsigned n) {
297 return set_simple_string(bus, "SetIconName", args[1]);
300 static int set_chassis(sd_bus *bus, char **args, unsigned n) {
304 return set_simple_string(bus, "SetChassis", args[1]);
307 static int help(void) {
309 printf("%s [OPTIONS...] COMMAND ...\n\n"
310 "Query or change system hostname.\n\n"
311 " -h --help Show this help\n"
312 " --version Show package version\n"
313 " --no-ask-password Do not prompt for password\n"
314 " -H --host=[USER@]HOST Operate on remote host\n"
315 " -M --machine=CONTAINER Operate on local container\n"
316 " --transient Only set transient hostname\n"
317 " --static Only set static hostname\n"
318 " --pretty Only set pretty hostname\n\n"
320 " status Show current hostname settings\n"
321 " set-hostname NAME Set system hostname\n"
322 " set-icon-name NAME Set icon name for host\n"
323 " set-chassis NAME Set chassis type for host\n",
324 program_invocation_short_name);
329 static int parse_argv(int argc, char *argv[]) {
339 static const struct option options[] = {
340 { "help", no_argument, NULL, 'h' },
341 { "version", no_argument, NULL, ARG_VERSION },
342 { "transient", no_argument, NULL, ARG_TRANSIENT },
343 { "static", no_argument, NULL, ARG_STATIC },
344 { "pretty", no_argument, NULL, ARG_PRETTY },
345 { "host", required_argument, NULL, 'H' },
346 { "machine", required_argument, NULL, 'M' },
347 { "no-ask-password", no_argument, NULL, ARG_NO_ASK_PASSWORD },
356 while ((c = getopt_long(argc, argv, "hH:M:", options, NULL)) >= 0) {
364 puts(PACKAGE_STRING);
365 puts(SYSTEMD_FEATURES);
369 arg_transport = BUS_TRANSPORT_REMOTE;
374 arg_transport = BUS_TRANSPORT_CONTAINER;
379 arg_transient = true;
390 case ARG_NO_ASK_PASSWORD:
391 arg_ask_password = false;
398 assert_not_reached("Unhandled option");
405 static int hostnamectl_main(sd_bus *bus, int argc, char *argv[]) {
407 static const struct {
415 int (* const dispatch)(sd_bus *bus, char **args, unsigned n);
417 { "status", LESS, 1, show_status },
418 { "set-hostname", EQUAL, 2, set_hostname },
419 { "set-icon-name", EQUAL, 2, set_icon_name },
420 { "set-chassis", EQUAL, 2, set_chassis },
429 left = argc - optind;
432 /* Special rule: no arguments means "status" */
435 if (streq(argv[optind], "help")) {
440 for (i = 0; i < ELEMENTSOF(verbs); i++)
441 if (streq(argv[optind], verbs[i].verb))
444 if (i >= ELEMENTSOF(verbs)) {
445 log_error("Unknown operation %s", argv[optind]);
450 switch (verbs[i].argc_cmp) {
453 if (left != verbs[i].argc) {
454 log_error("Invalid number of arguments.");
461 if (left < verbs[i].argc) {
462 log_error("Too few arguments.");
469 if (left > verbs[i].argc) {
470 log_error("Too many arguments.");
477 assert_not_reached("Unknown comparison operator.");
480 return verbs[i].dispatch(bus, argv + optind, left);
483 int main(int argc, char *argv[]) {
484 _cleanup_bus_unref_ sd_bus *bus = NULL;
487 setlocale(LC_ALL, "");
488 log_parse_environment();
491 r = parse_argv(argc, argv);
495 r = bus_open_transport(arg_transport, arg_host, false, &bus);
497 log_error("Failed to create bus connection: %s", strerror(-r));
501 r = hostnamectl_main(bus, argc, argv);
504 return r < 0 ? EXIT_FAILURE : r;