luci2: implement process_list call
[project/rpcd.git] / luci2.c
1 /*
2  * luci-rpcd - LuCI UBUS RPC server
3  *
4  *   Copyright (C) 2013 Jo-Philipp Wich <jow@openwrt.org>
5  *
6  * Permission to use, copy, modify, and/or distribute this software for any
7  * purpose with or without fee is hereby granted, provided that the above
8  * copyright notice and this permission notice appear in all copies.
9  *
10  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17  */
18
19 #include <fcntl.h>
20 #include <errno.h>
21 #include <unistd.h>
22 #include <stdlib.h>
23 #include <string.h>
24 #include <sys/stat.h>
25 #include <arpa/inet.h>
26
27 #include "luci2.h"
28
29 static struct blob_buf buf;
30 static struct uci_context *cursor;
31
32
33 static int
34 rpc_errno_status(void)
35 {
36         switch (errno)
37         {
38         case EACCES:
39                 return UBUS_STATUS_PERMISSION_DENIED;
40
41         case ENOTDIR:
42                 return UBUS_STATUS_INVALID_ARGUMENT;
43
44         case ENOENT:
45                 return UBUS_STATUS_NOT_FOUND;
46
47         case EINVAL:
48                 return UBUS_STATUS_INVALID_ARGUMENT;
49
50         default:
51                 return UBUS_STATUS_UNKNOWN_ERROR;
52         }
53 }
54
55 static void
56 log_read(FILE *log, int logsize)
57 {
58         int len;
59         char *logbuf;
60
61         if (logsize == 0)
62                 logsize = RPC_LUCI2_DEF_LOGSIZE;
63
64         len = (logsize > RPC_LUCI2_MAX_LOGSIZE) ? RPC_LUCI2_MAX_LOGSIZE : logsize;
65         logbuf = blobmsg_alloc_string_buffer(&buf, "log", len + 1);
66
67         if (!logbuf)
68                 return;
69
70         while (logsize > RPC_LUCI2_MAX_LOGSIZE)
71         {
72                 len = logsize % RPC_LUCI2_MAX_LOGSIZE;
73
74                 if (len == 0)
75                         len = RPC_LUCI2_MAX_LOGSIZE;
76
77                 fread(logbuf, 1, len, log);
78                 logsize -= len;
79         }
80
81         len = fread(logbuf, 1, logsize, log);
82         *(logbuf + len) = 0;
83
84         blobmsg_add_string_buffer(&buf);
85 }
86
87 static int
88 rpc_luci2_system_log(struct ubus_context *ctx, struct ubus_object *obj,
89                      struct ubus_request_data *req, const char *method,
90                      struct blob_attr *msg)
91 {
92         FILE *log;
93         int logsize = 0;
94         const char *logfile = NULL;
95         struct stat st;
96         struct uci_package *p;
97         struct uci_element *e;
98         struct uci_section *s;
99         struct uci_ptr ptr = { .package = "system" };
100
101         uci_load(cursor, ptr.package, &p);
102
103         if (!p)
104                 return UBUS_STATUS_NOT_FOUND;
105
106         uci_foreach_element(&p->sections, e)
107         {
108                 s = uci_to_section(e);
109
110                 if (strcmp(s->type, "system"))
111                         continue;
112
113                 ptr.o = NULL;
114                 ptr.option = "log_type";
115                 ptr.section = e->name;
116                 uci_lookup_ptr(cursor, &ptr, NULL, true);
117                 break;
118         }
119
120         if (ptr.o && ptr.o->type == UCI_TYPE_STRING &&
121             !strcmp(ptr.o->v.string, "file"))
122         {
123                 ptr.o = NULL;
124                 ptr.option = "log_file";
125                 uci_lookup_ptr(cursor, &ptr, NULL, true);
126
127                 if (ptr.o && ptr.o->type == UCI_TYPE_STRING)
128                         logfile = ptr.o->v.string;
129                 else
130                         logfile = "/var/log/messages";
131
132                 if (stat(logfile, &st) || !(log = fopen(logfile, "r")))
133                         goto fail;
134
135                 logsize = st.st_size;
136         }
137         else
138         {
139                 ptr.o = NULL;
140                 ptr.option = "log_size";
141                 uci_lookup_ptr(cursor, &ptr, NULL, true);
142
143                 if (ptr.o && ptr.o->type == UCI_TYPE_STRING)
144                         logsize = atoi(ptr.o->v.string) * 1024;
145
146                 if (!(log = popen("logread", "r")))
147                         goto fail;
148         }
149
150         blob_buf_init(&buf, 0);
151
152         log_read(log, logsize);
153         fclose(log);
154
155         uci_unload(cursor, p);
156         ubus_send_reply(ctx, req, buf.head);
157         return 0;
158
159 fail:
160         uci_unload(cursor, p);
161         return rpc_errno_status();
162 }
163
164 static int
165 rpc_luci2_system_dmesg(struct ubus_context *ctx, struct ubus_object *obj,
166                        struct ubus_request_data *req, const char *method,
167                        struct blob_attr *msg)
168 {
169         FILE *log;
170
171         if (!(log = popen("dmesg", "r")))
172                 return rpc_errno_status();
173
174         blob_buf_init(&buf, 0);
175
176         log_read(log, RPC_LUCI2_MAX_LOGSIZE);
177         fclose(log);
178
179         ubus_send_reply(ctx, req, buf.head);
180         return 0;
181 }
182
183 static int
184 rpc_luci2_process_list(struct ubus_context *ctx, struct ubus_object *obj,
185                        struct ubus_request_data *req, const char *method,
186                        struct blob_attr *msg)
187 {
188         FILE *top;
189         void *c, *d;
190         char line[1024];
191         char *pid, *ppid, *user, *stat, *vsz, *pvsz, *pcpu, *cmd;
192
193         if (!(top = popen("/bin/busybox top -bn1", "r")))
194                 return rpc_errno_status();
195
196         blob_buf_init(&buf, 0);
197         c = blobmsg_open_array(&buf, "processes");
198
199         while (fgets(line, sizeof(line) - 1, top))
200         {
201                 pid  = strtok(line, " ");
202
203                 if (*pid < '0' || *pid > '9')
204                         continue;
205
206                 ppid = strtok(NULL, " ");
207                 user = strtok(NULL, " ");
208                 stat = strtok(NULL, " ");
209
210                 if (!stat)
211                         continue;
212
213                 if (!*(stat + 1))
214                         *(stat + 1) = ' ';
215
216                 if (!*(stat + 2))
217                         *(stat + 2) = ' ';
218
219                 *(stat + 3) = 0;
220
221                 vsz  = strtok(stat + 4, " ");
222                 pvsz = strtok(NULL, " ");
223                 pcpu = strtok(NULL, " ");
224                 cmd  = strtok(NULL, "\n");
225
226                 if (!cmd)
227                         continue;
228
229                 d = blobmsg_open_table(&buf, NULL);
230
231                 blobmsg_add_u32(&buf, "pid", atoi(pid));
232                 blobmsg_add_u32(&buf, "ppid", atoi(ppid));
233                 blobmsg_add_string(&buf, "user", user);
234                 blobmsg_add_string(&buf, "stat", stat);
235                 blobmsg_add_u32(&buf, "vsize", atoi(vsz) * 1024);
236                 blobmsg_add_u32(&buf, "vsize_percent", atoi(pvsz));
237                 blobmsg_add_u32(&buf, "cpu_percent", atoi(pcpu));
238                 blobmsg_add_string(&buf, "command", cmd);
239
240                 blobmsg_close_table(&buf, d);
241         }
242
243         fclose(top);
244         blobmsg_close_array(&buf, c);
245
246         ubus_send_reply(ctx, req, buf.head);
247         return 0;
248 }
249
250
251 static FILE *
252 dnsmasq_leasefile(void)
253 {
254         FILE *leases = NULL;
255         struct uci_package *p;
256         struct uci_element *e;
257         struct uci_section *s;
258         struct uci_ptr ptr = {
259                 .package = "dhcp",
260                 .section = NULL,
261                 .option  = "leasefile"
262         };
263
264         uci_load(cursor, ptr.package, &p);
265
266         if (!p)
267                 return NULL;
268
269         uci_foreach_element(&p->sections, e)
270         {
271                 s = uci_to_section(e);
272
273                 if (strcmp(s->type, "dnsmasq"))
274                         continue;
275
276                 ptr.section = e->name;
277                 uci_lookup_ptr(cursor, &ptr, NULL, true);
278                 break;
279         }
280
281         if (ptr.o && ptr.o->type == UCI_TYPE_STRING)
282                 leases = fopen(ptr.o->v.string, "r");
283
284         uci_unload(cursor, p);
285
286         return leases;
287 }
288
289 static int
290 rpc_luci2_network_leases(struct ubus_context *ctx, struct ubus_object *obj,
291                          struct ubus_request_data *req, const char *method,
292                          struct blob_attr *msg)
293 {
294         FILE *leases;
295         void *c, *d;
296         char line[128];
297         char *ts, *mac, *addr, *name;
298         time_t now = time(NULL);
299
300         blob_buf_init(&buf, 0);
301         c = blobmsg_open_array(&buf, "leases");
302
303         leases = dnsmasq_leasefile();
304
305         if (!leases)
306                 goto out;
307
308         while (fgets(line, sizeof(line) - 1, leases))
309         {
310                 ts   = strtok(line, " \t");
311                 mac  = strtok(NULL, " \t");
312                 addr = strtok(NULL, " \t");
313                 name = strtok(NULL, " \t");
314
315                 if (!ts || !mac || !addr || !name)
316                         continue;
317
318                 if (strchr(addr, ':'))
319                         continue;
320
321                 d = blobmsg_open_table(&buf, NULL);
322
323                 blobmsg_add_u32(&buf, "expires", atoi(ts) - now);
324                 blobmsg_add_string(&buf, "macaddr", mac);
325                 blobmsg_add_string(&buf, "ipaddr", addr);
326
327                 if (strcmp(name, "*"))
328                         blobmsg_add_string(&buf, "hostname", name);
329
330                 blobmsg_close_table(&buf, d);
331         }
332
333         fclose(leases);
334
335 out:
336         blobmsg_close_array(&buf, c);
337         ubus_send_reply(ctx, req, buf.head);
338
339         return 0;
340 }
341
342 static int
343 rpc_luci2_network_leases6(struct ubus_context *ctx, struct ubus_object *obj,
344                           struct ubus_request_data *req, const char *method,
345                           struct blob_attr *msg)
346 {
347         FILE *leases;
348         void *c, *d;
349         char line[128];
350         char *ts, *mac, *addr, *name, *duid;
351         time_t now = time(NULL);
352
353         blob_buf_init(&buf, 0);
354         c = blobmsg_open_array(&buf, "leases");
355
356         leases = fopen("/tmp/hosts/6relayd", "r");
357
358         if (leases)
359         {
360                 while (fgets(line, sizeof(line) - 1, leases))
361                 {
362                         if (strncmp(line, "# ", 2))
363                                 continue;
364
365                         strtok(line + 2, " \t"); /* iface */
366
367                         duid = strtok(NULL, " \t");
368
369                         strtok(NULL, " \t"); /* iaid */
370
371                         name = strtok(NULL, " \t");
372                         ts   = strtok(NULL, " \t");
373
374                         strtok(NULL, " \t"); /* id */
375                         strtok(NULL, " \t"); /* length */
376
377                         addr = strtok(NULL, " \t\n");
378
379                         if (!addr)
380                                 continue;
381
382                         d = blobmsg_open_table(&buf, NULL);
383
384                         blobmsg_add_u32(&buf, "expires", atoi(ts) - now);
385                         blobmsg_add_string(&buf, "duid", duid);
386                         blobmsg_add_string(&buf, "ip6addr", addr);
387
388                         if (strcmp(name, "-"))
389                                 blobmsg_add_string(&buf, "hostname", name);
390
391                         blobmsg_close_array(&buf, d);
392                 }
393
394                 fclose(leases);
395         }
396         else
397         {
398                 leases = dnsmasq_leasefile();
399
400                 if (!leases)
401                         goto out;
402
403                 while (fgets(line, sizeof(line) - 1, leases))
404                 {
405                         ts   = strtok(line, " \t");
406                         mac  = strtok(NULL, " \t");
407                         addr = strtok(NULL, " \t");
408                         name = strtok(NULL, " \t");
409                         duid = strtok(NULL, " \t\n");
410
411                         if (!ts || !mac || !addr || !duid)
412                                 continue;
413
414                         if (!strchr(addr, ':'))
415                                 continue;
416
417                         d = blobmsg_open_table(&buf, NULL);
418
419                         blobmsg_add_u32(&buf, "expires", atoi(ts) - now);
420                         blobmsg_add_string(&buf, "macaddr", mac);
421                         blobmsg_add_string(&buf, "ip6addr", addr);
422
423                         if (strcmp(name, "*"))
424                                 blobmsg_add_string(&buf, "hostname", name);
425
426                         if (strcmp(duid, "*"))
427                                 blobmsg_add_string(&buf, "duid", name);
428
429                         blobmsg_close_table(&buf, d);
430                 }
431
432                 fclose(leases);
433         }
434
435 out:
436         blobmsg_close_array(&buf, c);
437         ubus_send_reply(ctx, req, buf.head);
438
439         return 0;
440 }
441
442 static int
443 rpc_luci2_network_ct_count(struct ubus_context *ctx, struct ubus_object *obj,
444                            struct ubus_request_data *req, const char *method,
445                            struct blob_attr *msg)
446 {
447         FILE *f;
448         char line[128];
449
450         blob_buf_init(&buf, 0);
451
452         if ((f = fopen("/proc/sys/net/netfilter/nf_conntrack_count", "r")) != NULL)
453         {
454                 if (fgets(line, sizeof(line) - 1, f))
455                         blobmsg_add_u32(&buf, "count", atoi(line));
456
457                 fclose(f);
458         }
459
460         if ((f = fopen("/proc/sys/net/netfilter/nf_conntrack_max", "r")) != NULL)
461         {
462                 if (fgets(line, sizeof(line) - 1, f))
463                         blobmsg_add_u32(&buf, "limit", atoi(line));
464
465                 fclose(f);
466         }
467
468         ubus_send_reply(ctx, req, buf.head);
469
470         return 0;
471 }
472
473 static int
474 rpc_luci2_network_ct_table(struct ubus_context *ctx, struct ubus_object *obj,
475                            struct ubus_request_data *req, const char *method,
476                            struct blob_attr *msg)
477 {
478         FILE *f;
479         int i;
480         void *c, *d;
481         char *p, line[512];
482         bool seen[6];
483
484         blob_buf_init(&buf, 0);
485         c = blobmsg_open_array(&buf, "entries");
486
487         if ((f = fopen("/proc/net/nf_conntrack", "r")) != NULL)
488         {
489                 while (fgets(line, sizeof(line) - 1, f))
490                 {
491                         d = blobmsg_open_table(&buf, NULL);
492                         memset(seen, 0, sizeof(seen));
493
494                         for (i = 0, p = strtok(line, " "); p; i++, p = strtok(NULL, " "))
495                         {
496                                 if (i == 0)
497                                         blobmsg_add_u8(&buf, "ipv6", !strcmp(p, "ipv6"));
498                                 else if (i == 3)
499                                         blobmsg_add_u32(&buf, "protocol", atoi(p));
500                                 else if (i == 4)
501                                         blobmsg_add_u32(&buf, "expires", atoi(p));
502                                 else if (i >= 5)
503                                 {
504                                         if (*p == '[')
505                                                 continue;
506
507                                         if (!seen[0] && !strncmp(p, "src=", 4))
508                                         {
509                                                 blobmsg_add_string(&buf, "src", p + 4);
510                                                 seen[0] = true;
511                                         }
512                                         else if (!seen[1] && !strncmp(p, "dst=", 4))
513                                         {
514                                                 blobmsg_add_string(&buf, "dest", p + 4);
515                                                 seen[1] = true;
516                                         }
517                                         else if (!seen[2] && !strncmp(p, "sport=", 6))
518                                         {
519                                                 blobmsg_add_u32(&buf, "sport", atoi(p + 6));
520                                                 seen[2] = true;
521                                         }
522                                         else if (!seen[3] && !strncmp(p, "dport=", 6))
523                                         {
524                                                 blobmsg_add_u32(&buf, "dport", atoi(p + 6));
525                                                 seen[3] = true;
526                                         }
527                                         else if (!strncmp(p, "packets=", 8))
528                                         {
529                                                 blobmsg_add_u32(&buf,
530                                                                 seen[4] ? "tx_packets" : "rx_packets",
531                                                                 atoi(p + 8));
532                                                 seen[4] = true;
533                                         }
534                                         else if (!strncmp(p, "bytes=", 6))
535                                         {
536                                                 blobmsg_add_u32(&buf,
537                                                                                 seen[5] ? "tx_bytes" : "rx_bytes",
538                                                                 atoi(p + 6));
539                                                 seen[5] = true;
540                                         }
541                                 }
542                         }
543
544                         blobmsg_close_table(&buf, d);
545                 }
546
547                 fclose(f);
548         }
549
550         blobmsg_close_array(&buf, c);
551         ubus_send_reply(ctx, req, buf.head);
552
553         return 0;
554 }
555
556 static int
557 rpc_luci2_network_arp_table(struct ubus_context *ctx, struct ubus_object *obj,
558                             struct ubus_request_data *req, const char *method,
559                             struct blob_attr *msg)
560 {
561         FILE *f;
562         void *c, *d;
563         char *addr, *mac, *dev, line[128];
564
565         blob_buf_init(&buf, 0);
566         c = blobmsg_open_array(&buf, "entries");
567
568         if ((f = fopen("/proc/net/arp", "r")) != NULL)
569         {
570                 /* skip header line */
571                 fgets(line, sizeof(line) - 1, f);
572
573                 while (fgets(line, sizeof(line) - 1, f))
574                 {
575                         addr = strtok(line, " \t");
576
577                         strtok(NULL, " \t"); /* HW type */
578                         strtok(NULL, " \t"); /* Flags */
579
580                         mac = strtok(NULL, " \t");
581
582                         strtok(NULL, " \t"); /* Mask */
583
584                         dev = strtok(NULL, " \t\n");
585
586                         if (!dev)
587                                 continue;
588
589                         d = blobmsg_open_table(&buf, NULL);
590                         blobmsg_add_string(&buf, "ipaddr", addr);
591                         blobmsg_add_string(&buf, "macaddr", mac);
592                         blobmsg_add_string(&buf, "device", dev);
593                         blobmsg_close_table(&buf, d);
594                 }
595
596                 fclose(f);
597         }
598
599         blobmsg_close_array(&buf, c);
600         ubus_send_reply(ctx, req, buf.head);
601
602         return 0;
603 }
604
605 static void
606 put_hexaddr(const char *name, const char *s, const char *m)
607 {
608         int bits;
609         struct in_addr a;
610         char as[sizeof("255.255.255.255/32\0")];
611
612         a.s_addr = strtoul(s, NULL, 16);
613         inet_ntop(AF_INET, &a, as, sizeof(as));
614
615         if (m)
616         {
617                 for (a.s_addr = ntohl(strtoul(m, NULL, 16)), bits = 0;
618                      a.s_addr & 0x80000000;
619                      a.s_addr <<= 1)
620                         bits++;
621
622                 sprintf(as + strlen(as), "/%u", bits);
623         }
624
625         blobmsg_add_string(&buf, name, as);
626 }
627
628 static int
629 rpc_luci2_network_routes(struct ubus_context *ctx, struct ubus_object *obj,
630                          struct ubus_request_data *req, const char *method,
631                          struct blob_attr *msg)
632 {
633         FILE *routes;
634         void *c, *d;
635         char *dst, *dmask, *next, *metric, *device;
636         char line[256];
637         unsigned int n;
638
639         if (!(routes = fopen("/proc/net/route", "r")))
640                 return rpc_errno_status();
641
642         blob_buf_init(&buf, 0);
643         c = blobmsg_open_array(&buf, "routes");
644
645         /* skip header line */
646         fgets(line, sizeof(line) - 1, routes);
647
648         while (fgets(line, sizeof(line) - 1, routes))
649         {
650                 device = strtok(line, "\t ");
651                 dst    = strtok(NULL, "\t ");
652                 next   = strtok(NULL, "\t ");
653
654                 strtok(NULL, "\t "); /* flags */
655                 strtok(NULL, "\t "); /* refcount */
656                 strtok(NULL, "\t "); /* usecount */
657
658                 metric = strtok(NULL, "\t ");
659                 dmask  = strtok(NULL, "\t ");
660
661                 if (!dmask)
662                         continue;
663
664                 d = blobmsg_open_table(&buf, NULL);
665
666                 put_hexaddr("target", dst, dmask);
667                 put_hexaddr("nexthop", next, NULL);
668
669                 n = strtoul(metric, NULL, 10);
670                 blobmsg_add_u32(&buf, "metric", n);
671
672                 blobmsg_add_string(&buf, "device", device);
673
674                 blobmsg_close_table(&buf, d);
675         }
676
677         blobmsg_close_array(&buf, c);
678         fclose(routes);
679
680         ubus_send_reply(ctx, req, buf.head);
681         return 0;
682 }
683
684 static void
685 put_hex6addr(const char *name, const char *s, const char *m)
686 {
687         int i;
688         struct in6_addr a;
689         char as[INET6_ADDRSTRLEN + sizeof("/128")];
690
691 #define hex(x) \
692         (((x) <= '9') ? ((x) - '0') : \
693                 (((x) <= 'F') ? ((x) - 'A' + 10) : \
694                         ((x) - 'a' + 10)))
695
696         for (i = 0; i < 16; i++, s += 2)
697                 a.s6_addr[i] = (16 * hex(*s)) + hex(*(s+1));
698
699         inet_ntop(AF_INET6, &a, as, sizeof(as));
700
701         if (m)
702                 sprintf(as + strlen(as), "/%lu", strtoul(m, NULL, 16));
703
704         blobmsg_add_string(&buf, name, as);
705 }
706
707 static int
708 rpc_luci2_network_routes6(struct ubus_context *ctx, struct ubus_object *obj,
709                           struct ubus_request_data *req, const char *method,
710                           struct blob_attr *msg)
711 {
712         FILE *routes;
713         void *c, *d;
714         char *src, *smask, *dst, *dmask, *next, *metric, *flags, *device;
715         char line[256];
716         unsigned int n;
717
718         if (!(routes = fopen("/proc/net/ipv6_route", "r")))
719                 return rpc_errno_status();
720
721         blob_buf_init(&buf, 0);
722         c = blobmsg_open_array(&buf, "routes");
723
724         while (fgets(line, sizeof(line) - 1, routes))
725         {
726                 dst    = strtok(line, " ");
727                 dmask  = strtok(NULL, " ");
728                 src    = strtok(NULL, " ");
729                 smask  = strtok(NULL, " ");
730                 next   = strtok(NULL, " ");
731                 metric = strtok(NULL, " ");
732
733                 strtok(NULL, " "); /* refcount */
734                 strtok(NULL, " "); /* usecount */
735
736                 flags  = strtok(NULL, " ");
737                 device = strtok(NULL, " \n");
738
739                 if (!device)
740                         continue;
741
742                 n = strtoul(flags, NULL, 16);
743
744                 if (!(n & 1))
745                         continue;
746
747                 d = blobmsg_open_table(&buf, NULL);
748
749                 put_hex6addr("target", dst, dmask);
750                 put_hex6addr("source", src, smask);
751                 put_hex6addr("nexthop", next, NULL);
752
753                 n = strtoul(metric, NULL, 16);
754                 blobmsg_add_u32(&buf, "metric", n);
755
756                 blobmsg_add_string(&buf, "device", device);
757
758                 blobmsg_close_table(&buf, d);
759         }
760
761         blobmsg_close_array(&buf, c);
762         fclose(routes);
763
764         ubus_send_reply(ctx, req, buf.head);
765         return 0;
766 }
767
768
769 int rpc_luci2_api_init(struct ubus_context *ctx)
770 {
771         int rv = 0;
772
773         static const struct ubus_method luci2_system_methods[] = {
774                 UBUS_METHOD_NOARG("syslog",       rpc_luci2_system_log),
775                 UBUS_METHOD_NOARG("dmesg",        rpc_luci2_system_dmesg),
776                 UBUS_METHOD_NOARG("process_list", rpc_luci2_process_list)
777         };
778
779         static struct ubus_object_type luci2_system_type =
780                 UBUS_OBJECT_TYPE("luci-rpc-luci2-system", luci2_system_methods);
781
782         static struct ubus_object system_obj = {
783                 .name = "luci2.system",
784                 .type = &luci2_system_type,
785                 .methods = luci2_system_methods,
786                 .n_methods = ARRAY_SIZE(luci2_system_methods),
787         };
788
789
790         static const struct ubus_method luci2_network_methods[] = {
791                 UBUS_METHOD_NOARG("conntrack_count", rpc_luci2_network_ct_count),
792                 UBUS_METHOD_NOARG("conntrack_table", rpc_luci2_network_ct_table),
793                 UBUS_METHOD_NOARG("arp_table",       rpc_luci2_network_arp_table),
794                 UBUS_METHOD_NOARG("dhcp_leases",     rpc_luci2_network_leases),
795                 UBUS_METHOD_NOARG("dhcp6_leases",    rpc_luci2_network_leases6),
796                 UBUS_METHOD_NOARG("routes",          rpc_luci2_network_routes),
797                 UBUS_METHOD_NOARG("routes6",         rpc_luci2_network_routes6),
798         };
799
800         static struct ubus_object_type luci2_network_type =
801                 UBUS_OBJECT_TYPE("luci-rpc-luci2-network", luci2_network_methods);
802
803         static struct ubus_object network_obj = {
804                 .name = "luci2.network",
805                 .type = &luci2_network_type,
806                 .methods = luci2_network_methods,
807                 .n_methods = ARRAY_SIZE(luci2_network_methods),
808         };
809
810         cursor = uci_alloc_context();
811
812         if (!cursor)
813                 return UBUS_STATUS_UNKNOWN_ERROR;
814
815         rv |= ubus_add_object(ctx, &system_obj);
816         rv |= ubus_add_object(ctx, &network_obj);
817
818         return rv;
819 }