+ if (ret < 0)
+ PARA_CRIT_LOG("%s\n", para_strerror(-ret));
+ return 0;
+}
+
+static int command_post_select(struct sched *s, void *context)
+{
+ struct server_command_task *sct = context;
+ unsigned n;
+ int ret;
+
+ ret = task_get_notification(sct->task);
+ if (ret < 0)
+ return ret;
+ for (n = 0; n < sct->num_listen_fds; n++) {
+ ret = command_task_accept(n, s, sct);
+ if (ret < 0) {
+ free(sct->listen_fds);
+ return ret;
+ }
+ }
+ return 0;
+}
+
+static void init_server_command_task(struct server_command_task *sct,
+ int argc, char **argv)
+{
+ int ret;
+ unsigned n;
+ uint32_t port = OPT_UINT32_VAL(PORT);
+
+ PARA_NOTICE_LOG("initializing tcp command socket\n");
+ sct->child_fd = -1;
+ sct->argc = argc;
+ sct->argv = argv;
+ if (!OPT_GIVEN(LISTEN_ADDRESS)) {
+ sct->num_listen_fds = 1;
+ sct->listen_fds = para_malloc(sizeof(int));
+ ret = para_listen_simple(IPPROTO_TCP, port);
+ if (ret < 0)
+ goto err;
+ sct->listen_fds[0] = ret;
+ } else {
+ sct->num_listen_fds = OPT_GIVEN(LISTEN_ADDRESS);
+ sct->listen_fds = para_malloc(sct->num_listen_fds * sizeof(int));
+ for (n = 0; n < OPT_GIVEN(LISTEN_ADDRESS); n++) {
+ const char *arg;
+ arg = lls_string_val(n, OPT_RESULT(LISTEN_ADDRESS));
+ ret = para_listen(IPPROTO_TCP, arg, port);
+ if (ret < 0)
+ goto err;
+ sct->listen_fds[n] = ret;
+ }
+ }
+ for (n = 0; n < sct->num_listen_fds; n++) {
+ ret = mark_fd_nonblocking(sct->listen_fds[n]);
+ if (ret < 0)
+ goto err;
+ /* child doesn't need the listener */
+ add_close_on_fork_list(sct->listen_fds[n]);
+ }
+
+ sct->task = task_register(&(struct task_info) {
+ .name = "server command",
+ .pre_select = command_pre_select,
+ .post_select = command_post_select,
+ .context = sct,
+ }, &sched);
+ /*
+ * Detect whether the abstract Unix domain socket space is supported,
+ * but do not create the socket. We check this once in server context
+ * so that the command handlers inherit this bit of information and
+ * don't need to check again.
+ */
+ create_local_socket(NULL);
+ return;