Update Red Hat Copyright Notices
[nbdkit.git] / server / main.c
blob631401b727122b1e872487e186bafa998f2b7cad
1 /* nbdkit
2 * Copyright Red Hat
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
6 * met:
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
30 * SUCH DAMAGE.
33 #include <config.h>
35 #include <stdio.h>
36 #include <stdlib.h>
37 #include <stdbool.h>
38 #include <string.h>
39 #include <fcntl.h>
40 #include <unistd.h>
41 #include <getopt.h>
42 #include <limits.h>
43 #include <errno.h>
44 #include <assert.h>
45 #include <sys/types.h>
46 #include <sys/stat.h>
48 #ifdef HAVE_SYS_MMAN_H
49 #include <sys/mman.h>
50 #endif
52 #ifdef HAVE_SYS_SOCKET_H
53 #include <sys/socket.h>
54 #endif
56 #ifdef HAVE_LINUX_VM_SOCKETS_H
57 #include <linux/vm_sockets.h>
58 #elif HAVE_SYS_VSOCK_H
59 #include <sys/vsock.h>
60 #endif
62 #include <pthread.h>
64 #include <dlfcn.h>
66 #include "ascii-string.h"
67 #include "exit-with-parent.h"
68 #include "nbd-protocol.h"
69 #include "realpath.h"
70 #include "strndup.h"
71 #include "syslog.h"
72 #include "utils.h"
74 #include "internal.h"
75 #include "options.h"
77 #ifdef ENABLE_LIBFUZZER
78 #define main fuzzer_main
79 #endif
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. */
123 struct backend *top;
125 static char *random_fifo_dir = NULL;
126 static char *random_fifo = NULL;
128 static void
129 usage (void)
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");
139 static void
140 display_version (void)
142 if (strcmp (NBDKIT_VERSION_EXTRA, "") == 0)
143 printf ("%s %s\n", PACKAGE_NAME, PACKAGE_VERSION);
144 else
145 printf ("%s %s (%s)\n",
146 PACKAGE_NAME, PACKAGE_VERSION, NBDKIT_VERSION_EXTRA);
149 static void
150 dump_config (void)
152 CLEANUP_FREE char *binary = NULL;
154 #ifdef __linux__
155 binary = realpath ("/proc/self/exe", NULL);
156 #else
157 #ifdef WIN32
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)) {
166 free (binary);
167 binary = NULL;
169 #endif
170 #endif
172 if (binary != NULL)
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");
177 else
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");
190 #else
191 printf ("selinux=no\n");
192 #endif
193 printf ("%s=%s\n", "sysconfdir", sysconfdir);
194 #ifdef HAVE_GNUTLS
195 printf ("tls=yes\n");
196 #else
197 printf ("tls=no\n");
198 #endif
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);
204 #ifdef HAVE_LIBZSTD
205 printf ("zstd=yes\n");
206 #else
207 printf ("zstd=no\n");
208 #endif
212 main (int argc, char *argv[])
214 int c;
215 bool help = false, version = false, dump_plugin = false;
216 int tls_set_on_cli = false;
217 bool short_name;
218 const char *filename;
219 char *p;
220 static struct filter_filename {
221 struct filter_filename *next;
222 const char *filename;
223 } *filter_filenames = NULL;
224 size_t i;
225 const char *magic_config_key;
227 error_if_stdio_closed ();
228 winsock_init ();
230 #if !ENABLE_LIBFUZZER
231 threadlocal_init ();
232 #else
233 static bool main_called = false;
234 if (!main_called) {
235 threadlocal_init ();
236 main_called = true;
238 #endif
240 /* The default setting for TLS depends on whether we were
241 * compiled with GnuTLS.
243 #ifdef HAVE_GNUTLS
244 tls = 1;
245 #else
246 tls = 0;
247 #endif
249 /* Returns 0 if no socket activation, or the number of FDs. */
250 socket_activation = get_socket_activation ();
252 for (;;) {
253 c = getopt_long (argc, argv, short_options, long_options, NULL);
254 if (c == -1)
255 break;
257 switch (c) {
258 case DUMP_CONFIG_OPTION:
259 dump_config ();
260 exit (EXIT_SUCCESS);
262 case DUMP_PLUGIN_OPTION:
263 dump_plugin = true;
264 break;
266 case EXIT_WITH_PARENT_OPTION:
267 if (can_exit_with_parent ()) {
268 exit_with_parent = true;
269 foreground = true;
271 else {
272 fprintf (stderr,
273 "%s: --exit-with-parent is not implemented "
274 "for this operating system\n",
275 program_name);
276 exit (EXIT_FAILURE);
278 break;
280 case FILTER_OPTION:
282 struct filter_filename *t;
284 t = malloc (sizeof *t);
285 if (t == NULL) {
286 perror ("malloc");
287 exit (EXIT_FAILURE);
289 t->next = filter_filenames;
290 t->filename = optarg;
291 filter_filenames = t;
293 break;
295 case LOG_OPTION:
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;
302 else {
303 fprintf (stderr, "%s: "
304 "--log must be \"stderr\", \"syslog\" or \"null\"\n",
305 program_name);
306 exit (EXIT_FAILURE);
308 break;
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);
316 exit (EXIT_SUCCESS);
318 case RUN_OPTION:
319 if (socket_activation) {
320 fprintf (stderr, "%s: cannot use socket activation with --run flag\n",
321 program_name);
322 exit (EXIT_FAILURE);
324 run = optarg;
325 foreground = true;
326 break;
328 case SELINUX_LABEL_OPTION:
329 selinux_label = optarg;
330 break;
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]);
337 exit (EXIT_SUCCESS);
339 case SWAP_OPTION:
340 swap = 1;
341 break;
343 case TLS_OPTION:
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)
348 tls = 2;
349 else {
350 tls = nbdkit_parse_bool (optarg);
351 if (tls == -1)
352 exit (EXIT_FAILURE);
354 break;
356 case TLS_CERTIFICATES_OPTION:
357 tls_certificates_dir = optarg;
358 break;
360 case TLS_PSK_OPTION:
361 tls_psk = optarg;
362 break;
364 case TLS_VERIFY_PEER_OPTION:
365 #ifdef HAVE_GNUTLS_SESSION_SET_VERIFY_CERT
366 tls_verify_peer = true;
367 #else
368 nbdkit_error ("--tls-verify-peer: "
369 "GnuTLS >= 3.4.6 is required for this feature");
370 exit (EXIT_FAILURE);
371 #endif
372 break;
374 case VSOCK_OPTION:
375 #if defined (AF_VSOCK) && defined (VMADDR_CID_ANY)
376 vsock = true;
377 break;
378 #else
379 fprintf (stderr, "%s: AF_VSOCK is not supported on this platform\n",
380 program_name);
381 exit (EXIT_FAILURE);
382 #endif
384 case '4':
385 tcpip_sock_af = AF_INET;
386 break;
388 case '6':
389 tcpip_sock_af = AF_INET6;
390 break;
392 case 'D':
393 add_debug_flag (optarg);
394 break;
396 case 'e':
397 export_name = optarg;
398 break;
400 case 'f':
401 foreground = true;
402 break;
404 case 'g':
405 group = optarg;
406 break;
408 case 'i':
409 if (socket_activation) {
410 fprintf (stderr, "%s: cannot use socket activation with -i flag\n",
411 program_name);
412 exit (EXIT_FAILURE);
414 ipaddr = optarg;
415 break;
417 case MASK_HANDSHAKE_OPTION:
418 if (nbdkit_parse_unsigned ("mask-handshake",
419 optarg, &mask_handshake) == -1)
420 exit (EXIT_FAILURE);
421 break;
423 case 'n':
424 newstyle = true;
425 break;
427 case NO_SR_OPTION:
428 no_sr = true;
429 break;
431 case 'o':
432 newstyle = false;
433 break;
435 case 'P':
436 pidfile = nbdkit_absolute_path (optarg);
437 if (pidfile == NULL)
438 exit (EXIT_FAILURE);
439 break;
441 case 'p':
442 if (socket_activation) {
443 fprintf (stderr, "%s: cannot use socket activation with -p flag\n",
444 program_name);
445 exit (EXIT_FAILURE);
447 port = optarg;
448 break;
450 case 'r':
451 read_only = true;
452 break;
454 case 's':
455 if (socket_activation) {
456 fprintf (stderr, "%s: cannot use socket activation with -s flag\n",
457 program_name);
458 exit (EXIT_FAILURE);
460 listen_stdin = true;
461 #ifdef WIN32
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
467 * appropriate.
469 NOT_IMPLEMENTED_ON_WINDOWS ("-s");
470 #endif
471 break;
473 case 't':
474 if (nbdkit_parse_unsigned ("threads", optarg, &threads) == -1)
475 exit (EXIT_FAILURE);
476 /* XXX Worth a maximimum limit on threads? */
477 break;
479 case 'U':
480 if (socket_activation) {
481 fprintf (stderr, "%s: cannot use socket activation with -U flag\n",
482 program_name);
483 exit (EXIT_FAILURE);
485 if (strcmp (optarg, "-") == 0)
486 unixsocket = make_random_fifo ();
487 else
488 unixsocket = nbdkit_absolute_path (optarg);
489 if (unixsocket == NULL)
490 exit (EXIT_FAILURE);
491 break;
493 case 'u':
494 user = optarg;
495 break;
497 case 'v':
498 verbose = true;
499 break;
501 case 'V':
502 version = true;
503 break;
505 case HELP_OPTION:
506 help = true;
507 break;
509 default:
510 usage ();
511 exit (EXIT_FAILURE);
515 /* No extra parameters. */
516 if (optind >= argc) {
517 if (help) {
518 usage ();
519 exit (EXIT_SUCCESS);
521 if (version) {
522 display_version ();
523 exit (EXIT_SUCCESS);
525 if (dump_plugin) {
526 /* Incorrect use of --dump-plugin. */
527 fprintf (stderr,
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",
531 program_name);
532 exit (EXIT_FAILURE);
535 /* Otherwise this is an error. */
536 fprintf (stderr,
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);
541 exit (EXIT_FAILURE);
544 /* --tls=require and oldstyle won't work. */
545 if (tls == 2 && !newstyle) {
546 fprintf (stderr,
547 "%s: cannot use oldstyle protocol (-o) and require TLS\n",
548 program_name);
549 exit (EXIT_FAILURE);
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).
556 umask (0022);
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);
565 else
566 debug ("%s %s (%s)", PACKAGE_NAME, PACKAGE_VERSION, NBDKIT_VERSION_EXTRA);
568 /* Initialize TLS. */
569 crypto_init (tls_set_on_cli);
570 assert (tls != -1);
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");
577 exit (EXIT_FAILURE);
580 /* If the user has mixed up -p/--run/-s/-U/--vsock options, then
581 * give an error.
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)) {
593 fprintf (stderr,
594 "%s: --dump-plugin, -p, --run, -s, -U or --vsock options "
595 "cannot be used in this combination\n",
596 program_name);
597 exit (EXIT_FAILURE);
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.
611 if (short_name) {
612 struct stat statbuf;
613 CLEANUP_FREE char *script;
615 if (asprintf (&script,
616 "%s/nbdkit-%s-plugin", plugindir, filename) == -1) {
617 perror ("asprintf");
618 exit (EXIT_FAILURE);
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
625 * down the list.
627 argv[0] = argv[optind-1];
628 for (i = optind; i <= argc; i++)
629 argv[i-1] = argv[i];
630 execv (script, argv);
631 perror (script);
632 exit (EXIT_FAILURE);
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);
642 i = 1;
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;
652 free (t);
655 /* Apply nbdkit.* flags for the server. */
656 apply_debug_flags (RTLD_DEFAULT, "nbdkit");
658 /* Check all debug flags were used, and free them. */
659 free_debug_flags ();
661 if (help) {
662 struct backend *b;
664 usage ();
665 for_each_backend (b) {
666 printf ("\n");
667 b->usage (b);
669 top->free (top);
670 exit (EXIT_SUCCESS);
673 if (version) {
674 const char *v;
675 struct backend *b;
677 display_version ();
678 for_each_backend (b) {
679 printf ("%s", b->name);
680 if ((v = b->version (b)) != NULL)
681 printf (" %s", v);
682 printf ("\n");
684 top->free (top);
685 exit (EXIT_SUCCESS);
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) {
705 size_t n;
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);
711 if (key == NULL)
712 exit (EXIT_FAILURE);
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]);
718 else {
719 fprintf (stderr,
720 "%s: expecting key=value on the command line but got: %s\n",
721 program_name, argv[optind]);
722 exit (EXIT_FAILURE);
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
733 * parameters.
735 if (dump_plugin) {
736 top->dump_fields (top);
737 top->free (top);
738 free_interns ();
739 exit (EXIT_SUCCESS);
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);
752 switch_stdio ();
753 configured = true;
755 start_serving ();
757 top->cleanup (top);
758 top->free (top);
759 top = NULL;
761 free (unixsocket);
762 free (pidfile);
764 if (random_fifo) {
765 unlink (random_fifo);
766 free (random_fifo);
769 if (random_fifo_dir) {
770 rmdir (random_fifo_dir);
771 free (random_fifo_dir);
774 crypto_free ();
775 close_quit_pipe ();
777 free_interns ();
779 /* Note: Don't exit here, otherwise this won't work when compiled
780 * for libFuzzer.
782 return EXIT_SUCCESS;
785 /* Implementation of '-U -' */
786 static char *
787 make_random_fifo (void)
789 char *sock;
791 random_fifo_dir = make_temporary_directory ();
792 if (random_fifo_dir == NULL) {
793 perror ("make_temporary_directory");
794 return NULL;
797 if (asprintf (&random_fifo, "%s" DIR_SEPARATOR_STR "socket",
798 random_fifo_dir) == -1) {
799 perror ("asprintf");
800 goto error;
803 sock = strdup (random_fifo);
804 if (sock == NULL) {
805 perror ("strdup");
806 goto error;
809 return sock;
811 error:
812 free (random_fifo);
813 random_fifo = NULL;
814 rmdir (random_fifo_dir);
815 free (random_fifo_dir);
816 random_fifo_dir = NULL;
817 return NULL;
820 static struct backend *
821 open_plugin_so (size_t i, const char *name, int short_name)
823 struct backend *ret;
824 char *filename = (char *) name;
825 bool free_filename = false;
826 void *dl;
827 struct nbdkit_plugin *(*plugin_init) (void);
828 char *error;
830 if (short_name) {
831 /* Short names are rewritten relative to the plugindir. */
832 if (asprintf (&filename,
833 "%s/nbdkit-%s-plugin." SOEXT, plugindir, name) == -1) {
834 perror ("asprintf");
835 exit (EXIT_FAILURE);
837 free_filename = true;
840 dl = dlopen (filename, RTLD_NOW|RTLD_GLOBAL);
841 if (dl == NULL) {
842 fprintf (stderr,
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 (),
847 program_name);
848 exit (EXIT_FAILURE);
851 /* Initialize the plugin. See dlopen(3) to understand C weirdness. */
852 dlerror ();
853 plugin_init = dlsym (dl, "plugin_init");
854 if ((error = dlerror ()) != NULL) {
855 fprintf (stderr, "%s: %s: %s\n", program_name, name, error);
856 exit (EXIT_FAILURE);
858 if (!plugin_init) {
859 fprintf (stderr, "%s: %s: invalid plugin_init\n", program_name, name);
860 exit (EXIT_FAILURE);
863 /* Register the plugin. */
864 ret = plugin_register (i, filename, dl, plugin_init);
866 if (free_filename)
867 free (filename);
869 return ret;
872 static struct backend *
873 open_filter_so (struct backend *next, size_t i,
874 const char *name, int short_name)
876 struct backend *ret;
877 char *filename = (char *) name;
878 bool free_filename = false;
879 void *dl;
880 struct nbdkit_filter *(*filter_init) (void);
881 char *error;
883 if (short_name) {
884 /* Short names are rewritten relative to the filterdir. */
885 if (asprintf (&filename,
886 "%s/nbdkit-%s-filter." SOEXT, filterdir, name) == -1) {
887 perror ("asprintf");
888 exit (EXIT_FAILURE);
890 free_filename = true;
893 dl = dlopen (filename, RTLD_NOW|RTLD_GLOBAL);
894 if (dl == NULL) {
895 fprintf (stderr, "%s: error: cannot open filter '%s': %s\n",
896 program_name, name, dlerror ());
897 exit (EXIT_FAILURE);
900 /* Initialize the filter. See dlopen(3) to understand C weirdness. */
901 dlerror ();
902 filter_init = dlsym (dl, "filter_init");
903 if ((error = dlerror ()) != NULL) {
904 fprintf (stderr, "%s: %s: %s\n", program_name, name, error);
905 exit (EXIT_FAILURE);
907 if (!filter_init) {
908 fprintf (stderr, "%s: %s: invalid filter_init\n", program_name, name);
909 exit (EXIT_FAILURE);
912 /* Register the filter. */
913 ret = filter_register (next, i, filename, dl, filter_init);
915 if (free_filename)
916 free (filename);
918 return ret;
921 static void
922 start_serving (void)
924 sockets socks = empty_vector;
925 size_t i;
927 set_up_quit_pipe ();
928 #if !ENABLE_LIBFUZZER
929 set_up_signals ();
930 #endif
932 /* Lock the process into memory if requested. */
933 if (swap) {
934 #ifdef HAVE_MLOCKALL
935 if (mlockall (MCL_CURRENT | MCL_FUTURE) == -1) {
936 fprintf (stderr, "%s: --swap: mlockall: %m\n", program_name);
937 exit (EXIT_FAILURE);
939 debug ("mlockall done");
940 #else
941 fprintf (stderr, "%s: mlockall (--swap option) "
942 "is not supported on this platform\n", program_name);
943 exit (EXIT_FAILURE);
944 #endif
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) {
953 perror ("realloc");
954 exit (EXIT_FAILURE);
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);
960 assert (r == 0);
962 debug ("using socket activation, nr_socks = %zu", socks.len);
963 change_user ();
964 write_pidfile ();
965 top->after_fork (top);
966 accept_incoming_connections (&socks);
967 return;
970 /* Handling a single connection on stdin/stdout. */
971 if (listen_stdin) {
972 change_user ();
973 write_pidfile ();
974 top->after_fork (top);
975 threadlocal_new_server_thread ();
976 handle_single_connection (saved_stdin, saved_stdout);
977 return;
980 /* Handling multiple connections on TCP/IP, Unix domain socket or
981 * AF_VSOCK.
983 if (unixsocket)
984 bind_unix_socket (&socks);
985 else if (vsock)
986 bind_vsock (&socks);
987 else
988 bind_tcpip_socket (&socks);
990 run_command ();
991 change_user ();
992 fork_into_background ();
993 write_pidfile ();
994 top->after_fork (top);
995 accept_incoming_connections (&socks);
998 static void
999 write_pidfile (void)
1001 int fd;
1002 pid_t pid;
1003 char pidstr[64];
1004 size_t len;
1006 if (!pidfile)
1007 return;
1009 pid = getpid ();
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
1013 * suite.
1015 snprintf (pidstr, sizeof pidstr, "%d"
1016 #ifndef WIN32
1017 "\n"
1018 #endif
1019 , (int) pid);
1020 len = strlen (pidstr);
1022 fd = open (pidfile, O_WRONLY|O_TRUNC|O_CREAT|O_CLOEXEC|O_NOCTTY, 0644);
1023 if (fd == -1) {
1024 perror (pidfile);
1025 exit (EXIT_FAILURE);
1028 if (write (fd, pidstr, len) < len ||
1029 close (fd) == -1) {
1030 perror (pidfile);
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
1039 * dash?
1041 static bool
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[] =
1048 "._-"
1049 "0123456789"
1050 "abcdefghijklmnopqrstuvwxyz"
1051 "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
1053 if (len == 0)
1054 return false;
1056 if (strchr (allowed_first, key[0]) == NULL)
1057 return false;
1059 /* This works in context of the caller since key[len] == '='. */
1060 if (strspn (key, allowed) != len)
1061 return false;
1063 return true;
1066 /* Refuse to run if stdin/out/err are closed, whether or not -s is used. */
1067 static void
1068 error_if_stdio_closed (void)
1070 #ifdef F_GETFL
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);
1080 #endif
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
1092 static void
1093 switch_stdio (void)
1095 #if defined (F_DUPFD_CLOEXEC) || defined (F_DUPFD)
1096 fflush (stdin);
1097 fflush (NULL);
1098 if (listen_stdin || run) {
1099 #ifndef F_DUPFD_CLOEXEC
1100 #define F_DUPFD_CLOEXEC F_DUPFD
1101 #endif
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);
1107 #endif
1108 if (saved_stdin == -1 || saved_stdout == -1) {
1109 perror ("fcntl");
1110 exit (EXIT_FAILURE);
1113 #endif
1114 #ifndef WIN32
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) {
1119 perror ("open");
1120 exit (EXIT_FAILURE);
1122 #endif
1125 /* On Windows the Winsock library must be initialized early.
1126 * https://docs.microsoft.com/en-us/windows/win32/winsock/initializing-winsock
1128 static void
1129 winsock_init (void)
1131 #ifdef WIN32
1132 WSADATA wsaData;
1133 int result;
1135 result = WSAStartup (MAKEWORD (2, 2), &wsaData);
1136 if (result != 0) {
1137 fprintf (stderr, "WSAStartup failed: %d\n", result);
1138 exit (EXIT_FAILURE);
1140 #endif