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/>.
31 #include "architecture.h"
32 #include "bus-error.h"
34 #include "hostname-util.h"
35 #include "spawn-polkit-agent.h"
38 static bool arg_ask_password
= true;
39 static BusTransport arg_transport
= BUS_TRANSPORT_LOCAL
;
40 static char *arg_host
= NULL
;
41 static bool arg_transient
= false;
42 static bool arg_pretty
= false;
43 static bool arg_static
= false;
45 static void polkit_agent_open_if_enabled(void) {
47 /* Open the polkit agent as a child process if necessary */
48 if (!arg_ask_password
)
51 if (arg_transport
!= BUS_TRANSPORT_LOCAL
)
57 typedef struct StatusInfo
{
59 char *static_hostname
;
60 char *pretty_hostname
;
73 static void print_status_info(StatusInfo
*i
) {
74 sd_id128_t mid
= {}, bid
= {};
79 printf(" Static hostname: %s\n", strna(i
->static_hostname
));
81 if (!isempty(i
->pretty_hostname
) &&
82 !streq_ptr(i
->pretty_hostname
, i
->static_hostname
))
83 printf(" Pretty hostname: %s\n", i
->pretty_hostname
);
85 if (!isempty(i
->hostname
) &&
86 !streq_ptr(i
->hostname
, i
->static_hostname
))
87 printf("Transient hostname: %s\n", i
->hostname
);
89 if (!isempty(i
->icon_name
))
90 printf(" Icon name: %s\n",
93 if (!isempty(i
->chassis
))
94 printf(" Chassis: %s\n",
97 if (!isempty(i
->deployment
))
98 printf(" Deployment: %s\n", i
->deployment
);
100 if (!isempty(i
->location
))
101 printf(" Location: %s\n", i
->location
);
103 r
= sd_id128_get_machine(&mid
);
105 printf(" Machine ID: " SD_ID128_FORMAT_STR
"\n", SD_ID128_FORMAT_VAL(mid
));
107 r
= sd_id128_get_boot(&bid
);
109 printf(" Boot ID: " SD_ID128_FORMAT_STR
"\n", SD_ID128_FORMAT_VAL(bid
));
111 if (!isempty(i
->virtualization
))
112 printf(" Virtualization: %s\n", i
->virtualization
);
114 if (!isempty(i
->os_pretty_name
))
115 printf(" Operating System: %s\n", i
->os_pretty_name
);
117 if (!isempty(i
->os_cpe_name
))
118 printf(" CPE OS Name: %s\n", i
->os_cpe_name
);
120 if (!isempty(i
->kernel_name
) && !isempty(i
->kernel_release
))
121 printf(" Kernel: %s %s\n", i
->kernel_name
, i
->kernel_release
);
123 if (!isempty(i
->architecture
))
124 printf(" Architecture: %s\n", i
->architecture
);
128 static int show_one_name(sd_bus
*bus
, const char* attr
) {
129 _cleanup_bus_message_unref_ sd_bus_message
*reply
= NULL
;
130 _cleanup_bus_error_free_ sd_bus_error error
= SD_BUS_ERROR_NULL
;
134 r
= sd_bus_get_property(
136 "org.freedesktop.hostname1",
137 "/org/freedesktop/hostname1",
138 "org.freedesktop.hostname1",
140 &error
, &reply
, "s");
142 log_error("Could not get property: %s", bus_error_message(&error
, -r
));
146 r
= sd_bus_message_read(reply
, "s", &s
);
148 return bus_log_parse_error(r
);
155 static int show_all_names(sd_bus
*bus
) {
156 StatusInfo info
= {};
158 static const struct bus_properties_map hostname_map
[] = {
159 { "Hostname", "s", NULL
, offsetof(StatusInfo
, hostname
) },
160 { "StaticHostname", "s", NULL
, offsetof(StatusInfo
, static_hostname
) },
161 { "PrettyHostname", "s", NULL
, offsetof(StatusInfo
, pretty_hostname
) },
162 { "IconName", "s", NULL
, offsetof(StatusInfo
, icon_name
) },
163 { "Chassis", "s", NULL
, offsetof(StatusInfo
, chassis
) },
164 { "Deployment", "s", NULL
, offsetof(StatusInfo
, deployment
) },
165 { "Location", "s", NULL
, offsetof(StatusInfo
, location
) },
166 { "KernelName", "s", NULL
, offsetof(StatusInfo
, kernel_name
) },
167 { "KernelRelease", "s", NULL
, offsetof(StatusInfo
, kernel_release
) },
168 { "OperatingSystemPrettyName", "s", NULL
, offsetof(StatusInfo
, os_pretty_name
) },
169 { "OperatingSystemCPEName", "s", NULL
, offsetof(StatusInfo
, os_cpe_name
) },
173 static const struct bus_properties_map manager_map
[] = {
174 { "Virtualization", "s", NULL
, offsetof(StatusInfo
, virtualization
) },
175 { "Architecture", "s", NULL
, offsetof(StatusInfo
, architecture
) },
181 r
= bus_map_all_properties(bus
,
182 "org.freedesktop.hostname1",
183 "/org/freedesktop/hostname1",
189 bus_map_all_properties(bus
,
190 "org.freedesktop.systemd1",
191 "/org/freedesktop/systemd1",
195 print_status_info(&info
);
199 free(info
.static_hostname
);
200 free(info
.pretty_hostname
);
201 free(info
.icon_name
);
203 free(info
.deployment
);
205 free(info
.kernel_name
);
206 free(info
.kernel_release
);
207 free(info
.os_pretty_name
);
208 free(info
.os_cpe_name
);
209 free(info
.virtualization
);
210 free(info
.architecture
);
215 static int show_status(sd_bus
*bus
, char **args
, unsigned n
) {
218 if (arg_pretty
|| arg_static
|| arg_transient
) {
221 if (!!arg_static
+ !!arg_pretty
+ !!arg_transient
> 1) {
222 log_error("Cannot query more than one name type at a time");
226 attr
= arg_pretty
? "PrettyHostname" :
227 arg_static
? "StaticHostname" : "Hostname";
229 return show_one_name(bus
, attr
);
231 return show_all_names(bus
);
234 static int set_simple_string(sd_bus
*bus
, const char *method
, const char *value
) {
235 _cleanup_bus_error_free_ sd_bus_error error
= SD_BUS_ERROR_NULL
;
238 polkit_agent_open_if_enabled();
240 r
= sd_bus_call_method(
242 "org.freedesktop.hostname1",
243 "/org/freedesktop/hostname1",
244 "org.freedesktop.hostname1",
247 "sb", value
, arg_ask_password
);
249 log_error("Could not set property: %s", bus_error_message(&error
, -r
));
253 static int set_hostname(sd_bus
*bus
, char **args
, unsigned n
) {
254 _cleanup_free_
char *h
= NULL
;
255 char *hostname
= args
[1];
261 if (!arg_pretty
&& !arg_static
&& !arg_transient
)
262 arg_pretty
= arg_static
= arg_transient
= true;
267 /* If the passed hostname is already valid, then
268 * assume the user doesn't know anything about pretty
269 * hostnames, so let's unset the pretty hostname, and
270 * just set the passed hostname as static/dynamic
273 if (arg_static
&& hostname_is_valid(hostname
, true)) {
275 /* maybe get rid of trailing dot */
276 hostname
= hostname_cleanup(hostname
);
278 p
= h
= strdup(hostname
);
282 hostname_cleanup(hostname
);
285 r
= set_simple_string(bus
, "SetPrettyHostname", p
);
291 r
= set_simple_string(bus
, "SetStaticHostname", hostname
);
297 r
= set_simple_string(bus
, "SetHostname", hostname
);
305 static int set_icon_name(sd_bus
*bus
, char **args
, unsigned n
) {
309 return set_simple_string(bus
, "SetIconName", args
[1]);
312 static int set_chassis(sd_bus
*bus
, char **args
, unsigned n
) {
316 return set_simple_string(bus
, "SetChassis", args
[1]);
319 static int set_deployment(sd_bus
*bus
, char **args
, unsigned n
) {
323 return set_simple_string(bus
, "SetDeployment", args
[1]);
326 static int set_location(sd_bus
*bus
, char **args
, unsigned n
) {
330 return set_simple_string(bus
, "SetLocation", args
[1]);
333 static void help(void) {
334 printf("%s [OPTIONS...] COMMAND ...\n\n"
335 "Query or change system hostname.\n\n"
336 " -h --help Show this help\n"
337 " --version Show package version\n"
338 " --no-ask-password Do not prompt for password\n"
339 " -H --host=[USER@]HOST Operate on remote host\n"
340 " -M --machine=CONTAINER Operate on local container\n"
341 " --transient Only set transient hostname\n"
342 " --static Only set static hostname\n"
343 " --pretty Only set pretty hostname\n\n"
345 " status Show current hostname settings\n"
346 " set-hostname NAME Set system hostname\n"
347 " set-icon-name NAME Set icon name for host\n"
348 " set-chassis NAME Set chassis type for host\n"
349 " set-deployment NAME Set deployment environment for host\n"
350 " set-location NAME Set location for host\n"
351 , program_invocation_short_name
);
354 static int parse_argv(int argc
, char *argv
[]) {
364 static const struct option options
[] = {
365 { "help", no_argument
, NULL
, 'h' },
366 { "version", no_argument
, NULL
, ARG_VERSION
},
367 { "transient", no_argument
, NULL
, ARG_TRANSIENT
},
368 { "static", no_argument
, NULL
, ARG_STATIC
},
369 { "pretty", no_argument
, NULL
, ARG_PRETTY
},
370 { "host", required_argument
, NULL
, 'H' },
371 { "machine", required_argument
, NULL
, 'M' },
372 { "no-ask-password", no_argument
, NULL
, ARG_NO_ASK_PASSWORD
},
381 while ((c
= getopt_long(argc
, argv
, "hH:M:", options
, NULL
)) >= 0)
393 arg_transport
= BUS_TRANSPORT_REMOTE
;
398 arg_transport
= BUS_TRANSPORT_MACHINE
;
403 arg_transient
= true;
414 case ARG_NO_ASK_PASSWORD
:
415 arg_ask_password
= false;
422 assert_not_reached("Unhandled option");
428 static int hostnamectl_main(sd_bus
*bus
, int argc
, char *argv
[]) {
430 static const struct {
438 int (* const dispatch
)(sd_bus
*bus
, char **args
, unsigned n
);
440 { "status", LESS
, 1, show_status
},
441 { "set-hostname", EQUAL
, 2, set_hostname
},
442 { "set-icon-name", EQUAL
, 2, set_icon_name
},
443 { "set-chassis", EQUAL
, 2, set_chassis
},
444 { "set-deployment", EQUAL
, 2, set_deployment
},
445 { "set-location", EQUAL
, 2, set_location
},
454 left
= argc
- optind
;
457 /* Special rule: no arguments means "status" */
460 if (streq(argv
[optind
], "help")) {
465 for (i
= 0; i
< ELEMENTSOF(verbs
); i
++)
466 if (streq(argv
[optind
], verbs
[i
].verb
))
469 if (i
>= ELEMENTSOF(verbs
)) {
470 log_error("Unknown operation %s", argv
[optind
]);
475 switch (verbs
[i
].argc_cmp
) {
478 if (left
!= verbs
[i
].argc
) {
479 log_error("Invalid number of arguments.");
486 if (left
< verbs
[i
].argc
) {
487 log_error("Too few arguments.");
494 if (left
> verbs
[i
].argc
) {
495 log_error("Too many arguments.");
502 assert_not_reached("Unknown comparison operator.");
505 return verbs
[i
].dispatch(bus
, argv
+ optind
, left
);
508 int main(int argc
, char *argv
[]) {
509 _cleanup_bus_flush_close_unref_ sd_bus
*bus
= NULL
;
512 setlocale(LC_ALL
, "");
513 log_parse_environment();
516 r
= parse_argv(argc
, argv
);
520 r
= bus_open_transport(arg_transport
, arg_host
, false, &bus
);
522 log_error_errno(r
, "Failed to create bus connection: %m");
526 r
= hostnamectl_main(bus
, argc
, argv
);
529 return r
< 0 ? EXIT_FAILURE
: EXIT_SUCCESS
;