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