client: Use D-Bus helpers for Technology GetTechnologies method call
[platform/upstream/connman.git] / client / commands.c
1 /*
2  *
3  *  Connection Manager
4  *
5  *  Copyright (C) 2012-2013  Intel Corporation. All rights reserved.
6  *
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.
11  *
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.
16  *
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
20  *
21  */
22
23 #ifdef HAVE_CONFIG_H
24 #include <config.h>
25 #endif
26
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <string.h>
30 #include <errno.h>
31 #include <getopt.h>
32 #include <stdbool.h>
33
34 #include <glib.h>
35 #include <gdbus.h>
36
37 #include "services.h"
38 #include "technology.h"
39 #include "data_manager.h"
40
41 #include "dbus_helpers.h"
42 #include "input.h"
43 #include "commands.h"
44
45 #define MANDATORY_ARGS 3
46
47 static DBusConnection *connection;
48
49 static char *ipv4[] = {
50         "Method",
51         "Address",
52         "Netmask",
53         "Gateway",
54         NULL
55 };
56
57 static char *ipv6[] = {
58         "Method",
59         "Address",
60         "PrefixLength",
61         "Gateway",
62         "Privacy",
63         NULL
64 };
65
66 static char *proxy_simple[] = {
67         "Method",
68         "URL",
69         NULL
70 };
71
72 static int cmd_help(char *args[], int num, struct option *options);
73
74 static int parse_args(char *arg, struct option *options)
75 {
76         int i;
77
78         if (arg == NULL)
79                 return -1;
80
81         for (i = 0; options[i].name != NULL; i++) {
82                 if (strcmp(options[i].name, arg) == 0 ||
83                                 (strncmp(arg, "--", 2) == 0 &&
84                                         strcmp(&arg[2], options[i].name) == 0))
85                         return options[i].val;
86         }
87
88         return '?';
89 }
90
91 static int cmd_enable(char *args[], int num, struct option *options)
92 {
93         DBusMessage *message;
94         int err;
95
96         if (num > 2)
97                 return -E2BIG;
98
99         if (num < 2)
100                 return -EINVAL;
101
102         if (strcmp(args[1], "offlinemode") == 0) {
103                 err = set_manager(connection, "OfflineMode", TRUE);
104                 if (err == 0)
105                         printf("OfflineMode enabled\n");
106
107                 return 0;
108         }
109
110         message = get_message(connection, "GetTechnologies");
111         if (message == NULL)
112                 return -ENOMEM;
113
114         set_technology(connection, message, "Powered", args[1], TRUE);
115
116         return 0;
117 }
118
119 static int cmd_disable(char *args[], int num, struct option *options)
120 {
121         DBusMessage *message;
122         int err;
123
124         if (num > 2)
125                 return -E2BIG;
126
127         if (num < 2)
128                 return -EINVAL;
129
130         if (strcmp(args[1], "offlinemode") == 0) {
131                 err = set_manager(connection, "OfflineMode", FALSE);
132                 if (err == 0)
133                         printf("OfflineMode enabled\n");
134
135                 return 0;
136         }
137
138         message = get_message(connection, "GetTechnologies");
139         if (message == NULL)
140                 return -ENOMEM;
141
142         set_technology(connection, message, "Powered", args[1], FALSE);
143
144         return 0;
145 }
146
147 static void state_print(DBusMessageIter *iter, const char *error,
148                 void *user_data)
149 {
150         DBusMessageIter entry;
151
152         if (error != NULL) {
153                 fprintf(stderr, "Error: %s", error);
154                 return;
155         }
156
157         dbus_message_iter_recurse(iter, &entry);
158         __connmanctl_dbus_print(&entry, "  ", " = ", "\n");
159         fprintf(stdout, "\n");
160 }
161
162 static int cmd_state(char *args[], int num, struct option *options)
163 {
164         if (num > 1)
165                 return -E2BIG;
166
167         return __connmanctl_dbus_method_call(connection, "/",
168                         "net.connman.Manager", "GetProperties",
169                         state_print, NULL, DBUS_TYPE_INVALID);
170 }
171
172 static int cmd_services(char *args[], int num, struct option *options)
173 {
174         char *service_name = NULL;
175         int err = 0;
176         int c;
177         DBusMessage *message;
178
179         if (num > 3)
180                 return -E2BIG;
181
182         c = parse_args(args[1], options);
183         switch (c) {
184         case -1:
185                 break;
186         case 'p':
187                 if (num < 3)
188                         return -EINVAL;
189                 service_name = args[2];
190                 break;
191         default:
192                 if (num > 2)
193                         return -E2BIG;
194                 service_name = args[1];
195                 break;
196         }
197
198         message = get_message(connection, "GetServices");
199         if (message == NULL)
200                 return -ENOMEM;
201
202         err = list_properties(connection, "GetServices", service_name);
203         dbus_message_unref(message);
204
205         return err;
206 }
207
208 static void technology_print(DBusMessageIter *iter, const char *error,
209                 void *user_data)
210 {
211         DBusMessageIter array;
212
213         if (error != NULL) {
214                 fprintf(stderr, "Error: %s\n", error);
215                 return;
216         }
217
218         dbus_message_iter_recurse(iter, &array);
219         while (dbus_message_iter_get_arg_type(&array) == DBUS_TYPE_STRUCT) {
220                 DBusMessageIter entry, dict;
221                 const char *path;
222
223                 dbus_message_iter_recurse(&array, &entry);
224                 dbus_message_iter_get_basic(&entry, &path);
225                 fprintf(stdout, "%s\n", path);
226
227                 dbus_message_iter_next(&entry);
228
229                 dbus_message_iter_recurse(&entry, &dict);
230                 __connmanctl_dbus_print(&dict, "  ", " = ", "\n");
231                 fprintf(stdout, "\n");
232
233                 dbus_message_iter_next(&array);
234         }
235 }
236
237 static int cmd_technologies(char *args[], int num, struct option *options)
238 {
239         if (num > 1)
240                 return -E2BIG;
241
242         return __connmanctl_dbus_method_call(connection, "/",
243                         "net.connman.Manager", "GetTechnologies",
244                         technology_print, NULL, DBUS_TYPE_INVALID);
245 }
246
247 static int cmd_scan(char *args[], int num, struct option *options)
248 {
249         DBusMessage *message;
250         int err;
251
252         if (num > 2)
253                 return -E2BIG;
254
255         if (num < 2)
256                 return -EINVAL;
257
258         message = get_message(connection, "GetTechnologies");
259         if (message == NULL)
260                 err = -ENOMEM;
261         else {
262                 err = scan_technology(connection, message, args[1]);
263                 if (err == 0)
264                         printf("Scan completed\n");
265         }
266
267         return 0;
268 }
269
270 static void connect_return(DBusMessageIter *iter, const char *error,
271                 void *user_data)
272 {
273         char *path = user_data;
274
275         if (error == NULL) {
276                 char *str = strrchr(path, '/');
277                 str++;
278                 fprintf(stdout, "Connected %s\n", str);
279         } else
280                 fprintf(stderr, "Error %s: %s\n", path, error);
281
282         g_free(user_data);
283 }
284
285 static int cmd_connect(char *args[], int num, struct option *options)
286 {
287         char *path;
288
289         if (num > 2)
290                 return -E2BIG;
291
292         if (num < 2)
293                 return -EINVAL;
294
295         path = g_strdup_printf("/net/connman/service/%s", args[1]);
296         return __connmanctl_dbus_method_call(connection, path,
297                         "net.connman.Service", "Connect",
298                         connect_return, path, DBUS_TYPE_INVALID);
299 }
300
301 static void disconnect_return(DBusMessageIter *iter, const char *error,
302                 void *user_data)
303 {
304         char *path = user_data;
305
306         if (error == NULL) {
307                 char *str = strrchr(path, '/');
308                 str++;
309                 fprintf(stdout, "Disconnected %s\n", str);
310         } else
311                 fprintf(stderr, "Error %s: %s\n", path, error);
312
313         g_free(user_data);
314 }
315
316 static int cmd_disconnect(char *args[], int num, struct option *options)
317 {
318         char *path;
319
320         if (num > 2)
321                 return -E2BIG;
322
323         if (num < 2)
324                 return -EINVAL;
325
326         path = g_strdup_printf("/net/connman/service/%s", args[1]);
327         return __connmanctl_dbus_method_call(connection, path,
328                         "net.connman.Service", "Disconnect",
329                         disconnect_return, path, DBUS_TYPE_INVALID);
330
331         return 0;
332 }
333
334 static int cmd_config(char *args[], int num, struct option *options)
335 {
336         int res = 0, index = 2, oldindex = 0;
337         int c;
338         char *service_name;
339         DBusMessage *message;
340         char **opt_start;
341         dbus_bool_t val;
342
343         service_name = args[1];
344         if (service_name == NULL)
345                 return -EINVAL;
346
347         while (index < num && args[index] != NULL) {
348                 c = parse_args(args[index], options);
349                 opt_start = &args[index + 1];
350                 res = 0;
351
352                 message = get_message(connection, "GetServices");
353                 if (message == NULL)
354                         return -ENOMEM;
355
356                 oldindex = index;
357
358                 switch (c) {
359                 case 'a':
360                         switch (parse_boolean(*opt_start)) {
361                         case 1:
362                                 val = TRUE;
363                                 break;
364                         case 0:
365                                 val = FALSE;
366                                 break;
367                         default:
368                                 res = -EINVAL;
369                                 break;
370                         }
371                         if (res == 0)
372                                 res = set_service_property(connection, message,
373                                                 service_name, "AutoConnect",
374                                                 NULL, &val, 0);
375                         break;
376                 case 'i':
377                         res = set_service_property(connection, message,
378                                         service_name, "IPv4.Configuration",
379                                         ipv4, opt_start, 0);
380                         if (res < 0)
381                                 index += 4;
382                         break;
383                 case 'v':
384                         res = set_service_property(connection, message,
385                                         service_name, "IPv6.Configuration",
386                                         ipv6, opt_start, 0);
387                         if (res < 0)
388                                 index += 5;
389                         break;
390                 case 'n':
391                         res = set_service_property(connection, message,
392                                         service_name,
393                                         "Nameservers.Configuration",
394                                         NULL, opt_start, 0);
395                         break;
396                 case 't':
397                         res = set_service_property(connection, message,
398                                         service_name,
399                                         "Timeservers.Configuration",
400                                         NULL, opt_start, 0);
401                         break;
402                 case 'd':
403                         res = set_service_property(connection, message,
404                                         service_name,
405                                         "Domains.Configuration",
406                                         NULL, opt_start, 0);
407                         break;
408                 case 'x':
409                         if (*opt_start == NULL) {
410                                 res = -EINVAL;
411                                 break;
412                         }
413
414                         if (strcmp(*opt_start, "direct") == 0) {
415                                 res = set_service_property(connection, message,
416                                                 service_name,
417                                                 "Proxy.Configuration",
418                                                 proxy_simple, opt_start, 1);
419                                 break;
420                         }
421
422                         if (strcmp(*opt_start, "auto") == 0) {
423                                 res = set_service_property(connection, message,
424                                                 service_name,
425                                                 "Proxy.Configuration",
426                                                 proxy_simple, opt_start, 1);
427                                 break;
428                         }
429
430                         if (strcmp(*opt_start, "manual") == 0) {
431                                         char **url_start = &args[index + 2];
432
433                                         if (*url_start != NULL &&
434                                                 strcmp(*url_start,
435                                                         "servers") == 0) {
436                                                 url_start = &args[index + 3];
437                                                 index++;
438                                         }
439                                         res = store_proxy_input(connection,
440                                                         message, service_name,
441                                                         0, url_start);
442                         }
443
444                         break;
445                 case 'r':
446                         res = remove_service(connection, message, service_name);
447                         break;
448                 default:
449                         res = -EINVAL;
450                         break;
451                 }
452
453                 dbus_message_unref(message);
454
455                 if (res < 0) {
456                         printf("Error '%s': %s\n", args[oldindex],
457                                         strerror(-res));
458                 } else
459                         index += res;
460
461                 index++;
462         }
463
464         return 0;
465 }
466
467 static DBusHandlerResult monitor_changed(DBusConnection *connection,
468                 DBusMessage *message, void *user_data)
469 {
470         DBusMessageIter iter;
471         const char *interface, *path;
472
473         interface = dbus_message_get_interface(message);
474         if (strncmp(interface, "net.connman.", 12) != 0)
475                 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
476
477         interface = strrchr(interface, '.');
478         if (interface != NULL && *interface != '\0')
479                 interface++;
480
481         path = strrchr(dbus_message_get_path(message), '/');
482         if (path != NULL && *path != '\0')
483                 path++;
484
485         __connmanctl_save_rl();
486
487         if (dbus_message_is_signal(message, "net.connman.Manager",
488                                         "ServicesChanged") == TRUE) {
489
490                 fprintf(stdout, "%-12s %-20s = {\n", interface,
491                                 "ServicesChanged");
492                 dbus_message_iter_init(message, &iter);
493                 __connmanctl_services_list(&iter);
494                 fprintf(stdout, "\n}\n");
495
496                 __connmanctl_redraw_rl();
497
498                 return DBUS_HANDLER_RESULT_HANDLED;
499         }
500
501         if (dbus_message_is_signal(message, "net.connman.Manager",
502                                         "TechnologyAdded") == TRUE)
503                 path = "TechnologyAdded";
504
505         if (dbus_message_is_signal(message, "net.connman.Manager",
506                                         "TechnologyRemoved") == TRUE)
507                 path = "TechnologyRemoved";
508
509         fprintf(stdout, "%-12s %-20s ", interface, path);
510         dbus_message_iter_init(message, &iter);
511
512         __connmanctl_dbus_print(&iter, "", " = ", " = ");
513         fprintf(stdout, "\n");
514
515         __connmanctl_redraw_rl();
516
517         return DBUS_HANDLER_RESULT_HANDLED;
518 }
519
520 static bool monitor_s = false;
521 static bool monitor_t = false;
522 static bool monitor_m = false;
523
524 static void monitor_add(char *interface)
525 {
526         char *rule;
527         DBusError err;
528
529         if (monitor_s == false && monitor_t == false && monitor_m == false)
530                 dbus_connection_add_filter(connection, monitor_changed,
531                                 NULL, NULL);
532
533         if (g_strcmp0(interface, "Service") == 0) {
534                 if (monitor_s == true)
535                         return;
536                 monitor_s = true;
537         } else if (g_strcmp0(interface, "Technology") == 0) {
538                 if (monitor_t == true)
539                         return;
540                 monitor_t = true;
541         } else if (g_strcmp0(interface, "Manager") == 0) {
542                 if (monitor_m == true)
543                         return;
544                 monitor_m = true;
545         } else
546                 return;
547
548         dbus_error_init(&err);
549         rule  = g_strdup_printf("type='signal',interface='net.connman.%s'",
550                         interface);
551         dbus_bus_add_match(connection, rule, &err);
552         g_free(rule);
553
554         if (dbus_error_is_set(&err))
555                 fprintf(stderr, "Error: %s\n", err.message);
556 }
557
558 static void monitor_del(char *interface)
559 {
560         char *rule;
561
562         if (g_strcmp0(interface, "Service") == 0) {
563                 if (monitor_s == false)
564                         return;
565                 monitor_s = false;
566         } else if (g_strcmp0(interface, "Technology") == 0) {
567                 if (monitor_t == false)
568                         return;
569                 monitor_t = false;
570         } else if (g_strcmp0(interface, "Manager") == 0) {
571                 if (monitor_m == false)
572                         return;
573                 monitor_m = false;
574         } else
575                 return;
576
577         rule  = g_strdup_printf("type='signal',interface='net.connman.%s'",
578                         interface);
579         dbus_bus_remove_match(connection, rule, NULL);
580         g_free(rule);
581
582         if (monitor_s == false && monitor_t == false && monitor_m == false)
583                 dbus_connection_remove_filter(connection, monitor_changed,
584                                 NULL);
585 }
586
587 static int cmd_monitor(char *args[], int num, struct option *options)
588 {
589         bool add = true;
590         int c;
591
592         if (num > 3)
593                 return -E2BIG;
594
595         if (num == 3) {
596                 switch (parse_boolean(args[2])) {
597                 case 0:
598                         add = false;
599                         break;
600
601                 default:
602                         break;
603                 }
604         }
605
606         c = parse_args(args[1], options);
607         switch (c) {
608         case -1:
609                 monitor_add("Service");
610                 monitor_add("Technology");
611                 monitor_add("Manager");
612                 break;
613
614         case 's':
615                 if (add == true)
616                         monitor_add("Service");
617                 else
618                         monitor_del("Service");
619                 break;
620
621         case 'c':
622                 if (add == true)
623                         monitor_add("Technology");
624                 else
625                         monitor_del("Technology");
626                 break;
627
628         case 'm':
629                 if (add == true)
630                         monitor_add("Manager");
631                 else
632                         monitor_del("Manager");
633                 break;
634
635         default:
636                 switch(parse_boolean(args[1])) {
637                 case 0:
638                         monitor_del("Service");
639                         monitor_del("Technology");
640                         monitor_del("Manager");
641                         break;
642
643                 case 1:
644                         monitor_add("Service");
645                         monitor_add("Technology");
646                         monitor_add("Manager");
647                         break;
648
649                 default:
650                         return -EINVAL;
651                 }
652         }
653
654         if (add == true)
655                 return -EINPROGRESS;
656
657         return 0;
658 }
659
660 static int cmd_exit(char *args[], int num, struct option *options)
661 {
662         return 1;
663 }
664
665 static struct option service_options[] = {
666         {"properties", required_argument, 0, 'p'},
667         { NULL, }
668 };
669
670 static const char *service_desc[] = {
671         "[<service>]      (obsolete)",
672         NULL
673 };
674
675 static struct option config_options[] = {
676         {"nameservers", required_argument, 0, 'n'},
677         {"timeservers", required_argument, 0, 't'},
678         {"domains", required_argument, 0, 'd'},
679         {"ipv6", required_argument, 0, 'v'},
680         {"proxy", required_argument, 0, 'x'},
681         {"autoconnect", required_argument, 0, 'a'},
682         {"ipv4", required_argument, 0, 'i'},
683         {"remove", 0, 0, 'r'},
684         { NULL, }
685 };
686
687 static const char *config_desc[] = {
688         "<dns1> [<dns2>] [<dns3>]",
689         "<ntp1> [<ntp2>] [...]",
690         "<domain1> [<domain2>] [...]",
691         "off|auto|manual <address> <prefixlength> <gateway> <privacy>",
692         "direct|auto <URL>|manual <URL1> [<URL2>] [...]\n"
693         "                   [exclude <exclude1> [<exclude2>] [...]]",
694         "yes|no",
695         "off|dhcp|manual <address> <prefixlength> <gateway>",
696         "                 Remove service",
697         NULL
698 };
699
700 static struct option monitor_options[] = {
701         {"services", no_argument, 0, 's'},
702         {"tech", no_argument, 0, 'c'},
703         {"manager", no_argument, 0, 'm'},
704         { NULL, }
705 };
706
707 static const char *monitor_desc[] = {
708         "[off]            Monitor only services",
709         "[off]            Monitor only technologies",
710         "[off]            Monitor only manager interface",
711         NULL
712 };
713
714 static const struct {
715         const char *cmd;
716         const char *argument;
717         struct option *options;
718         const char **options_desc;
719         int (*func) (char *args[], int num, struct option *options);
720         const char *desc;
721 } cmd_table[] = {
722         { "enable",       "<technology>|offline", NULL,    NULL,
723           cmd_enable, "Enables given technology or offline mode" },
724         { "disable",      "<technology>|offline", NULL,    NULL,
725           cmd_disable, "Disables given technology or offline mode"},
726         { "state",        NULL,           NULL,            NULL,
727           cmd_state, "Shows if the system is online or offline" },
728         { "services",     "[<service>]",  service_options, &service_desc[0],
729           cmd_services, "Display services" },
730         { "technologies", NULL,           NULL,            NULL,
731           cmd_technologies, "Display technologies" },
732         { "scan",         "<technology>", NULL,            NULL,
733           cmd_scan, "Scans for new services for given technology" },
734         { "connect",      "<service>",    NULL,            NULL,
735           cmd_connect, "Connect a given service" },
736         { "disconnect",   "<service>",    NULL,            NULL,
737           cmd_disconnect, "Disconnect a given service" },
738         { "config",       "<service>",    config_options,  &config_desc[0],
739           cmd_config, "Set service configuration options" },
740         { "monitor",      "[off]",        monitor_options, &monitor_desc[0],
741           cmd_monitor, "Monitor signals from interfaces" },
742         { "help",         NULL,           NULL,            NULL,
743           cmd_help, "Show help" },
744         { "exit",         NULL,           NULL,            NULL,
745           cmd_exit,       "Exit" },
746         { "quit",         NULL,           NULL,            NULL,
747           cmd_exit,       "Quit" },
748         {  NULL, },
749 };
750
751 static int cmd_help(char *args[], int num, struct option *options)
752 {
753         bool interactive = __connmanctl_is_interactive();
754         int i, j;
755
756         if (interactive == false)
757                 fprintf(stdout, "Usage: connmanctl [[command] [args]]\n");
758
759         for (i = 0; cmd_table[i].cmd != NULL; i++) {
760                 const char *cmd = cmd_table[i].cmd;
761                 const char *argument = cmd_table[i].argument;
762                 const char *desc = cmd_table[i].desc;
763
764                 printf("%-12s%-22s%s\n", cmd != NULL? cmd: "",
765                                 argument != NULL? argument: "",
766                                 desc != NULL? desc: "");
767
768                 if (cmd_table[i].options != NULL) {
769                         for (j = 0; cmd_table[i].options[j].name != NULL;
770                              j++) {
771                                 const char *options_desc =
772                                         cmd_table[i].options_desc != NULL ?
773                                         cmd_table[i].options_desc[j]: "";
774
775                                 printf("   --%-12s%s\n",
776                                                 cmd_table[i].options[j].name,
777                                                 options_desc);
778                         }
779                 }
780         }
781
782         if (interactive == false)
783                 fprintf(stdout, "\nNote: arguments and output are considered "
784                                 "EXPERIMENTAL for now.\n");
785
786         return 0;
787 }
788
789 int commands(DBusConnection *dbus_conn, char *argv[], int argc)
790 {
791         int i, result;
792
793         connection = dbus_conn;
794
795         for (i = 0; cmd_table[i].cmd != NULL; i++) {
796                 if (g_strcmp0(cmd_table[i].cmd, argv[0]) == 0 &&
797                                 cmd_table[i].func != NULL) {
798                         result = cmd_table[i].func(argv, argc,
799                                         cmd_table[i].options);
800                         if (result < 0 && result != -EINPROGRESS)
801                                 fprintf(stderr, "Error '%s': %s\n", argv[0],
802                                                 strerror(-result));
803                         return result;
804                 }
805         }
806
807         fprintf(stderr, "Error '%s': Unknown command\n", argv[0]);
808         return -EINVAL;
809 }