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 if (can_exit_with_parent ())
176 printf ("exit_with_parent=yes\n");
178 printf ("exit_with_parent=no\n");
179 printf ("%s=%s\n", "filterdir", filterdir
);
180 printf ("%s=%s\n", "host_cpu", host_cpu
);
181 printf ("%s=%s\n", "host_os", host_os
);
182 printf ("%s=%s\n", "libdir", libdir
);
183 printf ("%s=%s\n", "mandir", mandir
);
184 printf ("%s=%s\n", "name", PACKAGE_NAME
);
185 printf ("%s=%s\n", "plugindir", plugindir
);
186 printf ("%s=%s\n", "root_tls_certificates_dir", root_tls_certificates_dir
);
187 printf ("%s=%s\n", "sbindir", sbindir
);
188 #ifdef HAVE_LIBSELINUX
189 printf ("selinux=yes\n");
191 printf ("selinux=no\n");
193 printf ("%s=%s\n", "sysconfdir", sysconfdir
);
195 printf ("tls=yes\n");
199 printf ("%s=%s\n", "version", PACKAGE_VERSION
);
200 if (strcmp (NBDKIT_VERSION_EXTRA
, "") != 0)
201 printf ("%s=%s\n", "version_extra", NBDKIT_VERSION_EXTRA
);
202 printf ("%s=%d\n", "version_major", NBDKIT_VERSION_MAJOR
);
203 printf ("%s=%d\n", "version_minor", NBDKIT_VERSION_MINOR
);
205 printf ("zstd=yes\n");
207 printf ("zstd=no\n");
212 main (int argc
, char *argv
[])
215 bool help
= false, version
= false, dump_plugin
= false;
216 int tls_set_on_cli
= false;
218 const char *filename
;
220 static struct filter_filename
{
221 struct filter_filename
*next
;
222 const char *filename
;
223 } *filter_filenames
= NULL
;
225 const char *magic_config_key
;
227 error_if_stdio_closed ();
230 #if !ENABLE_LIBFUZZER
233 static bool main_called
= false;
240 /* The default setting for TLS depends on whether we were
241 * compiled with GnuTLS.
249 /* Returns 0 if no socket activation, or the number of FDs. */
250 socket_activation
= get_socket_activation ();
253 c
= getopt_long (argc
, argv
, short_options
, long_options
, NULL
);
258 case DUMP_CONFIG_OPTION
:
262 case DUMP_PLUGIN_OPTION
:
266 case EXIT_WITH_PARENT_OPTION
:
267 if (can_exit_with_parent ()) {
268 exit_with_parent
= true;
273 "%s: --exit-with-parent is not implemented "
274 "for this operating system\n",
282 struct filter_filename
*t
;
284 t
= malloc (sizeof *t
);
289 t
->next
= filter_filenames
;
290 t
->filename
= optarg
;
291 filter_filenames
= t
;
296 if (strcmp (optarg
, "stderr") == 0)
297 log_to
= LOG_TO_STDERR
;
298 else if (strcmp (optarg
, "syslog") == 0)
299 log_to
= LOG_TO_SYSLOG
;
300 else if (strcmp (optarg
, "null") == 0)
301 log_to
= LOG_TO_NULL
;
303 fprintf (stderr
, "%s: "
304 "--log must be \"stderr\", \"syslog\" or \"null\"\n",
310 case LONG_OPTIONS_OPTION
:
311 for (i
= 0; long_options
[i
].name
!= NULL
; ++i
) {
312 if (strcmp (long_options
[i
].name
, "long-options") != 0 &&
313 strcmp (long_options
[i
].name
, "short-options") != 0)
314 printf ("--%s\n", long_options
[i
].name
);
319 if (socket_activation
) {
320 fprintf (stderr
, "%s: cannot use socket activation with --run flag\n",
328 case SELINUX_LABEL_OPTION
:
329 selinux_label
= optarg
;
332 case SHORT_OPTIONS_OPTION
:
333 for (i
= 0; short_options
[i
]; ++i
) {
334 if (short_options
[i
] != ':')
335 printf ("-%c\n", short_options
[i
]);
344 tls_set_on_cli
= true;
345 if (ascii_strcasecmp (optarg
, "require") == 0 ||
346 ascii_strcasecmp (optarg
, "required") == 0 ||
347 ascii_strcasecmp (optarg
, "force") == 0)
350 tls
= nbdkit_parse_bool (optarg
);
356 case TLS_CERTIFICATES_OPTION
:
357 tls_certificates_dir
= optarg
;
364 case TLS_VERIFY_PEER_OPTION
:
365 #ifdef HAVE_GNUTLS_SESSION_SET_VERIFY_CERT
366 tls_verify_peer
= true;
368 nbdkit_error ("--tls-verify-peer: "
369 "GnuTLS >= 3.4.6 is required for this feature");
375 #if defined (AF_VSOCK) && defined (VMADDR_CID_ANY)
379 fprintf (stderr
, "%s: AF_VSOCK is not supported on this platform\n",
385 tcpip_sock_af
= AF_INET
;
389 tcpip_sock_af
= AF_INET6
;
393 add_debug_flag (optarg
);
397 export_name
= optarg
;
409 if (socket_activation
) {
410 fprintf (stderr
, "%s: cannot use socket activation with -i flag\n",
417 case MASK_HANDSHAKE_OPTION
:
418 if (nbdkit_parse_unsigned ("mask-handshake",
419 optarg
, &mask_handshake
) == -1)
436 pidfile
= nbdkit_absolute_path (optarg
);
442 if (socket_activation
) {
443 fprintf (stderr
, "%s: cannot use socket activation with -p flag\n",
455 if (socket_activation
) {
456 fprintf (stderr
, "%s: cannot use socket activation with -s flag\n",
462 /* This could be implemented with a bit of work. The problem
463 * currently is that we try to use recv() on the stdio file
464 * descriptor which winsock does not support (nor Linux in
465 * fact). We would need to implement a test to see if the file
466 * descriptor is a socket or not and use either read or recv as
469 NOT_IMPLEMENTED_ON_WINDOWS ("-s");
474 if (nbdkit_parse_unsigned ("threads", optarg
, &threads
) == -1)
476 /* XXX Worth a maximimum limit on threads? */
480 if (socket_activation
) {
481 fprintf (stderr
, "%s: cannot use socket activation with -U flag\n",
485 if (strcmp (optarg
, "-") == 0)
486 unixsocket
= make_random_fifo ();
488 unixsocket
= nbdkit_absolute_path (optarg
);
489 if (unixsocket
== NULL
)
515 /* No extra parameters. */
516 if (optind
>= argc
) {
526 /* Incorrect use of --dump-plugin. */
528 "%s: use 'nbdkit plugin --dump-plugin' or\n"
529 "'nbdkit /path/to/plugin." SOEXT
" --dump-plugin' or\n"
530 "if you want to find out about the server use --dump-config\n",
535 /* Otherwise this is an error. */
537 "%s: no plugins given on the command line.\n"
538 "Use '%s --help' or "
539 "read the nbdkit(1) manual page for documentation.\n",
540 program_name
, program_name
);
544 /* --tls=require and oldstyle won't work. */
545 if (tls
== 2 && !newstyle
) {
547 "%s: cannot use oldstyle protocol (-o) and require TLS\n",
552 /* Set the umask to a known value. This makes the behaviour of
553 * plugins when creating files more predictable, and also removes an
554 * implicit dependency on umask when calling mkstemp(3).
558 /* If we will or might use syslog. */
559 if (log_to
== LOG_TO_SYSLOG
|| log_to
== LOG_TO_DEFAULT
)
560 openlog (program_name
, LOG_PID
, 0);
562 /* Print the version in debug output, right after syslog initialization. */
563 if (strcmp (NBDKIT_VERSION_EXTRA
, "") == 0)
564 debug ("%s %s", PACKAGE_NAME
, PACKAGE_VERSION
);
566 debug ("%s %s (%s)", PACKAGE_NAME
, PACKAGE_VERSION
, NBDKIT_VERSION_EXTRA
);
568 /* Initialize TLS. */
569 crypto_init (tls_set_on_cli
);
572 /* Implement --exit-with-parent early in case plugin initialization
573 * takes a long time and the parent exits during that time.
575 if (set_exit_with_parent () == -1) {
576 perror ("nbdkit: --exit-with-parent");
580 /* If the user has mixed up -p/--run/-s/-U/--vsock options, then
583 * XXX Actually the server could easily be extended to handle both
584 * TCP/IP and Unix sockets, or even multiple TCP/IP ports.
586 if ((port
&& unixsocket
) ||
587 (port
&& listen_stdin
) ||
588 (unixsocket
&& listen_stdin
) ||
589 (listen_stdin
&& run
) ||
590 (listen_stdin
&& dump_plugin
) ||
591 (vsock
&& unixsocket
) ||
592 (vsock
&& listen_stdin
)) {
594 "%s: --dump-plugin, -p, --run, -s, -U or --vsock options "
595 "cannot be used in this combination\n",
600 /* The remaining command line arguments are the plugin name and
601 * parameters. If --help, --version or --dump-plugin were specified
602 * then we open the plugin so that we can display the per-plugin
603 * help/version/plugin information.
605 filename
= argv
[optind
++];
606 short_name
= is_short_name (filename
);
608 /* Is there an executable script located in the plugindir?
609 * If so we simply execute it with the current command line.
613 CLEANUP_FREE
char *script
;
615 if (asprintf (&script
,
616 "%s/nbdkit-%s-plugin", plugindir
, filename
) == -1) {
621 if (stat (script
, &statbuf
) == 0 &&
622 (statbuf
.st_mode
& S_IXUSR
) != 0) {
623 /* We're going to execute the plugin directly.
624 * Replace argv[0] with argv[optind-1] and move further arguments
627 argv
[0] = argv
[optind
-1];
628 for (i
= optind
; i
<= argc
; i
++)
630 execv (script
, argv
);
636 /* Open the plugin (first) and then wrap the plugin with the
637 * filters. The filters are wrapped in reverse order that they
638 * appear on the command line so that in the end ‘top’ points to
639 * the first filter on the command line.
641 top
= open_plugin_so (0, filename
, short_name
);
643 while (filter_filenames
) {
644 struct filter_filename
*t
= filter_filenames
;
646 filename
= t
->filename
;
647 short_name
= is_short_name (filename
);
649 top
= open_filter_so (top
, i
++, filename
, short_name
);
651 filter_filenames
= t
->next
;
655 /* Apply nbdkit.* flags for the server. */
656 apply_debug_flags (RTLD_DEFAULT
, "nbdkit");
658 /* Check all debug flags were used, and free them. */
665 for_each_backend (b
) {
678 for_each_backend (b
) {
679 printf ("%s", b
->name
);
680 if ((v
= b
->version (b
)) != NULL
)
688 /* Call config and config_complete to parse the parameters.
690 * If the plugin provides magic_config_key then any "bare" values
691 * (ones not containing "=") are prefixed with this key.
693 * For backwards compatibility with old plugins, and to support
694 * scripting languages, if magic_config_key == NULL then if the
695 * first parameter is bare it is prefixed with the key "script", and
696 * any other bare parameters are errors.
698 * Keys must live for the life of nbdkit. Since we want to avoid
699 * modifying argv (so that /proc/PID/cmdline remains sane) but we
700 * need to create a key from argv[i] = "key=value" we must intern
701 * the keys, which are then freed at the end of main().
703 magic_config_key
= top
->magic_config_key (top
);
704 for (i
= 0; optind
< argc
; ++i
, ++optind
) {
707 p
= strchr (argv
[optind
], '=');
708 n
= p
- argv
[optind
];
709 if (p
&& is_config_key (argv
[optind
], n
)) { /* Is it key=value? */
710 const char *key
= nbdkit_strndup_intern (argv
[optind
], n
);
713 top
->config (top
, key
, p
+1);
715 else if (magic_config_key
== NULL
) {
716 if (i
== 0) /* magic script parameter */
717 top
->config (top
, "script", argv
[optind
]);
720 "%s: expecting key=value on the command line but got: %s\n",
721 program_name
, argv
[optind
]);
725 else { /* magic config key */
726 top
->config (top
, magic_config_key
, argv
[optind
]);
730 /* This must run after parsing the parameters so that the script can
731 * be loaded for scripting languages. But it must be called before
732 * config_complete so that the plugin doesn't check for missing
736 top
->dump_fields (top
);
742 top
->config_complete (top
);
744 /* Select the correct thread model based on config. */
745 lock_init_thread_model ();
747 /* Tell the plugin that we are about to start serving. This must be
748 * called before we change user, fork, or open any sockets.
750 top
->get_ready (top
);
765 unlink (random_fifo
);
769 if (random_fifo_dir
) {
770 rmdir (random_fifo_dir
);
771 free (random_fifo_dir
);
779 /* Note: Don't exit here, otherwise this won't work when compiled
785 /* Implementation of '-U -' */
787 make_random_fifo (void)
791 random_fifo_dir
= make_temporary_directory ();
792 if (random_fifo_dir
== NULL
) {
793 perror ("make_temporary_directory");
797 if (asprintf (&random_fifo
, "%s" DIR_SEPARATOR_STR
"socket",
798 random_fifo_dir
) == -1) {
803 sock
= strdup (random_fifo
);
814 rmdir (random_fifo_dir
);
815 free (random_fifo_dir
);
816 random_fifo_dir
= NULL
;
820 static struct backend
*
821 open_plugin_so (size_t i
, const char *name
, int short_name
)
824 char *filename
= (char *) name
;
825 bool free_filename
= false;
827 struct nbdkit_plugin
*(*plugin_init
) (void);
831 /* Short names are rewritten relative to the plugindir. */
832 if (asprintf (&filename
,
833 "%s/nbdkit-%s-plugin." SOEXT
, plugindir
, name
) == -1) {
837 free_filename
= true;
840 dl
= dlopen (filename
, RTLD_NOW
|RTLD_GLOBAL
);
843 "%s: error: cannot open plugin '%s': %s\n"
844 "Use '%s --help' or "
845 "read the nbdkit(1) manual page for documentation.\n",
846 program_name
, name
, dlerror (),
851 /* Initialize the plugin. See dlopen(3) to understand C weirdness. */
853 plugin_init
= dlsym (dl
, "plugin_init");
854 if ((error
= dlerror ()) != NULL
) {
855 fprintf (stderr
, "%s: %s: %s\n", program_name
, name
, error
);
859 fprintf (stderr
, "%s: %s: invalid plugin_init\n", program_name
, name
);
863 /* Register the plugin. */
864 ret
= plugin_register (i
, filename
, dl
, plugin_init
);
872 static struct backend
*
873 open_filter_so (struct backend
*next
, size_t i
,
874 const char *name
, int short_name
)
877 char *filename
= (char *) name
;
878 bool free_filename
= false;
880 struct nbdkit_filter
*(*filter_init
) (void);
884 /* Short names are rewritten relative to the filterdir. */
885 if (asprintf (&filename
,
886 "%s/nbdkit-%s-filter." SOEXT
, filterdir
, name
) == -1) {
890 free_filename
= true;
893 dl
= dlopen (filename
, RTLD_NOW
|RTLD_GLOBAL
);
895 fprintf (stderr
, "%s: error: cannot open filter '%s': %s\n",
896 program_name
, name
, dlerror ());
900 /* Initialize the filter. See dlopen(3) to understand C weirdness. */
902 filter_init
= dlsym (dl
, "filter_init");
903 if ((error
= dlerror ()) != NULL
) {
904 fprintf (stderr
, "%s: %s: %s\n", program_name
, name
, error
);
908 fprintf (stderr
, "%s: %s: invalid filter_init\n", program_name
, name
);
912 /* Register the filter. */
913 ret
= filter_register (next
, i
, filename
, dl
, filter_init
);
924 sockets socks
= empty_vector
;
928 #if !ENABLE_LIBFUZZER
932 /* Lock the process into memory if requested. */
935 if (mlockall (MCL_CURRENT
| MCL_FUTURE
) == -1) {
936 fprintf (stderr
, "%s: --swap: mlockall: %m\n", program_name
);
939 debug ("mlockall done");
941 fprintf (stderr
, "%s: mlockall (--swap option) "
942 "is not supported on this platform\n", program_name
);
947 /* Socket activation: the ‘socket_activation’ variable (> 0) is the
948 * number of file descriptors from FIRST_SOCKET_ACTIVATION_FD to
949 * FIRST_SOCKET_ACTIVATION_FD+socket_activation-1.
951 if (socket_activation
) {
952 if (sockets_reserve (&socks
, socket_activation
) == -1) {
956 for (i
= 0; i
< socket_activation
; ++i
) {
957 int s
= FIRST_SOCKET_ACTIVATION_FD
+ i
, r
;
958 /* This can't fail because of the reservation above. */
959 r
= sockets_append (&socks
, s
);
962 debug ("using socket activation, nr_socks = %zu", socks
.len
);
965 top
->after_fork (top
);
966 accept_incoming_connections (&socks
);
970 /* Handling a single connection on stdin/stdout. */
974 top
->after_fork (top
);
975 threadlocal_new_server_thread ();
976 handle_single_connection (saved_stdin
, saved_stdout
);
980 /* Handling multiple connections on TCP/IP, Unix domain socket or
984 bind_unix_socket (&socks
);
988 bind_tcpip_socket (&socks
);
992 fork_into_background ();
994 top
->after_fork (top
);
995 accept_incoming_connections (&socks
);
1010 /* Don't put a trailing \n after the PID file on Windows. It is
1011 * turned into \r\n which causes problems if you process the file
1012 * using a Unix tool like bash, especially when running the test
1015 snprintf (pidstr
, sizeof pidstr
, "%d"
1020 len
= strlen (pidstr
);
1022 fd
= open (pidfile
, O_WRONLY
|O_TRUNC
|O_CREAT
|O_CLOEXEC
|O_NOCTTY
, 0644);
1025 exit (EXIT_FAILURE
);
1028 if (write (fd
, pidstr
, len
) < len
||
1031 exit (EXIT_FAILURE
);
1034 debug ("written pidfile %s", pidfile
);
1037 /* When parsing plugin and filter config key=value from the command
1038 * line, is the key a simple alphanumeric with period, underscore or
1042 is_config_key (const char *key
, size_t len
)
1044 static const char allowed_first
[] =
1045 "abcdefghijklmnopqrstuvwxyz"
1046 "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
1047 static const char allowed
[] =
1050 "abcdefghijklmnopqrstuvwxyz"
1051 "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
1056 if (strchr (allowed_first
, key
[0]) == NULL
)
1059 /* This works in context of the caller since key[len] == '='. */
1060 if (strspn (key
, allowed
) != len
)
1066 /* Refuse to run if stdin/out/err are closed, whether or not -s is used. */
1068 error_if_stdio_closed (void)
1071 if (fcntl (STDERR_FILENO
, F_GETFL
) == -1) {
1072 /* Nowhere we can report the error. Oh well. */
1073 exit (EXIT_FAILURE
);
1075 if (fcntl (STDIN_FILENO
, F_GETFL
) == -1 ||
1076 fcntl (STDOUT_FILENO
, F_GETFL
) == -1) {
1077 perror ("expecting stdin/stdout to be opened");
1078 exit (EXIT_FAILURE
);
1083 /* Sanitize stdin/stdout to /dev/null, after saving the originals
1084 * when needed. We are still single-threaded at this point, and
1085 * already checked that stdin/out were open, so we don't have to
1086 * worry about other threads accidentally grabbing our intended fds,
1087 * or races on FD_CLOEXEC. POSIX says that 'fflush(NULL)' is
1088 * supposed to reset the underlying offset of seekable stdin, but
1089 * glibc is buggy and requires an explicit fflush(stdin) as
1090 * well. https://sourceware.org/bugzilla/show_bug.cgi?id=12799
1095 #if defined (F_DUPFD_CLOEXEC) || defined (F_DUPFD)
1098 if (listen_stdin
|| run
) {
1099 #ifndef F_DUPFD_CLOEXEC
1100 #define F_DUPFD_CLOEXEC F_DUPFD
1102 saved_stdin
= fcntl (STDIN_FILENO
, F_DUPFD_CLOEXEC
, STDERR_FILENO
+ 1);
1103 saved_stdout
= fcntl (STDOUT_FILENO
, F_DUPFD_CLOEXEC
, STDERR_FILENO
+ 1);
1104 #if F_DUPFD == F_DUPFD_CLOEXEC
1105 saved_stdin
= set_cloexec (saved_stdin
);
1106 saved_stdout
= set_cloexec (saved_stdout
);
1108 if (saved_stdin
== -1 || saved_stdout
== -1) {
1110 exit (EXIT_FAILURE
);
1115 close (STDIN_FILENO
);
1116 close (STDOUT_FILENO
);
1117 if (open ("/dev/null", O_RDONLY
) != STDIN_FILENO
||
1118 open ("/dev/null", O_WRONLY
) != STDOUT_FILENO
) {
1120 exit (EXIT_FAILURE
);
1125 /* On Windows the Winsock library must be initialized early.
1126 * https://docs.microsoft.com/en-us/windows/win32/winsock/initializing-winsock
1135 result
= WSAStartup (MAKEWORD (2, 2), &wsaData
);
1137 fprintf (stderr
, "WSAStartup failed: %d\n", result
);
1138 exit (EXIT_FAILURE
);