1 /* SPDX-License-Identifier: LGPL-2.1+ */
3 This file is part of systemd.
5 Copyright 2012 Lennart Poettering
7 systemd is free software; you can redistribute it and/or modify it
8 under the terms of the GNU Lesser General Public License as published by
9 the Free Software Foundation; either version 2.1 of the License, or
10 (at your option) any later version.
12 systemd is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Lesser General Public License for more details.
17 You should have received a copy of the GNU Lesser General Public License
18 along with systemd; If not, see <http://www.gnu.org/licenses/>.
30 #include "alloc-util.h"
31 #include "architecture.h"
32 #include "bus-error.h"
34 #include "hostname-util.h"
35 #include "spawn-polkit-agent.h"
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;
46 typedef struct StatusInfo
{
48 const char *static_hostname
;
49 const char *pretty_hostname
;
50 const char *icon_name
;
52 const char *deployment
;
54 const char *kernel_name
;
55 const char *kernel_release
;
56 const char *os_pretty_name
;
57 const char *os_cpe_name
;
58 const char *virtualization
;
59 const char *architecture
;
62 static void print_status_info(StatusInfo
*i
) {
63 sd_id128_t mid
= {}, bid
= {};
68 printf(" Static hostname: %s\n", strna(i
->static_hostname
));
70 if (!isempty(i
->pretty_hostname
) &&
71 !streq_ptr(i
->pretty_hostname
, i
->static_hostname
))
72 printf(" Pretty hostname: %s\n", i
->pretty_hostname
);
74 if (!isempty(i
->hostname
) &&
75 !streq_ptr(i
->hostname
, i
->static_hostname
))
76 printf("Transient hostname: %s\n", i
->hostname
);
78 if (!isempty(i
->icon_name
))
79 printf(" Icon name: %s\n",
82 if (!isempty(i
->chassis
))
83 printf(" Chassis: %s\n",
86 if (!isempty(i
->deployment
))
87 printf(" Deployment: %s\n", i
->deployment
);
89 if (!isempty(i
->location
))
90 printf(" Location: %s\n", i
->location
);
92 r
= sd_id128_get_machine(&mid
);
94 printf(" Machine ID: " SD_ID128_FORMAT_STR
"\n", SD_ID128_FORMAT_VAL(mid
));
96 r
= sd_id128_get_boot(&bid
);
98 printf(" Boot ID: " SD_ID128_FORMAT_STR
"\n", SD_ID128_FORMAT_VAL(bid
));
100 if (!isempty(i
->virtualization
))
101 printf(" Virtualization: %s\n", i
->virtualization
);
103 if (!isempty(i
->os_pretty_name
))
104 printf(" Operating System: %s\n", i
->os_pretty_name
);
106 if (!isempty(i
->os_cpe_name
))
107 printf(" CPE OS Name: %s\n", i
->os_cpe_name
);
109 if (!isempty(i
->kernel_name
) && !isempty(i
->kernel_release
))
110 printf(" Kernel: %s %s\n", i
->kernel_name
, i
->kernel_release
);
112 if (!isempty(i
->architecture
))
113 printf(" Architecture: %s\n", i
->architecture
);
117 static int show_one_name(sd_bus
*bus
, const char* attr
) {
118 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
*reply
= NULL
;
119 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
123 r
= sd_bus_get_property(
125 "org.freedesktop.hostname1",
126 "/org/freedesktop/hostname1",
127 "org.freedesktop.hostname1",
129 &error
, &reply
, "s");
131 return log_error_errno(r
, "Could not get property: %s", bus_error_message(&error
, r
));
133 r
= sd_bus_message_read(reply
, "s", &s
);
135 return bus_log_parse_error(r
);
142 static int show_all_names(sd_bus
*bus
, sd_bus_error
*error
) {
143 StatusInfo info
= {};
145 static const struct bus_properties_map hostname_map
[] = {
146 { "Hostname", "s", NULL
, offsetof(StatusInfo
, hostname
) },
147 { "StaticHostname", "s", NULL
, offsetof(StatusInfo
, static_hostname
) },
148 { "PrettyHostname", "s", NULL
, offsetof(StatusInfo
, pretty_hostname
) },
149 { "IconName", "s", NULL
, offsetof(StatusInfo
, icon_name
) },
150 { "Chassis", "s", NULL
, offsetof(StatusInfo
, chassis
) },
151 { "Deployment", "s", NULL
, offsetof(StatusInfo
, deployment
) },
152 { "Location", "s", NULL
, offsetof(StatusInfo
, location
) },
153 { "KernelName", "s", NULL
, offsetof(StatusInfo
, kernel_name
) },
154 { "KernelRelease", "s", NULL
, offsetof(StatusInfo
, kernel_release
) },
155 { "OperatingSystemPrettyName", "s", NULL
, offsetof(StatusInfo
, os_pretty_name
) },
156 { "OperatingSystemCPEName", "s", NULL
, offsetof(StatusInfo
, os_cpe_name
) },
160 static const struct bus_properties_map manager_map
[] = {
161 { "Virtualization", "s", NULL
, offsetof(StatusInfo
, virtualization
) },
162 { "Architecture", "s", NULL
, offsetof(StatusInfo
, architecture
) },
166 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
*host_message
= NULL
, *manager_message
= NULL
;
169 r
= bus_map_all_properties(bus
,
170 "org.freedesktop.hostname1",
171 "/org/freedesktop/hostname1",
179 r
= bus_map_all_properties(bus
,
180 "org.freedesktop.systemd1",
181 "/org/freedesktop/systemd1",
187 print_status_info(&info
);
192 static int show_status(int argc
, char **argv
, void *userdata
) {
193 sd_bus
*bus
= userdata
;
196 if (arg_pretty
|| arg_static
|| arg_transient
) {
199 if (!!arg_static
+ !!arg_pretty
+ !!arg_transient
> 1) {
200 log_error("Cannot query more than one name type at a time");
204 attr
= arg_pretty
? "PrettyHostname" :
205 arg_static
? "StaticHostname" : "Hostname";
207 return show_one_name(bus
, attr
);
209 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
211 r
= show_all_names(bus
, &error
);
213 return log_error_errno(r
, "Failed to query system properties: %s", bus_error_message(&error
, r
));
219 static int set_simple_string(sd_bus
*bus
, const char *method
, const char *value
) {
220 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
223 polkit_agent_open_if_enabled(arg_transport
, arg_ask_password
);
225 r
= sd_bus_call_method(
227 "org.freedesktop.hostname1",
228 "/org/freedesktop/hostname1",
229 "org.freedesktop.hostname1",
232 "sb", value
, arg_ask_password
);
234 log_error("Could not set property: %s", bus_error_message(&error
, -r
));
238 static int set_hostname(int argc
, char **argv
, void *userdata
) {
239 _cleanup_free_
char *h
= NULL
;
240 const char *hostname
= argv
[1];
241 sd_bus
*bus
= userdata
;
244 if (!arg_pretty
&& !arg_static
&& !arg_transient
)
245 arg_pretty
= arg_static
= arg_transient
= true;
250 /* If the passed hostname is already valid, then assume the user doesn't know anything about pretty
251 * hostnames, so let's unset the pretty hostname, and just set the passed hostname as static/dynamic
253 if (arg_static
&& hostname_is_valid(hostname
, true))
254 p
= ""; /* No pretty hostname (as it is redundant), just a static one */
256 p
= hostname
; /* Use the passed name as pretty hostname */
258 r
= set_simple_string(bus
, "SetPrettyHostname", p
);
262 /* Now that we set the pretty hostname, let's clean up the parameter and use that as static
263 * hostname. If the hostname was already valid as static hostname, this will only chop off the trailing
264 * dot if there is one. If it was not valid, then it will be made fully valid by truncating, dropping
265 * multiple dots, and dropping weird chars. Note that we clean the name up only if we also are
266 * supposed to set the pretty name. If the pretty name is not being set we assume the user knows what
267 * he does and pass the name as-is. */
268 h
= strdup(hostname
);
272 hostname
= hostname_cleanup(h
); /* Use the cleaned up name as static hostname */
276 r
= set_simple_string(bus
, "SetStaticHostname", hostname
);
282 r
= set_simple_string(bus
, "SetHostname", hostname
);
290 static int set_icon_name(int argc
, char **argv
, void *userdata
) {
291 return set_simple_string(userdata
, "SetIconName", argv
[1]);
294 static int set_chassis(int argc
, char **argv
, void *userdata
) {
295 return set_simple_string(userdata
, "SetChassis", argv
[1]);
298 static int set_deployment(int argc
, char **argv
, void *userdata
) {
299 return set_simple_string(userdata
, "SetDeployment", argv
[1]);
302 static int set_location(int argc
, char **argv
, void *userdata
) {
303 return set_simple_string(userdata
, "SetLocation", argv
[1]);
306 static int help(void) {
307 printf("%s [OPTIONS...] COMMAND ...\n\n"
308 "Query or change system hostname.\n\n"
309 " -h --help Show this help\n"
310 " --version Show package version\n"
311 " --no-ask-password Do not prompt for password\n"
312 " -H --host=[USER@]HOST Operate on remote host\n"
313 " -M --machine=CONTAINER Operate on local container\n"
314 " --transient Only set transient hostname\n"
315 " --static Only set static hostname\n"
316 " --pretty Only set pretty hostname\n\n"
318 " status Show current hostname settings\n"
319 " set-hostname NAME Set system hostname\n"
320 " set-icon-name NAME Set icon name for host\n"
321 " set-chassis NAME Set chassis type for host\n"
322 " set-deployment NAME Set deployment environment for host\n"
323 " set-location NAME Set location for host\n"
324 , program_invocation_short_name
);
329 static int verb_help(int argc
, char **argv
, void *userdata
) {
333 static int parse_argv(int argc
, char *argv
[]) {
343 static const struct option options
[] = {
344 { "help", no_argument
, NULL
, 'h' },
345 { "version", no_argument
, NULL
, ARG_VERSION
},
346 { "transient", no_argument
, NULL
, ARG_TRANSIENT
},
347 { "static", no_argument
, NULL
, ARG_STATIC
},
348 { "pretty", no_argument
, NULL
, ARG_PRETTY
},
349 { "host", required_argument
, NULL
, 'H' },
350 { "machine", required_argument
, NULL
, 'M' },
351 { "no-ask-password", no_argument
, NULL
, ARG_NO_ASK_PASSWORD
},
360 while ((c
= getopt_long(argc
, argv
, "hH:M:", options
, NULL
)) >= 0)
371 arg_transport
= BUS_TRANSPORT_REMOTE
;
376 arg_transport
= BUS_TRANSPORT_MACHINE
;
381 arg_transient
= true;
392 case ARG_NO_ASK_PASSWORD
:
393 arg_ask_password
= false;
400 assert_not_reached("Unhandled option");
406 static int hostnamectl_main(sd_bus
*bus
, int argc
, char *argv
[]) {
408 static const Verb verbs
[] = {
409 { "status", VERB_ANY
, 1, VERB_DEFAULT
, show_status
},
410 { "set-hostname", 2, 2, 0, set_hostname
},
411 { "set-icon-name", 2, 2, 0, set_icon_name
},
412 { "set-chassis", 2, 2, 0, set_chassis
},
413 { "set-deployment", 2, 2, 0, set_deployment
},
414 { "set-location", 2, 2, 0, set_location
},
415 { "help", VERB_ANY
, VERB_ANY
, 0, verb_help
}, /* Not documented, but supported since it is created. */
419 return dispatch_verb(argc
, argv
, verbs
, bus
);
422 int main(int argc
, char *argv
[]) {
423 _cleanup_(sd_bus_flush_close_unrefp
) sd_bus
*bus
= NULL
;
426 setlocale(LC_ALL
, "");
427 log_parse_environment();
430 r
= parse_argv(argc
, argv
);
434 r
= bus_connect_transport(arg_transport
, arg_host
, false, &bus
);
436 log_error_errno(r
, "Failed to create bus connection: %m");
440 r
= hostnamectl_main(bus
, argc
, argv
);
443 return r
< 0 ? EXIT_FAILURE
: EXIT_SUCCESS
;