Update Red Hat Copyright Notices
[nbdkit.git] / common / utils / utils.c
blob0e46adeb11aaa81533b63dad4430c6767bcfd772
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 #include <config.h>
35 #include <stdio.h>
36 #include <stdlib.h>
37 #include <fcntl.h>
38 #include <unistd.h>
39 #include <string.h>
40 #include <sys/types.h>
42 #ifdef HAVE_SYS_SOCKET_H
43 #include <sys/socket.h>
44 #endif
46 #ifdef HAVE_SYS_WAIT_H
47 #include <sys/wait.h>
48 #endif
50 #include <nbdkit-plugin.h>
52 #include "windows-compat.h"
54 #ifndef WIN32
56 /* Convert exit status to nbd_error. If the exit status was nonzero
57 * or another failure then -1 is returned.
59 int
60 exit_status_to_nbd_error (int status, const char *cmd)
62 if (WIFEXITED (status) && WEXITSTATUS (status) != 0) {
63 nbdkit_error ("%s: command failed with exit code %d",
64 cmd, WEXITSTATUS (status));
65 return -1;
67 else if (WIFSIGNALED (status)) {
68 nbdkit_error ("%s: command was killed by signal %d",
69 cmd, WTERMSIG (status));
70 return -1;
72 else if (WIFSTOPPED (status)) {
73 nbdkit_error ("%s: command was stopped by signal %d",
74 cmd, WSTOPSIG (status));
75 return -1;
78 return 0;
81 #else /* WIN32 */
83 /* This assumes we're using Win32 system(). See:
84 * https://docs.microsoft.com/en-us/cpp/c-runtime-library/reference/system-wsystem?view=vs-2019
86 int
87 exit_status_to_nbd_error (int status, const char *cmd)
89 if (status == 0)
90 return 0;
92 nbdkit_error ("%s: command failed: errno = %d", cmd, errno);
93 return -1;
96 #endif /* WIN32 */
98 #ifndef WIN32
100 /* Set the FD_CLOEXEC flag on the given fd, if it is non-negative.
101 * On failure, close fd and return -1; on success, return fd.
103 * Note that this function should ONLY be used on platforms that lack
104 * atomic CLOEXEC support during fd creation (such as Haiku in 2019);
105 * when using it as a fallback path, you must also consider how to
106 * prevent fd leaks to plugins that want to fork().
109 set_cloexec (int fd)
111 #if (defined SOCK_CLOEXEC && defined HAVE_MKOSTEMP && defined HAVE_PIPE2 && \
112 defined HAVE_ACCEPT4)
113 nbdkit_error ("prefer creating fds with CLOEXEC atomically set");
114 close (fd);
115 errno = EBADF;
116 return -1;
117 #else
118 # if !defined __APPLE__ && \
119 (defined SOCK_CLOEXEC || defined HAVE_MKOSTEMP || defined HAVE_PIPE2 || \
120 defined HAVE_ACCEPT4)
121 # error "Unexpected: your system has incomplete atomic CLOEXEC support"
122 # endif
123 int f;
124 int err;
126 if (fd == -1)
127 return -1;
129 f = fcntl (fd, F_GETFD);
130 if (f == -1 || fcntl (fd, F_SETFD, f | FD_CLOEXEC) == -1) {
131 err = errno;
132 nbdkit_error ("fcntl: %m");
133 close (fd);
134 errno = err;
135 return -1;
137 return fd;
138 #endif
141 #else /* WIN32 */
144 set_cloexec (int fd)
146 return fd;
149 #endif /* WIN32 */
151 #ifndef WIN32
153 /* Set the O_NONBLOCK flag on the given fd, if it is non-negative.
154 * On failure, close fd and return -1; on success, return fd.
157 set_nonblock (int fd)
159 int f;
160 int err;
162 if (fd == -1)
163 return -1;
165 f = fcntl (fd, F_GETFL);
166 if (f == -1 || fcntl (fd, F_SETFL, f | O_NONBLOCK) == -1) {
167 err = errno;
168 nbdkit_error ("fcntl: %m");
169 close (fd);
170 errno = err;
171 return -1;
173 return fd;
176 #else /* WIN32 */
179 set_nonblock (int fd)
181 return fd;
184 #endif /* WIN32 */
186 #ifndef WIN32
188 char *
189 make_temporary_directory (void)
191 char template[] = "/tmp/nbdkitXXXXXX";
193 if (mkdtemp (template) == NULL)
194 return NULL;
196 return strdup (template);
199 #else /* WIN32 */
201 char *
202 make_temporary_directory (void)
204 char tmppath[MAX_PATH];
205 char tmpname[MAX_PATH];
206 DWORD ret;
208 ret = GetTempPath (MAX_PATH, tmppath);
209 if (ret > MAX_PATH || ret == 0) {
210 fprintf (stderr, "mkdtemp: GetTempPath: %lu\n", GetLastError ());
211 return NULL;
214 ret = GetTempFileName (tmppath, TEXT ("nbdkit"), 0, tmpname);
215 if (!ret) {
216 fprintf (stderr, "mkdtemp: GetTempFileName: %lu\n", GetLastError ());
217 return NULL;
220 /* The above function actually creates the file, so we must remove
221 * it before creating the directory. Not ideal because it leaves a
222 * small window for exploitation (XXX).
224 unlink (tmpname);
226 if (mkdir (tmpname) == -1) {
227 fprintf (stderr, "mkdtemp: mkdir: %s: %lu\n", tmpname, GetLastError ());
228 return NULL;
231 return strdup (tmpname);
234 #endif /* WIN32 */