X-Git-Url: http://git.archive.openwrt.org/?p=project%2Fprocd.git;a=blobdiff_plain;f=system.c;h=151f613002369de61194434c692339aae8618aa9;hp=658dd5e79f9ec73f7602c78ce28dda6cbdaebf22;hb=d4a183f91f88be1e195e40277f709177d5142ba9;hpb=b9fcb589a4c086d786891f13dfececcfabc0c91f diff --git a/system.c b/system.c index 658dd5e..151f613 100644 --- a/system.c +++ b/system.c @@ -13,51 +13,273 @@ */ #include +#ifdef linux +#include +#endif #include #include +#include #include #include - +#include #include +#include #include #include "procd.h" +#include "sysupgrade.h" #include "watchdog.h" -#define HOSTNAME_PATH "/proc/sys/kernel/hostname" - static struct blob_buf b; -static char *board_name; -static char *board_model; +static int notify; +static struct ubus_context *_ctx; -static int system_info(struct ubus_context *ctx, struct ubus_object *obj, - struct ubus_request_data *req, const char *method, - struct blob_attr *msg) +static int system_board(struct ubus_context *ctx, struct ubus_object *obj, + struct ubus_request_data *req, const char *method, + struct blob_attr *msg) { - struct timespec ts; - struct utsname uts; + void *c; + char line[256]; + char *key, *val, *next; + struct utsname utsname; + FILE *f; blob_buf_init(&b, 0); - if (board_name && board_model) { - blobmsg_add_string(&b, "boardname", board_name); - blobmsg_add_string(&b, "boardmodel", board_model); + + if (uname(&utsname) >= 0) + { + blobmsg_add_string(&b, "kernel", utsname.release); + blobmsg_add_string(&b, "hostname", utsname.nodename); + } + + if ((f = fopen("/proc/cpuinfo", "r")) != NULL) + { + while(fgets(line, sizeof(line), f)) + { + key = strtok(line, "\t:"); + val = strtok(NULL, "\t\n"); + + if (!key || !val) + continue; + + if (!strcasecmp(key, "system type") || + !strcasecmp(key, "processor") || + !strcasecmp(key, "model name")) + { + strtoul(val + 2, &key, 0); + + if (key == (val + 2) || *key != 0) + { + blobmsg_add_string(&b, "system", val + 2); + break; + } + } + } + + fclose(f); + } + + if ((f = fopen("/tmp/sysinfo/model", "r")) != NULL || + (f = fopen("/proc/device-tree/model", "r")) != NULL) + { + if (fgets(line, sizeof(line), f)) + { + val = strtok(line, "\t\n"); + + if (val) + blobmsg_add_string(&b, "model", val); + } + + fclose(f); + } + else if ((f = fopen("/proc/cpuinfo", "r")) != NULL) + { + while(fgets(line, sizeof(line), f)) + { + key = strtok(line, "\t:"); + val = strtok(NULL, "\t\n"); + + if (!key || !val) + continue; + + if (!strcasecmp(key, "machine") || + !strcasecmp(key, "hardware")) + { + blobmsg_add_string(&b, "model", val + 2); + break; + } + } + + fclose(f); } - if (!uname(&uts)) { - blobmsg_add_string(&b, "hostname", uts.nodename); - blobmsg_add_string(&b, "machine", uts.machine); - blobmsg_add_string(&b, "kernel", uts.release); + + if ((f = fopen("/tmp/sysinfo/board_name", "r")) != NULL) + { + if (fgets(line, sizeof(line), f)) + { + val = strtok(line, "\t\n"); + + if (val) + blobmsg_add_string(&b, "board_name", val); + } + + fclose(f); } - if (!clock_gettime(CLOCK_MONOTONIC, &ts)) - blobmsg_add_u32(&b, "uptime", ts.tv_sec); + else if ((f = fopen("/proc/device-tree/compatible", "r")) != NULL) + { + if (fgets(line, sizeof(line), f)) + { + val = strtok(line, "\t\n"); + + if (val) + { + next = val; + while ((next = strchr(next, ',')) != NULL) + { + *next = '-'; + next++; + } + + blobmsg_add_string(&b, "board_name", val); + } + } + + fclose(f); + } + + if ((f = fopen("/etc/openwrt_release", "r")) != NULL) + { + c = blobmsg_open_table(&b, "release"); + + while (fgets(line, sizeof(line), f)) + { + char *dest; + char ch; + + key = line; + val = strchr(line, '='); + if (!val) + continue; + + *(val++) = 0; + + if (!strcasecmp(key, "DISTRIB_ID")) + key = "distribution"; + else if (!strcasecmp(key, "DISTRIB_RELEASE")) + key = "version"; + else if (!strcasecmp(key, "DISTRIB_REVISION")) + key = "revision"; + else if (!strcasecmp(key, "DISTRIB_CODENAME")) + key = "codename"; + else if (!strcasecmp(key, "DISTRIB_TARGET")) + key = "target"; + else if (!strcasecmp(key, "DISTRIB_DESCRIPTION")) + key = "description"; + else + continue; + + dest = blobmsg_alloc_string_buffer(&b, key, strlen(val)); + if (!dest) { + ERROR("Failed to allocate blob.\n"); + continue; + } + + while (val && (ch = *(val++)) != 0) { + switch (ch) { + case '\'': + case '"': + next = strchr(val, ch); + if (next) + *next = 0; + + strcpy(dest, val); + + if (next) + val = next + 1; + + dest += strlen(dest); + break; + case '\\': + *(dest++) = *(val++); + break; + } + } + blobmsg_add_string_buffer(&b); + } + + blobmsg_close_array(&b, c); + + fclose(f); + } + ubus_send_reply(ctx, req, b.head); + return UBUS_STATUS_OK; +} + +static int system_info(struct ubus_context *ctx, struct ubus_object *obj, + struct ubus_request_data *req, const char *method, + struct blob_attr *msg) +{ + time_t now; + struct tm *tm; +#ifdef linux + struct sysinfo info; + void *c; + + if (sysinfo(&info)) + return UBUS_STATUS_UNKNOWN_ERROR; +#endif + + now = time(NULL); + + if (!(tm = localtime(&now))) + return UBUS_STATUS_UNKNOWN_ERROR; + + blob_buf_init(&b, 0); + + blobmsg_add_u32(&b, "localtime", now + tm->tm_gmtoff); + +#ifdef linux + blobmsg_add_u32(&b, "uptime", info.uptime); + + c = blobmsg_open_array(&b, "load"); + blobmsg_add_u32(&b, NULL, info.loads[0]); + blobmsg_add_u32(&b, NULL, info.loads[1]); + blobmsg_add_u32(&b, NULL, info.loads[2]); + blobmsg_close_array(&b, c); + + c = blobmsg_open_table(&b, "memory"); + blobmsg_add_u64(&b, "total", info.mem_unit * info.totalram); + blobmsg_add_u64(&b, "free", info.mem_unit * info.freeram); + blobmsg_add_u64(&b, "shared", info.mem_unit * info.sharedram); + blobmsg_add_u64(&b, "buffered", info.mem_unit * info.bufferram); + blobmsg_close_table(&b, c); + + c = blobmsg_open_table(&b, "swap"); + blobmsg_add_u64(&b, "total", info.mem_unit * info.totalswap); + blobmsg_add_u64(&b, "free", info.mem_unit * info.freeswap); + blobmsg_close_table(&b, c); +#endif + + ubus_send_reply(ctx, req, b.head); + + return UBUS_STATUS_OK; +} + +static int system_reboot(struct ubus_context *ctx, struct ubus_object *obj, + struct ubus_request_data *req, const char *method, + struct blob_attr *msg) +{ + procd_shutdown(RB_AUTOBOOT); return 0; } enum { WDT_FREQUENCY, WDT_TIMEOUT, + WDT_MAGICCLOSE, WDT_STOP, __WDT_MAX }; @@ -65,6 +287,7 @@ enum { static const struct blobmsg_policy watchdog_policy[__WDT_MAX] = { [WDT_FREQUENCY] = { .name = "frequency", .type = BLOBMSG_TYPE_INT32 }, [WDT_TIMEOUT] = { .name = "timeout", .type = BLOBMSG_TYPE_INT32 }, + [WDT_MAGICCLOSE] = { .name = "magicclose", .type = BLOBMSG_TYPE_BOOL }, [WDT_STOP] = { .name = "stop", .type = BLOBMSG_TYPE_BOOL }, }; @@ -99,10 +322,13 @@ static int watchdog_set(struct ubus_context *ctx, struct ubus_object *obj, watchdog_timeout(timeout); } + if (tb[WDT_MAGICCLOSE]) + watchdog_set_magicclose(blobmsg_get_bool(tb[WDT_MAGICCLOSE])); + if (tb[WDT_STOP]) watchdog_set_stopped(blobmsg_get_bool(tb[WDT_STOP])); - if (watchdog_fd() < 0) + if (watchdog_fd() == NULL) status = "offline"; else if (watchdog_get_stopped()) status = "stopped"; @@ -113,14 +339,89 @@ static int watchdog_set(struct ubus_context *ctx, struct ubus_object *obj, blobmsg_add_string(&b, "status", status); blobmsg_add_u32(&b, "timeout", watchdog_timeout(0)); blobmsg_add_u32(&b, "frequency", watchdog_frequency(0)); + blobmsg_add_u8(&b, "magicclose", watchdog_get_magicclose()); ubus_send_reply(ctx, req, b.head); return 0; } +enum { + SIGNAL_PID, + SIGNAL_NUM, + __SIGNAL_MAX +}; + +static const struct blobmsg_policy signal_policy[__SIGNAL_MAX] = { + [SIGNAL_PID] = { .name = "pid", .type = BLOBMSG_TYPE_INT32 }, + [SIGNAL_NUM] = { .name = "signum", .type = BLOBMSG_TYPE_INT32 }, +}; + +static int proc_signal(struct ubus_context *ctx, struct ubus_object *obj, + struct ubus_request_data *req, const char *method, + struct blob_attr *msg) +{ + struct blob_attr *tb[__SIGNAL_MAX]; + + if (!msg) + return UBUS_STATUS_INVALID_ARGUMENT; + + blobmsg_parse(signal_policy, __SIGNAL_MAX, tb, blob_data(msg), blob_len(msg)); + if (!tb[SIGNAL_PID || !tb[SIGNAL_NUM]]) + return UBUS_STATUS_INVALID_ARGUMENT; + + kill(blobmsg_get_u32(tb[SIGNAL_PID]), blobmsg_get_u32(tb[SIGNAL_NUM])); + + return 0; +} + +enum { + SYSUPGRADE_PATH, + SYSUPGRADE_PREFIX, + SYSUPGRADE_COMMAND, + __SYSUPGRADE_MAX +}; + +static const struct blobmsg_policy sysupgrade_policy[__SYSUPGRADE_MAX] = { + [SYSUPGRADE_PATH] = { .name = "path", .type = BLOBMSG_TYPE_STRING }, + [SYSUPGRADE_PREFIX] = { .name = "prefix", .type = BLOBMSG_TYPE_STRING }, + [SYSUPGRADE_COMMAND] = { .name = "command", .type = BLOBMSG_TYPE_STRING }, +}; + +static int sysupgrade(struct ubus_context *ctx, struct ubus_object *obj, + struct ubus_request_data *req, const char *method, + struct blob_attr *msg) +{ + struct blob_attr *tb[__SYSUPGRADE_MAX]; + + if (!msg) + return UBUS_STATUS_INVALID_ARGUMENT; + + blobmsg_parse(sysupgrade_policy, __SYSUPGRADE_MAX, tb, blob_data(msg), blob_len(msg)); + if (!tb[SYSUPGRADE_PATH] || !tb[SYSUPGRADE_PREFIX]) + return UBUS_STATUS_INVALID_ARGUMENT; + + sysupgrade_exec_upgraded(blobmsg_get_string(tb[SYSUPGRADE_PREFIX]), + blobmsg_get_string(tb[SYSUPGRADE_PATH]), + tb[SYSUPGRADE_COMMAND] ? blobmsg_get_string(tb[SYSUPGRADE_COMMAND]) : NULL); + + /* sysupgrade_exec_upgraded() will never return unless something has gone wrong */ + return UBUS_STATUS_UNKNOWN_ERROR; +} + +static void +procd_subscribe_cb(struct ubus_context *ctx, struct ubus_object *obj) +{ + notify = obj->has_subscribers; +} + + static const struct ubus_method system_methods[] = { - UBUS_METHOD_NOARG("info", system_info), + UBUS_METHOD_NOARG("board", system_board), + UBUS_METHOD_NOARG("info", system_info), + UBUS_METHOD_NOARG("reboot", system_reboot), UBUS_METHOD("watchdog", watchdog_set, watchdog_policy), + UBUS_METHOD("signal", proc_signal, signal_policy), + UBUS_METHOD("sysupgrade", sysupgrade, sysupgrade_policy), }; static struct ubus_object_type system_object_type = @@ -131,36 +432,27 @@ static struct ubus_object system_object = { .type = &system_object_type, .methods = system_methods, .n_methods = ARRAY_SIZE(system_methods), + .subscribe_cb = procd_subscribe_cb, }; -static char* load_file_content(const char *file) +void +procd_bcast_event(char *event, struct blob_attr *msg) { - char buf[32]; - int fd, r; - - fd = open(file, O_RDONLY); - if (!fd) - return NULL; - r = read(fd, buf, sizeof(buf) - 1); - close(fd); - if (r < 1) - return NULL; - if (buf[r - 1] == '\n') - buf[r - 1] = '\0'; - else - buf[r] = '\0'; + int ret; + + if (!notify) + return; - return strdup(buf); + ret = ubus_notify(_ctx, &system_object, event, msg, -1); + if (ret) + fprintf(stderr, "Failed to notify log: %s\n", ubus_strerror(ret)); } void ubus_init_system(struct ubus_context *ctx) { int ret; - if (!board_model) - board_model = load_file_content("/tmp/sysinfo/model"); - if (!board_name); - board_name = load_file_content("/tmp/sysinfo/board_name"); + _ctx = ctx; ret = ubus_add_object(ctx, &system_object); if (ret) ERROR("Failed to add object: %s\n", ubus_strerror(ret));