]> git.proxmox.com Git - qemu.git/blame - osdep.c
fdc: fix FD_SR0_SEEK for non-DMA transfers and multi sectors transfers
[qemu.git] / osdep.c
CommitLineData
ea88812f
FB
1/*
2 * QEMU low level functions
5fafdf24 3 *
ea88812f 4 * Copyright (c) 2003 Fabrice Bellard
5fafdf24 5 *
ea88812f
FB
6 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 * of this software and associated documentation files (the "Software"), to deal
8 * in the Software without restriction, including without limitation the rights
9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 * copies of the Software, and to permit persons to whom the Software is
11 * furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 * THE SOFTWARE.
23 */
24#include <stdlib.h>
25#include <stdio.h>
26#include <stdarg.h>
0f66998f 27#include <stdbool.h>
ea88812f 28#include <string.h>
ea88812f
FB
29#include <errno.h>
30#include <unistd.h>
aa26bb2d 31#include <fcntl.h>
f582af58
PB
32
33/* Needed early for CONFIG_BSD etc. */
34#include "config-host.h"
35
e78815a5
AF
36#if defined(CONFIG_MADVISE) || defined(CONFIG_POSIX_MADVISE)
37#include <sys/mman.h>
38#endif
39
dfe5fff3 40#ifdef CONFIG_SOLARIS
605686cd
TS
41#include <sys/types.h>
42#include <sys/statvfs.h>
e78815a5
AF
43/* See MySQL bug #7156 (http://bugs.mysql.com/bug.php?id=7156) for
44 discussion about Solaris header problems */
45extern int madvise(caddr_t, size_t, int);
605686cd 46#endif
ea88812f 47
511d2b14 48#include "qemu-common.h"
cd245a19 49#include "trace.h"
03ff3ca3 50#include "qemu_socket.h"
adb696f3 51#include "monitor.h"
03ff3ca3 52
0f66998f
PM
53static bool fips_enabled = false;
54
93bfef4c
CV
55static const char *qemu_version = QEMU_VERSION;
56
1f001dc7
PB
57static int default_fdset_get_fd(int64_t fdset_id, int flags)
58{
59 return -1;
60}
61QEMU_WEAK_ALIAS(monitor_fdset_get_fd, default_fdset_get_fd);
62#define monitor_fdset_get_fd \
63 QEMU_WEAK_REF(monitor_fdset_get_fd, default_fdset_get_fd)
64
65static int default_fdset_dup_fd_add(int64_t fdset_id, int dup_fd)
66{
67 return -1;
68}
69QEMU_WEAK_ALIAS(monitor_fdset_dup_fd_add, default_fdset_dup_fd_add);
70#define monitor_fdset_dup_fd_add \
71 QEMU_WEAK_REF(monitor_fdset_dup_fd_add, default_fdset_dup_fd_add)
72
73static int default_fdset_dup_fd_remove(int dup_fd)
74{
75 return -1;
76}
77QEMU_WEAK_ALIAS(monitor_fdset_dup_fd_remove, default_fdset_dup_fd_remove);
78#define monitor_fdset_dup_fd_remove \
79 QEMU_WEAK_REF(monitor_fdset_dup_fd_remove, default_fdset_dup_fd_remove)
80
81static int default_fdset_dup_fd_find(int dup_fd)
82{
83 return -1;
84}
85QEMU_WEAK_ALIAS(monitor_fdset_dup_fd_find, default_fdset_dup_fd_find);
86#define monitor_fdset_dup_fd_find \
87 QEMU_WEAK_REF(monitor_fdset_dup_fd_remove, default_fdset_dup_fd_find)
88
128aa589
PB
89int socket_set_cork(int fd, int v)
90{
91#if defined(SOL_TCP) && defined(TCP_CORK)
92 return setsockopt(fd, SOL_TCP, TCP_CORK, &v, sizeof(v));
93#else
94 return 0;
95#endif
96}
97
e78815a5
AF
98int qemu_madvise(void *addr, size_t len, int advice)
99{
100 if (advice == QEMU_MADV_INVALID) {
101 errno = EINVAL;
102 return -1;
103 }
104#if defined(CONFIG_MADVISE)
105 return madvise(addr, len, advice);
106#elif defined(CONFIG_POSIX_MADVISE)
107 return posix_madvise(addr, len, advice);
108#else
109 errno = EINVAL;
110 return -1;
111#endif
112}
113
adb696f3
CB
114#ifndef _WIN32
115/*
116 * Dups an fd and sets the flags
117 */
118static int qemu_dup_flags(int fd, int flags)
119{
120 int ret;
121 int serrno;
122 int dup_flags;
adb696f3
CB
123
124#ifdef F_DUPFD_CLOEXEC
125 ret = fcntl(fd, F_DUPFD_CLOEXEC, 0);
126#else
127 ret = dup(fd);
128 if (ret != -1) {
129 qemu_set_cloexec(ret);
130 }
131#endif
132 if (ret == -1) {
133 goto fail;
134 }
135
136 dup_flags = fcntl(ret, F_GETFL);
137 if (dup_flags == -1) {
138 goto fail;
139 }
140
141 if ((flags & O_SYNC) != (dup_flags & O_SYNC)) {
142 errno = EINVAL;
143 goto fail;
144 }
145
146 /* Set/unset flags that we can with fcntl */
3b6eda2f 147 if (fcntl(ret, F_SETFL, flags) == -1) {
adb696f3
CB
148 goto fail;
149 }
150
151 /* Truncate the file in the cases that open() would truncate it */
152 if (flags & O_TRUNC ||
153 ((flags & (O_CREAT | O_EXCL)) == (O_CREAT | O_EXCL))) {
154 if (ftruncate(ret, 0) == -1) {
155 goto fail;
156 }
157 }
158
159 return ret;
160
161fail:
162 serrno = errno;
163 if (ret != -1) {
164 close(ret);
165 }
166 errno = serrno;
167 return -1;
168}
0100fbbe
PB
169
170static int qemu_parse_fdset(const char *param)
171{
172 return qemu_parse_fd(param);
173}
adb696f3 174#endif
03ff3ca3 175
40ff6d7e
KW
176/*
177 * Opens a file with FD_CLOEXEC set
178 */
179int qemu_open(const char *name, int flags, ...)
180{
181 int ret;
182 int mode = 0;
183
adb696f3
CB
184#ifndef _WIN32
185 const char *fdset_id_str;
186
187 /* Attempt dup of fd from fd set */
188 if (strstart(name, "/dev/fdset/", &fdset_id_str)) {
189 int64_t fdset_id;
190 int fd, dupfd;
191
192 fdset_id = qemu_parse_fdset(fdset_id_str);
193 if (fdset_id == -1) {
194 errno = EINVAL;
195 return -1;
196 }
197
198 fd = monitor_fdset_get_fd(fdset_id, flags);
199 if (fd == -1) {
200 return -1;
201 }
202
203 dupfd = qemu_dup_flags(fd, flags);
204 if (dupfd == -1) {
205 return -1;
206 }
207
208 ret = monitor_fdset_dup_fd_add(fdset_id, dupfd);
209 if (ret == -1) {
210 close(dupfd);
211 errno = EINVAL;
212 return -1;
213 }
214
215 return dupfd;
216 }
217#endif
218
40ff6d7e
KW
219 if (flags & O_CREAT) {
220 va_list ap;
221
222 va_start(ap, flags);
223 mode = va_arg(ap, int);
224 va_end(ap);
225 }
226
227#ifdef O_CLOEXEC
228 ret = open(name, flags | O_CLOEXEC, mode);
229#else
230 ret = open(name, flags, mode);
231 if (ret >= 0) {
232 qemu_set_cloexec(ret);
233 }
03ff3ca3 234#endif
40ff6d7e
KW
235
236 return ret;
237}
238
2e1e79da
CB
239int qemu_close(int fd)
240{
adb696f3
CB
241 int64_t fdset_id;
242
243 /* Close fd that was dup'd from an fdset */
244 fdset_id = monitor_fdset_dup_fd_find(fd);
245 if (fdset_id != -1) {
246 int ret;
247
248 ret = close(fd);
249 if (ret == 0) {
250 monitor_fdset_dup_fd_remove(fd);
251 }
252
253 return ret;
254 }
255
2e1e79da
CB
256 return close(fd);
257}
258
7b5f699d
KS
259/*
260 * A variant of write(2) which handles partial write.
261 *
262 * Return the number of bytes transferred.
263 * Set errno if fewer than `count' bytes are written.
1298cb68
JQ
264 *
265 * This function don't work with non-blocking fd's.
266 * Any of the possibilities with non-bloking fd's is bad:
267 * - return a short write (then name is wrong)
268 * - busy wait adding (errno == EAGAIN) to the loop
7b5f699d
KS
269 */
270ssize_t qemu_write_full(int fd, const void *buf, size_t count)
271{
272 ssize_t ret = 0;
273 ssize_t total = 0;
274
275 while (count) {
276 ret = write(fd, buf, count);
277 if (ret < 0) {
278 if (errno == EINTR)
279 continue;
280 break;
281 }
282
283 count -= ret;
284 buf += ret;
285 total += ret;
286 }
287
288 return total;
289}
290
40ff6d7e
KW
291/*
292 * Opens a socket with FD_CLOEXEC set
293 */
294int qemu_socket(int domain, int type, int protocol)
295{
296 int ret;
297
298#ifdef SOCK_CLOEXEC
299 ret = socket(domain, type | SOCK_CLOEXEC, protocol);
3a03bfa5
AP
300 if (ret != -1 || errno != EINVAL) {
301 return ret;
302 }
303#endif
40ff6d7e
KW
304 ret = socket(domain, type, protocol);
305 if (ret >= 0) {
306 qemu_set_cloexec(ret);
307 }
40ff6d7e
KW
308
309 return ret;
310}
311
312/*
313 * Accept a connection and set FD_CLOEXEC
314 */
315int qemu_accept(int s, struct sockaddr *addr, socklen_t *addrlen)
316{
317 int ret;
318
319#ifdef CONFIG_ACCEPT4
320 ret = accept4(s, addr, addrlen, SOCK_CLOEXEC);
347ed55c 321 if (ret != -1 || errno != ENOSYS) {
3a03bfa5
AP
322 return ret;
323 }
324#endif
40ff6d7e
KW
325 ret = accept(s, addr, addrlen);
326 if (ret >= 0) {
327 qemu_set_cloexec(ret);
328 }
40ff6d7e
KW
329
330 return ret;
331}
993295fe
PB
332
333/*
334 * A variant of send(2) which handles partial write.
335 *
336 * Return the number of bytes transferred, which is only
337 * smaller than `count' if there is an error.
338 *
339 * This function won't work with non-blocking fd's.
340 * Any of the possibilities with non-bloking fd's is bad:
341 * - return a short write (then name is wrong)
342 * - busy wait adding (errno == EAGAIN) to the loop
343 */
344ssize_t qemu_send_full(int fd, const void *buf, size_t count, int flags)
345{
346 ssize_t ret = 0;
347 ssize_t total = 0;
348
349 while (count) {
350 ret = send(fd, buf, count, flags);
351 if (ret < 0) {
352 if (errno == EINTR) {
353 continue;
354 }
355 break;
356 }
357
358 count -= ret;
359 buf += ret;
360 total += ret;
361 }
362
363 return total;
364}
365
366/*
367 * A variant of recv(2) which handles partial write.
368 *
369 * Return the number of bytes transferred, which is only
370 * smaller than `count' if there is an error.
371 *
372 * This function won't work with non-blocking fd's.
373 * Any of the possibilities with non-bloking fd's is bad:
374 * - return a short write (then name is wrong)
375 * - busy wait adding (errno == EAGAIN) to the loop
376 */
377ssize_t qemu_recv_full(int fd, void *buf, size_t count, int flags)
378{
379 ssize_t ret = 0;
380 ssize_t total = 0;
381
382 while (count) {
383 ret = qemu_recv(fd, buf, count, flags);
384 if (ret <= 0) {
385 if (ret < 0 && errno == EINTR) {
386 continue;
387 }
388 break;
389 }
390
391 count -= ret;
392 buf += ret;
393 total += ret;
394 }
395
396 return total;
397}
398
93bfef4c
CV
399void qemu_set_version(const char *version)
400{
401 qemu_version = version;
402}
403
404const char *qemu_get_version(void)
405{
406 return qemu_version;
407}
0f66998f
PM
408
409void fips_set_state(bool requested)
410{
411#ifdef __linux__
412 if (requested) {
413 FILE *fds = fopen("/proc/sys/crypto/fips_enabled", "r");
414 if (fds != NULL) {
415 fips_enabled = (fgetc(fds) == '1');
416 fclose(fds);
417 }
418 }
419#else
420 fips_enabled = false;
421#endif /* __linux__ */
422
423#ifdef _FIPS_DEBUG
424 fprintf(stderr, "FIPS mode %s (requested %s)\n",
425 (fips_enabled ? "enabled" : "disabled"),
426 (requested ? "enabled" : "disabled"));
427#endif
428}
429
430bool fips_get_state(void)
431{
432 return fips_enabled;
433}
0100fbbe 434