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