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