/* SPDX-License-Identifier: LGPL-2.1+ */
-/***
- This file is part of systemd.
-
- Copyright 2013 Zbigniew Jędrzejewski-Szmek
-***/
#include <getopt.h>
#include <sys/epoll.h>
#include "sd-daemon.h"
#include "alloc-util.h"
+#include "errno-util.h"
#include "escape.h"
#include "fd-util.h"
#include "log.h"
#include "macro.h"
+#include "pretty-print.h"
#include "process-util.h"
#include "signal-util.h"
#include "socket-util.h"
#include "string-util.h"
#include "strv.h"
+#include "terminal-util.h"
+#include "util.h"
static char** arg_listen = NULL;
static bool arg_accept = false;
except[fd] = fd;
log_close();
- close_all_fds(except, 3 + n);
+ r = close_all_fds(except, 3 + n);
+ if (r < 0)
+ return log_error_errno(r, "Failed to close all file descriptors: %m");
}
/** Note: we leak some fd's on error here. I doesn't matter
return count;
}
-static int exec_process(const char* name, char **argv, char **env, int start_fd, int n_fds) {
+static int exec_process(const char* name, char **argv, char **env, int start_fd, size_t n_fds) {
_cleanup_strv_free_ char **envp = NULL;
_cleanup_free_ char *joined = NULL;
- unsigned n_env = 0, length;
+ size_t n_env = 0, length;
const char *tocopy;
char **s;
int r;
- if (arg_inetd && n_fds != 1) {
- log_error("--inetd only supported for single file descriptors.");
- return -EINVAL;
- }
+ if (arg_inetd && n_fds != 1)
+ return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
+ "--inetd only supported for single file descriptors.");
length = strv_length(arg_setenv);
start_fd = SD_LISTEN_FDS_START;
}
- if (asprintf((char**)(envp + n_env++), "LISTEN_FDS=%i", n_fds) < 0)
+ if (asprintf((char**)(envp + n_env++), "LISTEN_FDS=%zu", n_fds) < 0)
return log_oom();
if (asprintf((char**)(envp + n_env++), "LISTEN_PID=" PID_FMT, getpid_cached()) < 0)
_cleanup_free_ char *names = NULL;
size_t len;
char *e;
- int i;
len = strv_length(arg_fdnames);
- if (len == 1)
+ if (len == 1) {
+ size_t i;
+
for (i = 1; i < n_fds; i++) {
r = strv_extend(&arg_fdnames, arg_fdnames[0]);
if (r < 0)
return log_error_errno(r, "Failed to extend strv: %m");
}
- else if (len != (unsigned) n_fds)
- log_warning("The number of fd names is different than number of fds: %zu vs %d",
- len, n_fds);
+ } else if (len != n_fds)
+ log_warning("The number of fd names is different than number of fds: %zu vs %zu", len, n_fds);
names = strv_join(arg_fdnames, ":");
if (!names)
if (!joined)
return log_oom();
- r = safe_fork("(activate)", FORK_RESET_SIGNALS|FORK_DEATHSIG|FORK_LOG, &child_pid);
+ r = safe_fork("(activate)", FORK_RESET_SIGNALS|FORK_DEATHSIG|FORK_RLIMIT_NOFILE_SAFE|FORK_LOG, &child_pid);
if (r < 0)
return r;
if (r == 0) {
_cleanup_close_ int fd_accepted = -1;
fd_accepted = accept4(fd, NULL, NULL, 0);
- if (fd_accepted < 0)
+ if (fd_accepted < 0) {
+ if (ERRNO_IS_ACCEPT_AGAIN(errno))
+ return 0;
+
return log_error_errno(errno, "Failed to accept connection on fd:%d: %m", fd);
+ }
- getsockname_pretty(fd_accepted, &local);
- getpeername_pretty(fd_accepted, true, &peer);
+ (void) getsockname_pretty(fd_accepted, &local);
+ (void) getpeername_pretty(fd_accepted, true, &peer);
log_info("Connection from %s to %s", strna(peer), strna(local));
return fork_and_exec_process(name, argv, envp, fd_accepted);
return 0;
}
-static void help(void) {
+static int help(void) {
+ _cleanup_free_ char *link = NULL;
+ int r;
+
+ r = terminal_urlify_man("systemd-socket-activate", "1", &link);
+ if (r < 0)
+ return log_oom();
+
printf("%s [OPTIONS...]\n\n"
"Listen on sockets and launch child on connection.\n\n"
"Options:\n"
" -E --setenv=NAME[=VALUE] Pass an environment variable to children\n"
" --fdname=NAME[:NAME...] Specify names for file descriptors\n"
" --inetd Enable inetd file descriptor passing protocol\n"
- "\n"
- "Note: file descriptors from sd_listen_fds() will be passed through.\n"
- , program_invocation_short_name);
+ "\nNote: file descriptors from sd_listen_fds() will be passed through.\n"
+ "\nSee the %s for details.\n"
+ , program_invocation_short_name
+ , link
+ );
+
+ return 0;
}
static int parse_argv(int argc, char *argv[]) {
while ((c = getopt_long(argc, argv, "+hl:aE:d", options, NULL)) >= 0)
switch(c) {
case 'h':
- help();
- return 0;
+ return help();
case ARG_VERSION:
return version();
break;
case 'd':
- if (arg_socket_type == SOCK_SEQPACKET) {
- log_error("--datagram may not be combined with --seqpacket.");
- return -EINVAL;
- }
+ if (arg_socket_type == SOCK_SEQPACKET)
+ return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
+ "--datagram may not be combined with --seqpacket.");
arg_socket_type = SOCK_DGRAM;
break;
case ARG_SEQPACKET:
- if (arg_socket_type == SOCK_DGRAM) {
- log_error("--seqpacket may not be combined with --datagram.");
- return -EINVAL;
- }
+ if (arg_socket_type == SOCK_DGRAM)
+ return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
+ "--seqpacket may not be combined with --datagram.");
arg_socket_type = SOCK_SEQPACKET;
break;
assert_not_reached("Unhandled option");
}
- if (optind == argc) {
- log_error("%s: command to execute is missing.",
- program_invocation_short_name);
- return -EINVAL;
- }
+ if (optind == argc)
+ return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
+ "%s: command to execute is missing.",
+ program_invocation_short_name);
- if (arg_socket_type == SOCK_DGRAM && arg_accept) {
- log_error("Datagram sockets do not accept connections. "
- "The --datagram and --accept options may not be combined.");
- return -EINVAL;
- }
+ if (arg_socket_type == SOCK_DGRAM && arg_accept)
+ return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
+ "Datagram sockets do not accept connections. "
+ "The --datagram and --accept options may not be combined.");
arg_args = argv + optind;
break;
}
- exec_process(argv[optind], argv + optind, envp, SD_LISTEN_FDS_START, n);
+ exec_process(argv[optind], argv + optind, envp, SD_LISTEN_FDS_START, (size_t) n);
return EXIT_SUCCESS;
}