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 typedef struct StatusInfo
{
46 char *static_hostname
;
47 char *pretty_hostname
;
60 static void print_status_info(StatusInfo
*i
) {
61 sd_id128_t mid
= {}, bid
= {};
66 printf(" Static hostname: %s\n", strna(i
->static_hostname
));
68 if (!isempty(i
->pretty_hostname
) &&
69 !streq_ptr(i
->pretty_hostname
, i
->static_hostname
))
70 printf(" Pretty hostname: %s\n", i
->pretty_hostname
);
72 if (!isempty(i
->hostname
) &&
73 !streq_ptr(i
->hostname
, i
->static_hostname
))
74 printf("Transient hostname: %s\n", i
->hostname
);
76 if (!isempty(i
->icon_name
))
77 printf(" Icon name: %s\n",
80 if (!isempty(i
->chassis
))
81 printf(" Chassis: %s\n",
84 if (!isempty(i
->deployment
))
85 printf(" Deployment: %s\n", i
->deployment
);
87 if (!isempty(i
->location
))
88 printf(" Location: %s\n", i
->location
);
90 r
= sd_id128_get_machine(&mid
);
92 printf(" Machine ID: " SD_ID128_FORMAT_STR
"\n", SD_ID128_FORMAT_VAL(mid
));
94 r
= sd_id128_get_boot(&bid
);
96 printf(" Boot ID: " SD_ID128_FORMAT_STR
"\n", SD_ID128_FORMAT_VAL(bid
));
98 if (!isempty(i
->virtualization
))
99 printf(" Virtualization: %s\n", i
->virtualization
);
101 if (!isempty(i
->os_pretty_name
))
102 printf(" Operating System: %s\n", i
->os_pretty_name
);
104 if (!isempty(i
->os_cpe_name
))
105 printf(" CPE OS Name: %s\n", i
->os_cpe_name
);
107 if (!isempty(i
->kernel_name
) && !isempty(i
->kernel_release
))
108 printf(" Kernel: %s %s\n", i
->kernel_name
, i
->kernel_release
);
110 if (!isempty(i
->architecture
))
111 printf(" Architecture: %s\n", i
->architecture
);
115 static int show_one_name(sd_bus
*bus
, const char* attr
) {
116 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
*reply
= NULL
;
117 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
121 r
= sd_bus_get_property(
123 "org.freedesktop.hostname1",
124 "/org/freedesktop/hostname1",
125 "org.freedesktop.hostname1",
127 &error
, &reply
, "s");
129 return log_error_errno(r
, "Could not get property: %s", bus_error_message(&error
, r
));
131 r
= sd_bus_message_read(reply
, "s", &s
);
133 return bus_log_parse_error(r
);
140 static int show_all_names(sd_bus
*bus
, sd_bus_error
*error
) {
141 StatusInfo info
= {};
143 static const struct bus_properties_map hostname_map
[] = {
144 { "Hostname", "s", NULL
, offsetof(StatusInfo
, hostname
) },
145 { "StaticHostname", "s", NULL
, offsetof(StatusInfo
, static_hostname
) },
146 { "PrettyHostname", "s", NULL
, offsetof(StatusInfo
, pretty_hostname
) },
147 { "IconName", "s", NULL
, offsetof(StatusInfo
, icon_name
) },
148 { "Chassis", "s", NULL
, offsetof(StatusInfo
, chassis
) },
149 { "Deployment", "s", NULL
, offsetof(StatusInfo
, deployment
) },
150 { "Location", "s", NULL
, offsetof(StatusInfo
, location
) },
151 { "KernelName", "s", NULL
, offsetof(StatusInfo
, kernel_name
) },
152 { "KernelRelease", "s", NULL
, offsetof(StatusInfo
, kernel_release
) },
153 { "OperatingSystemPrettyName", "s", NULL
, offsetof(StatusInfo
, os_pretty_name
) },
154 { "OperatingSystemCPEName", "s", NULL
, offsetof(StatusInfo
, os_cpe_name
) },
158 static const struct bus_properties_map manager_map
[] = {
159 { "Virtualization", "s", NULL
, offsetof(StatusInfo
, virtualization
) },
160 { "Architecture", "s", NULL
, offsetof(StatusInfo
, architecture
) },
166 r
= bus_map_all_properties(bus
,
167 "org.freedesktop.hostname1",
168 "/org/freedesktop/hostname1",
175 bus_map_all_properties(bus
,
176 "org.freedesktop.systemd1",
177 "/org/freedesktop/systemd1",
182 print_status_info(&info
);
186 free(info
.static_hostname
);
187 free(info
.pretty_hostname
);
188 free(info
.icon_name
);
190 free(info
.deployment
);
192 free(info
.kernel_name
);
193 free(info
.kernel_release
);
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
) {
207 if (arg_pretty
|| arg_static
|| arg_transient
) {
210 if (!!arg_static
+ !!arg_pretty
+ !!arg_transient
> 1) {
211 log_error("Cannot query more than one name type at a time");
215 attr
= arg_pretty
? "PrettyHostname" :
216 arg_static
? "StaticHostname" : "Hostname";
218 return show_one_name(bus
, attr
);
220 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
222 r
= show_all_names(bus
, &error
);
224 return log_error_errno(r
, "Failed to query system properties: %s", bus_error_message(&error
, r
));
230 static int set_simple_string(sd_bus
*bus
, const char *method
, const char *value
) {
231 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
234 polkit_agent_open_if_enabled(arg_transport
, arg_ask_password
);
236 r
= sd_bus_call_method(
238 "org.freedesktop.hostname1",
239 "/org/freedesktop/hostname1",
240 "org.freedesktop.hostname1",
243 "sb", value
, arg_ask_password
);
245 log_error("Could not set property: %s", bus_error_message(&error
, -r
));
249 static int set_hostname(sd_bus
*bus
, char **args
, unsigned n
) {
250 _cleanup_free_
char *h
= NULL
;
251 const char *hostname
= args
[1];
257 if (!arg_pretty
&& !arg_static
&& !arg_transient
)
258 arg_pretty
= arg_static
= arg_transient
= true;
263 /* If the passed hostname is already valid, then assume the user doesn't know anything about pretty
264 * hostnames, so let's unset the pretty hostname, and just set the passed hostname as static/dynamic
266 if (arg_static
&& hostname_is_valid(hostname
, true))
267 p
= ""; /* No pretty hostname (as it is redundant), just a static one */
269 p
= hostname
; /* Use the passed name as pretty hostname */
271 r
= set_simple_string(bus
, "SetPrettyHostname", p
);
275 /* Now that we set the pretty hostname, let's clean up the parameter and use that as static
276 * hostname. If the hostname was already valid as static hostname, this will only chop off the trailing
277 * dot if there is one. If it was not valid, then it will be made fully valid by truncating, dropping
278 * multiple dots, and dropping weird chars. Note that we clean the name up only if we also are
279 * supposed to set the pretty name. If the pretty name is not being set we assume the user knows what
280 * he does and pass the name as-is. */
281 h
= strdup(hostname
);
285 hostname
= hostname_cleanup(h
); /* Use the cleaned up name as static hostname */
289 r
= set_simple_string(bus
, "SetStaticHostname", hostname
);
295 r
= set_simple_string(bus
, "SetHostname", hostname
);
303 static int set_icon_name(sd_bus
*bus
, char **args
, unsigned n
) {
307 return set_simple_string(bus
, "SetIconName", args
[1]);
310 static int set_chassis(sd_bus
*bus
, char **args
, unsigned n
) {
314 return set_simple_string(bus
, "SetChassis", args
[1]);
317 static int set_deployment(sd_bus
*bus
, char **args
, unsigned n
) {
321 return set_simple_string(bus
, "SetDeployment", args
[1]);
324 static int set_location(sd_bus
*bus
, char **args
, unsigned n
) {
328 return set_simple_string(bus
, "SetLocation", args
[1]);
331 static void help(void) {
332 printf("%s [OPTIONS...] COMMAND ...\n\n"
333 "Query or change system hostname.\n\n"
334 " -h --help Show this help\n"
335 " --version Show package version\n"
336 " --no-ask-password Do not prompt for password\n"
337 " -H --host=[USER@]HOST Operate on remote host\n"
338 " -M --machine=CONTAINER Operate on local container\n"
339 " --transient Only set transient hostname\n"
340 " --static Only set static hostname\n"
341 " --pretty Only set pretty hostname\n\n"
343 " status Show current hostname settings\n"
344 " set-hostname NAME Set system hostname\n"
345 " set-icon-name NAME Set icon name for host\n"
346 " set-chassis NAME Set chassis type for host\n"
347 " set-deployment NAME Set deployment environment for host\n"
348 " set-location NAME Set location for host\n"
349 , program_invocation_short_name
);
352 static int parse_argv(int argc
, char *argv
[]) {
362 static const struct option options
[] = {
363 { "help", no_argument
, NULL
, 'h' },
364 { "version", no_argument
, NULL
, ARG_VERSION
},
365 { "transient", no_argument
, NULL
, ARG_TRANSIENT
},
366 { "static", no_argument
, NULL
, ARG_STATIC
},
367 { "pretty", no_argument
, NULL
, ARG_PRETTY
},
368 { "host", required_argument
, NULL
, 'H' },
369 { "machine", required_argument
, NULL
, 'M' },
370 { "no-ask-password", no_argument
, NULL
, ARG_NO_ASK_PASSWORD
},
379 while ((c
= getopt_long(argc
, argv
, "hH:M:", options
, NULL
)) >= 0)
391 arg_transport
= BUS_TRANSPORT_REMOTE
;
396 arg_transport
= BUS_TRANSPORT_MACHINE
;
401 arg_transient
= true;
412 case ARG_NO_ASK_PASSWORD
:
413 arg_ask_password
= false;
420 assert_not_reached("Unhandled option");
426 static int hostnamectl_main(sd_bus
*bus
, int argc
, char *argv
[]) {
428 static const struct {
436 int (* const dispatch
)(sd_bus
*bus
, char **args
, unsigned n
);
438 { "status", LESS
, 1, show_status
},
439 { "set-hostname", EQUAL
, 2, set_hostname
},
440 { "set-icon-name", EQUAL
, 2, set_icon_name
},
441 { "set-chassis", EQUAL
, 2, set_chassis
},
442 { "set-deployment", EQUAL
, 2, set_deployment
},
443 { "set-location", EQUAL
, 2, set_location
},
452 left
= argc
- optind
;
455 /* Special rule: no arguments means "status" */
458 if (streq(argv
[optind
], "help")) {
463 for (i
= 0; i
< ELEMENTSOF(verbs
); i
++)
464 if (streq(argv
[optind
], verbs
[i
].verb
))
467 if (i
>= ELEMENTSOF(verbs
)) {
468 log_error("Unknown operation %s", argv
[optind
]);
473 switch (verbs
[i
].argc_cmp
) {
476 if (left
!= verbs
[i
].argc
) {
477 log_error("Invalid number of arguments.");
484 if (left
< verbs
[i
].argc
) {
485 log_error("Too few arguments.");
492 if (left
> verbs
[i
].argc
) {
493 log_error("Too many arguments.");
500 assert_not_reached("Unknown comparison operator.");
503 return verbs
[i
].dispatch(bus
, argv
+ optind
, left
);
506 int main(int argc
, char *argv
[]) {
507 _cleanup_(sd_bus_flush_close_unrefp
) sd_bus
*bus
= NULL
;
510 setlocale(LC_ALL
, "");
511 log_parse_environment();
514 r
= parse_argv(argc
, argv
);
518 r
= bus_connect_transport(arg_transport
, arg_host
, false, &bus
);
520 log_error_errno(r
, "Failed to create bus connection: %m");
524 r
= hostnamectl_main(bus
, argc
, argv
);
527 return r
< 0 ? EXIT_FAILURE
: EXIT_SUCCESS
;