2 This file is part of systemd.
4 Copyright 2012 Lennart Poettering
6 systemd is free software; you can redistribute it and/or modify it
7 under the terms of the GNU Lesser General Public License as published by
8 the Free Software Foundation; either version 2.1 of the License, or
9 (at your option) any later version.
11 systemd is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Lesser General Public License for more details.
16 You should have received a copy of the GNU Lesser General Public License
17 along with systemd; If not, see <http://www.gnu.org/licenses/>.
29 #include "alloc-util.h"
30 #include "architecture.h"
31 #include "bus-error.h"
33 #include "hostname-util.h"
34 #include "spawn-polkit-agent.h"
37 static bool arg_ask_password
= true;
38 static BusTransport arg_transport
= BUS_TRANSPORT_LOCAL
;
39 static char *arg_host
= NULL
;
40 static bool arg_transient
= false;
41 static bool arg_pretty
= false;
42 static bool arg_static
= false;
44 static void polkit_agent_open_if_enabled(void) {
46 /* Open the polkit agent as a child process if necessary */
47 if (!arg_ask_password
)
50 if (arg_transport
!= BUS_TRANSPORT_LOCAL
)
56 typedef struct StatusInfo
{
58 char *static_hostname
;
59 char *pretty_hostname
;
72 static void print_status_info(StatusInfo
*i
) {
73 sd_id128_t mid
= {}, bid
= {};
78 printf(" Static hostname: %s\n", strna(i
->static_hostname
));
80 if (!isempty(i
->pretty_hostname
) &&
81 !streq_ptr(i
->pretty_hostname
, i
->static_hostname
))
82 printf(" Pretty hostname: %s\n", i
->pretty_hostname
);
84 if (!isempty(i
->hostname
) &&
85 !streq_ptr(i
->hostname
, i
->static_hostname
))
86 printf("Transient hostname: %s\n", i
->hostname
);
88 if (!isempty(i
->icon_name
))
89 printf(" Icon name: %s\n",
92 if (!isempty(i
->chassis
))
93 printf(" Chassis: %s\n",
96 if (!isempty(i
->deployment
))
97 printf(" Deployment: %s\n", i
->deployment
);
99 if (!isempty(i
->location
))
100 printf(" Location: %s\n", i
->location
);
102 r
= sd_id128_get_machine(&mid
);
104 printf(" Machine ID: " SD_ID128_FORMAT_STR
"\n", SD_ID128_FORMAT_VAL(mid
));
106 r
= sd_id128_get_boot(&bid
);
108 printf(" Boot ID: " SD_ID128_FORMAT_STR
"\n", SD_ID128_FORMAT_VAL(bid
));
110 if (!isempty(i
->virtualization
))
111 printf(" Virtualization: %s\n", i
->virtualization
);
113 if (!isempty(i
->os_pretty_name
))
114 printf(" Operating System: %s\n", i
->os_pretty_name
);
116 if (!isempty(i
->os_cpe_name
))
117 printf(" CPE OS Name: %s\n", i
->os_cpe_name
);
119 if (!isempty(i
->kernel_name
) && !isempty(i
->kernel_release
))
120 printf(" Kernel: %s %s\n", i
->kernel_name
, i
->kernel_release
);
122 if (!isempty(i
->architecture
))
123 printf(" Architecture: %s\n", i
->architecture
);
127 static int show_one_name(sd_bus
*bus
, const char* attr
) {
128 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
*reply
= NULL
;
129 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
133 r
= sd_bus_get_property(
135 "org.freedesktop.hostname1",
136 "/org/freedesktop/hostname1",
137 "org.freedesktop.hostname1",
139 &error
, &reply
, "s");
141 log_error("Could not get property: %s", bus_error_message(&error
, -r
));
145 r
= sd_bus_message_read(reply
, "s", &s
);
147 return bus_log_parse_error(r
);
154 static int show_all_names(sd_bus
*bus
) {
155 StatusInfo info
= {};
157 static const struct bus_properties_map hostname_map
[] = {
158 { "Hostname", "s", NULL
, offsetof(StatusInfo
, hostname
) },
159 { "StaticHostname", "s", NULL
, offsetof(StatusInfo
, static_hostname
) },
160 { "PrettyHostname", "s", NULL
, offsetof(StatusInfo
, pretty_hostname
) },
161 { "IconName", "s", NULL
, offsetof(StatusInfo
, icon_name
) },
162 { "Chassis", "s", NULL
, offsetof(StatusInfo
, chassis
) },
163 { "Deployment", "s", NULL
, offsetof(StatusInfo
, deployment
) },
164 { "Location", "s", NULL
, offsetof(StatusInfo
, location
) },
165 { "KernelName", "s", NULL
, offsetof(StatusInfo
, kernel_name
) },
166 { "KernelRelease", "s", NULL
, offsetof(StatusInfo
, kernel_release
) },
167 { "OperatingSystemPrettyName", "s", NULL
, offsetof(StatusInfo
, os_pretty_name
) },
168 { "OperatingSystemCPEName", "s", NULL
, offsetof(StatusInfo
, os_cpe_name
) },
172 static const struct bus_properties_map manager_map
[] = {
173 { "Virtualization", "s", NULL
, offsetof(StatusInfo
, virtualization
) },
174 { "Architecture", "s", NULL
, offsetof(StatusInfo
, architecture
) },
180 r
= bus_map_all_properties(bus
,
181 "org.freedesktop.hostname1",
182 "/org/freedesktop/hostname1",
188 bus_map_all_properties(bus
,
189 "org.freedesktop.systemd1",
190 "/org/freedesktop/systemd1",
194 print_status_info(&info
);
198 free(info
.static_hostname
);
199 free(info
.pretty_hostname
);
200 free(info
.icon_name
);
202 free(info
.deployment
);
204 free(info
.kernel_name
);
205 free(info
.kernel_release
);
206 free(info
.os_pretty_name
);
207 free(info
.os_cpe_name
);
208 free(info
.virtualization
);
209 free(info
.architecture
);
214 static int show_status(sd_bus
*bus
, char **args
, unsigned n
) {
217 if (arg_pretty
|| arg_static
|| arg_transient
) {
220 if (!!arg_static
+ !!arg_pretty
+ !!arg_transient
> 1) {
221 log_error("Cannot query more than one name type at a time");
225 attr
= arg_pretty
? "PrettyHostname" :
226 arg_static
? "StaticHostname" : "Hostname";
228 return show_one_name(bus
, attr
);
230 return show_all_names(bus
);
233 static int set_simple_string(sd_bus
*bus
, const char *method
, const char *value
) {
234 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
237 polkit_agent_open_if_enabled();
239 r
= sd_bus_call_method(
241 "org.freedesktop.hostname1",
242 "/org/freedesktop/hostname1",
243 "org.freedesktop.hostname1",
246 "sb", value
, arg_ask_password
);
248 log_error("Could not set property: %s", bus_error_message(&error
, -r
));
252 static int set_hostname(sd_bus
*bus
, char **args
, unsigned n
) {
253 _cleanup_free_
char *h
= NULL
;
254 char *hostname
= args
[1];
260 if (!arg_pretty
&& !arg_static
&& !arg_transient
)
261 arg_pretty
= arg_static
= arg_transient
= true;
266 /* If the passed hostname is already valid, then
267 * assume the user doesn't know anything about pretty
268 * hostnames, so let's unset the pretty hostname, and
269 * just set the passed hostname as static/dynamic
272 if (arg_static
&& hostname_is_valid(hostname
, true)) {
274 /* maybe get rid of trailing dot */
275 hostname
= hostname_cleanup(hostname
);
277 p
= h
= strdup(hostname
);
281 hostname_cleanup(hostname
);
284 r
= set_simple_string(bus
, "SetPrettyHostname", p
);
290 r
= set_simple_string(bus
, "SetStaticHostname", hostname
);
296 r
= set_simple_string(bus
, "SetHostname", hostname
);
304 static int set_icon_name(sd_bus
*bus
, char **args
, unsigned n
) {
308 return set_simple_string(bus
, "SetIconName", args
[1]);
311 static int set_chassis(sd_bus
*bus
, char **args
, unsigned n
) {
315 return set_simple_string(bus
, "SetChassis", args
[1]);
318 static int set_deployment(sd_bus
*bus
, char **args
, unsigned n
) {
322 return set_simple_string(bus
, "SetDeployment", args
[1]);
325 static int set_location(sd_bus
*bus
, char **args
, unsigned n
) {
329 return set_simple_string(bus
, "SetLocation", args
[1]);
332 static void help(void) {
333 printf("%s [OPTIONS...] COMMAND ...\n\n"
334 "Query or change system hostname.\n\n"
335 " -h --help Show this help\n"
336 " --version Show package version\n"
337 " --no-ask-password Do not prompt for password\n"
338 " -H --host=[USER@]HOST Operate on remote host\n"
339 " -M --machine=CONTAINER Operate on local container\n"
340 " --transient Only set transient hostname\n"
341 " --static Only set static hostname\n"
342 " --pretty Only set pretty hostname\n\n"
344 " status Show current hostname settings\n"
345 " set-hostname NAME Set system hostname\n"
346 " set-icon-name NAME Set icon name for host\n"
347 " set-chassis NAME Set chassis type for host\n"
348 " set-deployment NAME Set deployment environment for host\n"
349 " set-location NAME Set location for host\n"
350 , program_invocation_short_name
);
353 static int parse_argv(int argc
, char *argv
[]) {
363 static const struct option options
[] = {
364 { "help", no_argument
, NULL
, 'h' },
365 { "version", no_argument
, NULL
, ARG_VERSION
},
366 { "transient", no_argument
, NULL
, ARG_TRANSIENT
},
367 { "static", no_argument
, NULL
, ARG_STATIC
},
368 { "pretty", no_argument
, NULL
, ARG_PRETTY
},
369 { "host", required_argument
, NULL
, 'H' },
370 { "machine", required_argument
, NULL
, 'M' },
371 { "no-ask-password", no_argument
, NULL
, ARG_NO_ASK_PASSWORD
},
380 while ((c
= getopt_long(argc
, argv
, "hH:M:", options
, NULL
)) >= 0)
392 arg_transport
= BUS_TRANSPORT_REMOTE
;
397 arg_transport
= BUS_TRANSPORT_MACHINE
;
402 arg_transient
= true;
413 case ARG_NO_ASK_PASSWORD
:
414 arg_ask_password
= false;
421 assert_not_reached("Unhandled option");
427 static int hostnamectl_main(sd_bus
*bus
, int argc
, char *argv
[]) {
429 static const struct {
437 int (* const dispatch
)(sd_bus
*bus
, char **args
, unsigned n
);
439 { "status", LESS
, 1, show_status
},
440 { "set-hostname", EQUAL
, 2, set_hostname
},
441 { "set-icon-name", EQUAL
, 2, set_icon_name
},
442 { "set-chassis", EQUAL
, 2, set_chassis
},
443 { "set-deployment", EQUAL
, 2, set_deployment
},
444 { "set-location", EQUAL
, 2, set_location
},
453 left
= argc
- optind
;
456 /* Special rule: no arguments means "status" */
459 if (streq(argv
[optind
], "help")) {
464 for (i
= 0; i
< ELEMENTSOF(verbs
); i
++)
465 if (streq(argv
[optind
], verbs
[i
].verb
))
468 if (i
>= ELEMENTSOF(verbs
)) {
469 log_error("Unknown operation %s", argv
[optind
]);
474 switch (verbs
[i
].argc_cmp
) {
477 if (left
!= verbs
[i
].argc
) {
478 log_error("Invalid number of arguments.");
485 if (left
< verbs
[i
].argc
) {
486 log_error("Too few arguments.");
493 if (left
> verbs
[i
].argc
) {
494 log_error("Too many arguments.");
501 assert_not_reached("Unknown comparison operator.");
504 return verbs
[i
].dispatch(bus
, argv
+ optind
, left
);
507 int main(int argc
, char *argv
[]) {
508 _cleanup_(sd_bus_flush_close_unrefp
) sd_bus
*bus
= NULL
;
511 setlocale(LC_ALL
, "");
512 log_parse_environment();
515 r
= parse_argv(argc
, argv
);
519 r
= bus_connect_transport(arg_transport
, arg_host
, false, &bus
);
521 log_error_errno(r
, "Failed to create bus connection: %m");
525 r
= hostnamectl_main(bus
, argc
, argv
);
528 return r
< 0 ? EXIT_FAILURE
: EXIT_SUCCESS
;