service: add method to query available container features
authorDaniel Golle <daniel@makrotopia.org>
Wed, 29 Jul 2020 12:49:38 +0000 (13:49 +0100)
committerDaniel Golle <daniel@makrotopia.org>
Thu, 30 Jul 2020 15:40:32 +0000 (16:40 +0100)
Signed-off-by: Daniel Golle <daniel@makrotopia.org>
service/service.c

index c2d072be1802b16679586d647a2f3ee39df3ebc4..cabc69cce783e2e44792e3be2d570de8867a1a59 100644 (file)
 
 #include <sys/types.h>
 #include <sys/stat.h>
+#include <sys/utsname.h>
+#include <sys/types.h>
+#include <fcntl.h>
+
 #include <unistd.h>
+#include <sched.h>
 
 #include <libubox/blobmsg_json.h>
 #include <libubox/avl-cmp.h>
@@ -297,6 +302,97 @@ static inline bool is_container_obj(struct ubus_object *obj)
        return (obj && (strcmp(obj->name, "container") == 0));
 }
 
+static inline void put_namespace(struct blob_buf *b, char *name)
+{
+       char nsfname[32];
+       struct stat statbuf;
+
+       snprintf(nsfname, sizeof(nsfname), "/proc/self/ns/%s", name);
+
+       if (!stat(nsfname, &statbuf))
+               blobmsg_add_string(b, NULL, name);
+}
+
+static void put_cgroups(struct blob_buf *b)
+{
+       int fd, ret;
+       static char buf[512] = "";
+       char *t, *z;
+
+       fd = open("/sys/fs/cgroup/cgroup.controllers", O_RDONLY);
+       if (fd == -1)
+               return;
+
+       ret = read(fd, &buf, sizeof(buf));
+       close(fd);
+
+       if (ret < 2)
+               return;
+
+       t = buf;
+       while(t) {
+               z = t;
+               /* replace space with \0 and direct next entry */
+               t = strchr(z, ' ');
+               if (t) {
+                       *(t++) = '\0';
+               } else { /* replace trailing new-line with \0 */
+                       t = strchr(z, '\n');
+                       if (!t) /* shouldn't happen, but don't segfault if it does */
+                               break;
+
+                       *t = '\0';
+                       t = NULL;
+               }
+               blobmsg_add_string(b, NULL, z);
+       }
+}
+
+static int
+container_handle_features(struct ubus_context *ctx, struct ubus_object *obj,
+                   struct ubus_request_data *req, const char *method,
+                   struct blob_attr *msg)
+{
+       struct utsname utsbuf;
+       struct stat statbuf;
+       void *nsarray, *cgarray;
+
+       if (stat("/sbin/ujail", &statbuf))
+               return UBUS_STATUS_NOT_SUPPORTED;
+
+       if (uname(&utsbuf) < 0)
+               return UBUS_STATUS_UNKNOWN_ERROR;
+
+       blob_buf_init(&b, 0);
+       blobmsg_add_string(&b, "machine", utsbuf.machine);
+
+#ifdef SECCOMP_SUPPORT
+       blobmsg_add_u8(&b, "seccomp", true);
+#else
+       blobmsg_add_u8(&b, "seccomp", false);
+#endif
+
+       cgarray = blobmsg_open_array(&b, "cgroup");
+       put_cgroups(&b);
+       blobmsg_close_array(&b, cgarray);
+
+       nsarray = blobmsg_open_array(&b, "namespaces");
+       put_namespace(&b, "cgroup");
+       put_namespace(&b, "ipc");
+       put_namespace(&b, "mnt");
+       put_namespace(&b, "net");
+       put_namespace(&b, "pid");
+#ifdef CLONE_NEWTIME
+       put_namespace(&b, "time");
+#endif
+       put_namespace(&b, "user");
+       put_namespace(&b, "uts");
+       blobmsg_close_array(&b, nsarray);
+       ubus_send_reply(ctx, req, b.head);
+
+       return UBUS_STATUS_OK;
+}
+
 static int
 service_handle_set(struct ubus_context *ctx, struct ubus_object *obj,
                   struct ubus_request_data *req, const char *method,
@@ -936,6 +1032,7 @@ static struct ubus_method container_object_methods[] = {
        UBUS_METHOD("list", service_handle_list, service_list_attrs),
        UBUS_METHOD("delete", service_handle_delete, service_del_attrs),
        UBUS_METHOD("state", service_handle_state, service_state_attrs),
+       UBUS_METHOD_NOARG("get_features", container_handle_features),
        UBUS_METHOD("console_set", container_handle_console, container_console_policy),
        UBUS_METHOD("console_attach", container_handle_console, container_console_policy),
 };