5 * Copyright (C) 2012-2013 Intel Corporation. All rights reserved.
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
37 #include "dbus_helpers.h"
42 static DBusConnection *connection;
44 static char *ipv4[] = {
52 static char *ipv6[] = {
60 static int cmd_help(char *args[], int num, struct option *options);
62 static int parse_args(char *arg, struct option *options)
69 for (i = 0; options[i].name != NULL; i++) {
70 if (strcmp(options[i].name, arg) == 0 ||
71 (strncmp(arg, "--", 2) == 0 &&
72 strcmp(&arg[2], options[i].name) == 0))
73 return options[i].val;
79 static void enable_return(DBusMessageIter *iter, const char *error,
82 char *tech = user_data;
85 str = strrchr(tech, '/');
92 fprintf(stdout, "Enabled %s\n", str);
94 fprintf(stderr, "Error %s: %s\n", str, error);
99 static int cmd_enable(char *args[], int num, struct option *options)
102 dbus_bool_t b = TRUE;
110 if (strcmp(args[1], "offlinemode") == 0) {
111 tech = g_strdup(args[1]);
112 return __connmanctl_dbus_set_property(connection, "/",
113 "net.connman.Manager", enable_return, tech,
114 "OfflineMode", DBUS_TYPE_BOOLEAN, &b);
117 tech = g_strdup_printf("/net/connman/technology/%s", args[1]);
118 return __connmanctl_dbus_set_property(connection, tech,
119 "net.connman.Technology", enable_return, tech,
120 "Powered", DBUS_TYPE_BOOLEAN, &b);
123 static void disable_return(DBusMessageIter *iter, const char *error,
126 char *tech = user_data;
129 str = strrchr(tech, '/');
136 fprintf(stdout, "Disabled %s\n", str);
138 fprintf(stderr, "Error %s: %s\n", str, error);
143 static int cmd_disable(char *args[], int num, struct option *options)
146 dbus_bool_t b = FALSE;
154 if (strcmp(args[1], "offlinemode") == 0) {
155 tech = g_strdup(args[1]);
156 return __connmanctl_dbus_set_property(connection, "/",
157 "net.connman.Manager", disable_return, tech,
158 "OfflineMode", DBUS_TYPE_BOOLEAN, &b);
161 tech = g_strdup_printf("/net/connman/technology/%s", args[1]);
162 return __connmanctl_dbus_set_property(connection, tech,
163 "net.connman.Technology", disable_return, tech,
164 "Powered", DBUS_TYPE_BOOLEAN, &b);
167 static void state_print(DBusMessageIter *iter, const char *error,
170 DBusMessageIter entry;
173 fprintf(stderr, "Error: %s", error);
177 dbus_message_iter_recurse(iter, &entry);
178 __connmanctl_dbus_print(&entry, " ", " = ", "\n");
179 fprintf(stdout, "\n");
182 static int cmd_state(char *args[], int num, struct option *options)
187 return __connmanctl_dbus_method_call(connection, "/",
188 "net.connman.Manager", "GetProperties",
189 state_print, NULL, DBUS_TYPE_INVALID);
192 static void services_list(DBusMessageIter *iter, const char *error,
196 __connmanctl_services_list(iter);
197 fprintf(stdout, "\n");
199 fprintf(stderr, "Error: %s\n", error);
203 static void services_properties(DBusMessageIter *iter, const char *error,
206 char *path = user_data;
208 DBusMessageIter dict;
211 fprintf(stdout, "%s\n", path);
213 dbus_message_iter_recurse(iter, &dict);
214 __connmanctl_dbus_print(&dict, " ", " = ", "\n");
216 fprintf(stdout, "\n");
219 str = strrchr(path, '/');
225 fprintf(stderr, "Error %s: %s\n", str, error);
231 static int cmd_services(char *args[], int num, struct option *options)
233 char *service_name = NULL;
240 c = parse_args(args[1], options);
247 service_name = args[2];
252 service_name = args[1];
256 if (service_name == NULL) {
257 return __connmanctl_dbus_method_call(connection, "/",
258 "net.connman.Manager", "GetServices",
259 services_list, NULL, DBUS_TYPE_INVALID);
262 path = g_strdup_printf("/net/connman/service/%s", service_name);
263 return __connmanctl_dbus_method_call(connection, path,
264 "net.connman.Service", "GetProperties",
265 services_properties, path, DBUS_TYPE_INVALID);
268 static void technology_print(DBusMessageIter *iter, const char *error,
271 DBusMessageIter array;
274 fprintf(stderr, "Error: %s\n", error);
278 dbus_message_iter_recurse(iter, &array);
279 while (dbus_message_iter_get_arg_type(&array) == DBUS_TYPE_STRUCT) {
280 DBusMessageIter entry, dict;
283 dbus_message_iter_recurse(&array, &entry);
284 dbus_message_iter_get_basic(&entry, &path);
285 fprintf(stdout, "%s\n", path);
287 dbus_message_iter_next(&entry);
289 dbus_message_iter_recurse(&entry, &dict);
290 __connmanctl_dbus_print(&dict, " ", " = ", "\n");
291 fprintf(stdout, "\n");
293 dbus_message_iter_next(&array);
297 static int cmd_technologies(char *args[], int num, struct option *options)
302 return __connmanctl_dbus_method_call(connection, "/",
303 "net.connman.Manager", "GetTechnologies",
304 technology_print, NULL, DBUS_TYPE_INVALID);
307 static void scan_return(DBusMessageIter *iter, const char *error,
310 char *path = user_data;
313 char *str = strrchr(path, '/');
315 fprintf(stdout, "Scan completed for %s\n", str);
317 fprintf(stderr, "Error %s: %s", path, error);
322 static int cmd_scan(char *args[], int num, struct option *options)
332 path = g_strdup_printf("/net/connman/technology/%s", args[1]);
333 return __connmanctl_dbus_method_call(connection, path,
334 "net.connman.Technology", "Scan",
335 scan_return, path, DBUS_TYPE_INVALID);
338 static void connect_return(DBusMessageIter *iter, const char *error,
341 char *path = user_data;
344 char *str = strrchr(path, '/');
346 fprintf(stdout, "Connected %s\n", str);
348 fprintf(stderr, "Error %s: %s\n", path, error);
353 static int cmd_connect(char *args[], int num, struct option *options)
363 path = g_strdup_printf("/net/connman/service/%s", args[1]);
364 return __connmanctl_dbus_method_call(connection, path,
365 "net.connman.Service", "Connect",
366 connect_return, path, DBUS_TYPE_INVALID);
369 static void disconnect_return(DBusMessageIter *iter, const char *error,
372 char *path = user_data;
375 char *str = strrchr(path, '/');
377 fprintf(stdout, "Disconnected %s\n", str);
379 fprintf(stderr, "Error %s: %s\n", path, error);
384 static int cmd_disconnect(char *args[], int num, struct option *options)
394 path = g_strdup_printf("/net/connman/service/%s", args[1]);
395 return __connmanctl_dbus_method_call(connection, path,
396 "net.connman.Service", "Disconnect",
397 disconnect_return, path, DBUS_TYPE_INVALID);
402 static void config_return(DBusMessageIter *iter, const char *error,
405 char *service_name = user_data;
408 fprintf(stderr, "Error %s: %s\n", service_name, error);
413 struct config_append {
418 static void config_append_ipv4(DBusMessageIter *iter,
421 struct config_append *append = user_data;
422 char **opts = append->opts;
428 while (opts[i] != NULL && ipv4[i] != NULL) {
429 __connmanctl_dbus_append_dict_entry(iter, ipv4[i],
430 DBUS_TYPE_STRING, &opts[i]);
437 static void config_append_ipv6(DBusMessageIter *iter, void *user_data)
439 struct config_append *append = user_data;
440 char **opts = append->opts;
447 if (g_strcmp0(opts[0], "auto") == 0) {
450 switch (parse_boolean(opts[1])) {
455 __connmanctl_dbus_append_dict_entry(iter, "Privacy",
456 DBUS_TYPE_STRING, &str);
463 __connmanctl_dbus_append_dict_entry(iter, "Privacy",
464 DBUS_TYPE_STRING, &str);
468 if (opts[1] != NULL) {
471 if (g_strcmp0(opts[0], "prefered") != 0) {
472 fprintf(stderr, "Error %s: %s\n",
479 __connmanctl_dbus_append_dict_entry(iter,
480 "Privacy", DBUS_TYPE_STRING,
485 } else if (g_strcmp0(opts[0], "manual") == 0) {
488 while (opts[i] != NULL && ipv6[i] != NULL) {
490 int value = atoi(opts[i]);
491 __connmanctl_dbus_append_dict_entry(iter,
492 ipv6[i], DBUS_TYPE_BYTE,
495 __connmanctl_dbus_append_dict_entry(iter,
496 ipv6[i], DBUS_TYPE_STRING,
504 } else if (g_strcmp0(opts[0], "off") != 0) {
505 fprintf(stderr, "Error %s: %s\n", opts[0], strerror(-EINVAL));
510 __connmanctl_dbus_append_dict_entry(iter, "Method", DBUS_TYPE_STRING,
514 static void config_append_str(DBusMessageIter *iter, void *user_data)
516 struct config_append *append = user_data;
517 char **opts = append->opts;
523 while (opts[i] != NULL) {
524 dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING,
532 static void append_servers(DBusMessageIter *iter, void *user_data)
534 struct config_append *append = user_data;
535 char **opts = append->opts;
541 while (opts[i] != NULL && g_strcmp0(opts[i], "--excludes") != 0) {
542 dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING,
550 static void append_excludes(DBusMessageIter *iter, void *user_data)
552 struct config_append *append = user_data;
553 char **opts = append->opts;
554 int i = append->values;
556 if (opts == NULL || opts[i] == NULL ||
557 g_strcmp0(opts[i], "--excludes") != 0)
561 while (opts[i] != NULL) {
562 dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING,
570 static void config_append_proxy(DBusMessageIter *iter, void *user_data)
572 struct config_append *append = user_data;
573 char **opts = append->opts;
578 if (g_strcmp0(opts[0], "manual") == 0) {
579 __connmanctl_dbus_append_dict_string_array(iter, "Servers",
580 append_servers, append);
582 __connmanctl_dbus_append_dict_string_array(iter, "Excludes",
583 append_excludes, append);
585 } else if (g_strcmp0(opts[0], "auto") == 0) {
586 if (opts[1] != NULL) {
587 __connmanctl_dbus_append_dict_entry(iter, "URL",
588 DBUS_TYPE_STRING, &opts[1]);
592 } else if (g_strcmp0(opts[0], "direct") != 0)
595 __connmanctl_dbus_append_dict_entry(iter, "Method",DBUS_TYPE_STRING,
601 static int cmd_config(char *args[], int num, struct option *options)
603 int result = 0, res = 0, index = 2, oldindex = 0;
605 char *service_name, *path;
608 struct config_append append;
610 service_name = args[1];
611 if (service_name == NULL)
614 while (index < num && args[index] != NULL) {
615 c = parse_args(args[index], options);
616 opt_start = &args[index + 1];
617 append.opts = opt_start;
623 path = g_strdup_printf("/net/connman/service/%s", service_name);
627 switch (parse_boolean(*opt_start)) {
642 res = __connmanctl_dbus_set_property(connection,
643 path, "net.connman.Service",
645 g_strdup(service_name),
647 DBUS_TYPE_BOOLEAN, &val);
651 res = __connmanctl_dbus_set_property_dict(connection,
652 path, "net.connman.Service",
653 config_return, g_strdup(service_name),
654 "IPv4.Configuration", DBUS_TYPE_STRING,
655 config_append_ipv4, &append);
656 index += append.values;
660 res = __connmanctl_dbus_set_property_dict(connection,
661 path, "net.connman.Service",
662 config_return, g_strdup(service_name),
663 "IPv6.Configuration", DBUS_TYPE_STRING,
664 config_append_ipv6, &append);
665 index += append.values;
669 res = __connmanctl_dbus_set_property_array(connection,
670 path, "net.connman.Service",
671 config_return, g_strdup(service_name),
672 "Nameservers.Configuration",
673 DBUS_TYPE_STRING, config_append_str,
675 index += append.values;
679 res = __connmanctl_dbus_set_property_array(connection,
680 path, "net.connman.Service",
681 config_return, g_strdup(service_name),
682 "Timeservers.Configuration",
683 DBUS_TYPE_STRING, config_append_str,
685 index += append.values;
689 res = __connmanctl_dbus_set_property_array(connection,
690 path, "net.connman.Service",
691 config_return, g_strdup(service_name),
692 "Domains.Configuration",
693 DBUS_TYPE_STRING, config_append_str,
695 index += append.values;
699 res = __connmanctl_dbus_set_property_dict(connection,
700 path, "net.connman.Service",
701 config_return, g_strdup(service_name),
702 "Proxy.Configuration",
703 DBUS_TYPE_STRING, config_append_proxy,
705 index += append.values;
708 res = __connmanctl_dbus_method_call(connection,
709 path, "net.connman.Service", "Remove",
710 config_return, g_strdup(service_name),
721 if (res == -EINPROGRESS)
722 result = -EINPROGRESS;
724 printf("Error '%s': %s\n", args[oldindex],
735 static DBusHandlerResult monitor_changed(DBusConnection *connection,
736 DBusMessage *message, void *user_data)
738 DBusMessageIter iter;
739 const char *interface, *path;
741 interface = dbus_message_get_interface(message);
742 if (strncmp(interface, "net.connman.", 12) != 0)
743 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
745 interface = strrchr(interface, '.');
746 if (interface != NULL && *interface != '\0')
749 path = strrchr(dbus_message_get_path(message), '/');
750 if (path != NULL && *path != '\0')
753 __connmanctl_save_rl();
755 if (dbus_message_is_signal(message, "net.connman.Manager",
756 "ServicesChanged") == TRUE) {
758 fprintf(stdout, "%-12s %-20s = {\n", interface,
760 dbus_message_iter_init(message, &iter);
761 __connmanctl_services_list(&iter);
762 fprintf(stdout, "\n}\n");
764 __connmanctl_redraw_rl();
766 return DBUS_HANDLER_RESULT_HANDLED;
769 if (dbus_message_is_signal(message, "net.connman.Manager",
770 "TechnologyAdded") == TRUE)
771 path = "TechnologyAdded";
773 if (dbus_message_is_signal(message, "net.connman.Manager",
774 "TechnologyRemoved") == TRUE)
775 path = "TechnologyRemoved";
777 fprintf(stdout, "%-12s %-20s ", interface, path);
778 dbus_message_iter_init(message, &iter);
780 __connmanctl_dbus_print(&iter, "", " = ", " = ");
781 fprintf(stdout, "\n");
783 __connmanctl_redraw_rl();
785 return DBUS_HANDLER_RESULT_HANDLED;
788 static bool monitor_s = false;
789 static bool monitor_t = false;
790 static bool monitor_m = false;
792 static void monitor_add(char *interface)
797 if (monitor_s == false && monitor_t == false && monitor_m == false)
798 dbus_connection_add_filter(connection, monitor_changed,
801 if (g_strcmp0(interface, "Service") == 0) {
802 if (monitor_s == true)
805 } else if (g_strcmp0(interface, "Technology") == 0) {
806 if (monitor_t == true)
809 } else if (g_strcmp0(interface, "Manager") == 0) {
810 if (monitor_m == true)
816 dbus_error_init(&err);
817 rule = g_strdup_printf("type='signal',interface='net.connman.%s'",
819 dbus_bus_add_match(connection, rule, &err);
822 if (dbus_error_is_set(&err))
823 fprintf(stderr, "Error: %s\n", err.message);
826 static void monitor_del(char *interface)
830 if (g_strcmp0(interface, "Service") == 0) {
831 if (monitor_s == false)
834 } else if (g_strcmp0(interface, "Technology") == 0) {
835 if (monitor_t == false)
838 } else if (g_strcmp0(interface, "Manager") == 0) {
839 if (monitor_m == false)
845 rule = g_strdup_printf("type='signal',interface='net.connman.%s'",
847 dbus_bus_remove_match(connection, rule, NULL);
850 if (monitor_s == false && monitor_t == false && monitor_m == false)
851 dbus_connection_remove_filter(connection, monitor_changed,
855 static int cmd_monitor(char *args[], int num, struct option *options)
864 switch (parse_boolean(args[2])) {
874 c = parse_args(args[1], options);
877 monitor_add("Service");
878 monitor_add("Technology");
879 monitor_add("Manager");
884 monitor_add("Service");
886 monitor_del("Service");
891 monitor_add("Technology");
893 monitor_del("Technology");
898 monitor_add("Manager");
900 monitor_del("Manager");
904 switch(parse_boolean(args[1])) {
906 monitor_del("Service");
907 monitor_del("Technology");
908 monitor_del("Manager");
912 monitor_add("Service");
913 monitor_add("Technology");
914 monitor_add("Manager");
928 static int cmd_exit(char *args[], int num, struct option *options)
933 static struct option service_options[] = {
934 {"properties", required_argument, 0, 'p'},
938 static const char *service_desc[] = {
939 "[<service>] (obsolete)",
943 static struct option config_options[] = {
944 {"nameservers", required_argument, 0, 'n'},
945 {"timeservers", required_argument, 0, 't'},
946 {"domains", required_argument, 0, 'd'},
947 {"ipv6", required_argument, 0, 'v'},
948 {"proxy", required_argument, 0, 'x'},
949 {"autoconnect", required_argument, 0, 'a'},
950 {"ipv4", required_argument, 0, 'i'},
951 {"remove", 0, 0, 'r'},
955 static const char *config_desc[] = {
956 "<dns1> [<dns2>] [<dns3>]",
957 "<ntp1> [<ntp2>] [...]",
958 "<domain1> [<domain2>] [...]",
959 "off|auto [enable|disable|prefered]|\n"
960 "\t\t\tmanual <address> <prefixlength> <gateway>",
961 "direct|auto <URL>|manual <URL1> [<URL2>] [...]\n"
962 "\t\t\t[exclude <exclude1> [<exclude2>] [...]]",
964 "off|dhcp|manual <address> <prefixlength> <gateway>",
969 static struct option monitor_options[] = {
970 {"services", no_argument, 0, 's'},
971 {"tech", no_argument, 0, 'c'},
972 {"manager", no_argument, 0, 'm'},
976 static const char *monitor_desc[] = {
977 "[off] Monitor only services",
978 "[off] Monitor only technologies",
979 "[off] Monitor only manager interface",
983 static const struct {
985 const char *argument;
986 struct option *options;
987 const char **options_desc;
988 int (*func) (char *args[], int num, struct option *options);
991 { "enable", "<technology>|offline", NULL, NULL,
992 cmd_enable, "Enables given technology or offline mode" },
993 { "disable", "<technology>|offline", NULL, NULL,
994 cmd_disable, "Disables given technology or offline mode"},
995 { "state", NULL, NULL, NULL,
996 cmd_state, "Shows if the system is online or offline" },
997 { "services", "[<service>]", service_options, &service_desc[0],
998 cmd_services, "Display services" },
999 { "technologies", NULL, NULL, NULL,
1000 cmd_technologies, "Display technologies" },
1001 { "scan", "<technology>", NULL, NULL,
1002 cmd_scan, "Scans for new services for given technology" },
1003 { "connect", "<service>", NULL, NULL,
1004 cmd_connect, "Connect a given service" },
1005 { "disconnect", "<service>", NULL, NULL,
1006 cmd_disconnect, "Disconnect a given service" },
1007 { "config", "<service>", config_options, &config_desc[0],
1008 cmd_config, "Set service configuration options" },
1009 { "monitor", "[off]", monitor_options, &monitor_desc[0],
1010 cmd_monitor, "Monitor signals from interfaces" },
1011 { "help", NULL, NULL, NULL,
1012 cmd_help, "Show help" },
1013 { "exit", NULL, NULL, NULL,
1015 { "quit", NULL, NULL, NULL,
1020 static int cmd_help(char *args[], int num, struct option *options)
1022 bool interactive = __connmanctl_is_interactive();
1025 if (interactive == false)
1026 fprintf(stdout, "Usage: connmanctl [[command] [args]]\n");
1028 for (i = 0; cmd_table[i].cmd != NULL; i++) {
1029 const char *cmd = cmd_table[i].cmd;
1030 const char *argument = cmd_table[i].argument;
1031 const char *desc = cmd_table[i].desc;
1033 printf("%-12s%-22s%s\n", cmd != NULL? cmd: "",
1034 argument != NULL? argument: "",
1035 desc != NULL? desc: "");
1037 if (cmd_table[i].options != NULL) {
1038 for (j = 0; cmd_table[i].options[j].name != NULL;
1040 const char *options_desc =
1041 cmd_table[i].options_desc != NULL ?
1042 cmd_table[i].options_desc[j]: "";
1044 printf(" --%-12s%s\n",
1045 cmd_table[i].options[j].name,
1051 if (interactive == false)
1052 fprintf(stdout, "\nNote: arguments and output are considered "
1053 "EXPERIMENTAL for now.\n");
1058 int commands(DBusConnection *dbus_conn, char *argv[], int argc)
1062 connection = dbus_conn;
1064 for (i = 0; cmd_table[i].cmd != NULL; i++) {
1065 if (g_strcmp0(cmd_table[i].cmd, argv[0]) == 0 &&
1066 cmd_table[i].func != NULL) {
1067 result = cmd_table[i].func(argv, argc,
1068 cmd_table[i].options);
1069 if (result < 0 && result != -EINPROGRESS)
1070 fprintf(stderr, "Error '%s': %s\n", argv[0],
1076 fprintf(stderr, "Error '%s': Unknown command\n", argv[0]);