2d28429e9c12d9a53bc885ffe6574a8725cdc365
[project/rpcd.git] / system.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 <time.h>
20 #include <stdio.h>
21 #include <string.h>
22 #include <ctype.h>
23 #include <sys/sysinfo.h>
24 #include <sys/utsname.h>
25
26 #include "system.h"
27
28 static struct blob_buf buf;
29
30 static int
31 rpc_system_board(struct ubus_context *ctx, struct ubus_object *obj,
32                  struct ubus_request_data *req, const char *method,
33                  struct blob_attr *msg)
34 {
35         void *c;
36         char line[256];
37         char *key, *val;
38         struct utsname utsname;
39         FILE *f;
40
41         blob_buf_init(&buf, 0);
42
43         if (uname(&utsname) >= 0)
44         {
45                 blobmsg_add_string(&buf, "kernel", utsname.release);
46                 blobmsg_add_string(&buf, "hostname", utsname.nodename);
47         }
48
49         if ((f = fopen("/proc/cpuinfo", "r")) != NULL)
50         {
51                 while(fgets(line, sizeof(line), f))
52                 {
53                         key = strtok(line, "\t:");
54                         val = strtok(NULL, "\t\n");
55
56                         if (!key || !val)
57                                 continue;
58
59                         if (!strcasecmp(key, "system type") ||
60                             !strcasecmp(key, "processor") ||
61                             !strcasecmp(key, "model name"))
62                         {
63                                 blobmsg_add_string(&buf, "system", val + 2);
64                                 break;
65                         }
66                 }
67
68                 fclose(f);
69         }
70
71         if ((f = fopen("/tmp/sysinfo/model", "r")) != NULL)
72         {
73                 if (fgets(line, sizeof(line), f))
74                 {
75                         val = strtok(line, "\t\n");
76
77                         if (val)
78                                 blobmsg_add_string(&buf, "model", val);
79                 }
80
81                 fclose(f);
82         }
83         else if ((f = fopen("/proc/cpuinfo", "r")) != NULL)
84         {
85                 while(fgets(line, sizeof(line), f))
86                 {
87                         key = strtok(line, "\t:");
88                         val = strtok(NULL, "\t\n");
89
90                         if (!key || !val)
91                                 continue;
92
93                         if (!strcasecmp(key, "machine") ||
94                             !strcasecmp(key, "hardware"))
95                         {
96                                 blobmsg_add_string(&buf, "model", val + 2);
97                                 break;
98                         }
99                 }
100
101                 fclose(f);
102         }
103
104         if ((f = fopen("/etc/openwrt_release", "r")) != NULL)
105         {
106                 c = blobmsg_open_table(&buf, "release");
107
108                 while (fgets(line, sizeof(line), f))
109                 {
110                         key = strtok(line, "=\"");
111                         val = strtok(NULL, "\"\n");
112
113                         if (!key || !val)
114                                 continue;
115
116                         if (!strcasecmp(key, "DISTRIB_ID"))
117                                 blobmsg_add_string(&buf, "distribution", val);
118                         else if (!strcasecmp(key, "DISTRIB_RELEASE"))
119                                 blobmsg_add_string(&buf, "version", val);
120                         else if (!strcasecmp(key, "DISTRIB_REVISION"))
121                                 blobmsg_add_string(&buf, "revision", val);
122                         else if (!strcasecmp(key, "DISTRIB_CODENAME"))
123                                 blobmsg_add_string(&buf, "codename", val);
124                         else if (!strcasecmp(key, "DISTRIB_TARGET"))
125                                 blobmsg_add_string(&buf, "target", val);
126                         else if (!strcasecmp(key, "DISTRIB_DESCRIPTION"))
127                                 blobmsg_add_string(&buf, "description", val);
128                 }
129
130                 blobmsg_close_array(&buf, c);
131
132                 fclose(f);
133         }
134
135         ubus_send_reply(ctx, req, buf.head);
136
137         return UBUS_STATUS_OK;
138 }
139
140 static int
141 rpc_system_info(struct ubus_context *ctx, struct ubus_object *obj,
142                 struct ubus_request_data *req, const char *method,
143                 struct blob_attr *msg)
144 {
145         void *c;
146         time_t now;
147         struct tm *tm;
148         struct sysinfo info;
149
150         now = time(NULL);
151
152         if (!(tm = localtime(&now)))
153                 return UBUS_STATUS_UNKNOWN_ERROR;
154
155         if (sysinfo(&info))
156                 return UBUS_STATUS_UNKNOWN_ERROR;
157
158         blob_buf_init(&buf, 0);
159
160         blobmsg_add_u32(&buf, "uptime",    info.uptime);
161         blobmsg_add_u32(&buf, "localtime", mktime(tm));
162
163         c = blobmsg_open_array(&buf, "load");
164         blobmsg_add_u32(&buf, NULL, info.loads[0]);
165         blobmsg_add_u32(&buf, NULL, info.loads[1]);
166         blobmsg_add_u32(&buf, NULL, info.loads[2]);
167         blobmsg_close_array(&buf, c);
168
169         c = blobmsg_open_table(&buf, "memory");
170         blobmsg_add_u32(&buf, "total",    info.mem_unit * info.totalram);
171         blobmsg_add_u32(&buf, "free",     info.mem_unit * info.freeram);
172         blobmsg_add_u32(&buf, "shared",   info.mem_unit * info.sharedram);
173         blobmsg_add_u32(&buf, "buffered", info.mem_unit * info.bufferram);
174         blobmsg_close_table(&buf, c);
175
176         c = blobmsg_open_table(&buf, "swap");
177         blobmsg_add_u32(&buf, "total",    info.mem_unit * info.totalswap);
178         blobmsg_add_u32(&buf, "free",     info.mem_unit * info.freeswap);
179         blobmsg_close_table(&buf, c);
180
181         ubus_send_reply(ctx, req, buf.head);
182
183         return UBUS_STATUS_OK;
184 }
185
186 int rpc_system_api_init(struct ubus_context *ctx)
187 {
188         static const struct ubus_method system_methods[] = {
189                 UBUS_METHOD_NOARG("board", rpc_system_board),
190                 UBUS_METHOD_NOARG("info",  rpc_system_info),
191         };
192
193         static struct ubus_object_type system_type =
194                 UBUS_OBJECT_TYPE("luci-rpc-system", system_methods);
195
196         static struct ubus_object obj = {
197                 .name = "system",
198                 .type = &system_type,
199                 .methods = system_methods,
200                 .n_methods = ARRAY_SIZE(system_methods),
201         };
202
203         return ubus_add_object(ctx, &obj);
204 }