client: Use D-Bus helpers for Technology Scan 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 void scan_return(DBusMessageIter *iter, const char *error,
248                 void *user_data)
249 {
250         char *path = user_data;
251
252         if (error == NULL) {
253                 char *str = strrchr(path, '/');
254                 str++;
255                 fprintf(stdout, "Scan completed for %s\n", str);
256         } else
257                 fprintf(stderr, "Error %s: %s", path, error);
258
259         g_free(user_data);
260 }
261
262 static int cmd_scan(char *args[], int num, struct option *options)
263 {
264         char *path;
265
266         if (num > 2)
267                 return -E2BIG;
268
269         if (num < 2)
270                 return -EINVAL;
271
272         path = g_strdup_printf("/net/connman/technology/%s", args[1]);
273         return __connmanctl_dbus_method_call(connection, path,
274                         "net.connman.Technology", "Scan",
275                         scan_return, path, DBUS_TYPE_INVALID);
276 }
277
278 static void connect_return(DBusMessageIter *iter, const char *error,
279                 void *user_data)
280 {
281         char *path = user_data;
282
283         if (error == NULL) {
284                 char *str = strrchr(path, '/');
285                 str++;
286                 fprintf(stdout, "Connected %s\n", str);
287         } else
288                 fprintf(stderr, "Error %s: %s\n", path, error);
289
290         g_free(user_data);
291 }
292
293 static int cmd_connect(char *args[], int num, struct option *options)
294 {
295         char *path;
296
297         if (num > 2)
298                 return -E2BIG;
299
300         if (num < 2)
301                 return -EINVAL;
302
303         path = g_strdup_printf("/net/connman/service/%s", args[1]);
304         return __connmanctl_dbus_method_call(connection, path,
305                         "net.connman.Service", "Connect",
306                         connect_return, path, DBUS_TYPE_INVALID);
307 }
308
309 static void disconnect_return(DBusMessageIter *iter, const char *error,
310                 void *user_data)
311 {
312         char *path = user_data;
313
314         if (error == NULL) {
315                 char *str = strrchr(path, '/');
316                 str++;
317                 fprintf(stdout, "Disconnected %s\n", str);
318         } else
319                 fprintf(stderr, "Error %s: %s\n", path, error);
320
321         g_free(user_data);
322 }
323
324 static int cmd_disconnect(char *args[], int num, struct option *options)
325 {
326         char *path;
327
328         if (num > 2)
329                 return -E2BIG;
330
331         if (num < 2)
332                 return -EINVAL;
333
334         path = g_strdup_printf("/net/connman/service/%s", args[1]);
335         return __connmanctl_dbus_method_call(connection, path,
336                         "net.connman.Service", "Disconnect",
337                         disconnect_return, path, DBUS_TYPE_INVALID);
338
339         return 0;
340 }
341
342 static int cmd_config(char *args[], int num, struct option *options)
343 {
344         int res = 0, index = 2, oldindex = 0;
345         int c;
346         char *service_name;
347         DBusMessage *message;
348         char **opt_start;
349         dbus_bool_t val;
350
351         service_name = args[1];
352         if (service_name == NULL)
353                 return -EINVAL;
354
355         while (index < num && args[index] != NULL) {
356                 c = parse_args(args[index], options);
357                 opt_start = &args[index + 1];
358                 res = 0;
359
360                 message = get_message(connection, "GetServices");
361                 if (message == NULL)
362                         return -ENOMEM;
363
364                 oldindex = index;
365
366                 switch (c) {
367                 case 'a':
368                         switch (parse_boolean(*opt_start)) {
369                         case 1:
370                                 val = TRUE;
371                                 break;
372                         case 0:
373                                 val = FALSE;
374                                 break;
375                         default:
376                                 res = -EINVAL;
377                                 break;
378                         }
379                         if (res == 0)
380                                 res = set_service_property(connection, message,
381                                                 service_name, "AutoConnect",
382                                                 NULL, &val, 0);
383                         break;
384                 case 'i':
385                         res = set_service_property(connection, message,
386                                         service_name, "IPv4.Configuration",
387                                         ipv4, opt_start, 0);
388                         if (res < 0)
389                                 index += 4;
390                         break;
391                 case 'v':
392                         res = set_service_property(connection, message,
393                                         service_name, "IPv6.Configuration",
394                                         ipv6, opt_start, 0);
395                         if (res < 0)
396                                 index += 5;
397                         break;
398                 case 'n':
399                         res = set_service_property(connection, message,
400                                         service_name,
401                                         "Nameservers.Configuration",
402                                         NULL, opt_start, 0);
403                         break;
404                 case 't':
405                         res = set_service_property(connection, message,
406                                         service_name,
407                                         "Timeservers.Configuration",
408                                         NULL, opt_start, 0);
409                         break;
410                 case 'd':
411                         res = set_service_property(connection, message,
412                                         service_name,
413                                         "Domains.Configuration",
414                                         NULL, opt_start, 0);
415                         break;
416                 case 'x':
417                         if (*opt_start == NULL) {
418                                 res = -EINVAL;
419                                 break;
420                         }
421
422                         if (strcmp(*opt_start, "direct") == 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, "auto") == 0) {
431                                 res = set_service_property(connection, message,
432                                                 service_name,
433                                                 "Proxy.Configuration",
434                                                 proxy_simple, opt_start, 1);
435                                 break;
436                         }
437
438                         if (strcmp(*opt_start, "manual") == 0) {
439                                         char **url_start = &args[index + 2];
440
441                                         if (*url_start != NULL &&
442                                                 strcmp(*url_start,
443                                                         "servers") == 0) {
444                                                 url_start = &args[index + 3];
445                                                 index++;
446                                         }
447                                         res = store_proxy_input(connection,
448                                                         message, service_name,
449                                                         0, url_start);
450                         }
451
452                         break;
453                 case 'r':
454                         res = remove_service(connection, message, service_name);
455                         break;
456                 default:
457                         res = -EINVAL;
458                         break;
459                 }
460
461                 dbus_message_unref(message);
462
463                 if (res < 0) {
464                         printf("Error '%s': %s\n", args[oldindex],
465                                         strerror(-res));
466                 } else
467                         index += res;
468
469                 index++;
470         }
471
472         return 0;
473 }
474
475 static DBusHandlerResult monitor_changed(DBusConnection *connection,
476                 DBusMessage *message, void *user_data)
477 {
478         DBusMessageIter iter;
479         const char *interface, *path;
480
481         interface = dbus_message_get_interface(message);
482         if (strncmp(interface, "net.connman.", 12) != 0)
483                 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
484
485         interface = strrchr(interface, '.');
486         if (interface != NULL && *interface != '\0')
487                 interface++;
488
489         path = strrchr(dbus_message_get_path(message), '/');
490         if (path != NULL && *path != '\0')
491                 path++;
492
493         __connmanctl_save_rl();
494
495         if (dbus_message_is_signal(message, "net.connman.Manager",
496                                         "ServicesChanged") == TRUE) {
497
498                 fprintf(stdout, "%-12s %-20s = {\n", interface,
499                                 "ServicesChanged");
500                 dbus_message_iter_init(message, &iter);
501                 __connmanctl_services_list(&iter);
502                 fprintf(stdout, "\n}\n");
503
504                 __connmanctl_redraw_rl();
505
506                 return DBUS_HANDLER_RESULT_HANDLED;
507         }
508
509         if (dbus_message_is_signal(message, "net.connman.Manager",
510                                         "TechnologyAdded") == TRUE)
511                 path = "TechnologyAdded";
512
513         if (dbus_message_is_signal(message, "net.connman.Manager",
514                                         "TechnologyRemoved") == TRUE)
515                 path = "TechnologyRemoved";
516
517         fprintf(stdout, "%-12s %-20s ", interface, path);
518         dbus_message_iter_init(message, &iter);
519
520         __connmanctl_dbus_print(&iter, "", " = ", " = ");
521         fprintf(stdout, "\n");
522
523         __connmanctl_redraw_rl();
524
525         return DBUS_HANDLER_RESULT_HANDLED;
526 }
527
528 static bool monitor_s = false;
529 static bool monitor_t = false;
530 static bool monitor_m = false;
531
532 static void monitor_add(char *interface)
533 {
534         char *rule;
535         DBusError err;
536
537         if (monitor_s == false && monitor_t == false && monitor_m == false)
538                 dbus_connection_add_filter(connection, monitor_changed,
539                                 NULL, NULL);
540
541         if (g_strcmp0(interface, "Service") == 0) {
542                 if (monitor_s == true)
543                         return;
544                 monitor_s = true;
545         } else if (g_strcmp0(interface, "Technology") == 0) {
546                 if (monitor_t == true)
547                         return;
548                 monitor_t = true;
549         } else if (g_strcmp0(interface, "Manager") == 0) {
550                 if (monitor_m == true)
551                         return;
552                 monitor_m = true;
553         } else
554                 return;
555
556         dbus_error_init(&err);
557         rule  = g_strdup_printf("type='signal',interface='net.connman.%s'",
558                         interface);
559         dbus_bus_add_match(connection, rule, &err);
560         g_free(rule);
561
562         if (dbus_error_is_set(&err))
563                 fprintf(stderr, "Error: %s\n", err.message);
564 }
565
566 static void monitor_del(char *interface)
567 {
568         char *rule;
569
570         if (g_strcmp0(interface, "Service") == 0) {
571                 if (monitor_s == false)
572                         return;
573                 monitor_s = false;
574         } else if (g_strcmp0(interface, "Technology") == 0) {
575                 if (monitor_t == false)
576                         return;
577                 monitor_t = false;
578         } else if (g_strcmp0(interface, "Manager") == 0) {
579                 if (monitor_m == false)
580                         return;
581                 monitor_m = false;
582         } else
583                 return;
584
585         rule  = g_strdup_printf("type='signal',interface='net.connman.%s'",
586                         interface);
587         dbus_bus_remove_match(connection, rule, NULL);
588         g_free(rule);
589
590         if (monitor_s == false && monitor_t == false && monitor_m == false)
591                 dbus_connection_remove_filter(connection, monitor_changed,
592                                 NULL);
593 }
594
595 static int cmd_monitor(char *args[], int num, struct option *options)
596 {
597         bool add = true;
598         int c;
599
600         if (num > 3)
601                 return -E2BIG;
602
603         if (num == 3) {
604                 switch (parse_boolean(args[2])) {
605                 case 0:
606                         add = false;
607                         break;
608
609                 default:
610                         break;
611                 }
612         }
613
614         c = parse_args(args[1], options);
615         switch (c) {
616         case -1:
617                 monitor_add("Service");
618                 monitor_add("Technology");
619                 monitor_add("Manager");
620                 break;
621
622         case 's':
623                 if (add == true)
624                         monitor_add("Service");
625                 else
626                         monitor_del("Service");
627                 break;
628
629         case 'c':
630                 if (add == true)
631                         monitor_add("Technology");
632                 else
633                         monitor_del("Technology");
634                 break;
635
636         case 'm':
637                 if (add == true)
638                         monitor_add("Manager");
639                 else
640                         monitor_del("Manager");
641                 break;
642
643         default:
644                 switch(parse_boolean(args[1])) {
645                 case 0:
646                         monitor_del("Service");
647                         monitor_del("Technology");
648                         monitor_del("Manager");
649                         break;
650
651                 case 1:
652                         monitor_add("Service");
653                         monitor_add("Technology");
654                         monitor_add("Manager");
655                         break;
656
657                 default:
658                         return -EINVAL;
659                 }
660         }
661
662         if (add == true)
663                 return -EINPROGRESS;
664
665         return 0;
666 }
667
668 static int cmd_exit(char *args[], int num, struct option *options)
669 {
670         return 1;
671 }
672
673 static struct option service_options[] = {
674         {"properties", required_argument, 0, 'p'},
675         { NULL, }
676 };
677
678 static const char *service_desc[] = {
679         "[<service>]      (obsolete)",
680         NULL
681 };
682
683 static struct option config_options[] = {
684         {"nameservers", required_argument, 0, 'n'},
685         {"timeservers", required_argument, 0, 't'},
686         {"domains", required_argument, 0, 'd'},
687         {"ipv6", required_argument, 0, 'v'},
688         {"proxy", required_argument, 0, 'x'},
689         {"autoconnect", required_argument, 0, 'a'},
690         {"ipv4", required_argument, 0, 'i'},
691         {"remove", 0, 0, 'r'},
692         { NULL, }
693 };
694
695 static const char *config_desc[] = {
696         "<dns1> [<dns2>] [<dns3>]",
697         "<ntp1> [<ntp2>] [...]",
698         "<domain1> [<domain2>] [...]",
699         "off|auto|manual <address> <prefixlength> <gateway> <privacy>",
700         "direct|auto <URL>|manual <URL1> [<URL2>] [...]\n"
701         "                   [exclude <exclude1> [<exclude2>] [...]]",
702         "yes|no",
703         "off|dhcp|manual <address> <prefixlength> <gateway>",
704         "                 Remove service",
705         NULL
706 };
707
708 static struct option monitor_options[] = {
709         {"services", no_argument, 0, 's'},
710         {"tech", no_argument, 0, 'c'},
711         {"manager", no_argument, 0, 'm'},
712         { NULL, }
713 };
714
715 static const char *monitor_desc[] = {
716         "[off]            Monitor only services",
717         "[off]            Monitor only technologies",
718         "[off]            Monitor only manager interface",
719         NULL
720 };
721
722 static const struct {
723         const char *cmd;
724         const char *argument;
725         struct option *options;
726         const char **options_desc;
727         int (*func) (char *args[], int num, struct option *options);
728         const char *desc;
729 } cmd_table[] = {
730         { "enable",       "<technology>|offline", NULL,    NULL,
731           cmd_enable, "Enables given technology or offline mode" },
732         { "disable",      "<technology>|offline", NULL,    NULL,
733           cmd_disable, "Disables given technology or offline mode"},
734         { "state",        NULL,           NULL,            NULL,
735           cmd_state, "Shows if the system is online or offline" },
736         { "services",     "[<service>]",  service_options, &service_desc[0],
737           cmd_services, "Display services" },
738         { "technologies", NULL,           NULL,            NULL,
739           cmd_technologies, "Display technologies" },
740         { "scan",         "<technology>", NULL,            NULL,
741           cmd_scan, "Scans for new services for given technology" },
742         { "connect",      "<service>",    NULL,            NULL,
743           cmd_connect, "Connect a given service" },
744         { "disconnect",   "<service>",    NULL,            NULL,
745           cmd_disconnect, "Disconnect a given service" },
746         { "config",       "<service>",    config_options,  &config_desc[0],
747           cmd_config, "Set service configuration options" },
748         { "monitor",      "[off]",        monitor_options, &monitor_desc[0],
749           cmd_monitor, "Monitor signals from interfaces" },
750         { "help",         NULL,           NULL,            NULL,
751           cmd_help, "Show help" },
752         { "exit",         NULL,           NULL,            NULL,
753           cmd_exit,       "Exit" },
754         { "quit",         NULL,           NULL,            NULL,
755           cmd_exit,       "Quit" },
756         {  NULL, },
757 };
758
759 static int cmd_help(char *args[], int num, struct option *options)
760 {
761         bool interactive = __connmanctl_is_interactive();
762         int i, j;
763
764         if (interactive == false)
765                 fprintf(stdout, "Usage: connmanctl [[command] [args]]\n");
766
767         for (i = 0; cmd_table[i].cmd != NULL; i++) {
768                 const char *cmd = cmd_table[i].cmd;
769                 const char *argument = cmd_table[i].argument;
770                 const char *desc = cmd_table[i].desc;
771
772                 printf("%-12s%-22s%s\n", cmd != NULL? cmd: "",
773                                 argument != NULL? argument: "",
774                                 desc != NULL? desc: "");
775
776                 if (cmd_table[i].options != NULL) {
777                         for (j = 0; cmd_table[i].options[j].name != NULL;
778                              j++) {
779                                 const char *options_desc =
780                                         cmd_table[i].options_desc != NULL ?
781                                         cmd_table[i].options_desc[j]: "";
782
783                                 printf("   --%-12s%s\n",
784                                                 cmd_table[i].options[j].name,
785                                                 options_desc);
786                         }
787                 }
788         }
789
790         if (interactive == false)
791                 fprintf(stdout, "\nNote: arguments and output are considered "
792                                 "EXPERIMENTAL for now.\n");
793
794         return 0;
795 }
796
797 int commands(DBusConnection *dbus_conn, char *argv[], int argc)
798 {
799         int i, result;
800
801         connection = dbus_conn;
802
803         for (i = 0; cmd_table[i].cmd != NULL; i++) {
804                 if (g_strcmp0(cmd_table[i].cmd, argv[0]) == 0 &&
805                                 cmd_table[i].func != NULL) {
806                         result = cmd_table[i].func(argv, argc,
807                                         cmd_table[i].options);
808                         if (result < 0 && result != -EINPROGRESS)
809                                 fprintf(stderr, "Error '%s': %s\n", argv[0],
810                                                 strerror(-result));
811                         return result;
812                 }
813         }
814
815         fprintf(stderr, "Error '%s': Unknown command\n", argv[0]);
816         return -EINVAL;
817 }