freebsd: In nbdkit_nanosleep, fallback to calling nanosleep(2).
[nbdkit/ericb.git] / server / public.c
blob630de9b3120d6d3f53aaab7ccf32f83481715cdf
1 /* nbdkit
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
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 /* This file contains the public utility APIs to be exported by nbdkit
34 * for use by filters and plugins, declared in nbdkit-common.h.
37 #include <config.h>
39 #include <fcntl.h>
40 #include <stdio.h>
41 #include <stdlib.h>
42 #include <stdbool.h>
43 #include <stdint.h>
44 #include <inttypes.h>
45 #include <string.h>
46 #include <unistd.h>
47 #include <limits.h>
48 #include <termios.h>
49 #include <errno.h>
50 #include <poll.h>
51 #include <signal.h>
53 #include "get-current-dir-name.h"
55 #include "internal.h"
57 char *
58 nbdkit_absolute_path (const char *path)
60 CLEANUP_FREE char *pwd = NULL;
61 char *ret;
63 if (path == NULL || *path == '\0') {
64 nbdkit_error ("cannot convert null or empty path to an absolute path");
65 return NULL;
68 if (*path == '/') {
69 ret = strdup (path);
70 if (!ret) {
71 nbdkit_error ("strdup: %m");
72 return NULL;
74 return ret;
77 pwd = get_current_dir_name ();
78 if (pwd == NULL) {
79 nbdkit_error ("get_current_dir_name: %m");
80 return NULL;
83 if (asprintf (&ret, "%s/%s", pwd, path) == -1) {
84 nbdkit_error ("asprintf: %m");
85 return NULL;
88 return ret;
91 /* Parse a string as a size with possible scaling suffix, or return -1
92 * after reporting the error.
94 int64_t
95 nbdkit_parse_size (const char *str)
97 int64_t size;
98 char *end;
99 uint64_t scale = 1;
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 */
106 errno = 0;
107 size = strtoimax (str, &end, 10);
108 if (str == end) {
109 nbdkit_error ("could not parse size string (%s)", str);
110 return -1;
112 if (size < 0) {
113 nbdkit_error ("size cannot be negative (%s)", str);
114 return -1;
116 if (errno) {
117 nbdkit_error ("size (%s) exceeds maximum value", str);
118 return -1;
121 switch (*end) {
122 /* No suffix */
123 case '\0':
124 end--; /* Safe, since we already filtered out empty string */
125 break;
127 /* Powers of 1024 */
128 case 'e': case 'E':
129 scale *= 1024;
130 /* fallthru */
131 case 'p': case 'P':
132 scale *= 1024;
133 /* fallthru */
134 case 't': case 'T':
135 scale *= 1024;
136 /* fallthru */
137 case 'g': case 'G':
138 scale *= 1024;
139 /* fallthru */
140 case 'm': case 'M':
141 scale *= 1024;
142 /* fallthru */
143 case 'k': case 'K':
144 scale *= 1024;
145 /* fallthru */
146 case 'b': case 'B':
147 break;
149 /* "sectors", ie. units of 512 bytes, even if that's not the real
150 * sector size */
151 case 's': case 'S':
152 scale = 512;
153 break;
155 default:
156 nbdkit_error ("could not parse size: unknown suffix '%s'", end);
157 return -1;
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. */
163 if (end[1]) {
164 nbdkit_error ("could not parse size: unknown suffix '%s'", end);
165 return -1;
168 if (INT64_MAX / scale < size) {
169 nbdkit_error ("overflow computing size (%s)", str);
170 return -1;
173 return size * scale;
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"))
187 return 1;
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"))
195 return 0;
197 nbdkit_error ("could not decipher boolean (%s)", str);
198 return -1;
201 /* Read a password from configuration value. */
203 nbdkit_read_password (const char *value, char **password)
205 int tty, err;
206 struct termios orig, temp;
207 ssize_t r;
208 size_t n;
209 FILE *fp;
211 *password = NULL;
213 /* Read from stdin. */
214 if (strcmp (value, "-") == 0) {
215 printf ("password: ");
217 /* Set no echo. */
218 tty = isatty (0);
219 if (tty) {
220 tcgetattr (0, &orig);
221 temp = orig;
222 temp.c_lflag &= ~ECHO;
223 tcsetattr (0, TCSAFLUSH, &temp);
226 r = getline (password, &n, stdin);
227 err = errno;
229 /* Restore echo. */
230 if (tty)
231 tcsetattr (0, TCSAFLUSH, &orig);
233 /* Complete the printf above. */
234 printf ("\n");
236 if (r == -1) {
237 errno = err;
238 nbdkit_error ("could not read password from stdin: %m");
239 return -1;
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] == '+') {
247 int fd;
249 fd = open (&value[1], O_CLOEXEC | O_RDONLY);
250 if (fd == -1) {
251 nbdkit_error ("open %s: %m", &value[1]);
252 return -1;
254 fp = fdopen (fd, "r");
255 if (fp == NULL) {
256 nbdkit_error ("fdopen %s: %m", &value[1]);
257 close (fd);
258 return -1;
260 r = getline (password, &n, fp);
261 err = errno;
262 fclose (fp);
263 if (r == -1) {
264 errno = err;
265 nbdkit_error ("could not read password from file %s: %m", &value[1]);
266 return -1;
268 if (*password && r > 0 && (*password)[r-1] == '\n')
269 (*password)[r-1] = '\0';
272 /* Parameter is the password. */
273 else {
274 *password = strdup (value);
275 if (*password == NULL) {
276 nbdkit_error ("strdup: %m");
277 return -1;
281 return 0;
284 char *
285 nbdkit_realpath (const char *path)
287 char *ret;
289 if (path == NULL || *path == '\0') {
290 nbdkit_error ("cannot resolve a null or empty path");
291 return NULL;
294 ret = realpath (path, NULL);
295 if (ret == NULL) {
296 nbdkit_error ("realpath: %s: %m", path);
297 return NULL;
300 return ret;
305 nbdkit_nanosleep (unsigned sec, unsigned nsec)
307 struct timespec ts;
309 if (sec >= INT_MAX - nsec / 1000000000) {
310 nbdkit_error ("sleep request is too long");
311 errno = EINVAL;
312 return -1;
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[] = {
326 [0].fd = quit_fd,
327 [0].events = POLLIN,
328 [1].fd = conn ? conn->status_pipe[0] : -1,
329 [1].events = POLLIN,
330 [2].fd = conn ? conn->sockin : -1,
331 [2].events = POLLRDHUP,
333 sigset_t all;
335 /* Block all signals to this thread during the poll, so we don't
336 * have to worry about EINTR
338 if (sigfillset(&all))
339 abort ();
340 switch (ppoll (fds, sizeof fds / sizeof fds[0], &ts, &all)) {
341 case -1:
342 assert (errno != EINTR);
343 nbdkit_error ("poll: %m");
344 return -1;
345 case 0:
346 return 0;
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.
352 assert (quit ||
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");
356 errno = ESHUTDOWN;
357 return -1;
359 #else
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)
372 int r;
374 r = nanosleep (&ts, NULL);
375 if (r == -1 && errno != EINTR && errno != EAGAIN) {
376 nbdkit_error ("nanosleep: %m");
377 return -1;
379 return 0;
380 #endif