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)
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
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,
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;
&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");
}
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);
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);
case SOCKET_FIFO:
return "FIFO";
+ case SOCKET_USB_FUNCTION:
+ return "USBFunction";
+
default:
return NULL;
}