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