+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;
+ }
+}
+