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 "alloc-util.h"
32 #include "architecture.h"
33 #include "bus-error.h"
35 #include "hostname-util.h"
36 #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 static void polkit_agent_open_if_enabled(void) {
48 /* Open the polkit agent as a child process if necessary */
49 if (!arg_ask_password
)
52 if (arg_transport
!= BUS_TRANSPORT_LOCAL
)
58 typedef struct StatusInfo
{
60 char *static_hostname
;
61 char *pretty_hostname
;
74 static void print_status_info(StatusInfo
*i
) {
75 sd_id128_t mid
= {}, bid
= {};
80 printf(" Static hostname: %s\n", strna(i
->static_hostname
));
82 if (!isempty(i
->pretty_hostname
) &&
83 !streq_ptr(i
->pretty_hostname
, i
->static_hostname
))
84 printf(" Pretty hostname: %s\n", i
->pretty_hostname
);
86 if (!isempty(i
->hostname
) &&
87 !streq_ptr(i
->hostname
, i
->static_hostname
))
88 printf("Transient hostname: %s\n", i
->hostname
);
90 if (!isempty(i
->icon_name
))
91 printf(" Icon name: %s\n",
94 if (!isempty(i
->chassis
))
95 printf(" Chassis: %s\n",
98 if (!isempty(i
->deployment
))
99 printf(" Deployment: %s\n", i
->deployment
);
101 if (!isempty(i
->location
))
102 printf(" Location: %s\n", i
->location
);
104 r
= sd_id128_get_machine(&mid
);
106 printf(" Machine ID: " SD_ID128_FORMAT_STR
"\n", SD_ID128_FORMAT_VAL(mid
));
108 r
= sd_id128_get_boot(&bid
);
110 printf(" Boot ID: " SD_ID128_FORMAT_STR
"\n", SD_ID128_FORMAT_VAL(bid
));
112 if (!isempty(i
->virtualization
))
113 printf(" Virtualization: %s\n", i
->virtualization
);
115 if (!isempty(i
->os_pretty_name
))
116 printf(" Operating System: %s\n", i
->os_pretty_name
);
118 if (!isempty(i
->os_cpe_name
))
119 printf(" CPE OS Name: %s\n", i
->os_cpe_name
);
121 if (!isempty(i
->kernel_name
) && !isempty(i
->kernel_release
))
122 printf(" Kernel: %s %s\n", i
->kernel_name
, i
->kernel_release
);
124 if (!isempty(i
->architecture
))
125 printf(" Architecture: %s\n", i
->architecture
);
129 static int show_one_name(sd_bus
*bus
, const char* attr
) {
130 _cleanup_bus_message_unref_ sd_bus_message
*reply
= NULL
;
131 _cleanup_bus_error_free_ sd_bus_error error
= SD_BUS_ERROR_NULL
;
135 r
= sd_bus_get_property(
137 "org.freedesktop.hostname1",
138 "/org/freedesktop/hostname1",
139 "org.freedesktop.hostname1",
141 &error
, &reply
, "s");
143 log_error("Could not get property: %s", bus_error_message(&error
, -r
));
147 r
= sd_bus_message_read(reply
, "s", &s
);
149 return bus_log_parse_error(r
);
156 static int show_all_names(sd_bus
*bus
) {
157 StatusInfo info
= {};
159 static const struct bus_properties_map hostname_map
[] = {
160 { "Hostname", "s", NULL
, offsetof(StatusInfo
, hostname
) },
161 { "StaticHostname", "s", NULL
, offsetof(StatusInfo
, static_hostname
) },
162 { "PrettyHostname", "s", NULL
, offsetof(StatusInfo
, pretty_hostname
) },
163 { "IconName", "s", NULL
, offsetof(StatusInfo
, icon_name
) },
164 { "Chassis", "s", NULL
, offsetof(StatusInfo
, chassis
) },
165 { "Deployment", "s", NULL
, offsetof(StatusInfo
, deployment
) },
166 { "Location", "s", NULL
, offsetof(StatusInfo
, location
) },
167 { "KernelName", "s", NULL
, offsetof(StatusInfo
, kernel_name
) },
168 { "KernelRelease", "s", NULL
, offsetof(StatusInfo
, kernel_release
) },
169 { "OperatingSystemPrettyName", "s", NULL
, offsetof(StatusInfo
, os_pretty_name
) },
170 { "OperatingSystemCPEName", "s", NULL
, offsetof(StatusInfo
, os_cpe_name
) },
174 static const struct bus_properties_map manager_map
[] = {
175 { "Virtualization", "s", NULL
, offsetof(StatusInfo
, virtualization
) },
176 { "Architecture", "s", NULL
, offsetof(StatusInfo
, architecture
) },
182 r
= bus_map_all_properties(bus
,
183 "org.freedesktop.hostname1",
184 "/org/freedesktop/hostname1",
190 bus_map_all_properties(bus
,
191 "org.freedesktop.systemd1",
192 "/org/freedesktop/systemd1",
196 print_status_info(&info
);
200 free(info
.static_hostname
);
201 free(info
.pretty_hostname
);
202 free(info
.icon_name
);
204 free(info
.deployment
);
206 free(info
.kernel_name
);
207 free(info
.kernel_release
);
208 free(info
.os_pretty_name
);
209 free(info
.os_cpe_name
);
210 free(info
.virtualization
);
211 free(info
.architecture
);
216 static int show_status(sd_bus
*bus
, char **args
, unsigned n
) {
219 if (arg_pretty
|| arg_static
|| arg_transient
) {
222 if (!!arg_static
+ !!arg_pretty
+ !!arg_transient
> 1) {
223 log_error("Cannot query more than one name type at a time");
227 attr
= arg_pretty
? "PrettyHostname" :
228 arg_static
? "StaticHostname" : "Hostname";
230 return show_one_name(bus
, attr
);
232 return show_all_names(bus
);
235 static int set_simple_string(sd_bus
*bus
, const char *method
, const char *value
) {
236 _cleanup_bus_error_free_ sd_bus_error error
= SD_BUS_ERROR_NULL
;
239 polkit_agent_open_if_enabled();
241 r
= sd_bus_call_method(
243 "org.freedesktop.hostname1",
244 "/org/freedesktop/hostname1",
245 "org.freedesktop.hostname1",
248 "sb", value
, arg_ask_password
);
250 log_error("Could not set property: %s", bus_error_message(&error
, -r
));
254 static int set_hostname(sd_bus
*bus
, char **args
, unsigned n
) {
255 _cleanup_free_
char *h
= NULL
;
256 char *hostname
= args
[1];
262 if (!arg_pretty
&& !arg_static
&& !arg_transient
)
263 arg_pretty
= arg_static
= arg_transient
= true;
268 /* If the passed hostname is already valid, then
269 * assume the user doesn't know anything about pretty
270 * hostnames, so let's unset the pretty hostname, and
271 * just set the passed hostname as static/dynamic
274 if (arg_static
&& hostname_is_valid(hostname
, true)) {
276 /* maybe get rid of trailing dot */
277 hostname
= hostname_cleanup(hostname
);
279 p
= h
= strdup(hostname
);
283 hostname_cleanup(hostname
);
286 r
= set_simple_string(bus
, "SetPrettyHostname", p
);
292 r
= set_simple_string(bus
, "SetStaticHostname", hostname
);
298 r
= set_simple_string(bus
, "SetHostname", hostname
);
306 static int set_icon_name(sd_bus
*bus
, char **args
, unsigned n
) {
310 return set_simple_string(bus
, "SetIconName", args
[1]);
313 static int set_chassis(sd_bus
*bus
, char **args
, unsigned n
) {
317 return set_simple_string(bus
, "SetChassis", args
[1]);
320 static int set_deployment(sd_bus
*bus
, char **args
, unsigned n
) {
324 return set_simple_string(bus
, "SetDeployment", args
[1]);
327 static int set_location(sd_bus
*bus
, char **args
, unsigned n
) {
331 return set_simple_string(bus
, "SetLocation", args
[1]);
334 static void help(void) {
335 printf("%s [OPTIONS...] COMMAND ...\n\n"
336 "Query or change system hostname.\n\n"
337 " -h --help Show this help\n"
338 " --version Show package version\n"
339 " --no-ask-password Do not prompt for password\n"
340 " -H --host=[USER@]HOST Operate on remote host\n"
341 " -M --machine=CONTAINER Operate on local container\n"
342 " --transient Only set transient hostname\n"
343 " --static Only set static hostname\n"
344 " --pretty Only set pretty hostname\n\n"
346 " status Show current hostname settings\n"
347 " set-hostname NAME Set system hostname\n"
348 " set-icon-name NAME Set icon name for host\n"
349 " set-chassis NAME Set chassis type for host\n"
350 " set-deployment NAME Set deployment environment for host\n"
351 " set-location NAME Set location for host\n"
352 , program_invocation_short_name
);
355 static int parse_argv(int argc
, char *argv
[]) {
365 static const struct option options
[] = {
366 { "help", no_argument
, NULL
, 'h' },
367 { "version", no_argument
, NULL
, ARG_VERSION
},
368 { "transient", no_argument
, NULL
, ARG_TRANSIENT
},
369 { "static", no_argument
, NULL
, ARG_STATIC
},
370 { "pretty", no_argument
, NULL
, ARG_PRETTY
},
371 { "host", required_argument
, NULL
, 'H' },
372 { "machine", required_argument
, NULL
, 'M' },
373 { "no-ask-password", no_argument
, NULL
, ARG_NO_ASK_PASSWORD
},
382 while ((c
= getopt_long(argc
, argv
, "hH:M:", options
, NULL
)) >= 0)
394 arg_transport
= BUS_TRANSPORT_REMOTE
;
399 arg_transport
= BUS_TRANSPORT_MACHINE
;
404 arg_transient
= true;
415 case ARG_NO_ASK_PASSWORD
:
416 arg_ask_password
= false;
423 assert_not_reached("Unhandled option");
429 static int hostnamectl_main(sd_bus
*bus
, int argc
, char *argv
[]) {
431 static const struct {
439 int (* const dispatch
)(sd_bus
*bus
, char **args
, unsigned n
);
441 { "status", LESS
, 1, show_status
},
442 { "set-hostname", EQUAL
, 2, set_hostname
},
443 { "set-icon-name", EQUAL
, 2, set_icon_name
},
444 { "set-chassis", EQUAL
, 2, set_chassis
},
445 { "set-deployment", EQUAL
, 2, set_deployment
},
446 { "set-location", EQUAL
, 2, set_location
},
455 left
= argc
- optind
;
458 /* Special rule: no arguments means "status" */
461 if (streq(argv
[optind
], "help")) {
466 for (i
= 0; i
< ELEMENTSOF(verbs
); i
++)
467 if (streq(argv
[optind
], verbs
[i
].verb
))
470 if (i
>= ELEMENTSOF(verbs
)) {
471 log_error("Unknown operation %s", argv
[optind
]);
476 switch (verbs
[i
].argc_cmp
) {
479 if (left
!= verbs
[i
].argc
) {
480 log_error("Invalid number of arguments.");
487 if (left
< verbs
[i
].argc
) {
488 log_error("Too few arguments.");
495 if (left
> verbs
[i
].argc
) {
496 log_error("Too many arguments.");
503 assert_not_reached("Unknown comparison operator.");
506 return verbs
[i
].dispatch(bus
, argv
+ optind
, left
);
509 int main(int argc
, char *argv
[]) {
510 _cleanup_bus_flush_close_unref_ sd_bus
*bus
= NULL
;
513 setlocale(LC_ALL
, "");
514 log_parse_environment();
517 r
= parse_argv(argc
, argv
);
521 r
= bus_connect_transport(arg_transport
, arg_host
, false, &bus
);
523 log_error_errno(r
, "Failed to create bus connection: %m");
527 r
= hostnamectl_main(bus
, argc
, argv
);
530 return r
< 0 ? EXIT_FAILURE
: EXIT_SUCCESS
;