2 * Copyright (C) 2013-2020 Red Hat Inc.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
8 * * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
11 * * Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
15 * * Neither the name of Red Hat nor the names of its contributors may be
16 * used to endorse or promote products derived from this software without
17 * specific prior written permission.
19 * THIS SOFTWARE IS PROVIDED BY RED HAT AND CONTRIBUTORS ''AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
21 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
22 * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL RED HAT OR
23 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
26 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
27 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
28 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
29 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
45 #include <sys/types.h>
48 #ifdef HAVE_SYS_MMAN_H
52 #ifdef HAVE_SYS_SOCKET_H
53 #include <sys/socket.h>
56 #ifdef HAVE_LINUX_VM_SOCKETS_H
57 #include <linux/vm_sockets.h>
58 #elif HAVE_SYS_VSOCK_H
59 #include <sys/vsock.h>
66 #include "ascii-string.h"
67 #include "exit-with-parent.h"
68 #include "nbd-protocol.h"
77 #ifdef ENABLE_LIBFUZZER
78 #define main fuzzer_main
81 static char *make_random_fifo (void);
82 static struct backend
*open_plugin_so (size_t i
, const char *filename
, int short_name
);
83 static struct backend
*open_filter_so (struct backend
*next
, size_t i
, const char *filename
, int short_name
);
84 static void start_serving (void);
85 static void write_pidfile (void);
86 static bool is_config_key (const char *key
, size_t len
);
87 static void error_if_stdio_closed (void);
88 static void switch_stdio (void);
89 static void winsock_init (void);
91 int tcpip_sock_af
= AF_UNSPEC
; /* -4, -6 */
92 struct debug_flag
*debug_flags
; /* -D */
93 bool exit_with_parent
; /* --exit-with-parent */
94 const char *export_name
; /* -e */
95 bool foreground
; /* -f */
96 const char *ipaddr
; /* -i */
97 enum log_to log_to
= LOG_TO_DEFAULT
; /* --log */
98 unsigned mask_handshake
= ~0U; /* --mask-handshake */
99 bool newstyle
= true; /* false = -o, true = -n */
100 bool no_sr
; /* --no-sr */
101 char *pidfile
; /* -P */
102 const char *port
; /* -p */
103 bool read_only
; /* -r */
104 const char *run
; /* --run */
105 bool listen_stdin
; /* -s */
106 const char *selinux_label
; /* --selinux-label */
107 bool swap
; /* --swap */
108 unsigned threads
; /* -t */
109 int tls
; /* --tls : 0=off 1=on 2=require */
110 const char *tls_certificates_dir
; /* --tls-certificates */
111 const char *tls_psk
; /* --tls-psk */
112 bool tls_verify_peer
; /* --tls-verify-peer */
113 char *unixsocket
; /* -U */
114 const char *user
, *group
; /* -u & -g */
115 bool verbose
; /* -v */
116 bool vsock
; /* --vsock */
117 unsigned int socket_activation
; /* $LISTEN_FDS and $LISTEN_PID set */
118 bool configured
; /* .config_complete done */
119 int saved_stdin
= -1; /* dup'd stdin during -s/--run */
120 int saved_stdout
= -1; /* dup'd stdout during -s/--run */
122 /* The linked list of zero or more filters, and one plugin. */
125 static char *random_fifo_dir
= NULL
;
126 static char *random_fifo
= NULL
;
131 /* --{short,long}-options remain undocumented */
132 const char *opt_list
=
133 #include "synopsis.c"
135 printf ("%s\n", opt_list
);
136 printf ("Please read the nbdkit(1) manual page for full usage.\n");
140 display_version (void)
142 if (strcmp (NBDKIT_VERSION_EXTRA
, "") == 0)
143 printf ("%s %s\n", PACKAGE_NAME
, PACKAGE_VERSION
);
145 printf ("%s %s (%s)\n",
146 PACKAGE_NAME
, PACKAGE_VERSION
, NBDKIT_VERSION_EXTRA
);
152 CLEANUP_FREE
char *binary
= NULL
;
155 binary
= realpath ("/proc/self/exe", NULL
);
158 /* GetModuleFileNameA has a crappy interface that prevents us from
159 * getting the length of the path so we just have to guess at an
160 * upper limit here. It will at least truncate it properly with \0.
161 * _get_pgmptr would be a better alternative except that it isn't
162 * implemented in MinGW. XXX
164 binary
= malloc (256);
165 if (!GetModuleFileNameA (NULL
, binary
, 256)) {
173 printf ("%s=%s\n", "binary", binary
);
174 printf ("%s=%s\n", "bindir", bindir
);
175 printf ("%s=%s\n", "filterdir", filterdir
);
176 printf ("%s=%s\n", "host_cpu", host_cpu
);
177 printf ("%s=%s\n", "host_os", host_os
);
178 printf ("%s=%s\n", "libdir", libdir
);
179 printf ("%s=%s\n", "mandir", mandir
);
180 printf ("%s=%s\n", "name", PACKAGE_NAME
);
181 printf ("%s=%s\n", "plugindir", plugindir
);
182 printf ("%s=%s\n", "root_tls_certificates_dir", root_tls_certificates_dir
);
183 printf ("%s=%s\n", "sbindir", sbindir
);
184 #ifdef HAVE_LIBSELINUX
185 printf ("selinux=yes\n");
187 printf ("selinux=no\n");
189 printf ("%s=%s\n", "sysconfdir", sysconfdir
);
191 printf ("tls=yes\n");
195 printf ("%s=%s\n", "version", PACKAGE_VERSION
);
196 if (strcmp (NBDKIT_VERSION_EXTRA
, "") != 0)
197 printf ("%s=%s\n", "version_extra", NBDKIT_VERSION_EXTRA
);
198 printf ("%s=%d\n", "version_major", NBDKIT_VERSION_MAJOR
);
199 printf ("%s=%d\n", "version_minor", NBDKIT_VERSION_MINOR
);
201 printf ("zstd=yes\n");
203 printf ("zstd=no\n");
208 main (int argc
, char *argv
[])
211 bool help
= false, version
= false, dump_plugin
= false;
212 int tls_set_on_cli
= false;
214 const char *filename
;
216 static struct filter_filename
{
217 struct filter_filename
*next
;
218 const char *filename
;
219 } *filter_filenames
= NULL
;
221 const char *magic_config_key
;
223 error_if_stdio_closed ();
226 #if !ENABLE_LIBFUZZER
229 static bool main_called
= false;
236 /* The default setting for TLS depends on whether we were
237 * compiled with GnuTLS.
245 /* Returns 0 if no socket activation, or the number of FDs. */
246 socket_activation
= get_socket_activation ();
249 c
= getopt_long (argc
, argv
, short_options
, long_options
, NULL
);
254 case DUMP_CONFIG_OPTION
:
258 case DUMP_PLUGIN_OPTION
:
262 case EXIT_WITH_PARENT_OPTION
:
263 #ifdef HAVE_EXIT_WITH_PARENT
264 exit_with_parent
= true;
269 "%s: --exit-with-parent is not implemented "
270 "for this operating system\n",
277 struct filter_filename
*t
;
279 t
= malloc (sizeof *t
);
284 t
->next
= filter_filenames
;
285 t
->filename
= optarg
;
286 filter_filenames
= t
;
291 if (strcmp (optarg
, "stderr") == 0)
292 log_to
= LOG_TO_STDERR
;
293 else if (strcmp (optarg
, "syslog") == 0)
294 log_to
= LOG_TO_SYSLOG
;
295 else if (strcmp (optarg
, "null") == 0)
296 log_to
= LOG_TO_NULL
;
298 fprintf (stderr
, "%s: "
299 "--log must be \"stderr\", \"syslog\" or \"null\"\n",
305 case LONG_OPTIONS_OPTION
:
306 for (i
= 0; long_options
[i
].name
!= NULL
; ++i
) {
307 if (strcmp (long_options
[i
].name
, "long-options") != 0 &&
308 strcmp (long_options
[i
].name
, "short-options") != 0)
309 printf ("--%s\n", long_options
[i
].name
);
314 if (socket_activation
) {
315 fprintf (stderr
, "%s: cannot use socket activation with --run flag\n",
323 case SELINUX_LABEL_OPTION
:
324 selinux_label
= optarg
;
327 case SHORT_OPTIONS_OPTION
:
328 for (i
= 0; short_options
[i
]; ++i
) {
329 if (short_options
[i
] != ':')
330 printf ("-%c\n", short_options
[i
]);
339 tls_set_on_cli
= true;
340 if (ascii_strcasecmp (optarg
, "require") == 0 ||
341 ascii_strcasecmp (optarg
, "required") == 0 ||
342 ascii_strcasecmp (optarg
, "force") == 0)
345 tls
= nbdkit_parse_bool (optarg
);
351 case TLS_CERTIFICATES_OPTION
:
352 tls_certificates_dir
= optarg
;
359 case TLS_VERIFY_PEER_OPTION
:
360 tls_verify_peer
= true;
364 #if defined(AF_VSOCK) && defined(VMADDR_CID_ANY)
368 fprintf (stderr
, "%s: AF_VSOCK is not supported on this platform\n",
374 tcpip_sock_af
= AF_INET
;
378 tcpip_sock_af
= AF_INET6
;
382 add_debug_flag (optarg
);
386 export_name
= optarg
;
398 if (socket_activation
) {
399 fprintf (stderr
, "%s: cannot use socket activation with -i flag\n",
406 case MASK_HANDSHAKE_OPTION
:
407 if (nbdkit_parse_unsigned ("mask-handshake",
408 optarg
, &mask_handshake
) == -1)
425 pidfile
= nbdkit_absolute_path (optarg
);
431 if (socket_activation
) {
432 fprintf (stderr
, "%s: cannot use socket activation with -p flag\n",
444 if (socket_activation
) {
445 fprintf (stderr
, "%s: cannot use socket activation with -s flag\n",
451 /* This could be implemented with a bit of work. The problem
452 * currently is that we try to use recv() on the stdio file
453 * descriptor which winsock does not support (nor Linux in
454 * fact). We would need to implement a test to see if the file
455 * descriptor is a socket or not and use either read or recv as
458 NOT_IMPLEMENTED_ON_WINDOWS ("-s");
463 if (nbdkit_parse_unsigned ("threads", optarg
, &threads
) == -1)
465 /* XXX Worth a maximimum limit on threads? */
469 if (socket_activation
) {
470 fprintf (stderr
, "%s: cannot use socket activation with -U flag\n",
474 if (strcmp (optarg
, "-") == 0)
475 unixsocket
= make_random_fifo ();
477 unixsocket
= nbdkit_absolute_path (optarg
);
478 if (unixsocket
== NULL
)
504 /* No extra parameters. */
505 if (optind
>= argc
) {
515 /* Incorrect use of --dump-plugin. */
517 "%s: use 'nbdkit plugin --dump-plugin' or\n"
518 "'nbdkit /path/to/plugin." SOEXT
" --dump-plugin' or\n"
519 "if you want to find out about the server use --dump-config\n",
524 /* Otherwise this is an error. */
526 "%s: no plugins given on the command line.\n"
527 "Use '%s --help' or "
528 "read the nbdkit(1) manual page for documentation.\n",
529 program_name
, program_name
);
533 /* --tls=require and oldstyle won't work. */
534 if (tls
== 2 && !newstyle
) {
536 "%s: cannot use oldstyle protocol (-o) and require TLS\n",
541 /* Set the umask to a known value. This makes the behaviour of
542 * plugins when creating files more predictable, and also removes an
543 * implicit dependency on umask when calling mkstemp(3).
547 /* If we will or might use syslog. */
548 if (log_to
== LOG_TO_SYSLOG
|| log_to
== LOG_TO_DEFAULT
)
549 openlog (program_name
, LOG_PID
, 0);
551 /* Print the version in debug output, right after syslog initialization. */
552 if (strcmp (NBDKIT_VERSION_EXTRA
, "") == 0)
553 debug ("%s %s", PACKAGE_NAME
, PACKAGE_VERSION
);
555 debug ("%s %s (%s)", PACKAGE_NAME
, PACKAGE_VERSION
, NBDKIT_VERSION_EXTRA
);
557 /* Initialize TLS. */
558 crypto_init (tls_set_on_cli
);
561 /* Implement --exit-with-parent early in case plugin initialization
562 * takes a long time and the parent exits during that time.
564 #ifdef HAVE_EXIT_WITH_PARENT
565 if (exit_with_parent
) {
566 if (set_exit_with_parent () == -1) {
567 perror ("nbdkit: --exit-with-parent");
573 /* If the user has mixed up -p/--run/-s/-U/--vsock options, then
576 * XXX Actually the server could easily be extended to handle both
577 * TCP/IP and Unix sockets, or even multiple TCP/IP ports.
579 if ((port
&& unixsocket
) ||
580 (port
&& listen_stdin
) ||
581 (unixsocket
&& listen_stdin
) ||
582 (listen_stdin
&& run
) ||
583 (listen_stdin
&& dump_plugin
) ||
584 (vsock
&& unixsocket
) ||
585 (vsock
&& listen_stdin
)) {
587 "%s: --dump-plugin, -p, --run, -s, -U or --vsock options "
588 "cannot be used in this combination\n",
593 /* The remaining command line arguments are the plugin name and
594 * parameters. If --help, --version or --dump-plugin were specified
595 * then we open the plugin so that we can display the per-plugin
596 * help/version/plugin information.
598 filename
= argv
[optind
++];
599 short_name
= is_short_name (filename
);
601 /* Is there an executable script located in the plugindir?
602 * If so we simply execute it with the current command line.
606 CLEANUP_FREE
char *script
;
608 if (asprintf (&script
,
609 "%s/nbdkit-%s-plugin", plugindir
, filename
) == -1) {
614 if (stat (script
, &statbuf
) == 0 &&
615 (statbuf
.st_mode
& S_IXUSR
) != 0) {
616 /* We're going to execute the plugin directly.
617 * Replace argv[0] with argv[optind-1] and move further arguments
620 argv
[0] = argv
[optind
-1];
621 for (i
= optind
; i
<= argc
; i
++)
623 execv (script
, argv
);
629 /* Open the plugin (first) and then wrap the plugin with the
630 * filters. The filters are wrapped in reverse order that they
631 * appear on the command line so that in the end ‘top’ points to
632 * the first filter on the command line.
634 top
= open_plugin_so (0, filename
, short_name
);
636 while (filter_filenames
) {
637 struct filter_filename
*t
= filter_filenames
;
639 filename
= t
->filename
;
640 short_name
= is_short_name (filename
);
642 top
= open_filter_so (top
, i
++, filename
, short_name
);
644 filter_filenames
= t
->next
;
648 /* Apply nbdkit.* flags for the server. */
649 apply_debug_flags (RTLD_DEFAULT
, "nbdkit");
651 /* Check all debug flags were used, and free them. */
658 for_each_backend (b
) {
671 for_each_backend (b
) {
672 printf ("%s", b
->name
);
673 if ((v
= b
->version (b
)) != NULL
)
681 /* Call config and config_complete to parse the parameters.
683 * If the plugin provides magic_config_key then any "bare" values
684 * (ones not containing "=") are prefixed with this key.
686 * For backwards compatibility with old plugins, and to support
687 * scripting languages, if magic_config_key == NULL then if the
688 * first parameter is bare it is prefixed with the key "script", and
689 * any other bare parameters are errors.
691 * Keys must live for the life of nbdkit. Since we want to avoid
692 * modifying argv (so that /proc/PID/cmdline remains sane) but we
693 * need to create a key from argv[i] = "key=value" we must intern
694 * the keys, which are then freed at the end of main().
696 magic_config_key
= top
->magic_config_key (top
);
697 for (i
= 0; optind
< argc
; ++i
, ++optind
) {
700 p
= strchr (argv
[optind
], '=');
701 n
= p
- argv
[optind
];
702 if (p
&& is_config_key (argv
[optind
], n
)) { /* Is it key=value? */
703 const char *key
= nbdkit_strndup_intern (argv
[optind
], n
);
706 top
->config (top
, key
, p
+1);
708 else if (magic_config_key
== NULL
) {
709 if (i
== 0) /* magic script parameter */
710 top
->config (top
, "script", argv
[optind
]);
713 "%s: expecting key=value on the command line but got: %s\n",
714 program_name
, argv
[optind
]);
718 else { /* magic config key */
719 top
->config (top
, magic_config_key
, argv
[optind
]);
723 /* This must run after parsing the parameters so that the script can
724 * be loaded for scripting languages. But it must be called before
725 * config_complete so that the plugin doesn't check for missing
729 top
->dump_fields (top
);
735 top
->config_complete (top
);
737 /* Select the correct thread model based on config. */
738 lock_init_thread_model ();
740 /* Tell the plugin that we are about to start serving. This must be
741 * called before we change user, fork, or open any sockets.
743 top
->get_ready (top
);
758 unlink (random_fifo
);
762 if (random_fifo_dir
) {
763 rmdir (random_fifo_dir
);
764 free (random_fifo_dir
);
772 /* Note: Don't exit here, otherwise this won't work when compiled
778 /* Implementation of '-U -' */
780 make_random_fifo (void)
784 random_fifo_dir
= make_temporary_directory ();
785 if (random_fifo_dir
== NULL
) {
786 perror ("make_temporary_directory");
790 if (asprintf (&random_fifo
, "%s" DIR_SEPARATOR_STR
"socket",
791 random_fifo_dir
) == -1) {
796 sock
= strdup (random_fifo
);
807 rmdir (random_fifo_dir
);
808 free (random_fifo_dir
);
809 random_fifo_dir
= NULL
;
813 static struct backend
*
814 open_plugin_so (size_t i
, const char *name
, int short_name
)
817 char *filename
= (char *) name
;
818 bool free_filename
= false;
820 struct nbdkit_plugin
*(*plugin_init
) (void);
824 /* Short names are rewritten relative to the plugindir. */
825 if (asprintf (&filename
,
826 "%s/nbdkit-%s-plugin." SOEXT
, plugindir
, name
) == -1) {
830 free_filename
= true;
833 dl
= dlopen (filename
, RTLD_NOW
|RTLD_GLOBAL
);
836 "%s: error: cannot open plugin '%s': %s\n"
837 "Use '%s --help' or "
838 "read the nbdkit(1) manual page for documentation.\n",
839 program_name
, name
, dlerror (),
844 /* Initialize the plugin. See dlopen(3) to understand C weirdness. */
846 plugin_init
= dlsym (dl
, "plugin_init");
847 if ((error
= dlerror ()) != NULL
) {
848 fprintf (stderr
, "%s: %s: %s\n", program_name
, name
, error
);
852 fprintf (stderr
, "%s: %s: invalid plugin_init\n", program_name
, name
);
856 /* Register the plugin. */
857 ret
= plugin_register (i
, filename
, dl
, plugin_init
);
865 static struct backend
*
866 open_filter_so (struct backend
*next
, size_t i
,
867 const char *name
, int short_name
)
870 char *filename
= (char *) name
;
871 bool free_filename
= false;
873 struct nbdkit_filter
*(*filter_init
) (void);
877 /* Short names are rewritten relative to the filterdir. */
878 if (asprintf (&filename
,
879 "%s/nbdkit-%s-filter." SOEXT
, filterdir
, name
) == -1) {
883 free_filename
= true;
886 dl
= dlopen (filename
, RTLD_NOW
|RTLD_GLOBAL
);
888 fprintf (stderr
, "%s: error: cannot open filter '%s': %s\n",
889 program_name
, name
, dlerror ());
893 /* Initialize the filter. See dlopen(3) to understand C weirdness. */
895 filter_init
= dlsym (dl
, "filter_init");
896 if ((error
= dlerror ()) != NULL
) {
897 fprintf (stderr
, "%s: %s: %s\n", program_name
, name
, error
);
901 fprintf (stderr
, "%s: %s: invalid filter_init\n", program_name
, name
);
905 /* Register the filter. */
906 ret
= filter_register (next
, i
, filename
, dl
, filter_init
);
917 sockets socks
= empty_vector
;
921 #if !ENABLE_LIBFUZZER
925 /* Lock the process into memory if requested. */
928 if (mlockall (MCL_CURRENT
| MCL_FUTURE
) == -1) {
929 fprintf (stderr
, "%s: --swap: mlockall: %m\n", program_name
);
932 debug ("mlockall done");
934 fprintf (stderr
, "%s: mlockall (--swap option) "
935 "is not supported on this platform\n", program_name
);
940 /* Socket activation: the ‘socket_activation’ variable (> 0) is the
941 * number of file descriptors from FIRST_SOCKET_ACTIVATION_FD to
942 * FIRST_SOCKET_ACTIVATION_FD+socket_activation-1.
944 if (socket_activation
) {
945 if (sockets_reserve (&socks
, socket_activation
) == -1) {
949 for (i
= 0; i
< socket_activation
; ++i
) {
950 int s
= FIRST_SOCKET_ACTIVATION_FD
+ i
, r
;
951 /* This can't fail because of the reservation above. */
952 r
= sockets_append (&socks
, s
);
955 debug ("using socket activation, nr_socks = %zu", socks
.len
);
958 top
->after_fork (top
);
959 accept_incoming_connections (&socks
);
963 /* Handling a single connection on stdin/stdout. */
967 top
->after_fork (top
);
968 threadlocal_new_server_thread ();
969 handle_single_connection (saved_stdin
, saved_stdout
);
973 /* Handling multiple connections on TCP/IP, Unix domain socket or
977 bind_unix_socket (&socks
);
981 bind_tcpip_socket (&socks
);
985 fork_into_background ();
987 top
->after_fork (top
);
988 accept_incoming_connections (&socks
);
1003 /* Don't put a trailing \n after the PID file on Windows. It is
1004 * turned into \r\n which causes problems if you process the file
1005 * using a Unix tool like bash, especially when running the test
1008 snprintf (pidstr
, sizeof pidstr
, "%d"
1013 len
= strlen (pidstr
);
1015 fd
= open (pidfile
, O_WRONLY
|O_TRUNC
|O_CREAT
|O_CLOEXEC
|O_NOCTTY
, 0644);
1018 exit (EXIT_FAILURE
);
1021 if (write (fd
, pidstr
, len
) < len
||
1024 exit (EXIT_FAILURE
);
1027 debug ("written pidfile %s", pidfile
);
1030 /* When parsing plugin and filter config key=value from the command
1031 * line, is the key a simple alphanumeric with period, underscore or
1035 is_config_key (const char *key
, size_t len
)
1037 static const char allowed_first
[] =
1038 "abcdefghijklmnopqrstuvwxyz"
1039 "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
1040 static const char allowed
[] =
1043 "abcdefghijklmnopqrstuvwxyz"
1044 "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
1049 if (strchr (allowed_first
, key
[0]) == NULL
)
1052 /* This works in context of the caller since key[len] == '='. */
1053 if (strspn (key
, allowed
) != len
)
1059 /* Refuse to run if stdin/out/err are closed, whether or not -s is used. */
1061 error_if_stdio_closed (void)
1064 if (fcntl (STDERR_FILENO
, F_GETFL
) == -1) {
1065 /* Nowhere we can report the error. Oh well. */
1066 exit (EXIT_FAILURE
);
1068 if (fcntl (STDIN_FILENO
, F_GETFL
) == -1 ||
1069 fcntl (STDOUT_FILENO
, F_GETFL
) == -1) {
1070 perror ("expecting stdin/stdout to be opened");
1071 exit (EXIT_FAILURE
);
1076 /* Sanitize stdin/stdout to /dev/null, after saving the originals
1077 * when needed. We are still single-threaded at this point, and
1078 * already checked that stdin/out were open, so we don't have to
1079 * worry about other threads accidentally grabbing our intended fds,
1080 * or races on FD_CLOEXEC. POSIX says that 'fflush(NULL)' is
1081 * supposed to reset the underlying offset of seekable stdin, but
1082 * glibc is buggy and requires an explicit fflush(stdin) as
1083 * well. https://sourceware.org/bugzilla/show_bug.cgi?id=12799
1088 #if defined(F_DUPFD_CLOEXEC) || defined(F_DUPFD)
1091 if (listen_stdin
|| run
) {
1092 #ifndef F_DUPFD_CLOEXEC
1093 #define F_DUPFD_CLOEXEC F_DUPFD
1095 saved_stdin
= fcntl (STDIN_FILENO
, F_DUPFD_CLOEXEC
, STDERR_FILENO
+ 1);
1096 saved_stdout
= fcntl (STDOUT_FILENO
, F_DUPFD_CLOEXEC
, STDERR_FILENO
+ 1);
1097 #if F_DUPFD == F_DUPFD_CLOEXEC
1098 saved_stdin
= set_cloexec (saved_stdin
);
1099 saved_stdout
= set_cloexec (saved_stdout
);
1101 if (saved_stdin
== -1 || saved_stdout
== -1) {
1103 exit (EXIT_FAILURE
);
1108 close (STDIN_FILENO
);
1109 close (STDOUT_FILENO
);
1110 if (open ("/dev/null", O_RDONLY
) != STDIN_FILENO
||
1111 open ("/dev/null", O_WRONLY
) != STDOUT_FILENO
) {
1113 exit (EXIT_FAILURE
);
1118 /* On Windows the Winsock library must be initialized early.
1119 * https://docs.microsoft.com/en-us/windows/win32/winsock/initializing-winsock
1128 result
= WSAStartup (MAKEWORD (2, 2), &wsaData
);
1130 fprintf (stderr
, "WSAStartup failed: %d\n", result
);
1131 exit (EXIT_FAILURE
);