sysupgrade: print errno on failure
[project/procd.git] / system.c
index 0fb98f1e36221f262a55712aaf81924aaa4249bb..93eac59c3b01ce3729dc27539ac483f5314759d3 100644 (file)
--- a/system.c
+++ b/system.c
@@ -20,6 +20,7 @@
 #include <sys/types.h>
 #include <sys/reboot.h>
 #include <sys/stat.h>
+#include <sys/statvfs.h>
 #include <fcntl.h>
 #include <signal.h>
 #include <unistd.h>
 #include "procd.h"
 #include "sysupgrade.h"
 #include "watchdog.h"
+#include "service/service.h"
 
 static struct blob_buf b;
 static int notify;
 static struct ubus_context *_ctx;
+static int initramfs;
 
 enum vjson_state {
        VJSON_ERROR,
@@ -43,6 +46,78 @@ enum vjson_state {
        VJSON_SUCCESS,
 };
 
+static const char *system_rootfs_type(void) {
+       const char proc_mounts[] = "/proc/self/mounts";
+       static char fstype[16] = { 0 };
+       char *mountstr = NULL, *mp = "/", *pos, *tmp;
+       FILE *mounts;
+       ssize_t nread;
+       size_t len = 0;
+       bool found;
+
+       if (initramfs)
+               return "initramfs";
+
+       if (fstype[0])
+               return fstype;
+
+       mounts = fopen(proc_mounts, "r");
+       if (!mounts)
+               return NULL;
+
+       while ((nread = getline(&mountstr, &len, mounts)) != -1) {
+               found = false;
+
+               pos = strchr(mountstr, ' ');
+               if (!pos)
+                       continue;
+
+               tmp = pos + 1;
+               pos = strchr(tmp, ' ');
+               if (!pos)
+                       continue;
+
+               *pos = '\0';
+               if (strcmp(tmp, mp))
+                       continue;
+
+               tmp = pos + 1;
+               pos = strchr(tmp, ' ');
+               if (!pos)
+                       continue;
+
+               *pos = '\0';
+
+               if (!strcmp(tmp, "overlay")) {
+                       /*
+                        * there is no point in parsing overlay option string for
+                        * lowerdir, as that can point to "/" being a previous
+                        * overlay mount (after firstboot or sysuprade config
+                        * restore). Hence just assume the lowerdir is "/rom" and
+                        * restart searching for that instead.
+                        */
+                       mp = "/rom";
+                       fseek(mounts, 0, SEEK_SET);
+                       continue;
+               }
+
+               found = true;
+               break;
+       }
+
+       if (found)
+               strncpy(fstype, tmp, sizeof(fstype) - 1);
+
+       fstype[sizeof(fstype) - 1]= '\0';
+       free(mountstr);
+       fclose(mounts);
+
+       if (found)
+               return fstype;
+       else
+               return NULL;
+}
+
 static int system_board(struct ubus_context *ctx, struct ubus_object *obj,
                  struct ubus_request_data *req, const char *method,
                  struct blob_attr *msg)
@@ -50,6 +125,7 @@ static int system_board(struct ubus_context *ctx, struct ubus_object *obj,
        void *c;
        char line[256];
        char *key, *val, *next;
+       const char *rootfs_type = system_rootfs_type();
        struct utsname utsname;
        FILE *f;
 
@@ -71,6 +147,13 @@ static int system_board(struct ubus_context *ctx, struct ubus_object *obj,
                        if (!key || !val)
                                continue;
 
+#ifdef __aarch64__
+                       if (!strcasecmp(key, "CPU revision")) {
+                               snprintf(line, sizeof(line), "ARMv8 Processor rev %lu", strtoul(val + 2, NULL, 16));
+                               blobmsg_add_string(&b, "system", line);
+                               break;
+                       }
+#else
                        if (!strcasecmp(key, "system type") ||
                            !strcasecmp(key, "processor") ||
                            !strcasecmp(key, "cpu") ||
@@ -84,6 +167,7 @@ static int system_board(struct ubus_context *ctx, struct ubus_object *obj,
                                        break;
                                }
                        }
+#endif
                }
 
                fclose(f);
@@ -157,6 +241,9 @@ static int system_board(struct ubus_context *ctx, struct ubus_object *obj,
                fclose(f);
        }
 
+       if (rootfs_type)
+               blobmsg_add_string(&b, "rootfs_type", rootfs_type);
+
        if ((f = fopen("/etc/openwrt_release", "r")) != NULL)
        {
                c = blobmsg_open_table(&b, "release");
@@ -227,6 +314,12 @@ static int system_board(struct ubus_context *ctx, struct ubus_object *obj,
        return UBUS_STATUS_OK;
 }
 
+static unsigned long
+kscale(unsigned long b, unsigned long bs)
+{
+       return (b * (unsigned long long) bs + 1024/2) / 1024;
+}
+
 static int system_info(struct ubus_context *ctx, struct ubus_object *obj,
                 struct ubus_request_data *req, const char *method,
                 struct blob_attr *msg)
@@ -240,6 +333,12 @@ static int system_info(struct ubus_context *ctx, struct ubus_object *obj,
        char *key, *val;
        unsigned long long available, cached;
        FILE *f;
+       int i;
+       struct statvfs s;
+       const char *fslist[] = {
+               "/",    "root",
+               "/tmp", "tmp",
+       };
 
        if (sysinfo(&info))
                return UBUS_STATUS_UNKNOWN_ERROR;
@@ -299,6 +398,23 @@ static int system_info(struct ubus_context *ctx, struct ubus_object *obj,
        blobmsg_add_u64(&b, "cached", cached);
        blobmsg_close_table(&b, c);
 
+       for (i = 0; i < sizeof(fslist) / sizeof(fslist[0]); i += 2) {
+               if (statvfs(fslist[i], &s))
+                       continue;
+
+               c = blobmsg_open_table(&b, fslist[i+1]);
+
+               if (!s.f_frsize)
+                       s.f_frsize = s.f_bsize;
+
+               blobmsg_add_u64(&b, "total", kscale(s.f_blocks, s.f_frsize));
+               blobmsg_add_u64(&b, "free",  kscale(s.f_bfree, s.f_frsize));
+               blobmsg_add_u64(&b, "used", kscale(s.f_blocks - s.f_bfree, s.f_frsize));
+               blobmsg_add_u64(&b, "avail", kscale(s.f_bavail, s.f_frsize));
+
+               blobmsg_close_table(&b, c);
+       }
+
        c = blobmsg_open_table(&b, "swap");
        blobmsg_add_u64(&b, "total",
                        (uint64_t)info.mem_unit * (uint64_t)info.totalswap);
@@ -695,6 +811,8 @@ static int sysupgrade(struct ubus_context *ctx, struct ubus_object *obj,
                return UBUS_STATUS_NOT_SUPPORTED;
        }
 
+       service_stop_all();
+
        sysupgrade_exec_upgraded(blobmsg_get_string(tb[SYSUPGRADE_PREFIX]),
                                 blobmsg_get_string(tb[SYSUPGRADE_PATH]),
                                 tb[SYSUPGRADE_BACKUP] ? blobmsg_get_string(tb[SYSUPGRADE_BACKUP]) : NULL,
@@ -751,6 +869,11 @@ void ubus_init_system(struct ubus_context *ctx)
        int ret;
 
        _ctx = ctx;
+
+       initramfs = !!getenv("INITRAMFS");
+       if (initramfs)
+               unsetenv("INITRAMFS");
+
        ret = ubus_add_object(ctx, &system_object);
        if (ret)
                ERROR("Failed to add object: %s\n", ubus_strerror(ret));