From 15087cdbd63312f706f21339489daf210ae609d0 Mon Sep 17 00:00:00 2001 From: Pawel Szewczyk Date: Mon, 21 Sep 2015 16:30:41 +0200 Subject: core: Add list of additional file descriptors to socket port Some additional files related to single socket may appear in the filesystem and they should be opened and passed to related service. This commit adds optional list of file descriptors, which are dynamically discovered and opened. --- src/core/load-fragment.c | 2 ++ src/core/socket.c | 23 ++++++++++++++++++++--- src/core/socket.h | 2 ++ 3 files changed, 24 insertions(+), 3 deletions(-) diff --git a/src/core/load-fragment.c b/src/core/load-fragment.c index b476d472b3..b8cdde3bff 100644 --- a/src/core/load-fragment.c +++ b/src/core/load-fragment.c @@ -381,6 +381,8 @@ int config_parse_socket_listen(const char *unit, } p->fd = -1; + p->auxiliary_fds = NULL; + p->n_auxiliary_fds = 0; p->socket = s; if (s->ports) { diff --git a/src/core/socket.c b/src/core/socket.c index 9db42a0333..518c935f96 100644 --- a/src/core/socket.c +++ b/src/core/socket.c @@ -104,6 +104,16 @@ static void socket_unwatch_control_pid(Socket *s) { s->control_pid = 0; } +static void socket_cleanup_fd_list(SocketPort *p) { + int k = p->n_auxiliary_fds; + + while (k--) + safe_close(p->auxiliary_fds[k]); + + p->auxiliary_fds = mfree(p->auxiliary_fds); + p->n_auxiliary_fds = 0; +} + void socket_free_ports(Socket *s) { SocketPort *p; @@ -114,6 +124,7 @@ void socket_free_ports(Socket *s) { sd_event_source_unref(p->event_source); + socket_cleanup_fd_list(p); safe_close(p->fd); free(p->path); free(p); @@ -775,6 +786,7 @@ static void socket_close_fds(Socket *s) { continue; p->fd = safe_close(p->fd); + socket_cleanup_fd_list(p); /* One little note: we should normally not delete any * sockets in the file system here! After all some @@ -2297,7 +2309,6 @@ static int socket_dispatch_io(sd_event_source *source, int fd, uint32_t revents, log_unit_error(UNIT(p->socket), "Got POLLHUP on a listening socket. The service probably invoked shutdown() on it, and should better not do that."); else log_unit_error(UNIT(p->socket), "Got unexpected poll event (0x%x) on socket.", revents); - goto fail; } @@ -2496,6 +2507,7 @@ static int socket_dispatch_timer(sd_event_source *source, usec_t usec, void *use int socket_collect_fds(Socket *s, int **fds, unsigned *n_fds) { int *rfds; unsigned rn_fds, k; + int i; SocketPort *p; assert(s); @@ -2505,9 +2517,11 @@ int socket_collect_fds(Socket *s, int **fds, unsigned *n_fds) { /* Called from the service code for requesting our fds */ rn_fds = 0; - LIST_FOREACH(port, p, s->ports) + LIST_FOREACH(port, p, s->ports) { if (p->fd >= 0) rn_fds++; + rn_fds += p->n_auxiliary_fds; + } if (rn_fds <= 0) { *fds = NULL; @@ -2520,9 +2534,12 @@ int socket_collect_fds(Socket *s, int **fds, unsigned *n_fds) { return -ENOMEM; k = 0; - LIST_FOREACH(port, p, s->ports) + LIST_FOREACH(port, p, s->ports) { if (p->fd >= 0) rfds[k++] = p->fd; + for (i = 0; i < p->n_auxiliary_fds; ++i) + rfds[k++] = p->auxiliary_fds[i]; + } assert(k == rn_fds); diff --git a/src/core/socket.h b/src/core/socket.h index fa3ebdafa0..e1046adad4 100644 --- a/src/core/socket.h +++ b/src/core/socket.h @@ -81,6 +81,8 @@ typedef struct SocketPort { SocketType type; int fd; + int *auxiliary_fds; + int n_auxiliary_fds; SocketAddress address; char *path; -- cgit v1.2.3-54-g00ecf From 602524469ecd7db0e0d5a71ecd1dce34f7a108b6 Mon Sep 17 00:00:00 2001 From: Pawel Szewczyk Date: Mon, 21 Sep 2015 15:43:47 +0200 Subject: core: Add socket type for usb functionfs endpoints For handling functionfs endpoints additional socket type is added. --- src/core/dbus-socket.c | 1 + src/core/load-fragment-gperf.gperf.m4 | 1 + src/core/socket.c | 121 +++++++++++++++++++++++++++++++++- src/core/socket.h | 1 + 4 files changed, 123 insertions(+), 1 deletion(-) diff --git a/src/core/dbus-socket.c b/src/core/dbus-socket.c index 02599a9e55..86732e2a45 100644 --- a/src/core/dbus-socket.c +++ b/src/core/dbus-socket.c @@ -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; diff --git a/src/core/load-fragment-gperf.gperf.m4 b/src/core/load-fragment-gperf.gperf.m4 index e056fd863c..d227f2af02 100644 --- a/src/core/load-fragment-gperf.gperf.m4 +++ b/src/core/load-fragment-gperf.gperf.m4 @@ -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 diff --git a/src/core/socket.c b/src/core/socket.c index 518c935f96..d8de58ef15 100644 --- a/src/core/socket.c +++ b/src/core/socket.c @@ -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; } diff --git a/src/core/socket.h b/src/core/socket.h index e1046adad4..286397b41c 100644 --- a/src/core/socket.h +++ b/src/core/socket.h @@ -60,6 +60,7 @@ typedef enum SocketType { SOCKET_FIFO, SOCKET_SPECIAL, SOCKET_MQUEUE, + SOCKET_USB_FUNCTION, _SOCKET_FIFO_MAX, _SOCKET_FIFO_INVALID = -1 } SocketType; -- cgit v1.2.3-54-g00ecf From 6b7e59231014b94636f4a1b730143fbe6f60c3f4 Mon Sep 17 00:00:00 2001 From: Pawel Szewczyk Date: Fri, 4 Sep 2015 12:23:51 +0200 Subject: core: Add FFSDescriptors and FFSStrings service parameters By using these parameters functionfs service can specify ffs descriptors and strings which should be written to ep0. --- src/core/dbus-service.c | 2 ++ src/core/load-fragment-gperf.gperf.m4 | 2 ++ src/core/service.c | 6 ++++++ src/core/service.h | 3 +++ src/core/socket.c | 21 +++++++++++++++++++++ 5 files changed, 34 insertions(+) diff --git a/src/core/dbus-service.c b/src/core/dbus-service.c index e1f3d56495..3436342bef 100644 --- a/src/core/dbus-service.c +++ b/src/core/dbus-service.c @@ -62,6 +62,8 @@ const sd_bus_vtable bus_service_vtable[] = { SD_BUS_PROPERTY("StatusText", "s", NULL, offsetof(Service, status_text), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE), SD_BUS_PROPERTY("StatusErrno", "i", NULL, offsetof(Service, status_errno), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE), SD_BUS_PROPERTY("Result", "s", property_get_result, offsetof(Service, result), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE), + SD_BUS_PROPERTY("USBFunctionDescriptors", "s", NULL, offsetof(Service, usb_function_descriptors), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE), + SD_BUS_PROPERTY("USBFunctionStrings", "s", NULL, offsetof(Service, usb_function_strings), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE), BUS_EXEC_STATUS_VTABLE("ExecMain", offsetof(Service, main_exec_status), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE), BUS_EXEC_COMMAND_LIST_VTABLE("ExecStartPre", offsetof(Service, exec_command[SERVICE_EXEC_START_PRE]), SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION), BUS_EXEC_COMMAND_LIST_VTABLE("ExecStart", offsetof(Service, exec_command[SERVICE_EXEC_START]), SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION), diff --git a/src/core/load-fragment-gperf.gperf.m4 b/src/core/load-fragment-gperf.gperf.m4 index d227f2af02..69e8d7a4d4 100644 --- a/src/core/load-fragment-gperf.gperf.m4 +++ b/src/core/load-fragment-gperf.gperf.m4 @@ -233,6 +233,8 @@ Service.FileDescriptorStoreMax, config_parse_unsigned, 0, Service.NotifyAccess, config_parse_notify_access, 0, offsetof(Service, notify_access) Service.Sockets, config_parse_service_sockets, 0, 0 Service.BusPolicy, config_parse_bus_endpoint_policy, 0, offsetof(Service, exec_context) +Service.USBFunctionDescriptors, config_parse_path, 0, offsetof(Service, usb_function_descriptors) +Service.USBFunctionStrings, config_parse_path, 0, offsetof(Service, usb_function_strings) EXEC_CONTEXT_CONFIG_ITEMS(Service)m4_dnl CGROUP_CONTEXT_CONFIG_ITEMS(Service)m4_dnl KILL_CONTEXT_CONFIG_ITEMS(Service)m4_dnl diff --git a/src/core/service.c b/src/core/service.c index fc28ba4d07..f7de5e89ff 100644 --- a/src/core/service.c +++ b/src/core/service.c @@ -482,6 +482,12 @@ static int service_verify(Service *s) { return -EINVAL; } + if (s->usb_function_descriptors && !s->usb_function_strings) + log_unit_warning(UNIT(s), "Service has USBFunctionDescriptors= setting, but no USBFunctionStrings=. Ignoring."); + + if (!s->usb_function_descriptors && s->usb_function_strings) + log_unit_warning(UNIT(s), "Service has USBFunctionStrings= setting, but no USBFunctionDescriptors=. Ignoring."); + return 0; } diff --git a/src/core/service.h b/src/core/service.h index 7da0a93961..789dff23a9 100644 --- a/src/core/service.h +++ b/src/core/service.h @@ -212,6 +212,9 @@ struct Service { ServiceFDStore *fd_store; unsigned n_fd_store; unsigned n_fd_store_max; + + char *usb_function_descriptors; + char *usb_function_strings; }; extern const UnitVTable service_vtable; diff --git a/src/core/socket.c b/src/core/socket.c index d8de58ef15..54e94c4f74 100644 --- a/src/core/socket.c +++ b/src/core/socket.c @@ -50,6 +50,7 @@ #include "formats-util.h" #include "signal-util.h" #include "socket.h" +#include "copy.h" static const UnitActiveState state_translation_table[_SOCKET_STATE_MAX] = { [SOCKET_DEAD] = UNIT_INACTIVE, @@ -1165,6 +1166,22 @@ static int socket_symlink(Socket *s) { return 0; } +static int ffs_write_descs(int fd, Unit *u) { + Service *s = SERVICE(u); + int r; + + if (!s->usb_function_descriptors || !s->usb_function_strings) + return -EINVAL; + + r = copy_file_fd(s->usb_function_descriptors, fd, false); + if (r < 0) + return 0; + + r = copy_file_fd(s->usb_function_strings, fd, false); + + return r; +} + static int select_ep(const struct dirent *d) { return d->d_name[0] != '.' && !streq(d->d_name, "ep0"); } @@ -1323,6 +1340,10 @@ static int socket_open_fds(Socket *s) { if (r < 0) goto rollback; + r = ffs_write_descs(p->fd, s->service.unit); + if (r < 0) + goto rollback; + r = ffs_dispatch_eps(p); if (r < 0) goto rollback; -- cgit v1.2.3-54-g00ecf From 8c7c98398bad362cfae7b5a239cca11b93a67710 Mon Sep 17 00:00:00 2001 From: Pawel Szewczyk Date: Fri, 4 Sep 2015 12:23:54 +0200 Subject: man: Add documentation for functionfs socket activation --- man/systemd.service.xml | 16 ++++++++++++++++ man/systemd.socket.xml | 11 +++++++++++ 2 files changed, 27 insertions(+) diff --git a/man/systemd.service.xml b/man/systemd.service.xml index 4c113a3479..642d95a029 100644 --- a/man/systemd.service.xml +++ b/man/systemd.service.xml @@ -903,6 +903,22 @@ and no job queued or being executed for it. + + USBFunctionDescriptors= + Configure the location of file containing + FunctionFS descriptors. This is is used only when socket with + ListenUSBFunction line want to activate this service. Content of + this file is writen to ep0 file after it is opened. This is required + for socket activation using ListenUSBFunction + (i.e. for passing all ffs endpoints to service). + + + + USBFunctionStrings= + Configure the location of file containing FunctionFS strings. + Behavior is similar to USBFunctionDescriptors. + + Check diff --git a/man/systemd.socket.xml b/man/systemd.socket.xml index 36fa3a86be..7f884aa1be 100644 --- a/man/systemd.socket.xml +++ b/man/systemd.socket.xml @@ -260,6 +260,17 @@ can be inherited between processes. + + ListenUSBFunction= + Specifies a functionfs endpoint location + to listen on. This expects an absolute file system path as + argument. Behavior otherwise is very similar to the + ListenFIFO= directive above. Use this to + open functionfs endpoint ep0. When using this option, activated + service has to have USBFunctionDescriptors + and USBFunctionStrings options set. + + BindIPv6Only= Takes a one of , -- cgit v1.2.3-54-g00ecf