session: expose rpc_session_access() function for testing session ACLs in other rpcd...
[project/rpcd.git] / luci2.c
diff --git a/luci2.c b/luci2.c
index ae36e42..b63123d 100644 (file)
--- a/luci2.c
+++ b/luci2.c
@@ -964,14 +964,235 @@ rpc_luci2_upgrade_start(struct ubus_context *ctx, struct ubus_object *obj,
 }
 
 static int
-rpc_luci2_upgrade_abort(struct ubus_context *ctx, struct ubus_object *obj,
+rpc_luci2_upgrade_clean(struct ubus_context *ctx, struct ubus_object *obj,
                         struct ubus_request_data *req, const char *method,
                         struct blob_attr *msg)
 {
-       unlink("/tmp/firmware.bin");
+       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)
@@ -1731,7 +1952,7 @@ rpc_luci2_opkg_config_set(struct ubus_context *ctx, struct ubus_object *obj,
                return rpc_errno_status();
 
        fwrite(blobmsg_data(tb[RPC_D_DATA]),
-              blobmsg_data_len(tb[RPC_D_DATA]), 1, f);
+              blobmsg_data_len(tb[RPC_D_DATA]) - 1, 1, f);
 
        fclose(f);
        return 0;
@@ -1768,7 +1989,16 @@ int rpc_luci2_api_init(struct ubus_context *ctx)
                UBUS_METHOD_NOARG("upgrade_test", rpc_luci2_upgrade_test),
                UBUS_METHOD("upgrade_start",      rpc_luci2_upgrade_start,
                                                  rpc_upgrade_policy),
-               UBUS_METHOD_NOARG("upgrade_abort", rpc_luci2_upgrade_abort)
+               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 =