X-Git-Url: http://git.archive.openwrt.org/?p=project%2Frpcd.git;a=blobdiff_plain;f=luci2.c;h=b63123d2f675f01fcb1ed54d28bbd5390232ec08;hp=a96bdd64886f6a8d3bbae3c6891d9048fbc5823e;hb=c6985dd5a60bf2aa48f7099cd8cb08edb1c8b561;hpb=c2460e1cacce0393966bd5580cffe4210bf263d2 diff --git a/luci2.c b/luci2.c index a96bdd6..b63123d 100644 --- a/luci2.c +++ b/luci2.c @@ -59,12 +59,12 @@ static const struct blobmsg_policy rpc_init_policy[__RPC_I_MAX] = { }; enum { - RPC_RC_DATA, - __RPC_RC_MAX + RPC_D_DATA, + __RPC_D_MAX }; -static const struct blobmsg_policy rpc_rclocal_policy[__RPC_RC_MAX] = { - [RPC_RC_DATA] = { .name = "data", .type = BLOBMSG_TYPE_STRING }, +static const struct blobmsg_policy rpc_data_policy[__RPC_D_MAX] = { + [RPC_D_DATA] = { .name = "data", .type = BLOBMSG_TYPE_STRING }, }; enum { @@ -110,12 +110,12 @@ static const struct blobmsg_policy rpc_opkg_package_policy[__RPC_OP_MAX] = { }; enum { - RPC_OC_CONFIG, - __RPC_OC_MAX + RPC_UPGRADE_KEEP, + __RPC_UPGRADE_MAX }; -static const struct blobmsg_policy rpc_opkg_config_policy[__RPC_OC_MAX] = { - [RPC_OC_CONFIG] = { .name = "config", .type = BLOBMSG_TYPE_STRING }, +static const struct blobmsg_policy rpc_upgrade_policy[__RPC_UPGRADE_MAX] = { + [RPC_UPGRADE_KEEP] = { .name = "keep", .type = BLOBMSG_TYPE_BOOL }, }; @@ -564,19 +564,68 @@ rpc_luci2_rclocal_set(struct ubus_context *ctx, struct ubus_object *obj, struct blob_attr *msg) { FILE *f; - struct blob_attr *tb[__RPC_RC_MAX]; + struct blob_attr *tb[__RPC_D_MAX]; - blobmsg_parse(rpc_rclocal_policy, __RPC_RC_MAX, tb, + blobmsg_parse(rpc_data_policy, __RPC_D_MAX, tb, blob_data(msg), blob_len(msg)); - if (!tb[RPC_RC_DATA] || blobmsg_data_len(tb[RPC_RC_DATA]) >= 4096) + if (!tb[RPC_D_DATA] || blobmsg_data_len(tb[RPC_D_DATA]) >= 4096) return UBUS_STATUS_INVALID_ARGUMENT; if (!(f = fopen("/etc/rc.local", "w"))) return rpc_errno_status(); - fwrite(blobmsg_data(tb[RPC_RC_DATA]), - blobmsg_data_len(tb[RPC_RC_DATA]) - 1, 1, f); + fwrite(blobmsg_data(tb[RPC_D_DATA]), + blobmsg_data_len(tb[RPC_D_DATA]) - 1, 1, f); + + fclose(f); + return 0; +} + +static int +rpc_luci2_crontab_get(struct ubus_context *ctx, struct ubus_object *obj, + struct ubus_request_data *req, const char *method, + struct blob_attr *msg) +{ + FILE *f; + char data[4096] = { 0 }; + + if (!(f = fopen("/etc/crontabs/root", "r"))) + return rpc_errno_status(); + + fread(data, sizeof(data) - 1, 1, f); + fclose(f); + + blob_buf_init(&buf, 0); + blobmsg_add_string(&buf, "data", data); + + ubus_send_reply(ctx, req, buf.head); + return 0; +} + +static int +rpc_luci2_crontab_set(struct ubus_context *ctx, struct ubus_object *obj, + struct ubus_request_data *req, const char *method, + struct blob_attr *msg) +{ + FILE *f; + struct stat s; + struct blob_attr *tb[__RPC_D_MAX]; + + blobmsg_parse(rpc_data_policy, __RPC_D_MAX, tb, + blob_data(msg), blob_len(msg)); + + if (!tb[RPC_D_DATA] || blobmsg_data_len(tb[RPC_D_DATA]) >= 4096) + return UBUS_STATUS_INVALID_ARGUMENT; + + if (stat("/etc/crontabs", &s) && mkdir("/etc/crontabs", 0755)) + return rpc_errno_status(); + + if (!(f = fopen("/etc/crontabs/root", "w"))) + return rpc_errno_status(); + + fwrite(blobmsg_data(tb[RPC_D_DATA]), + blobmsg_data_len(tb[RPC_D_DATA]) - 1, 1, f); fclose(f); return 0; @@ -720,6 +769,430 @@ rpc_luci2_password_set(struct ubus_context *ctx, struct ubus_object *obj, } } +static int +rpc_luci2_led_list(struct ubus_context *ctx, struct ubus_object *obj, + struct ubus_request_data *req, const char *method, + struct blob_attr *msg) +{ + DIR *d; + FILE *f; + void *list, *led, *trigger; + char *p, *active_trigger, line[512]; + struct dirent *e; + + if (!(d = opendir("/sys/class/leds"))) + return rpc_errno_status(); + + blob_buf_init(&buf, 0); + list = blobmsg_open_array(&buf, "leds"); + + while ((e = readdir(d)) != NULL) + { + snprintf(line, sizeof(line) - 1, "/sys/class/leds/%s/trigger", + e->d_name); + + if (!(f = fopen(line, "r"))) + continue; + + led = blobmsg_open_table(&buf, NULL); + + blobmsg_add_string(&buf, "name", e->d_name); + + if (fgets(line, sizeof(line) - 1, f)) + { + trigger = blobmsg_open_array(&buf, "triggers"); + + for (p = strtok(line, " \n"), active_trigger = NULL; + p != NULL; + p = strtok(NULL, " \n")) + { + if (*p == '[') + { + *(p + strlen(p) - 1) = 0; + *p++ = 0; + active_trigger = p; + } + + blobmsg_add_string(&buf, NULL, p); + } + + blobmsg_close_array(&buf, trigger); + + if (active_trigger) + blobmsg_add_string(&buf, "active_trigger", active_trigger); + } + + fclose(f); + + snprintf(line, sizeof(line) - 1, "/sys/class/leds/%s/brightness", + e->d_name); + + if ((f = fopen(line, "r")) != NULL) + { + if (fgets(line, sizeof(line) - 1, f)) + blobmsg_add_u32(&buf, "brightness", atoi(line)); + + fclose(f); + } + + snprintf(line, sizeof(line) - 1, "/sys/class/leds/%s/max_brightness", + e->d_name); + + if ((f = fopen(line, "r")) != NULL) + { + if (fgets(line, sizeof(line) - 1, f)) + blobmsg_add_u32(&buf, "max_brightness", atoi(line)); + + fclose(f); + } + + blobmsg_close_table(&buf, led); + } + + closedir(d); + + blobmsg_close_array(&buf, list); + ubus_send_reply(ctx, req, buf.head); + + return 0; +} + +static int +rpc_luci2_usb_list(struct ubus_context *ctx, struct ubus_object *obj, + struct ubus_request_data *req, const char *method, + struct blob_attr *msg) +{ + DIR *d; + FILE *f; + int i; + void *list, *device; + char *p, line[512]; + struct stat s; + struct dirent *e; + + const char *attributes[] = { + "manufacturer", "vendor_name", "s", + "product", "product_name", "s", + "idVendor", "vendor_id", "x", + "idProduct", "product_id", "x", + "serial", "serial", "s", + "speed", "speed", "d", + }; + + if (!(d = opendir("/sys/bus/usb/devices"))) + return rpc_errno_status(); + + blob_buf_init(&buf, 0); + list = blobmsg_open_array(&buf, "devices"); + + while ((e = readdir(d)) != NULL) + { + if (e->d_name[0] < '0' || e->d_name[0] > '9') + continue; + + snprintf(line, sizeof(line) - 1, + "/sys/bus/usb/devices/%s/%s", e->d_name, attributes[0]); + + if (stat(line, &s)) + continue; + + device = blobmsg_open_table(&buf, NULL); + + blobmsg_add_string(&buf, "name", e->d_name); + + for (i = 0; i < sizeof(attributes) / sizeof(attributes[0]); i += 3) + { + snprintf(line, sizeof(line) - 1, + "/sys/bus/usb/devices/%s/%s", e->d_name, attributes[i]); + + if (!(f = fopen(line, "r"))) + continue; + + if (fgets(line, sizeof(line) - 1, f)) + { + switch (*attributes[i+2]) + { + case 'x': + blobmsg_add_u32(&buf, attributes[i+1], + strtoul(line, NULL, 16)); + break; + + case 'd': + blobmsg_add_u32(&buf, attributes[i+1], + strtoul(line, NULL, 10)); + break; + + default: + if ((p = strchr(line, '\n')) != NULL) + while (p > line && isspace(*p)) + *p-- = 0; + + blobmsg_add_string(&buf, attributes[i+1], line); + break; + } + } + + fclose(f); + } + + blobmsg_close_table(&buf, device); + } + + closedir(d); + + blobmsg_close_array(&buf, list); + ubus_send_reply(ctx, req, buf.head); + + return 0; +} + +static int +rpc_luci2_upgrade_test(struct ubus_context *ctx, struct ubus_object *obj, + struct ubus_request_data *req, const char *method, + struct blob_attr *msg) +{ + const char *cmd[4] = { "sysupgrade", "--test", "/tmp/firmware.bin", NULL }; + return rpc_exec(cmd, NULL, NULL, NULL, NULL, ctx, req); +} + +static int +rpc_luci2_upgrade_start(struct ubus_context *ctx, struct ubus_object *obj, + struct ubus_request_data *req, const char *method, + struct blob_attr *msg) +{ + return 0; +} + +static int +rpc_luci2_upgrade_clean(struct ubus_context *ctx, struct ubus_object *obj, + struct ubus_request_data *req, const char *method, + struct blob_attr *msg) +{ + if (unlink("/tmp/firmware.bin")) + return rpc_errno_status(); + + return 0; +} + +static int +rpc_luci2_backup_restore(struct ubus_context *ctx, struct ubus_object *obj, + struct ubus_request_data *req, const char *method, + struct blob_attr *msg) +{ + const char *cmd[4] = { "sysupgrade", "--restore-backup", + "/tmp/backup.tar.gz", NULL }; + + return rpc_exec(cmd, NULL, NULL, NULL, NULL, ctx, req); +} + +static int +rpc_luci2_backup_clean(struct ubus_context *ctx, struct ubus_object *obj, + struct ubus_request_data *req, const char *method, + struct blob_attr *msg) +{ + if (unlink("/tmp/backup.tar.gz")) + return rpc_errno_status(); + + return 0; +} + +static int +rpc_luci2_backup_config_get(struct ubus_context *ctx, struct ubus_object *obj, + struct ubus_request_data *req, const char *method, + struct blob_attr *msg) +{ + FILE *f; + char conf[2048] = { 0 }; + + if (!(f = fopen("/etc/sysupgrade.conf", "r"))) + return rpc_errno_status(); + + fread(conf, sizeof(conf) - 1, 1, f); + fclose(f); + + blob_buf_init(&buf, 0); + blobmsg_add_string(&buf, "config", conf); + + ubus_send_reply(ctx, req, buf.head); + return 0; +} + +static int +rpc_luci2_backup_config_set(struct ubus_context *ctx, struct ubus_object *obj, + struct ubus_request_data *req, const char *method, + struct blob_attr *msg) +{ + FILE *f; + struct blob_attr *tb[__RPC_D_MAX]; + + blobmsg_parse(rpc_data_policy, __RPC_D_MAX, tb, + blob_data(msg), blob_len(msg)); + + if (!tb[RPC_D_DATA]) + return UBUS_STATUS_INVALID_ARGUMENT; + + if (blobmsg_data_len(tb[RPC_D_DATA]) >= 2048) + return UBUS_STATUS_NOT_SUPPORTED; + + if (!(f = fopen("/etc/sysupgrade.conf", "w"))) + return rpc_errno_status(); + + fwrite(blobmsg_data(tb[RPC_D_DATA]), + blobmsg_data_len(tb[RPC_D_DATA]) - 1, 1, f); + + fclose(f); + return 0; +} + +struct backup_state { + bool open; + void *array; +}; + +static int +backup_parse_list(struct blob_buf *blob, char *buf, int len, void *priv) +{ + struct backup_state *s = priv; + char *nl = strchr(buf, '\n'); + + if (!nl) + return 0; + + if (!s->open) + { + s->open = true; + s->array = blobmsg_open_array(blob, "files"); + } + + *nl = 0; + blobmsg_add_string(blob, NULL, buf); + + return (nl - buf + 1); +} + +static void +backup_finish_list(struct blob_buf *blob, int status, void *priv) +{ + struct backup_state *s = priv; + + if (!s->open) + return; + + blobmsg_close_array(blob, s->array); +} + +static int +rpc_luci2_backup_list(struct ubus_context *ctx, struct ubus_object *obj, + struct ubus_request_data *req, const char *method, + struct blob_attr *msg) +{ + struct backup_state *state = NULL; + const char *cmd[3] = { "sysupgrade", "--list-backup", NULL }; + + state = malloc(sizeof(*state)); + + if (!state) + return UBUS_STATUS_UNKNOWN_ERROR; + + memset(state, 0, sizeof(*state)); + + return rpc_exec(cmd, backup_parse_list, NULL, backup_finish_list, + state, ctx, req); +} + +static int +rpc_luci2_reset_test(struct ubus_context *ctx, struct ubus_object *obj, + struct ubus_request_data *req, const char *method, + struct blob_attr *msg) +{ + FILE *mtd; + struct stat s; + char line[64] = { 0 }; + bool supported = false; + + if (!stat("/sbin/mtd", &s) && (s.st_mode & S_IXUSR)) + { + if ((mtd = fopen("/proc/mtd", "r")) != NULL) + { + while (fgets(line, sizeof(line) - 1, mtd)) + { + if (strstr(line, "\"rootfs_data\"")) + { + supported = true; + break; + } + } + + fclose(mtd); + } + } + + blob_buf_init(&buf, 0); + blobmsg_add_u8(&buf, "supported", supported); + + ubus_send_reply(ctx, req, buf.head); + + return 0; +} + +static int +rpc_luci2_reset_start(struct ubus_context *ctx, struct ubus_object *obj, + struct ubus_request_data *req, const char *method, + struct blob_attr *msg) +{ + switch (fork()) + { + case -1: + return rpc_errno_status(); + + case 0: + uloop_done(); + + chdir("/"); + + close(0); + close(1); + close(2); + + sleep(1); + + execl("/sbin/mtd", "/sbin/mtd", "-r", "erase", "rootfs_data", NULL); + + return rpc_errno_status(); + + default: + return 0; + } +} + +static int +rpc_luci2_reboot(struct ubus_context *ctx, struct ubus_object *obj, + struct ubus_request_data *req, const char *method, + struct blob_attr *msg) +{ + switch (fork()) + { + case -1: + return rpc_errno_status(); + + case 0: + chdir("/"); + + close(0); + close(1); + close(2); + + sleep(1); + + execl("/sbin/reboot", "/sbin/reboot", NULL); + + return rpc_errno_status(); + + default: + return 0; + } +} + static FILE * dnsmasq_leasefile(void) @@ -1464,25 +1937,22 @@ rpc_luci2_opkg_config_set(struct ubus_context *ctx, struct ubus_object *obj, struct blob_attr *msg) { FILE *f; - struct blob_attr *tb[__RPC_OC_MAX]; + struct blob_attr *tb[__RPC_D_MAX]; - blobmsg_parse(rpc_opkg_package_policy, __RPC_OC_MAX, tb, + blobmsg_parse(rpc_data_policy, __RPC_D_MAX, tb, blob_data(msg), blob_len(msg)); - if (!tb[RPC_OC_CONFIG]) - return UBUS_STATUS_INVALID_ARGUMENT; - - if (blobmsg_type(tb[RPC_OC_CONFIG]) != BLOBMSG_TYPE_STRING) + if (!tb[RPC_D_DATA]) return UBUS_STATUS_INVALID_ARGUMENT; - if (blobmsg_data_len(tb[RPC_OC_CONFIG]) >= 2048) + if (blobmsg_data_len(tb[RPC_D_DATA]) >= 2048) return UBUS_STATUS_NOT_SUPPORTED; if (!(f = fopen("/etc/opkg.conf", "w"))) return rpc_errno_status(); - fwrite(blobmsg_data(tb[RPC_OC_CONFIG]), - blobmsg_data_len(tb[RPC_OC_CONFIG]), 1, f); + fwrite(blobmsg_data(tb[RPC_D_DATA]), + blobmsg_data_len(tb[RPC_D_DATA]) - 1, 1, f); fclose(f); return 0; @@ -1505,12 +1975,30 @@ int rpc_luci2_api_init(struct ubus_context *ctx) rpc_init_policy), UBUS_METHOD_NOARG("rclocal_get", rpc_luci2_rclocal_get), UBUS_METHOD("rclocal_set", rpc_luci2_rclocal_set, - rpc_rclocal_policy), + rpc_data_policy), + UBUS_METHOD_NOARG("crontab_get", rpc_luci2_crontab_get), + UBUS_METHOD("crontab_set", rpc_luci2_crontab_set, + rpc_data_policy), UBUS_METHOD_NOARG("sshkeys_get", rpc_luci2_sshkeys_get), UBUS_METHOD("sshkeys_set", rpc_luci2_sshkeys_set, rpc_sshkey_policy), UBUS_METHOD("password_set", rpc_luci2_password_set, - rpc_password_policy) + rpc_password_policy), + UBUS_METHOD_NOARG("led_list", rpc_luci2_led_list), + UBUS_METHOD_NOARG("usb_list", rpc_luci2_usb_list), + UBUS_METHOD_NOARG("upgrade_test", rpc_luci2_upgrade_test), + UBUS_METHOD("upgrade_start", rpc_luci2_upgrade_start, + rpc_upgrade_policy), + UBUS_METHOD_NOARG("upgrade_clean", rpc_luci2_upgrade_clean), + UBUS_METHOD_NOARG("backup_restore", rpc_luci2_backup_restore), + UBUS_METHOD_NOARG("backup_clean", rpc_luci2_backup_clean), + UBUS_METHOD_NOARG("backup_config_get", rpc_luci2_backup_config_get), + UBUS_METHOD("backup_config_set", rpc_luci2_backup_config_set, + rpc_data_policy), + UBUS_METHOD_NOARG("backup_list", rpc_luci2_backup_list), + UBUS_METHOD_NOARG("reset_test", rpc_luci2_reset_test), + UBUS_METHOD_NOARG("reset_start", rpc_luci2_reset_start), + UBUS_METHOD_NOARG("reboot", rpc_luci2_reboot) }; static struct ubus_object_type luci2_system_type = @@ -1559,7 +2047,7 @@ int rpc_luci2_api_init(struct ubus_context *ctx) UBUS_METHOD_NOARG("update", rpc_luci2_opkg_update), UBUS_METHOD_NOARG("config_get", rpc_luci2_opkg_config_get), UBUS_METHOD("config_set", rpc_luci2_opkg_config_set, - rpc_opkg_config_policy) + rpc_data_policy) }; static struct ubus_object_type luci2_opkg_type =