Update Red Hat Copyright Notices
[nbdkit.git] / server / public.c
blob71ea6779dffc376eb4d7ee22c8cf5624be9d482c
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 /* 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 <stdio.h>
40 #include <stdlib.h>
41 #include <stdbool.h>
42 #include <stdint.h>
43 #include <inttypes.h>
44 #include <string.h>
45 #include <unistd.h>
46 #include <fcntl.h>
47 #include <limits.h>
48 #include <errno.h>
49 #include <signal.h>
50 #include <sys/types.h>
52 #ifdef HAVE_TERMIOS_H
53 #include <termios.h>
54 #endif
56 #ifdef HAVE_SYS_SOCKET_H
57 #include <sys/socket.h>
58 #endif
60 #ifdef HAVE_SYS_UCRED_H
61 #include <sys/ucred.h>
62 #endif
64 #ifdef HAVE_SYS_UN_H
65 #include <sys/un.h>
66 #endif
68 #ifdef WIN32
69 /* For nanosleep on Windows. */
70 #include <pthread_time.h>
71 #endif
73 #include "array-size.h"
74 #include "ascii-ctype.h"
75 #include "ascii-string.h"
76 #include "get_current_dir_name.h"
77 #include "getline.h"
78 #include "poll.h"
79 #include "realpath.h"
80 #include "strndup.h"
82 #include "internal.h"
84 #ifndef WIN32
86 NBDKIT_DLL_PUBLIC char *
87 nbdkit_absolute_path (const char *path)
89 CLEANUP_FREE char *pwd = NULL;
90 char *ret;
92 if (path == NULL || *path == '\0') {
93 nbdkit_error ("cannot convert null or empty path to an absolute path");
94 return NULL;
97 if (*path == '/') {
98 ret = strdup (path);
99 if (!ret) {
100 nbdkit_error ("strdup: %m");
101 return NULL;
103 return ret;
106 pwd = get_current_dir_name ();
107 if (pwd == NULL) {
108 nbdkit_error ("get_current_dir_name: %m");
109 return NULL;
112 if (asprintf (&ret, "%s" DIR_SEPARATOR_STR "%s", pwd, path) == -1) {
113 nbdkit_error ("asprintf: %m");
114 return NULL;
117 return ret;
120 #else /* WIN32 */
122 /* On Windows realpath() is replaced by GetFullPathName which doesn't
123 * bother to check if the final path exists. Therefore we can simply
124 * replace nbdkit_absolute_path with nbdkit_realpath and everything
125 * should work the same.
127 NBDKIT_DLL_PUBLIC char *
128 nbdkit_absolute_path (const char *path)
130 return nbdkit_realpath (path);
133 #endif /* WIN32 */
135 NBDKIT_DLL_PUBLIC char *
136 nbdkit_realpath (const char *path)
138 char *ret;
140 if (path == NULL || *path == '\0') {
141 nbdkit_error ("cannot resolve a null or empty path");
142 return NULL;
145 ret = realpath (path, NULL);
146 if (ret == NULL) {
147 nbdkit_error ("realpath: %s: %m", path);
148 return NULL;
151 return ret;
154 /* Common code for parsing integers. */
155 #define PARSE_COMMON_TAIL \
156 if (errno != 0) { \
157 nbdkit_error ("%s: could not parse number: \"%s\": %m", \
158 what, str); \
159 return -1; \
161 if (end == str) { \
162 nbdkit_error ("%s: empty string where we expected a number", \
163 what); \
164 return -1; \
166 if (*end) { \
167 nbdkit_error ("%s: could not parse number: \"%s\": trailing garbage", \
168 what, str); \
169 return -1; \
172 if (rp) \
173 *rp = r; \
174 return 0
176 /* Functions for parsing signed integers. */
177 NBDKIT_DLL_PUBLIC int
178 nbdkit_parse_int (const char *what, const char *str, int *rp)
180 long r;
181 char *end;
183 errno = 0;
184 r = strtol (str, &end, 0);
185 #if INT_MAX != LONG_MAX
186 if (r < INT_MIN || r > INT_MAX)
187 errno = ERANGE;
188 #endif
189 PARSE_COMMON_TAIL;
192 NBDKIT_DLL_PUBLIC int
193 nbdkit_parse_int8_t (const char *what, const char *str, int8_t *rp)
195 long r;
196 char *end;
198 errno = 0;
199 r = strtol (str, &end, 0);
200 if (r < INT8_MIN || r > INT8_MAX)
201 errno = ERANGE;
202 PARSE_COMMON_TAIL;
205 NBDKIT_DLL_PUBLIC int
206 nbdkit_parse_int16_t (const char *what, const char *str, int16_t *rp)
208 long r;
209 char *end;
211 errno = 0;
212 r = strtol (str, &end, 0);
213 if (r < INT16_MIN || r > INT16_MAX)
214 errno = ERANGE;
215 PARSE_COMMON_TAIL;
218 NBDKIT_DLL_PUBLIC int
219 nbdkit_parse_int32_t (const char *what, const char *str, int32_t *rp)
221 long r;
222 char *end;
224 errno = 0;
225 r = strtol (str, &end, 0);
226 #if INT32_MAX != LONG_MAX
227 if (r < INT32_MIN || r > INT32_MAX)
228 errno = ERANGE;
229 #endif
230 PARSE_COMMON_TAIL;
233 NBDKIT_DLL_PUBLIC int
234 nbdkit_parse_int64_t (const char *what, const char *str, int64_t *rp)
236 long long r;
237 char *end;
239 errno = 0;
240 r = strtoll (str, &end, 0);
241 #if INT64_MAX != LONGLONG_MAX
242 if (r < INT64_MIN || r > INT64_MAX)
243 errno = ERANGE;
244 #endif
245 PARSE_COMMON_TAIL;
248 /* Functions for parsing unsigned integers. */
250 /* strtou* functions have surprising behaviour if the first character
251 * (after whitespace) is '-', so reject this early.
253 #define PARSE_ERROR_IF_NEGATIVE \
254 do { \
255 while (ascii_isspace (*str)) \
256 str++; \
257 if (*str == '-') { \
258 nbdkit_error ("%s: negative numbers are not allowed", what); \
259 return -1; \
261 } while (0)
263 NBDKIT_DLL_PUBLIC int
264 nbdkit_parse_unsigned (const char *what, const char *str, unsigned *rp)
266 unsigned long r;
267 char *end;
269 PARSE_ERROR_IF_NEGATIVE;
270 errno = 0;
271 r = strtoul (str, &end, 0);
272 #if UINT_MAX != ULONG_MAX
273 if (r > UINT_MAX)
274 errno = ERANGE;
275 #endif
276 PARSE_COMMON_TAIL;
279 NBDKIT_DLL_PUBLIC int
280 nbdkit_parse_uint8_t (const char *what, const char *str, uint8_t *rp)
282 unsigned long r;
283 char *end;
285 PARSE_ERROR_IF_NEGATIVE;
286 errno = 0;
287 r = strtoul (str, &end, 0);
288 if (r > UINT8_MAX)
289 errno = ERANGE;
290 PARSE_COMMON_TAIL;
293 NBDKIT_DLL_PUBLIC int
294 nbdkit_parse_uint16_t (const char *what, const char *str, uint16_t *rp)
296 unsigned long r;
297 char *end;
299 PARSE_ERROR_IF_NEGATIVE;
300 errno = 0;
301 r = strtoul (str, &end, 0);
302 if (r > UINT16_MAX)
303 errno = ERANGE;
304 PARSE_COMMON_TAIL;
307 NBDKIT_DLL_PUBLIC int
308 nbdkit_parse_uint32_t (const char *what, const char *str, uint32_t *rp)
310 unsigned long r;
311 char *end;
313 PARSE_ERROR_IF_NEGATIVE;
314 errno = 0;
315 r = strtoul (str, &end, 0);
316 #if UINT32_MAX != ULONG_MAX
317 if (r > UINT32_MAX)
318 errno = ERANGE;
319 #endif
320 PARSE_COMMON_TAIL;
323 NBDKIT_DLL_PUBLIC int
324 nbdkit_parse_uint64_t (const char *what, const char *str, uint64_t *rp)
326 unsigned long long r;
327 char *end;
329 PARSE_ERROR_IF_NEGATIVE;
330 errno = 0;
331 r = strtoull (str, &end, 0);
332 #if UINT64_MAX != ULONGLONG_MAX
333 if (r > UINT64_MAX)
334 errno = ERANGE;
335 #endif
336 PARSE_COMMON_TAIL;
339 /* Parse a string as a size with possible scaling suffix, or return -1
340 * after reporting the error.
342 NBDKIT_DLL_PUBLIC int64_t
343 nbdkit_parse_size (const char *str)
345 int64_t size;
346 char *end;
347 uint64_t scale = 1;
349 /* Disk sizes cannot usefully exceed off_t (which is signed) and
350 * cannot be negative. */
351 /* XXX Should we also parse things like '1.5M'? */
352 /* XXX Should we allow hex? If so, hex cannot use scaling suffixes,
353 * because some of them are valid hex digits */
354 errno = 0;
355 size = strtoimax (str, &end, 10);
356 if (str == end) {
357 nbdkit_error ("could not parse size string (%s)", str);
358 return -1;
360 if (size < 0) {
361 nbdkit_error ("size cannot be negative (%s)", str);
362 return -1;
364 if (errno) {
365 nbdkit_error ("size (%s) exceeds maximum value", str);
366 return -1;
369 switch (*end) {
370 /* No suffix */
371 case '\0':
372 end--; /* Safe, since we already filtered out empty string */
373 break;
375 /* Powers of 1024 */
376 case 'e': case 'E':
377 scale *= 1024;
378 /* fallthru */
379 case 'p': case 'P':
380 scale *= 1024;
381 /* fallthru */
382 case 't': case 'T':
383 scale *= 1024;
384 /* fallthru */
385 case 'g': case 'G':
386 scale *= 1024;
387 /* fallthru */
388 case 'm': case 'M':
389 scale *= 1024;
390 /* fallthru */
391 case 'k': case 'K':
392 scale *= 1024;
393 /* fallthru */
394 case 'b': case 'B':
395 break;
397 /* "sectors", ie. units of 512 bytes, even if that's not the real
398 * sector size */
399 case 's': case 'S':
400 scale = 512;
401 break;
403 default:
404 nbdkit_error ("could not parse size: unknown suffix '%s'", end);
405 return -1;
408 /* XXX Maybe we should support 'MiB' as a synonym for 'M'; and 'MB'
409 * for powers of 1000, for similarity to GNU tools. But for now,
410 * anything beyond 'M' is dropped. */
411 if (end[1]) {
412 nbdkit_error ("could not parse size: unknown suffix '%s'", end);
413 return -1;
416 if (INT64_MAX / scale < size) {
417 nbdkit_error ("overflow computing size (%s)", str);
418 return -1;
421 return size * scale;
424 /* Parse a string as a boolean, or return -1 after reporting the error.
426 NBDKIT_DLL_PUBLIC int
427 nbdkit_parse_bool (const char *str)
429 if (!strcmp (str, "1") ||
430 !ascii_strcasecmp (str, "true") ||
431 !ascii_strcasecmp (str, "t") ||
432 !ascii_strcasecmp (str, "yes") ||
433 !ascii_strcasecmp (str, "y") ||
434 !ascii_strcasecmp (str, "on"))
435 return 1;
437 if (!strcmp (str, "0") ||
438 !ascii_strcasecmp (str, "false") ||
439 !ascii_strcasecmp (str, "f") ||
440 !ascii_strcasecmp (str, "no") ||
441 !ascii_strcasecmp (str, "n") ||
442 !ascii_strcasecmp (str, "off"))
443 return 0;
445 nbdkit_error ("could not decipher boolean (%s)", str);
446 return -1;
449 /* Return true if it is safe to read from stdin during configuration. */
450 NBDKIT_DLL_PUBLIC int
451 nbdkit_stdio_safe (void)
453 return !listen_stdin && !configured;
456 /* Read a password from configuration value. */
457 static int read_password_interactive (char **password);
458 static int read_password_from_fd (const char *what, int fd, char **password);
460 NBDKIT_DLL_PUBLIC int
461 nbdkit_read_password (const char *value, char **password)
463 *password = NULL;
465 /* Read from stdin interactively. */
466 if (strcmp (value, "-") == 0) {
467 if (read_password_interactive (password) == -1)
468 return -1;
471 /* Read from numbered file descriptor. */
472 else if (value[0] == '-') {
473 #ifndef WIN32
474 int fd;
476 if (nbdkit_parse_int ("password file descriptor", &value[1], &fd) == -1)
477 return -1;
478 if (fd == STDIN_FILENO || fd == STDOUT_FILENO || fd == STDERR_FILENO) {
479 nbdkit_error ("cannot use password -FD for stdin/stdout/stderr");
480 return -1;
482 if (read_password_from_fd (&value[1], fd, password) == -1)
483 return -1;
485 #else /* WIN32 */
486 /* As far as I know this will never be possible on Windows, so
487 * it's a simple error.
489 nbdkit_error ("not possible to read passwords from file descriptors "
490 "under Windows");
491 return -1;
492 #endif /* WIN32 */
495 /* Read password from a file. */
496 else if (value[0] == '+') {
497 int fd;
499 fd = open (&value[1], O_RDONLY | O_CLOEXEC);
500 if (fd == -1) {
501 nbdkit_error ("open %s: %m", &value[1]);
502 return -1;
504 if (read_password_from_fd (&value[1], fd, password) == -1)
505 return -1;
508 /* Parameter is the password. */
509 else {
510 *password = strdup (value);
511 if (*password == NULL) {
512 nbdkit_error ("strdup: %m");
513 return -1;
517 return 0;
520 #ifndef WIN32
522 typedef struct termios echo_mode;
524 static void
525 echo_off (echo_mode *old_mode)
527 struct termios temp;
529 tcgetattr (STDIN_FILENO, old_mode);
530 temp = *old_mode;
531 temp.c_lflag &= ~ECHO;
532 tcsetattr (STDIN_FILENO, TCSAFLUSH, &temp);
535 static void
536 echo_restore (const echo_mode *old_mode)
538 tcsetattr (STDIN_FILENO, TCSAFLUSH, old_mode);
541 #else /* WIN32 */
543 /* Windows implementation of tty echo off based on this:
544 * https://stackoverflow.com/a/1455007
546 typedef DWORD echo_mode;
548 static void
549 echo_off (echo_mode *old_mode)
551 HANDLE h_stdin;
552 DWORD mode;
554 h_stdin = GetStdHandle (STD_INPUT_HANDLE);
555 GetConsoleMode (h_stdin, old_mode);
556 mode = *old_mode;
557 mode &= ~ENABLE_ECHO_INPUT;
558 SetConsoleMode (h_stdin, mode);
561 static void
562 echo_restore (const echo_mode *old_mode)
564 HANDLE h_stdin;
566 h_stdin = GetStdHandle (STD_INPUT_HANDLE);
567 SetConsoleMode (h_stdin, *old_mode);
570 #endif /* WIN32 */
572 static int
573 read_password_interactive (char **password)
575 int err;
576 echo_mode orig;
577 ssize_t r;
578 size_t n;
580 if (!nbdkit_stdio_safe ()) {
581 nbdkit_error ("stdin is not available for reading password");
582 return -1;
585 if (!isatty (STDIN_FILENO)) {
586 nbdkit_error ("stdin is not a tty, cannot read password interactively");
587 return -1;
590 printf ("password: ");
592 /* Set no echo. */
593 echo_off (&orig);
595 /* To distinguish between error and EOF we have to check errno.
596 * getline can return -1 and errno = 0 which means we got end of
597 * file, which is simply a zero length password.
599 errno = 0;
600 r = getline (password, &n, stdin);
601 err = errno;
603 /* Restore echo. */
604 echo_restore (&orig);
606 /* Complete the printf above. */
607 printf ("\n");
609 if (r == -1) {
610 if (err == 0) { /* EOF, not an error. */
611 free (*password); /* State of linebuf is undefined. */
612 *password = strdup ("");
613 if (*password == NULL) {
614 nbdkit_error ("strdup: %m");
615 return -1;
618 else {
619 errno = err;
620 nbdkit_error ("could not read password from stdin: %m");
621 return -1;
625 if (*password && r > 0 && (*password)[r-1] == '\n')
626 (*password)[r-1] = '\0';
628 return 0;
631 static int
632 read_password_from_fd (const char *what, int fd, char **password)
634 FILE *fp;
635 size_t n;
636 ssize_t r;
637 int err;
639 fp = fdopen (fd, "r");
640 if (fp == NULL) {
641 nbdkit_error ("fdopen %s: %m", what);
642 close (fd);
643 return -1;
646 /* To distinguish between error and EOF we have to check errno.
647 * getline can return -1 and errno = 0 which means we got end of
648 * file, which is simply a zero length password.
650 errno = 0;
651 r = getline (password, &n, fp);
652 err = errno;
654 fclose (fp);
656 if (r == -1) {
657 if (err == 0) { /* EOF, not an error. */
658 free (*password); /* State of linebuf is undefined. */
659 *password = strdup ("");
660 if (*password == NULL) {
661 nbdkit_error ("strdup: %m");
662 return -1;
665 else {
666 errno = err;
667 nbdkit_error ("could not read password from %s: %m", what);
668 return -1;
672 if (*password && r > 0 && (*password)[r-1] == '\n')
673 (*password)[r-1] = '\0';
675 return 0;
678 NBDKIT_DLL_PUBLIC int
679 nbdkit_nanosleep (unsigned sec, unsigned nsec)
681 struct timespec ts;
683 if (sec >= INT_MAX - nsec / 1000000000) {
684 nbdkit_error ("sleep request is too long");
685 errno = EINVAL;
686 return -1;
688 ts.tv_sec = sec + nsec / 1000000000;
689 ts.tv_nsec = nsec % 1000000000;
691 #if defined HAVE_PPOLL && defined POLLRDHUP
692 /* End the sleep early if any of these happen:
693 * - nbdkit has received a signal to shut down the server
694 * - the current connection is multi-threaded and another thread detects
695 * NBD_CMD_DISC or a problem with the connection
696 * - the input socket detects POLLRDHUP/POLLHUP/POLLERR
697 * - the input socket is invalid (POLLNVAL, probably closed by
698 * another thread)
700 struct connection *conn = threadlocal_get_conn ();
701 struct pollfd fds[] = {
702 [0].fd = quit_fd,
703 [0].events = POLLIN,
704 [1].fd = conn ? conn->status_pipe[0] : -1,
705 [1].events = POLLIN,
706 [2].fd = conn ? conn->sockin : -1,
707 [2].events = POLLRDHUP,
709 sigset_t all;
711 /* Block all signals to this thread during the poll, so we don't
712 * have to worry about EINTR
714 if (sigfillset (&all))
715 abort ();
716 switch (ppoll (fds, ARRAY_SIZE (fds), &ts, &all)) {
717 case -1:
718 assert (errno != EINTR);
719 nbdkit_error ("poll: %m");
720 return -1;
721 case 0:
722 return 0;
725 /* We don't have to read the pipe-to-self; if poll returned an
726 * event, we know the connection should be shutting down.
728 bool has_quit = quit;
729 assert (has_quit ||
730 (conn && conn->nworkers > 0 &&
731 connection_get_status () < STATUS_SHUTDOWN) ||
732 (conn && (fds[2].revents & (POLLRDHUP | POLLHUP | POLLERR |
733 POLLNVAL))));
734 if (has_quit)
735 nbdkit_error ("aborting sleep because of server shut down");
736 else
737 nbdkit_error ("aborting sleep because of connection close or error");
738 errno = ESHUTDOWN;
739 return -1;
741 #else
742 /* The fallback path simply calls ordinary nanosleep, and will
743 * cause long delays on server shutdown.
745 * If however you want to port this to your platform, then
746 * porting ideas, in order of preference:
747 * - POSIX requires pselect; it's a bit clunkier to set up than poll,
748 * but the same ability to atomically mask all signals and operate
749 * on struct timespec makes it similar to the preferred ppoll interface
750 * - calculate an end time target, then use poll in a loop on EINTR with
751 * a recalculation of the timeout to still reach the end time (masking
752 * signals in that case is not safe, as it is a non-atomic race)
754 int r;
756 r = nanosleep (&ts, NULL);
757 if (r == -1 && errno != EINTR && errno != EAGAIN) {
758 nbdkit_error ("nanosleep: %m");
759 return -1;
761 return 0;
762 #endif
765 /* This function will be deprecated for API V3 users. The preferred
766 * approach will be to get the exportname from .open().
768 NBDKIT_DLL_PUBLIC const char *
769 nbdkit_export_name (void)
771 struct context *c = threadlocal_get_context ();
773 if (!c || !c->conn) {
774 nbdkit_error ("no connection in this thread");
775 return NULL;
778 return c->conn->exportname;
781 /* This function will be deprecated for API V3 users. The preferred
782 * approach will be to get the tls mode from .open().
784 NBDKIT_DLL_PUBLIC int
785 nbdkit_is_tls (void)
787 struct context *c = threadlocal_get_context ();
789 if (!c) {
790 nbdkit_error ("no connection in this thread");
791 return -1;
794 if (!c->conn) {
795 /* If a filter opened this backend outside of a client connection,
796 * then we can only claim tls when the command line required it.
798 return tls == 2;
801 return c->conn->using_tls;
804 NBDKIT_DLL_PUBLIC int
805 nbdkit_peer_name (struct sockaddr *addr, socklen_t *addrlen)
807 struct connection *conn = threadlocal_get_conn ();
808 int s;
810 if (!conn) {
811 nbdkit_error ("no connection in this thread");
812 return -1;
815 s = conn->sockin;
816 if (s == -1) {
817 nbdkit_error ("socket not open");
818 return -1;
821 if (getpeername (s, addr, addrlen) == -1) {
822 nbdkit_error ("peername: %m");
823 return -1;
826 return 0;
829 #if defined (SO_PEERCRED) && \
830 (defined (HAVE_STRUCT_UCRED_UID) || defined (HAVE_STRUCT_SOCKPEERCRED_UID))
832 #define GET_PEERCRED_DEFINED 1
834 static int
835 get_peercred (int s, int64_t *pid, int64_t *uid, int64_t *gid)
837 #if HAVE_STRUCT_UCRED_UID
838 struct ucred cred;
839 #elif HAVE_STRUCT_SOCKPEERCRED_UID
840 /* The struct has a different name on OpenBSD, but the same members. */
841 struct sockpeercred cred;
842 #endif
843 socklen_t n = sizeof cred;
845 if (getsockopt (s, SOL_SOCKET, SO_PEERCRED, &cred, &n) == -1) {
846 nbdkit_error ("getsockopt: SO_PEERCRED: %m");
847 return -1;
850 if (pid && cred.pid >= 1) {
851 #if SIZEOF_PID_T >= 8
852 if (cred.pid > INT64_MAX)
853 nbdkit_error ("pid out of range: cannot be mapped to int64_t");
854 else
855 #endif
856 *pid = cred.pid;
858 if (uid && cred.uid >= 0) {
859 #if SIZEOF_UID_T >= 8
860 if (cred.uid > INT64_MAX)
861 nbdkit_error ("uid out of range: cannot be mapped to int64_t");
862 else
863 #endif
864 *uid = cred.uid;
866 if (gid && cred.gid >= 0) {
867 #if SIZEOF_GID_T >= 8
868 if (cred.gid > INT64_MAX)
869 nbdkit_error ("gid out of range: cannot be mapped to int64_t");
870 else
871 #endif
872 *gid = cred.gid;
875 return 0;
878 #endif /* SO_PEERCRED */
880 #ifdef LOCAL_PEERCRED
882 #define GET_PEERCRED_DEFINED 1
884 /* FreeBSD supports LOCAL_PEERCRED and struct xucred. */
885 static int
886 get_peercred (int s, int64_t *pid, int64_t *uid, int64_t *gid)
888 struct xucred xucred;
889 socklen_t n = sizeof xucred;
891 if (getsockopt (s, 0, LOCAL_PEERCRED, &xucred, &n) == -1) {
892 nbdkit_error ("getsockopt: LOCAL_PEERCRED: %m");
893 return -1;
896 if (xucred.cr_version != XUCRED_VERSION) {
897 nbdkit_error ("getsockopt: LOCAL_PEERCRED: "
898 "struct xucred version (%u) "
899 "did not match expected version (%u)",
900 xucred.cr_version, XUCRED_VERSION);
901 return -1;
904 if (n != sizeof xucred) {
905 nbdkit_error ("getsockopt: LOCAL_PEERCRED: did not return full struct");
906 return -1;
909 if (pid)
910 nbdkit_error ("nbdkit_peer_pid is not supported on this platform");
911 if (uid && xucred.cr_uid >= 0) {
912 #if SIZEOF_UID_T >= 8
913 if (xucred.cr_uid <= INT64_MAX)
914 #endif
915 *uid = xucred.cr_uid;
916 #if SIZEOF_UID_T >= 8
917 else
918 nbdkit_error ("uid out of range: cannot be mapped to int64_t");
919 #endif
921 if (gid && xucred.cr_ngroups > 0) {
922 #if SIZEOF_GID_T >= 8
923 if (xucred.cr_gid <= INT64_MAX)
924 #endif
925 *gid = xucred.cr_gid;
926 #if SIZEOF_GID_T >= 8
927 else
928 nbdkit_error ("gid out of range: cannot be mapped to int64_t");
929 #endif
932 return 0;
935 #endif /* LOCAL_PEERCRED */
937 #ifndef GET_PEERCRED_DEFINED
939 static int
940 get_peercred (int s, int64_t *pid, int64_t *uid, int64_t *gid)
942 nbdkit_error ("nbdkit_peer_pid, nbdkit_peer_uid and nbdkit_peer_gid "
943 "are not supported on this platform");
944 return -1;
947 #endif
949 static int
950 get_peercred_common (int64_t *pid, int64_t *uid, int64_t *gid)
952 struct connection *conn = threadlocal_get_conn ();
953 int s;
955 if (pid) *pid = -1;
956 if (uid) *uid = -1;
957 if (gid) *gid = -1;
959 if (!conn) {
960 nbdkit_error ("no connection in this thread");
961 return -1;
964 s = conn->sockin;
965 if (s == -1) {
966 nbdkit_error ("socket not open");
967 return -1;
970 return get_peercred (s, pid, uid, gid);
973 NBDKIT_DLL_PUBLIC int64_t
974 nbdkit_peer_pid ()
976 int64_t pid;
978 if (get_peercred_common (&pid, NULL, NULL) == -1)
979 return -1;
981 return pid;
984 NBDKIT_DLL_PUBLIC int64_t
985 nbdkit_peer_uid ()
987 int64_t uid;
989 if (get_peercred_common (NULL, &uid, NULL) == -1)
990 return -1;
992 return uid;
995 NBDKIT_DLL_PUBLIC int64_t
996 nbdkit_peer_gid ()
998 int64_t gid;
1000 if (get_peercred_common (NULL, NULL, &gid) == -1)
1001 return -1;
1003 return gid;
1006 /* Functions for manipulating intern'd strings. */
1008 static string_vector global_interns;
1010 void
1011 free_interns (void)
1013 struct connection *conn = threadlocal_get_conn ();
1014 string_vector *list = conn ? &conn->interns : &global_interns;
1016 string_vector_empty (list);
1019 static const char *
1020 add_intern (char *str)
1022 struct context *c = threadlocal_get_context ();
1023 struct connection *conn = c ? c->conn : NULL;
1024 string_vector *list = conn ? &conn->interns : &global_interns;
1026 if (string_vector_append (list, str) == -1) {
1027 nbdkit_error ("malloc: %m");
1028 free (str);
1029 return NULL;
1032 return str;
1035 NBDKIT_DLL_PUBLIC const char *
1036 nbdkit_strndup_intern (const char *str, size_t n)
1038 char *copy;
1040 if (str == NULL) {
1041 nbdkit_error ("nbdkit_strndup_intern: no string given");
1042 errno = EINVAL;
1043 return NULL;
1046 copy = strndup (str, n);
1047 if (copy == NULL) {
1048 nbdkit_error ("strndup: %m");
1049 return NULL;
1052 return add_intern (copy);
1055 NBDKIT_DLL_PUBLIC const char *
1056 nbdkit_strdup_intern (const char *str)
1058 char *copy;
1060 if (str == NULL) {
1061 nbdkit_error ("nbdkit_strdup_intern: no string given");
1062 errno = EINVAL;
1063 return NULL;
1066 copy = strdup (str);
1067 if (copy == NULL) {
1068 nbdkit_error ("strdup: %m");
1069 return NULL;
1072 return add_intern (copy);
1075 NBDKIT_DLL_PUBLIC const char *
1076 nbdkit_vprintf_intern (const char *fmt, va_list ap)
1078 char *str = NULL;
1080 if (vasprintf (&str, fmt, ap) == -1) {
1081 nbdkit_error ("asprintf: %m");
1082 return NULL;
1085 return add_intern (str);
1088 NBDKIT_DLL_PUBLIC const char *
1089 nbdkit_printf_intern (const char *fmt, ...)
1091 va_list ap;
1092 const char *ret;
1094 va_start (ap, fmt);
1095 ret = nbdkit_vprintf_intern (fmt, ap);
1096 va_end (ap);
1097 return ret;
1100 NBDKIT_DLL_PUBLIC void
1101 nbdkit_disconnect (int force)
1103 struct connection *conn = threadlocal_get_conn ();
1105 if (!conn) {
1106 debug ("no connection in this thread, ignoring disconnect request");
1107 return;
1109 if (connection_set_status (force ? STATUS_DEAD : STATUS_SHUTDOWN)) {
1110 ACQUIRE_LOCK_FOR_CURRENT_SCOPE (&conn->write_lock);
1111 conn->close (SHUT_WR);