2 * Copyright (C) 2013-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
33 /* This file contains the public utility APIs to be exported by nbdkit
34 * for use by filters and plugins, declared in nbdkit-common.h.
53 #include "get-current-dir-name.h"
58 nbdkit_absolute_path (const char *path
)
60 CLEANUP_FREE
char *pwd
= NULL
;
63 if (path
== NULL
|| *path
== '\0') {
64 nbdkit_error ("cannot convert null or empty path to an absolute path");
71 nbdkit_error ("strdup: %m");
77 pwd
= get_current_dir_name ();
79 nbdkit_error ("get_current_dir_name: %m");
83 if (asprintf (&ret
, "%s/%s", pwd
, path
) == -1) {
84 nbdkit_error ("asprintf: %m");
91 /* Parse a string as a size with possible scaling suffix, or return -1
92 * after reporting the error.
95 nbdkit_parse_size (const char *str
)
101 /* Disk sizes cannot usefully exceed off_t (which is signed) and
102 * cannot be negative. */
103 /* XXX Should we also parse things like '1.5M'? */
104 /* XXX Should we allow hex? If so, hex cannot use scaling suffixes,
105 * because some of them are valid hex digits */
107 size
= strtoimax (str
, &end
, 10);
109 nbdkit_error ("could not parse size string (%s)", str
);
113 nbdkit_error ("size cannot be negative (%s)", str
);
117 nbdkit_error ("size (%s) exceeds maximum value", str
);
124 end
--; /* Safe, since we already filtered out empty string */
149 /* "sectors", ie. units of 512 bytes, even if that's not the real
156 nbdkit_error ("could not parse size: unknown suffix '%s'", end
);
160 /* XXX Maybe we should support 'MiB' as a synonym for 'M'; and 'MB'
161 * for powers of 1000, for similarity to GNU tools. But for now,
162 * anything beyond 'M' is dropped. */
164 nbdkit_error ("could not parse size: unknown suffix '%s'", end
);
168 if (INT64_MAX
/ scale
< size
) {
169 nbdkit_error ("overflow computing size (%s)", str
);
176 /* Parse a string as a boolean, or return -1 after reporting the error.
179 nbdkit_parse_bool (const char *str
)
181 if (!strcmp (str
, "1") ||
182 !strcasecmp (str
, "true") ||
183 !strcasecmp (str
, "t") ||
184 !strcasecmp (str
, "yes") ||
185 !strcasecmp (str
, "y") ||
186 !strcasecmp (str
, "on"))
189 if (!strcmp (str
, "0") ||
190 !strcasecmp (str
, "false") ||
191 !strcasecmp (str
, "f") ||
192 !strcasecmp (str
, "no") ||
193 !strcasecmp (str
, "n") ||
194 !strcasecmp (str
, "off"))
197 nbdkit_error ("could not decipher boolean (%s)", str
);
201 /* Read a password from configuration value. */
203 nbdkit_read_password (const char *value
, char **password
)
206 struct termios orig
, temp
;
213 /* Read from stdin. */
214 if (strcmp (value
, "-") == 0) {
215 printf ("password: ");
220 tcgetattr (0, &orig
);
222 temp
.c_lflag
&= ~ECHO
;
223 tcsetattr (0, TCSAFLUSH
, &temp
);
226 r
= getline (password
, &n
, stdin
);
231 tcsetattr (0, TCSAFLUSH
, &orig
);
233 /* Complete the printf above. */
238 nbdkit_error ("could not read password from stdin: %m");
241 if (*password
&& r
> 0 && (*password
)[r
-1] == '\n')
242 (*password
)[r
-1] = '\0';
245 /* Read password from a file. */
246 else if (value
[0] == '+') {
249 fd
= open (&value
[1], O_CLOEXEC
| O_RDONLY
);
251 nbdkit_error ("open %s: %m", &value
[1]);
254 fp
= fdopen (fd
, "r");
256 nbdkit_error ("fdopen %s: %m", &value
[1]);
260 r
= getline (password
, &n
, fp
);
265 nbdkit_error ("could not read password from file %s: %m", &value
[1]);
268 if (*password
&& r
> 0 && (*password
)[r
-1] == '\n')
269 (*password
)[r
-1] = '\0';
272 /* Parameter is the password. */
274 *password
= strdup (value
);
275 if (*password
== NULL
) {
276 nbdkit_error ("strdup: %m");
285 nbdkit_realpath (const char *path
)
289 if (path
== NULL
|| *path
== '\0') {
290 nbdkit_error ("cannot resolve a null or empty path");
294 ret
= realpath (path
, NULL
);
296 nbdkit_error ("realpath: %s: %m", path
);
305 nbdkit_nanosleep (unsigned sec
, unsigned nsec
)
309 if (sec
>= INT_MAX
- nsec
/ 1000000000) {
310 nbdkit_error ("sleep request is too long");
314 ts
.tv_sec
= sec
+ nsec
/ 1000000000;
315 ts
.tv_nsec
= nsec
% 1000000000;
317 #if defined HAVE_PPOLL && defined POLLRDHUP
318 /* End the sleep early if any of these happen:
319 * - nbdkit has received a signal to shut down the server
320 * - the current connection is multi-threaded and another thread detects
321 * NBD_CMD_DISC or a problem with the connection
322 * - the input socket detects POLLRDHUP/POLLHUP/POLLERR
324 struct connection
*conn
= threadlocal_get_conn ();
325 struct pollfd fds
[] = {
328 [1].fd
= conn
? conn
->status_pipe
[0] : -1,
330 [2].fd
= conn
? conn
->sockin
: -1,
331 [2].events
= POLLRDHUP
,
335 /* Block all signals to this thread during the poll, so we don't
336 * have to worry about EINTR
338 if (sigfillset(&all
))
340 switch (ppoll (fds
, sizeof fds
/ sizeof fds
[0], &ts
, &all
)) {
342 assert (errno
!= EINTR
);
343 nbdkit_error ("poll: %m");
349 /* We don't have to read the pipe-to-self; if poll returned an
350 * event, we know the connection should be shutting down.
353 (conn
&& conn
->nworkers
> 0 && connection_get_status (conn
) < 1) ||
354 (conn
&& (fds
[2].revents
& (POLLRDHUP
| POLLHUP
| POLLERR
))));
355 nbdkit_error ("aborting sleep to shut down");
360 /* The fallback path simply calls ordinary nanosleep, and will
361 * cause long delays on server shutdown.
363 * If however you want to port this to your platform, then
364 * porting ideas, in order of preference:
365 * - POSIX requires pselect; it's a bit clunkier to set up than poll,
366 * but the same ability to atomically mask all signals and operate
367 * on struct timespec makes it similar to the preferred ppoll interface
368 * - calculate an end time target, then use poll in a loop on EINTR with
369 * a recalculation of the timeout to still reach the end time (masking
370 * signals in that case is not safe, as it is a non-atomic race)
374 r
= nanosleep (&ts
, NULL
);
375 if (r
== -1 && errno
!= EINTR
&& errno
!= EAGAIN
) {
376 nbdkit_error ("nanosleep: %m");