use int8 as boolean
[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 }