2 * Copyright (C) 2019 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
40 #include <sys/types.h>
49 /* Handle the --run option. If run is NULL, does nothing. If run is
50 * not NULL then run nbdkit as a captive subprocess of the command.
64 assert (exportname
!= NULL
);
66 fp
= open_memstream (&cmd
, &len
);
68 perror ("open_memstream");
75 fprintf (fp
, "nbd://localhost:");
76 shell_quote (port
, fp
);
77 if (strcmp (exportname
, "") != 0) {
79 uri_quote (exportname
, fp
);
82 else if (unixsocket
) {
83 fprintf (fp
, "nbd+unix://");
84 if (strcmp (exportname
, "") != 0) {
86 uri_quote (exportname
, fp
);
88 fprintf (fp
, "\\?socket=");
89 uri_quote (unixsocket
, fp
);
93 /* Expose $exportname. */
94 fprintf (fp
, "exportname=");
95 shell_quote (exportname
, fp
);
98 /* Construct older $nbd "URL". Unfortunately guestfish and qemu take
99 * different syntax, so try to guess which one we need.
101 fprintf (fp
, "nbd=");
102 if (strstr (run
, "guestfish")) {
104 fprintf (fp
, "nbd://localhost:");
105 shell_quote (port
, fp
);
107 else if (unixsocket
) {
108 fprintf (fp
, "nbd://\\?socket=");
109 shell_quote (unixsocket
, fp
);
116 fprintf (fp
, "nbd:localhost:");
117 shell_quote (port
, fp
);
119 else if (unixsocket
) {
120 fprintf (fp
, "nbd:unix:");
121 shell_quote (unixsocket
, fp
);
128 /* Construct $port and $unixsocket. */
129 fprintf (fp
, "port=");
131 shell_quote (port
, fp
);
133 fprintf (fp
, "unixsocket=");
135 shell_quote (unixsocket
, fp
);
138 /* Add the --run command. Note we don't have to quote this. */
139 fprintf (fp
, "%s", run
);
141 if (fclose (fp
) == EOF
) {
142 perror ("memstream failed");
146 /* Fork. Captive nbdkit runs as the child process. */
153 if (pid
> 0) { /* Parent process is the run command. */
156 nbdkit_error ("failure to execute external command: %m");
159 else if (WIFEXITED (r
))
162 assert (WIFSIGNALED (r
));
163 fprintf (stderr
, "%s: external command was killed by signal %d\n",
164 program_name
, WTERMSIG (r
));
165 r
= WTERMSIG (r
) + 128;
168 switch (waitpid (pid
, &status
, WNOHANG
)) {
170 nbdkit_error ("waitpid: %m");
174 /* Captive nbdkit still running; kill it, but no need to wait
175 * for it, as the --run program's exit status is good enough (if
176 * the captive nbdkit fails to exit after SIGTERM, we have a
177 * bigger bug to fix).
182 /* Captive nbdkit exited unexpectedly; update the exit status. */
183 if (WIFEXITED (status
)) {
185 r
= WEXITSTATUS (status
);
188 assert (WIFSIGNALED (status
));
189 fprintf (stderr
, "%s: nbdkit command was killed by signal %d\n",
190 program_name
, WTERMSIG (status
));
191 r
= WTERMSIG (status
) + 128;
200 debug ("forked into background (new pid = %d)", getpid ());