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 <sys/socket.h>
55 #include "get-current-dir-name.h"
60 nbdkit_absolute_path (const char *path
)
62 CLEANUP_FREE
char *pwd
= NULL
;
65 if (path
== NULL
|| *path
== '\0') {
66 nbdkit_error ("cannot convert null or empty path to an absolute path");
73 nbdkit_error ("strdup: %m");
79 pwd
= get_current_dir_name ();
81 nbdkit_error ("get_current_dir_name: %m");
85 if (asprintf (&ret
, "%s/%s", pwd
, path
) == -1) {
86 nbdkit_error ("asprintf: %m");
94 nbdkit_realpath (const char *path
)
98 if (path
== NULL
|| *path
== '\0') {
99 nbdkit_error ("cannot resolve a null or empty path");
103 ret
= realpath (path
, NULL
);
105 nbdkit_error ("realpath: %s: %m", path
);
112 /* Common code for parsing integers. */
113 #define PARSE_COMMON_TAIL \
115 nbdkit_error ("%s: could not parse number: \"%s\": %m", \
120 nbdkit_error ("%s: empty string where we expected a number", \
125 nbdkit_error ("%s: could not parse number: \"%s\": trailing garbage", \
134 /* Functions for parsing signed integers. */
136 nbdkit_parse_int (const char *what
, const char *str
, int *rp
)
142 r
= strtol (str
, &end
, 0);
143 #if INT_MAX != LONG_MAX
144 if (r
< INT_MIN
|| r
> INT_MAX
)
151 nbdkit_parse_int8_t (const char *what
, const char *str
, int8_t *rp
)
157 r
= strtol (str
, &end
, 0);
158 if (r
< INT8_MIN
|| r
> INT8_MAX
)
164 nbdkit_parse_int16_t (const char *what
, const char *str
, int16_t *rp
)
170 r
= strtol (str
, &end
, 0);
171 if (r
< INT16_MIN
|| r
> INT16_MAX
)
177 nbdkit_parse_int32_t (const char *what
, const char *str
, int32_t *rp
)
183 r
= strtol (str
, &end
, 0);
184 #if INT32_MAX != LONG_MAX
185 if (r
< INT32_MIN
|| r
> INT32_MAX
)
192 nbdkit_parse_int64_t (const char *what
, const char *str
, int64_t *rp
)
198 r
= strtoll (str
, &end
, 0);
199 #if INT64_MAX != LONGLONG_MAX
200 if (r
< INT64_MIN
|| r
> INT64_MAX
)
206 /* Functions for parsing unsigned integers. */
208 /* strtou* functions have surprising behaviour if the first character
209 * (after whitespace) is '-', so reject this early.
211 #define PARSE_ERROR_IF_NEGATIVE \
213 while (isspace (*str)) \
216 nbdkit_error ("%s: negative numbers are not allowed", what); \
222 nbdkit_parse_unsigned (const char *what
, const char *str
, unsigned *rp
)
227 PARSE_ERROR_IF_NEGATIVE
;
229 r
= strtoul (str
, &end
, 0);
230 #if UINT_MAX != ULONG_MAX
238 nbdkit_parse_uint8_t (const char *what
, const char *str
, uint8_t *rp
)
243 PARSE_ERROR_IF_NEGATIVE
;
245 r
= strtoul (str
, &end
, 0);
252 nbdkit_parse_uint16_t (const char *what
, const char *str
, uint16_t *rp
)
257 PARSE_ERROR_IF_NEGATIVE
;
259 r
= strtoul (str
, &end
, 0);
266 nbdkit_parse_uint32_t (const char *what
, const char *str
, uint32_t *rp
)
271 PARSE_ERROR_IF_NEGATIVE
;
273 r
= strtoul (str
, &end
, 0);
274 #if UINT32_MAX != ULONG_MAX
282 nbdkit_parse_uint64_t (const char *what
, const char *str
, uint64_t *rp
)
284 unsigned long long r
;
287 PARSE_ERROR_IF_NEGATIVE
;
289 r
= strtoull (str
, &end
, 0);
290 #if UINT64_MAX != ULONGLONG_MAX
297 /* Parse a string as a size with possible scaling suffix, or return -1
298 * after reporting the error.
301 nbdkit_parse_size (const char *str
)
307 /* Disk sizes cannot usefully exceed off_t (which is signed) and
308 * cannot be negative. */
309 /* XXX Should we also parse things like '1.5M'? */
310 /* XXX Should we allow hex? If so, hex cannot use scaling suffixes,
311 * because some of them are valid hex digits */
313 size
= strtoimax (str
, &end
, 10);
315 nbdkit_error ("could not parse size string (%s)", str
);
319 nbdkit_error ("size cannot be negative (%s)", str
);
323 nbdkit_error ("size (%s) exceeds maximum value", str
);
330 end
--; /* Safe, since we already filtered out empty string */
355 /* "sectors", ie. units of 512 bytes, even if that's not the real
362 nbdkit_error ("could not parse size: unknown suffix '%s'", end
);
366 /* XXX Maybe we should support 'MiB' as a synonym for 'M'; and 'MB'
367 * for powers of 1000, for similarity to GNU tools. But for now,
368 * anything beyond 'M' is dropped. */
370 nbdkit_error ("could not parse size: unknown suffix '%s'", end
);
374 if (INT64_MAX
/ scale
< size
) {
375 nbdkit_error ("overflow computing size (%s)", str
);
382 /* Parse a string as a boolean, or return -1 after reporting the error.
385 nbdkit_parse_bool (const char *str
)
387 if (!strcmp (str
, "1") ||
388 !strcasecmp (str
, "true") ||
389 !strcasecmp (str
, "t") ||
390 !strcasecmp (str
, "yes") ||
391 !strcasecmp (str
, "y") ||
392 !strcasecmp (str
, "on"))
395 if (!strcmp (str
, "0") ||
396 !strcasecmp (str
, "false") ||
397 !strcasecmp (str
, "f") ||
398 !strcasecmp (str
, "no") ||
399 !strcasecmp (str
, "n") ||
400 !strcasecmp (str
, "off"))
403 nbdkit_error ("could not decipher boolean (%s)", str
);
407 /* Read a password from configuration value. */
408 static int read_password_from_fd (const char *what
, int fd
, char **password
);
411 nbdkit_read_password (const char *value
, char **password
)
414 struct termios orig
, temp
;
420 /* Read from stdin. */
421 if (strcmp (value
, "-") == 0) {
422 printf ("password: ");
427 tcgetattr (0, &orig
);
429 temp
.c_lflag
&= ~ECHO
;
430 tcsetattr (0, TCSAFLUSH
, &temp
);
433 r
= getline (password
, &n
, stdin
);
438 tcsetattr (0, TCSAFLUSH
, &orig
);
440 /* Complete the printf above. */
445 nbdkit_error ("could not read password from stdin: %m");
448 if (*password
&& r
> 0 && (*password
)[r
-1] == '\n')
449 (*password
)[r
-1] = '\0';
452 /* Read from numbered file descriptor. */
453 else if (value
[0] == '-') {
456 if (nbdkit_parse_int ("password file descriptor", &value
[1], &fd
) == -1)
458 if (read_password_from_fd (&value
[1], fd
, password
) == -1)
462 /* Read password from a file. */
463 else if (value
[0] == '+') {
466 fd
= open (&value
[1], O_CLOEXEC
| O_RDONLY
);
468 nbdkit_error ("open %s: %m", &value
[1]);
471 if (read_password_from_fd (&value
[1], fd
, password
) == -1)
475 /* Parameter is the password. */
477 *password
= strdup (value
);
478 if (*password
== NULL
) {
479 nbdkit_error ("strdup: %m");
488 read_password_from_fd (const char *what
, int fd
, char **password
)
495 fp
= fdopen (fd
, "r");
497 nbdkit_error ("fdopen %s: %m", what
);
501 r
= getline (password
, &n
, fp
);
506 nbdkit_error ("could not read password from %s: %m", what
);
510 if (*password
&& r
> 0 && (*password
)[r
-1] == '\n')
511 (*password
)[r
-1] = '\0';
517 nbdkit_nanosleep (unsigned sec
, unsigned nsec
)
521 if (sec
>= INT_MAX
- nsec
/ 1000000000) {
522 nbdkit_error ("sleep request is too long");
526 ts
.tv_sec
= sec
+ nsec
/ 1000000000;
527 ts
.tv_nsec
= nsec
% 1000000000;
529 #if defined HAVE_PPOLL && defined POLLRDHUP
530 /* End the sleep early if any of these happen:
531 * - nbdkit has received a signal to shut down the server
532 * - the current connection is multi-threaded and another thread detects
533 * NBD_CMD_DISC or a problem with the connection
534 * - the input socket detects POLLRDHUP/POLLHUP/POLLERR
536 struct connection
*conn
= threadlocal_get_conn ();
537 struct pollfd fds
[] = {
540 [1].fd
= conn
? conn
->status_pipe
[0] : -1,
542 [2].fd
= conn
? conn
->sockin
: -1,
543 [2].events
= POLLRDHUP
,
547 /* Block all signals to this thread during the poll, so we don't
548 * have to worry about EINTR
550 if (sigfillset(&all
))
552 switch (ppoll (fds
, sizeof fds
/ sizeof fds
[0], &ts
, &all
)) {
554 assert (errno
!= EINTR
);
555 nbdkit_error ("poll: %m");
561 /* We don't have to read the pipe-to-self; if poll returned an
562 * event, we know the connection should be shutting down.
565 (conn
&& conn
->nworkers
> 0 && connection_get_status (conn
) < 1) ||
566 (conn
&& (fds
[2].revents
& (POLLRDHUP
| POLLHUP
| POLLERR
))));
567 nbdkit_error ("aborting sleep to shut down");
572 /* The fallback path simply calls ordinary nanosleep, and will
573 * cause long delays on server shutdown.
575 * If however you want to port this to your platform, then
576 * porting ideas, in order of preference:
577 * - POSIX requires pselect; it's a bit clunkier to set up than poll,
578 * but the same ability to atomically mask all signals and operate
579 * on struct timespec makes it similar to the preferred ppoll interface
580 * - calculate an end time target, then use poll in a loop on EINTR with
581 * a recalculation of the timeout to still reach the end time (masking
582 * signals in that case is not safe, as it is a non-atomic race)
586 r
= nanosleep (&ts
, NULL
);
587 if (r
== -1 && errno
!= EINTR
&& errno
!= EAGAIN
) {
588 nbdkit_error ("nanosleep: %m");
596 nbdkit_export_name (void)
598 struct connection
*conn
= threadlocal_get_conn ();
601 nbdkit_error ("no connection in this thread");
605 return conn
->exportname
;
609 nbdkit_peer_name (struct sockaddr
*addr
, socklen_t
*addrlen
)
611 struct connection
*conn
= threadlocal_get_conn ();
615 nbdkit_error ("no connection in this thread");
621 nbdkit_error ("socket not open");
625 if (getpeername (s
, addr
, addrlen
) == -1) {
626 nbdkit_error ("peername: %m");