1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
2 
3 #include <getopt.h>
4 #include <locale.h>
5 #include <stdbool.h>
6 #include <stdlib.h>
7 #include <string.h>
8 
9 #include "sd-bus.h"
10 #include "sd-id128.h"
11 
12 #include "alloc-util.h"
13 #include "architecture.h"
14 #include "bus-common-errors.h"
15 #include "bus-error.h"
16 #include "bus-map-properties.h"
17 #include "format-table.h"
18 #include "hostname-setup.h"
19 #include "hostname-util.h"
20 #include "json.h"
21 #include "main-func.h"
22 #include "parse-argument.h"
23 #include "pretty-print.h"
24 #include "spawn-polkit-agent.h"
25 #include "terminal-util.h"
26 #include "util.h"
27 #include "verbs.h"
28 
29 static bool arg_ask_password = true;
30 static BusTransport arg_transport = BUS_TRANSPORT_LOCAL;
31 static char *arg_host = NULL;
32 static bool arg_transient = false;
33 static bool arg_pretty = false;
34 static bool arg_static = false;
35 static JsonFormatFlags arg_json_format_flags = JSON_FORMAT_OFF;
36 
37 typedef struct StatusInfo {
38         const char *hostname;
39         const char *static_hostname;
40         const char *pretty_hostname;
41         const char *icon_name;
42         const char *chassis;
43         const char *deployment;
44         const char *location;
45         const char *kernel_name;
46         const char *kernel_release;
47         const char *os_pretty_name;
48         const char *os_cpe_name;
49         const char *virtualization;
50         const char *architecture;
51         const char *home_url;
52         const char *hardware_vendor;
53         const char *hardware_model;
54         const char *firmware_version;
55 } StatusInfo;
56 
chassis_string_to_glyph(const char * chassis)57 static const char* chassis_string_to_glyph(const char *chassis) {
58         if (streq_ptr(chassis, "laptop"))
59                 return u8"��"; /* Personal Computer */
60         if (streq_ptr(chassis, "desktop"))
61                 return u8"��️"; /* Desktop Computer */
62         if (streq_ptr(chassis, "server"))
63                 return u8"��"; /* Old Personal Computer */
64         if (streq_ptr(chassis, "tablet"))
65                 return u8"具"; /* Ideograph tool, implement; draw up, write, looks vaguely tabletty */
66         if (streq_ptr(chassis, "watch"))
67                 return u8"⌚"; /* Watch */
68         if (streq_ptr(chassis, "handset"))
69                 return u8"��"; /* Left Hand Telephone Receiver */
70         if (streq_ptr(chassis, "vm"))
71                 return u8"��"; /* Hard disk */
72         if (streq_ptr(chassis, "container"))
73                 return u8"☐"; /* Ballot Box  */
74         return NULL;
75 }
76 
print_status_info(StatusInfo * i)77 static int print_status_info(StatusInfo *i) {
78         _cleanup_(table_unrefp) Table *table = NULL;
79         sd_id128_t mid = {}, bid = {};
80         TableCell *cell;
81         int r;
82 
83         assert(i);
84 
85         table = table_new("key", "value");
86         if (!table)
87                 return log_oom();
88 
89         assert_se(cell = table_get_cell(table, 0, 0));
90         (void) table_set_ellipsize_percent(table, cell, 100);
91         (void) table_set_align_percent(table, cell, 100);
92 
93         table_set_header(table, false);
94 
95         r = table_set_empty_string(table, "n/a");
96         if (r < 0)
97                 return log_oom();
98 
99         r = table_add_many(table,
100                            TABLE_STRING, "Static hostname:",
101                            TABLE_STRING, i->static_hostname);
102         if (r < 0)
103                 return table_log_add_error(r);
104 
105         if (!isempty(i->pretty_hostname) &&
106             !streq_ptr(i->pretty_hostname, i->static_hostname)) {
107                 r = table_add_many(table,
108                                    TABLE_STRING, "Pretty hostname:",
109                                    TABLE_STRING, i->pretty_hostname);
110                 if (r < 0)
111                         return table_log_add_error(r);
112         }
113 
114         if (!isempty(i->hostname) &&
115             !streq_ptr(i->hostname, i->static_hostname)) {
116                 r = table_add_many(table,
117                                    TABLE_STRING, "Transient hostname:",
118                                    TABLE_STRING, i->hostname);
119                 if (r < 0)
120                         return table_log_add_error(r);
121         }
122 
123         if (!isempty(i->icon_name)) {
124                 r = table_add_many(table,
125                                    TABLE_STRING, "Icon name:",
126                                    TABLE_STRING, i->icon_name);
127                 if (r < 0)
128                         return table_log_add_error(r);
129         }
130 
131         if (!isempty(i->chassis)) {
132                 /* Possibly add a pretty symbol. Let's not bother with non-unicode fallbacks, because this is
133                  * just a prettification and we can't really express this with ASCII anyway. */
134                 const char *v = chassis_string_to_glyph(i->chassis);
135                 if (v)
136                         v = strjoina(i->chassis, " ", v);
137 
138                 r = table_add_many(table,
139                                    TABLE_STRING, "Chassis:",
140                                    TABLE_STRING, v ?: i->chassis);
141                 if (r < 0)
142                         return table_log_add_error(r);
143         }
144 
145         if (!isempty(i->deployment)) {
146                 r = table_add_many(table,
147                                    TABLE_STRING, "Deployment:",
148                                    TABLE_STRING, i->deployment);
149                 if (r < 0)
150                         return table_log_add_error(r);
151         }
152 
153         if (!isempty(i->location)) {
154                 r = table_add_many(table,
155                                    TABLE_STRING, "Location:",
156                                    TABLE_STRING, i->location);
157                 if (r < 0)
158                         return table_log_add_error(r);
159         }
160 
161         r = sd_id128_get_machine(&mid);
162         if (r >= 0) {
163                 r = table_add_many(table,
164                                    TABLE_STRING, "Machine ID:",
165                                    TABLE_ID128, mid);
166                 if (r < 0)
167                         return table_log_add_error(r);
168         }
169 
170         r = sd_id128_get_boot(&bid);
171         if (r >= 0) {
172                 r = table_add_many(table,
173                                    TABLE_STRING, "Boot ID:",
174                                    TABLE_ID128, bid);
175                 if (r < 0)
176                         return table_log_add_error(r);
177         }
178 
179         if (!isempty(i->virtualization)) {
180                 r = table_add_many(table,
181                                    TABLE_STRING, "Virtualization:",
182                                    TABLE_STRING, i->virtualization);
183                 if (r < 0)
184                         return table_log_add_error(r);
185         }
186 
187         if (!isempty(i->os_pretty_name)) {
188                 r = table_add_many(table,
189                                    TABLE_STRING, "Operating System:",
190                                    TABLE_STRING, i->os_pretty_name,
191                                    TABLE_SET_URL, i->home_url);
192                 if (r < 0)
193                         return table_log_add_error(r);
194         }
195 
196         if (!isempty(i->os_cpe_name)) {
197                 r = table_add_many(table,
198                                    TABLE_STRING, "CPE OS Name:",
199                                    TABLE_STRING, i->os_cpe_name);
200                 if (r < 0)
201                         return table_log_add_error(r);
202         }
203 
204         if (!isempty(i->kernel_name) && !isempty(i->kernel_release)) {
205                 const char *v;
206 
207                 v = strjoina(i->kernel_name, " ", i->kernel_release);
208                 r = table_add_many(table,
209                                    TABLE_STRING, "Kernel:",
210                                    TABLE_STRING, v);
211                 if (r < 0)
212                         return table_log_add_error(r);
213         }
214 
215         if (!isempty(i->architecture)) {
216                 r = table_add_many(table,
217                                    TABLE_STRING, "Architecture:",
218                                    TABLE_STRING, i->architecture);
219                 if (r < 0)
220                         return table_log_add_error(r);
221         }
222 
223         if (!isempty(i->hardware_vendor)) {
224                 r = table_add_many(table,
225                                    TABLE_STRING, "Hardware Vendor:",
226                                    TABLE_STRING, i->hardware_vendor);
227                 if (r < 0)
228                         return table_log_add_error(r);
229         }
230 
231         if (!isempty(i->hardware_model)) {
232                 r = table_add_many(table,
233                                    TABLE_STRING, "Hardware Model:",
234                                    TABLE_STRING, i->hardware_model);
235                 if (r < 0)
236                         return table_log_add_error(r);
237         }
238 
239         if (!isempty(i->firmware_version)) {
240                 r = table_add_many(table,
241                                    TABLE_STRING, "Firmware Version:",
242                                    TABLE_STRING, i->firmware_version);
243                 if (r < 0)
244                         return table_log_add_error(r);
245         }
246 
247         r = table_print(table, NULL);
248         if (r < 0)
249                 return table_log_print_error(r);
250 
251         return 0;
252 }
253 
get_one_name(sd_bus * bus,const char * attr,char ** ret)254 static int get_one_name(sd_bus *bus, const char* attr, char **ret) {
255         _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
256         _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
257         const char *s;
258         int r;
259 
260         assert(bus);
261         assert(attr);
262 
263         /* This obtains one string property, and copy it if 'ret' is set, or print it otherwise. */
264 
265         r = sd_bus_get_property(
266                         bus,
267                         "org.freedesktop.hostname1",
268                         "/org/freedesktop/hostname1",
269                         "org.freedesktop.hostname1",
270                         attr,
271                         &error, &reply, "s");
272         if (r < 0)
273                 return log_error_errno(r, "Could not get property: %s", bus_error_message(&error, r));
274 
275         r = sd_bus_message_read(reply, "s", &s);
276         if (r < 0)
277                 return bus_log_parse_error(r);
278 
279         if (ret) {
280                 char *str;
281 
282                 str = strdup(s);
283                 if (!str)
284                         return log_oom();
285 
286                 *ret = str;
287         } else
288                 printf("%s\n", s);
289 
290         return 0;
291 }
292 
show_all_names(sd_bus * bus)293 static int show_all_names(sd_bus *bus) {
294         StatusInfo info = {};
295 
296         static const struct bus_properties_map hostname_map[]  = {
297                 { "Hostname",                  "s", NULL, offsetof(StatusInfo, hostname)         },
298                 { "StaticHostname",            "s", NULL, offsetof(StatusInfo, static_hostname)  },
299                 { "PrettyHostname",            "s", NULL, offsetof(StatusInfo, pretty_hostname)  },
300                 { "IconName",                  "s", NULL, offsetof(StatusInfo, icon_name)        },
301                 { "Chassis",                   "s", NULL, offsetof(StatusInfo, chassis)          },
302                 { "Deployment",                "s", NULL, offsetof(StatusInfo, deployment)       },
303                 { "Location",                  "s", NULL, offsetof(StatusInfo, location)         },
304                 { "KernelName",                "s", NULL, offsetof(StatusInfo, kernel_name)      },
305                 { "KernelRelease",             "s", NULL, offsetof(StatusInfo, kernel_release)   },
306                 { "OperatingSystemPrettyName", "s", NULL, offsetof(StatusInfo, os_pretty_name)   },
307                 { "OperatingSystemCPEName",    "s", NULL, offsetof(StatusInfo, os_cpe_name)      },
308                 { "HomeURL",                   "s", NULL, offsetof(StatusInfo, home_url)         },
309                 { "HardwareVendor",            "s", NULL, offsetof(StatusInfo, hardware_vendor)  },
310                 { "HardwareModel",             "s", NULL, offsetof(StatusInfo, hardware_model)   },
311                 { "FirmwareVersion",           "s", NULL, offsetof(StatusInfo, firmware_version) },
312                 {}
313         };
314 
315         static const struct bus_properties_map manager_map[] = {
316                 { "Virtualization",            "s", NULL, offsetof(StatusInfo, virtualization)  },
317                 { "Architecture",              "s", NULL, offsetof(StatusInfo, architecture)    },
318                 {}
319         };
320 
321         _cleanup_(sd_bus_message_unrefp) sd_bus_message *host_message = NULL, *manager_message = NULL;
322         _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
323         int r;
324 
325         r = bus_map_all_properties(bus,
326                                    "org.freedesktop.hostname1",
327                                    "/org/freedesktop/hostname1",
328                                    hostname_map,
329                                    0,
330                                    &error,
331                                    &host_message,
332                                    &info);
333         if (r < 0)
334                 return log_error_errno(r, "Failed to query system properties: %s", bus_error_message(&error, r));
335 
336         r = bus_map_all_properties(bus,
337                                    "org.freedesktop.systemd1",
338                                    "/org/freedesktop/systemd1",
339                                    manager_map,
340                                    0,
341                                    &error,
342                                    &manager_message,
343                                    &info);
344         if (r < 0)
345                 return log_error_errno(r, "Failed to query system properties: %s", bus_error_message(&error, r));
346 
347         return print_status_info(&info);
348 }
349 
get_hostname_based_on_flag(sd_bus * bus)350 static int get_hostname_based_on_flag(sd_bus *bus) {
351         const char *attr;
352 
353         if (!!arg_static + !!arg_pretty + !!arg_transient > 1)
354                 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
355                                        "Cannot query more than one name type at a time");
356 
357         attr = arg_pretty ? "PrettyHostname" :
358                 arg_static ? "StaticHostname" : "Hostname";
359 
360         return get_one_name(bus, attr, NULL);
361 }
362 
show_status(int argc,char ** argv,void * userdata)363 static int show_status(int argc, char **argv, void *userdata) {
364         sd_bus *bus = userdata;
365         int r;
366 
367         if (arg_json_format_flags != JSON_FORMAT_OFF) {
368                 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
369                 _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
370                 _cleanup_(json_variant_unrefp) JsonVariant *v = NULL;
371                 const char *text = NULL;
372 
373                 r = sd_bus_call_method(
374                                 bus,
375                                 "org.freedesktop.hostname1",
376                                 "/org/freedesktop/hostname1",
377                                 "org.freedesktop.hostname1",
378                                 "Describe",
379                                 &error,
380                                 &reply,
381                                 NULL);
382                 if (r < 0)
383                         return log_error_errno(r, "Could not get description: %s", bus_error_message(&error, r));
384 
385                 r = sd_bus_message_read(reply, "s", &text);
386                 if (r < 0)
387                         return bus_log_parse_error(r);
388 
389                 r = json_parse(text, 0, &v, NULL, NULL);
390                 if (r < 0)
391                         return log_error_errno(r, "Failed to parse JSON: %m");
392 
393                 json_variant_dump(v, arg_json_format_flags, NULL, NULL);
394                 return 0;
395         }
396 
397         if (arg_pretty || arg_static || arg_transient)
398                 return get_hostname_based_on_flag(bus);
399 
400         return show_all_names(bus);
401 }
402 
403 
set_simple_string_internal(sd_bus * bus,sd_bus_error * error,const char * target,const char * method,const char * value)404 static int set_simple_string_internal(sd_bus *bus, sd_bus_error *error, const char *target, const char *method, const char *value) {
405         _cleanup_(sd_bus_error_free) sd_bus_error e = SD_BUS_ERROR_NULL;
406         int r;
407 
408         polkit_agent_open_if_enabled(arg_transport, arg_ask_password);
409 
410         if (!error)
411                 error = &e;
412 
413         r = sd_bus_call_method(
414                         bus,
415                         "org.freedesktop.hostname1",
416                         "/org/freedesktop/hostname1",
417                         "org.freedesktop.hostname1",
418                         method,
419                         error, NULL,
420                         "sb", value, arg_ask_password);
421         if (r < 0)
422                 return log_error_errno(r, "Could not set %s: %s", target, bus_error_message(error, r));
423 
424         return 0;
425 }
426 
set_simple_string(sd_bus * bus,const char * target,const char * method,const char * value)427 static int set_simple_string(sd_bus *bus, const char *target, const char *method, const char *value) {
428         return set_simple_string_internal(bus, NULL, target, method, value);
429 }
430 
set_hostname(int argc,char ** argv,void * userdata)431 static int set_hostname(int argc, char **argv, void *userdata) {
432         _cleanup_free_ char *h = NULL;
433         const char *hostname = argv[1];
434         sd_bus *bus = userdata;
435         bool implicit = false, show_hint = false;
436         int r, ret = 0;
437 
438         if (!arg_pretty && !arg_static && !arg_transient)
439                 arg_pretty = arg_static = arg_transient = implicit = true;
440 
441         if (!implicit && !arg_static && arg_transient) {
442                 _cleanup_free_ char *source = NULL;
443 
444                 r = get_one_name(bus, "HostnameSource", &source);
445                 if (r < 0)
446                         return r;
447 
448                 if (hostname_source_from_string(source) == HOSTNAME_STATIC)
449                         log_info("Hint: static hostname is already set, so the specified transient hostname will not be used.");
450         }
451 
452         if (arg_pretty) {
453                 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
454                 const char *p;
455 
456                 /* If the passed hostname is already valid, then assume the user doesn't know anything about pretty
457                  * hostnames, so let's unset the pretty hostname, and just set the passed hostname as static/dynamic
458                  * hostname. */
459                 if (implicit && hostname_is_valid(hostname, VALID_HOSTNAME_TRAILING_DOT))
460                         p = ""; /* No pretty hostname (as it is redundant), just a static one */
461                 else
462                         p = hostname; /* Use the passed name as pretty hostname */
463 
464                 r = set_simple_string_internal(bus, &error, "pretty hostname", "SetPrettyHostname", p);
465                 if (r < 0) {
466                         if (implicit &&
467                             sd_bus_error_has_names(&error,
468                                                    BUS_ERROR_FILE_IS_PROTECTED,
469                                                    BUS_ERROR_READ_ONLY_FILESYSTEM)) {
470                                 show_hint = true;
471                                 ret = r;
472                         } else
473                                 return r;
474                 }
475 
476                 /* Now that we set the pretty hostname, let's clean up the parameter and use that as static
477                  * hostname. If the hostname was already valid as static hostname, this will only chop off the trailing
478                  * dot if there is one. If it was not valid, then it will be made fully valid by truncating, dropping
479                  * multiple dots, and dropping weird chars. Note that we clean the name up only if we also are
480                  * supposed to set the pretty name. If the pretty name is not being set we assume the user knows what
481                  * they are doing and pass the name as-is. */
482                 h = strdup(hostname);
483                 if (!h)
484                         return log_oom();
485 
486                 hostname = hostname_cleanup(h); /* Use the cleaned up name as static hostname */
487         }
488 
489         if (arg_static) {
490                 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
491 
492                 r = set_simple_string_internal(bus, &error, "static hostname", "SetStaticHostname", hostname);
493                 if (r < 0) {
494                         if (implicit &&
495                             sd_bus_error_has_names(&error,
496                                                    BUS_ERROR_FILE_IS_PROTECTED,
497                                                    BUS_ERROR_READ_ONLY_FILESYSTEM)) {
498                                 show_hint = true;
499                                 ret = r;
500                         } else
501                                 return r;
502                 }
503         }
504 
505         if (arg_transient) {
506                 r = set_simple_string(bus, "transient hostname", "SetHostname", hostname);
507                 if (r < 0)
508                         return r;
509         }
510 
511         if (show_hint)
512                 log_info("Hint: use --transient option when /etc/machine-info or /etc/hostname cannot be modified (e.g. located in read-only filesystem).");
513 
514         return ret;
515 }
516 
get_or_set_hostname(int argc,char ** argv,void * userdata)517 static int get_or_set_hostname(int argc, char **argv, void *userdata) {
518         return argc == 1 ? get_hostname_based_on_flag(userdata) :
519                            set_hostname(argc, argv, userdata);
520 }
521 
get_or_set_icon_name(int argc,char ** argv,void * userdata)522 static int get_or_set_icon_name(int argc, char **argv, void *userdata) {
523         return argc == 1 ? get_one_name(userdata, "IconName", NULL) :
524                            set_simple_string(userdata, "icon", "SetIconName", argv[1]);
525 }
526 
get_or_set_chassis(int argc,char ** argv,void * userdata)527 static int get_or_set_chassis(int argc, char **argv, void *userdata) {
528         return argc == 1 ? get_one_name(userdata, "Chassis", NULL) :
529                            set_simple_string(userdata, "chassis", "SetChassis", argv[1]);
530 }
531 
get_or_set_deployment(int argc,char ** argv,void * userdata)532 static int get_or_set_deployment(int argc, char **argv, void *userdata) {
533         return argc == 1 ? get_one_name(userdata, "Deployment", NULL) :
534                            set_simple_string(userdata, "deployment", "SetDeployment", argv[1]);
535 }
536 
get_or_set_location(int argc,char ** argv,void * userdata)537 static int get_or_set_location(int argc, char **argv, void *userdata) {
538         return argc == 1 ? get_one_name(userdata, "Location", NULL) :
539                            set_simple_string(userdata, "location", "SetLocation", argv[1]);
540 }
541 
help(void)542 static int help(void) {
543         _cleanup_free_ char *link = NULL;
544         int r;
545 
546         r = terminal_urlify_man("hostnamectl", "1", &link);
547         if (r < 0)
548                 return log_oom();
549 
550         printf("%s [OPTIONS...] COMMAND ...\n\n"
551                "%sQuery or change system hostname.%s\n"
552                "\nCommands:\n"
553                "  status                 Show current hostname settings\n"
554                "  hostname [NAME]        Get/set system hostname\n"
555                "  icon-name [NAME]       Get/set icon name for host\n"
556                "  chassis [NAME]         Get/set chassis type for host\n"
557                "  deployment [NAME]      Get/set deployment environment for host\n"
558                "  location [NAME]        Get/set location for host\n"
559                "\nOptions:\n"
560                "  -h --help              Show this help\n"
561                "     --version           Show package version\n"
562                "     --no-ask-password   Do not prompt for password\n"
563                "  -H --host=[USER@]HOST  Operate on remote host\n"
564                "  -M --machine=CONTAINER Operate on local container\n"
565                "     --transient         Only set transient hostname\n"
566                "     --static            Only set static hostname\n"
567                "     --pretty            Only set pretty hostname\n"
568                "     --json=pretty|short|off\n"
569                "                         Generate JSON output\n"
570                "\nSee the %s for details.\n",
571                program_invocation_short_name,
572                ansi_highlight(),
573                ansi_normal(),
574                link);
575 
576         return 0;
577 }
578 
verb_help(int argc,char ** argv,void * userdata)579 static int verb_help(int argc, char **argv, void *userdata) {
580         return help();
581 }
582 
parse_argv(int argc,char * argv[])583 static int parse_argv(int argc, char *argv[]) {
584 
585         enum {
586                 ARG_VERSION = 0x100,
587                 ARG_NO_ASK_PASSWORD,
588                 ARG_TRANSIENT,
589                 ARG_STATIC,
590                 ARG_PRETTY,
591                 ARG_JSON,
592         };
593 
594         static const struct option options[] = {
595                 { "help",            no_argument,       NULL, 'h'                 },
596                 { "version",         no_argument,       NULL, ARG_VERSION         },
597                 { "transient",       no_argument,       NULL, ARG_TRANSIENT       },
598                 { "static",          no_argument,       NULL, ARG_STATIC          },
599                 { "pretty",          no_argument,       NULL, ARG_PRETTY          },
600                 { "host",            required_argument, NULL, 'H'                 },
601                 { "machine",         required_argument, NULL, 'M'                 },
602                 { "no-ask-password", no_argument,       NULL, ARG_NO_ASK_PASSWORD },
603                 { "json",            required_argument, NULL, ARG_JSON            },
604                 {}
605         };
606 
607         int c, r;
608 
609         assert(argc >= 0);
610         assert(argv);
611 
612         while ((c = getopt_long(argc, argv, "hH:M:", options, NULL)) >= 0)
613 
614                 switch (c) {
615 
616                 case 'h':
617                         return help();
618 
619                 case ARG_VERSION:
620                         return version();
621 
622                 case 'H':
623                         arg_transport = BUS_TRANSPORT_REMOTE;
624                         arg_host = optarg;
625                         break;
626 
627                 case 'M':
628                         arg_transport = BUS_TRANSPORT_MACHINE;
629                         arg_host = optarg;
630                         break;
631 
632                 case ARG_TRANSIENT:
633                         arg_transient = true;
634                         break;
635 
636                 case ARG_PRETTY:
637                         arg_pretty = true;
638                         break;
639 
640                 case ARG_STATIC:
641                         arg_static = true;
642                         break;
643 
644                 case ARG_NO_ASK_PASSWORD:
645                         arg_ask_password = false;
646                         break;
647 
648                 case ARG_JSON:
649                         r = parse_json_argument(optarg, &arg_json_format_flags);
650                         if (r <= 0)
651                                 return r;
652 
653                         break;
654 
655                 case '?':
656                         return -EINVAL;
657 
658                 default:
659                         assert_not_reached();
660                 }
661 
662         return 1;
663 }
664 
hostnamectl_main(sd_bus * bus,int argc,char * argv[])665 static int hostnamectl_main(sd_bus *bus, int argc, char *argv[]) {
666 
667         static const Verb verbs[] = {
668                 { "status",         VERB_ANY, 1,        VERB_DEFAULT, show_status           },
669                 { "hostname",       VERB_ANY, 2,        0,            get_or_set_hostname   },
670                 { "set-hostname",   2,        2,        0,            get_or_set_hostname   }, /* obsolete */
671                 { "icon-name",      VERB_ANY, 2,        0,            get_or_set_icon_name  },
672                 { "set-icon-name",  2,        2,        0,            get_or_set_icon_name  }, /* obsolete */
673                 { "chassis",        VERB_ANY, 2,        0,            get_or_set_chassis    },
674                 { "set-chassis",    2,        2,        0,            get_or_set_chassis    }, /* obsolete */
675                 { "deployment",     VERB_ANY, 2,        0,            get_or_set_deployment },
676                 { "set-deployment", 2,        2,        0,            get_or_set_deployment }, /* obsolete */
677                 { "location",       VERB_ANY, 2,        0,            get_or_set_location   },
678                 { "set-location",   2,        2,        0,            get_or_set_location   }, /* obsolete */
679                 { "help",           VERB_ANY, VERB_ANY, 0,            verb_help             }, /* Not documented, but supported since it is created. */
680                 {}
681         };
682 
683         return dispatch_verb(argc, argv, verbs, bus);
684 }
685 
run(int argc,char * argv[])686 static int run(int argc, char *argv[]) {
687         _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
688         int r;
689 
690         setlocale(LC_ALL, "");
691         log_setup();
692 
693         r = parse_argv(argc, argv);
694         if (r <= 0)
695                 return r;
696 
697         r = bus_connect_transport(arg_transport, arg_host, false, &bus);
698         if (r < 0)
699                 return bus_log_connect_error(r, arg_transport);
700 
701         return hostnamectl_main(bus, argc, argv);
702 }
703 
704 DEFINE_MAIN_FUNCTION(run);
705