be8ba23df9bb4bc8fec3354f3b19ebd2c5a8a3a3
[project/ubus.git] / cli.c
1 #include <unistd.h>
2
3 #include <libubox/blobmsg_json.h>
4 #include "libubus.h"
5
6 static struct blob_buf b;
7 static int timeout = 30;
8
9 static const char *format_type(void *priv, struct blob_attr *attr)
10 {
11         static const char * const attr_types[] = {
12                 [BLOBMSG_TYPE_INT8] = "\"Boolean\"",
13                 [BLOBMSG_TYPE_INT32] = "\"Integer\"",
14                 [BLOBMSG_TYPE_STRING] = "\"String\"",
15         };
16         const char *type = NULL;
17         int typeid;
18
19         if (blob_id(attr) != BLOBMSG_TYPE_INT32)
20                 return NULL;
21
22         typeid = blobmsg_get_u32(attr);
23         if (typeid < ARRAY_SIZE(attr_types))
24                 type = attr_types[typeid];
25         if (!type)
26                 type = "\"(unknown)\"";
27
28         return type;
29 }
30
31 static void receive_list_result(struct ubus_context *ctx, struct ubus_object_data *obj, void *priv)
32 {
33         struct blob_attr *cur;
34         char *s;
35         int rem;
36
37         printf("'%s' @%08x\n", obj->path, obj->id);
38
39         if (!obj->signature)
40                 return;
41
42         blob_for_each_attr(cur, obj->signature, rem) {
43                 s = blobmsg_format_json_with_cb(cur, false, format_type, NULL);
44                 printf("\t%s\n", s);
45                 free(s);
46         }
47 }
48
49 static void receive_call_result_data(struct ubus_request *req, int type, struct blob_attr *msg)
50 {
51         char *str;
52         if (!msg)
53                 return;
54
55         str = blobmsg_format_json(msg, true);
56         printf("%s\n", str);
57         free(str);
58 }
59
60 static void receive_event(struct ubus_context *ctx, struct ubus_event_handler *ev,
61                           const char *type, struct blob_attr *msg)
62 {
63         char *str;
64
65         str = blobmsg_format_json(msg, true);
66         printf("\"%s\": %s\n", type, str);
67         free(str);
68 }
69
70 static int ubus_cli_list(struct ubus_context *ctx, int argc, char **argv)
71 {
72         const char *path = NULL;
73
74         if (argc > 1)
75                 return -2;
76
77         if (argc == 1)
78                 path = argv[0];
79
80         return ubus_lookup(ctx, path, receive_list_result, NULL);
81 }
82
83 static int ubus_cli_call(struct ubus_context *ctx, int argc, char **argv)
84 {
85         uint32_t id;
86         int ret;
87
88         if (argc < 2 || argc > 3)
89                 return -2;
90
91         blob_buf_init(&b, 0);
92         if (argc == 3 && !blobmsg_add_json_from_string(&b, argv[2])) {
93                 fprintf(stderr, "Failed to parse message data\n");
94                 return -1;
95         }
96
97         ret = ubus_lookup_id(ctx, argv[0], &id);
98         if (ret)
99                 return ret;
100
101         return ubus_invoke(ctx, id, argv[1], b.head, receive_call_result_data, NULL, timeout * 1000);
102 }
103
104 static int ubus_cli_listen(struct ubus_context *ctx, int argc, char **argv)
105 {
106         static struct ubus_event_handler listener;
107         const char *event;
108         int ret = 0;
109
110         memset(&listener, 0, sizeof(listener));
111         listener.cb = receive_event;
112
113         if (argc > 0) {
114                 event = argv[0];
115         } else {
116                 event = "*";
117                 argc = 1;
118         }
119
120         do {
121                 ret = ubus_register_event_handler(ctx, &listener, event);
122                 if (ret)
123                         break;
124
125                 argv++;
126                 argc--;
127                 if (argc <= 0)
128                         break;
129
130                 event = argv[0];
131         } while (1);
132
133         if (ret) {
134                 fprintf(stderr, "Error while registering for event '%s': %s\n",
135                         event, ubus_strerror(ret));
136                 return -1;
137         }
138
139         uloop_init();
140         ubus_add_uloop(ctx);
141         uloop_run();
142         uloop_done();
143
144         return 0;
145 }
146
147 static int ubus_cli_send(struct ubus_context *ctx, int argc, char **argv)
148 {
149         if (argc < 1 || argc > 2)
150                 return -2;
151
152         blob_buf_init(&b, 0);
153
154         if (argc == 2 && !blobmsg_add_json_from_string(&b, argv[1])) {
155                 fprintf(stderr, "Failed to parse message data\n");
156                 return -1;
157         }
158
159         return ubus_send_event(ctx, argv[0], b.head);
160 }
161
162 static int usage(const char *prog)
163 {
164         fprintf(stderr,
165                 "Usage: %s [<options>] <command> [arguments...]\n"
166                 "Options:\n"
167                 " -s <socket>:          Set the unix domain socket to connect to\n"
168                 "\n"
169                 "Commands:\n"
170                 " - list [<path>]                       List objects\n"
171                 " - call <path> <method> [<message>]    Call an object method\n"
172                 " - listen [<path>...]                  Listen for events\n"
173                 " - send <type> [<message>]             Send an event\n"
174                 "\n", prog);
175         return 1;
176 }
177
178
179 struct {
180         const char *name;
181         int (*cb)(struct ubus_context *ctx, int argc, char **argv);
182 } commands[] = {
183         { "list", ubus_cli_list },
184         { "call", ubus_cli_call },
185         { "listen", ubus_cli_listen },
186         { "send", ubus_cli_send },
187 };
188
189 int main(int argc, char **argv)
190 {
191         const char *progname, *ubus_socket = NULL;
192         static struct ubus_context *ctx;
193         char *cmd;
194         int ret = 0;
195         int i, ch;
196
197         progname = argv[0];
198
199         while ((ch = getopt(argc, argv, "s:t:")) != -1) {
200                 switch (ch) {
201                 case 's':
202                         ubus_socket = optarg;
203                         break;
204                 case 't':
205                         timeout = atoi(optarg);
206                         break;
207                 default:
208                         return usage(progname);
209                 }
210         }
211
212         argc -= optind;
213         argv += optind;
214
215         cmd = argv[0];
216         if (argc < 1)
217                 return usage(progname);
218
219         ctx = ubus_connect(ubus_socket);
220         if (!ctx) {
221                 fprintf(stderr, "Failed to connect to ubus\n");
222                 return -1;
223         }
224
225         argv++;
226         argc--;
227
228         ret = -2;
229         for (i = 0; i < ARRAY_SIZE(commands); i++) {
230                 if (strcmp(commands[i].name, cmd) != 0)
231                         continue;
232
233                 ret = commands[i].cb(ctx, argc, argv);
234                 break;
235         }
236
237         if (ret > 0)
238                 fprintf(stderr, "Command failed: %s\n", ubus_strerror(ret));
239         else if (ret == -2)
240                 usage(progname);
241
242         ubus_free(ctx);
243         return ret;
244 }