]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
core: Add socket type for usb functionfs endpoints
authorPawel Szewczyk <p.szewczyk@samsung.com>
Mon, 21 Sep 2015 13:43:47 +0000 (15:43 +0200)
committerPawel Szewczyk <p.szewczyk@samsung.com>
Tue, 22 Sep 2015 14:32:16 +0000 (16:32 +0200)
For handling functionfs endpoints additional socket type is added.

src/core/dbus-socket.c
src/core/load-fragment-gperf.gperf.m4
src/core/socket.c
src/core/socket.h

index 02599a9e55e5cee8acca71a997215760e4991f3a..86732e2a4554697581ef09cb8316d897c9718bdd 100644 (file)
@@ -68,6 +68,7 @@ static int property_get_listen(
                         case SOCKET_SPECIAL:
                         case SOCKET_MQUEUE:
                         case SOCKET_FIFO:
+                        case SOCKET_USB_FUNCTION:
                                 a = p->path;
                                 break;
 
index e056fd863c9379d7ca276440e5d139bf706df0e6..d227f2af022f6ea7fb19c9aacd58a7e0b3913f4d 100644 (file)
@@ -244,6 +244,7 @@ Socket.ListenFIFO,               config_parse_socket_listen,         SOCKET_FIFO
 Socket.ListenNetlink,            config_parse_socket_listen,         SOCKET_SOCKET,                 0
 Socket.ListenSpecial,            config_parse_socket_listen,         SOCKET_SPECIAL,                0
 Socket.ListenMessageQueue,       config_parse_socket_listen,         SOCKET_MQUEUE,                 0
+Socket.ListenUSBFunction,        config_parse_socket_listen,         SOCKET_USB_FUNCTION,           0
 Socket.BindIPv6Only,             config_parse_socket_bind,           0,                             0,
 Socket.Backlog,                  config_parse_unsigned,              0,                             offsetof(Socket, backlog)
 Socket.BindToDevice,             config_parse_socket_bindtodevice,   0,                             0
index 518c935f96a84ad18ef189a9dfaba1564f64e9e7..d8de58ef156dfde943d1727094e3589338576e9c 100644 (file)
@@ -259,7 +259,7 @@ static int socket_add_mount_links(Socket *s) {
 
                 if (p->type == SOCKET_SOCKET)
                         path = socket_address_get_path(&p->address);
-                else if (p->type == SOCKET_FIFO || p->type == SOCKET_SPECIAL)
+                else if (IN_SET(p->type, SOCKET_FIFO, SOCKET_SPECIAL, SOCKET_USB_FUNCTION))
                         path = p->path;
 
                 if (!path)
@@ -650,6 +650,8 @@ static void socket_dump(Unit *u, FILE *f, const char *prefix) {
                         free(k);
                 } else if (p->type == SOCKET_SPECIAL)
                         fprintf(f, "%sListenSpecial: %s\n", prefix, p->path);
+                else if (p->type == SOCKET_USB_FUNCTION)
+                        fprintf(f, "%sListenUSBFunction: %s\n", prefix, p->path);
                 else if (p->type == SOCKET_MQUEUE)
                         fprintf(f, "%sListenMessageQueue: %s\n", prefix, p->path);
                 else
@@ -1063,6 +1065,33 @@ fail:
         return r;
 }
 
+static int ffs_address_create(
+                const char *path,
+                int *_fd) {
+
+        _cleanup_close_ int fd = -1;
+        struct stat st;
+
+        assert(path);
+        assert(_fd);
+
+        fd = open(path, O_RDWR|O_CLOEXEC|O_NOCTTY|O_NONBLOCK|O_NOFOLLOW);
+        if (fd < 0)
+                return -errno;
+
+        if (fstat(fd, &st) < 0)
+                return -errno;
+
+        /* Check whether this is a regular file (ffs endpoint)*/
+        if (!S_ISREG(st.st_mode))
+                return -EEXIST;
+
+        *_fd = fd;
+        fd = -1;
+
+        return 0;
+}
+
 static int mq_address_create(
                 const char *path,
                 mode_t mq_mode,
@@ -1136,6 +1165,60 @@ static int socket_symlink(Socket *s) {
         return 0;
 }
 
+static int select_ep(const struct dirent *d) {
+        return d->d_name[0] != '.' && !streq(d->d_name, "ep0");
+}
+
+static int ffs_dispatch_eps(SocketPort *p) {
+        _cleanup_free_ struct dirent **ent = NULL;
+        int r, i, n, k;
+        _cleanup_free_ char *path = NULL;
+
+        r = path_get_parent(p->path, &path);
+        if (r < 0)
+                return r;
+
+        r = scandir(path, &ent, select_ep, alphasort);
+        if (r < 0)
+                return -errno;
+
+        n = r;
+        p->auxiliary_fds = new(int, n);
+        if (!p->auxiliary_fds)
+                return -ENOMEM;
+
+        p->n_auxiliary_fds = n;
+
+        k = 0;
+        for (i = 0; i < n; ++i) {
+                _cleanup_free_ char *ep = NULL;
+
+                ep = path_make_absolute(ent[i]->d_name, path);
+                if (!ep)
+                        return -ENOMEM;
+
+                path_kill_slashes(ep);
+
+                r = ffs_address_create(ep, &p->auxiliary_fds[k]);
+                if (r < 0)
+                        goto fail;
+
+                ++k;
+                free(ent[i]);
+        }
+
+        return r;
+
+fail:
+        while (k)
+                safe_close(p->auxiliary_fds[--k]);
+
+        p->auxiliary_fds = mfree(p->auxiliary_fds);
+        p->n_auxiliary_fds = 0;
+
+        return r;
+}
+
 static int socket_open_fds(Socket *s) {
         SocketPort *p;
         int r;
@@ -1232,6 +1315,17 @@ static int socket_open_fds(Socket *s) {
                                         &p->fd);
                         if (r < 0)
                                 goto rollback;
+                } else  if (p->type == SOCKET_USB_FUNCTION) {
+
+                        r = ffs_address_create(
+                                        p->path,
+                                        &p->fd);
+                        if (r < 0)
+                                goto rollback;
+
+                        r = ffs_dispatch_eps(p);
+                        if (r < 0)
+                                goto rollback;
                 } else
                         assert_not_reached("Unknown port type");
         }
@@ -2047,6 +2141,8 @@ static int socket_serialize(Unit *u, FILE *f, FDSet *fds) {
                         unit_serialize_item_format(u, f, "special", "%i %s", copy, p->path);
                 else if (p->type == SOCKET_MQUEUE)
                         unit_serialize_item_format(u, f, "mqueue", "%i %s", copy, p->path);
+                else if (p->type == SOCKET_USB_FUNCTION)
+                        unit_serialize_item_format(u, f, "ffs", "%i %s", copy, p->path);
                 else {
                         assert(p->type == SOCKET_FIFO);
                         unit_serialize_item_format(u, f, "fifo", "%i %s", copy, p->path);
@@ -2196,6 +2292,26 @@ static int socket_deserialize_item(Unit *u, const char *key, const char *value,
                                 p->fd = fdset_remove(fds, fd);
                         }
                 }
+
+        } else if (streq(key, "ffs")) {
+                int fd, skip = 0;
+                SocketPort *p;
+
+                if (sscanf(value, "%i %n", &fd, &skip) < 1 || fd < 0 || !fdset_contains(fds, fd))
+                        log_unit_debug(u, "Failed to parse ffs value: %s", value);
+                else {
+
+                        LIST_FOREACH(port, p, s->ports)
+                                if (p->type == SOCKET_USB_FUNCTION &&
+                                    path_equal_or_files_same(p->path, value+skip))
+                                        break;
+
+                        if (p) {
+                                safe_close(p->fd);
+                                p->fd = fdset_remove(fds, fd);
+                        }
+                }
+
         } else
                 log_unit_debug(UNIT(s), "Unknown serialization key: %s", key);
 
@@ -2278,6 +2394,9 @@ const char* socket_port_type_to_string(SocketPort *p) {
         case SOCKET_FIFO:
                 return "FIFO";
 
+        case SOCKET_USB_FUNCTION:
+                return "USBFunction";
+
         default:
                 return NULL;
         }
index e1046adad4c47b5955cf8f6238c1f036fd7c4a79..286397b41c0950dc820b625583dedceb87d06ad4 100644 (file)
@@ -60,6 +60,7 @@ typedef enum SocketType {
         SOCKET_FIFO,
         SOCKET_SPECIAL,
         SOCKET_MQUEUE,
+        SOCKET_USB_FUNCTION,
         _SOCKET_FIFO_MAX,
         _SOCKET_FIFO_INVALID = -1
 } SocketType;