The Android Open Source Project | 8b23a6c | 2009-03-03 19:30:32 -0800 | [diff] [blame] | 1 | /* |
| 2 | * QEMU low level functions |
| 3 | * |
| 4 | * Copyright (c) 2003 Fabrice Bellard |
| 5 | * |
| 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> |
| 27 | #include <string.h> |
| 28 | #include <errno.h> |
| 29 | #include <unistd.h> |
| 30 | #include <fcntl.h> |
David Turner | f7dd220 | 2010-09-10 10:59:22 +0200 | [diff] [blame] | 31 | |
| 32 | /* Needed early for CONFIG_BSD etc. */ |
| 33 | #include "config-host.h" |
| 34 | |
David 'Digit' Turner | 2c538c8 | 2010-05-10 16:48:20 -0700 | [diff] [blame] | 35 | #ifdef CONFIG_SOLARIS |
The Android Open Source Project | 8b23a6c | 2009-03-03 19:30:32 -0800 | [diff] [blame] | 36 | #include <sys/types.h> |
| 37 | #include <sys/statvfs.h> |
| 38 | #endif |
| 39 | |
David Turner | f7dd220 | 2010-09-10 10:59:22 +0200 | [diff] [blame] | 40 | #ifdef CONFIG_EVENTFD |
| 41 | #include <sys/eventfd.h> |
| 42 | #endif |
David 'Digit' Turner | 2910f18 | 2010-05-10 18:48:35 -0700 | [diff] [blame] | 43 | |
| 44 | #ifdef _WIN32 |
| 45 | #include <windows.h> |
| 46 | #elif defined(CONFIG_BSD) |
| 47 | #include <stdlib.h> |
| 48 | #else |
| 49 | #include <malloc.h> |
| 50 | #endif |
| 51 | |
David Turner | 315ceb8 | 2010-09-10 14:15:17 +0200 | [diff] [blame] | 52 | #ifdef CONFIG_ANDROID |
| 53 | #ifdef WIN32 |
| 54 | #include <winsock2.h> |
David 'Digit' Turner | 37a43dc | 2010-09-13 00:15:41 -0700 | [diff] [blame] | 55 | #include <stdint.h> |
David Turner | 315ceb8 | 2010-09-10 14:15:17 +0200 | [diff] [blame] | 56 | typedef int32_t socklen_t; |
| 57 | #else |
| 58 | #include <sys/socket.h> |
| 59 | #endif |
| 60 | #endif /* CONFIG_ANDROID */ |
| 61 | |
The Android Open Source Project | 8b23a6c | 2009-03-03 19:30:32 -0800 | [diff] [blame] | 62 | #include "qemu-common.h" |
| 63 | #include "sysemu.h" |
David Turner | f7dd220 | 2010-09-10 10:59:22 +0200 | [diff] [blame] | 64 | #include "qemu_socket.h" |
The Android Open Source Project | 8b23a6c | 2009-03-03 19:30:32 -0800 | [diff] [blame] | 65 | |
David 'Digit' Turner | 747f7d1 | 2011-01-06 22:24:26 +0100 | [diff] [blame] | 66 | #if !defined(_POSIX_C_SOURCE) || defined(_WIN32) || defined(__sun__) || defined(__APPLE__) |
David Turner | f7dd220 | 2010-09-10 10:59:22 +0200 | [diff] [blame] | 67 | static void *oom_check(void *ptr) |
| 68 | { |
| 69 | if (ptr == NULL) { |
| 70 | #if defined(_WIN32) |
| 71 | fprintf(stderr, "Failed to allocate memory: %lu\n", GetLastError()); |
The Android Open Source Project | 8b23a6c | 2009-03-03 19:30:32 -0800 | [diff] [blame] | 72 | #else |
David Turner | f7dd220 | 2010-09-10 10:59:22 +0200 | [diff] [blame] | 73 | fprintf(stderr, "Failed to allocate memory: %s\n", strerror(errno)); |
The Android Open Source Project | 8b23a6c | 2009-03-03 19:30:32 -0800 | [diff] [blame] | 74 | #endif |
David Turner | f7dd220 | 2010-09-10 10:59:22 +0200 | [diff] [blame] | 75 | abort(); |
| 76 | } |
| 77 | return ptr; |
| 78 | } |
| 79 | #endif |
The Android Open Source Project | 8b23a6c | 2009-03-03 19:30:32 -0800 | [diff] [blame] | 80 | |
| 81 | #if defined(_WIN32) |
| 82 | void *qemu_memalign(size_t alignment, size_t size) |
| 83 | { |
David Turner | f7dd220 | 2010-09-10 10:59:22 +0200 | [diff] [blame] | 84 | if (!size) { |
| 85 | abort(); |
| 86 | } |
| 87 | return oom_check(VirtualAlloc(NULL, size, MEM_COMMIT, PAGE_READWRITE)); |
The Android Open Source Project | 8b23a6c | 2009-03-03 19:30:32 -0800 | [diff] [blame] | 88 | } |
| 89 | |
| 90 | void *qemu_vmalloc(size_t size) |
| 91 | { |
| 92 | /* FIXME: this is not exactly optimal solution since VirtualAlloc |
| 93 | has 64Kb granularity, but at least it guarantees us that the |
| 94 | memory is page aligned. */ |
David Turner | f7dd220 | 2010-09-10 10:59:22 +0200 | [diff] [blame] | 95 | if (!size) { |
| 96 | abort(); |
| 97 | } |
| 98 | return oom_check(VirtualAlloc(NULL, size, MEM_COMMIT, PAGE_READWRITE)); |
The Android Open Source Project | 8b23a6c | 2009-03-03 19:30:32 -0800 | [diff] [blame] | 99 | } |
| 100 | |
| 101 | void qemu_vfree(void *ptr) |
| 102 | { |
| 103 | VirtualFree(ptr, 0, MEM_RELEASE); |
| 104 | } |
| 105 | |
| 106 | #else |
| 107 | |
The Android Open Source Project | 8b23a6c | 2009-03-03 19:30:32 -0800 | [diff] [blame] | 108 | void *qemu_memalign(size_t alignment, size_t size) |
| 109 | { |
David 'Digit' Turner | 747f7d1 | 2011-01-06 22:24:26 +0100 | [diff] [blame] | 110 | #if defined(_POSIX_C_SOURCE) && !defined(__sun__) && !defined(__APPLE__) |
The Android Open Source Project | 8b23a6c | 2009-03-03 19:30:32 -0800 | [diff] [blame] | 111 | int ret; |
| 112 | void *ptr; |
| 113 | ret = posix_memalign(&ptr, alignment, size); |
David Turner | f7dd220 | 2010-09-10 10:59:22 +0200 | [diff] [blame] | 114 | if (ret != 0) { |
| 115 | fprintf(stderr, "Failed to allocate %zu B: %s\n", |
| 116 | size, strerror(ret)); |
| 117 | abort(); |
| 118 | } |
The Android Open Source Project | 8b23a6c | 2009-03-03 19:30:32 -0800 | [diff] [blame] | 119 | return ptr; |
David 'Digit' Turner | 2c538c8 | 2010-05-10 16:48:20 -0700 | [diff] [blame] | 120 | #elif defined(CONFIG_BSD) |
David Turner | f7dd220 | 2010-09-10 10:59:22 +0200 | [diff] [blame] | 121 | return oom_check(valloc(size)); |
The Android Open Source Project | 8b23a6c | 2009-03-03 19:30:32 -0800 | [diff] [blame] | 122 | #else |
David Turner | f7dd220 | 2010-09-10 10:59:22 +0200 | [diff] [blame] | 123 | return oom_check(memalign(alignment, size)); |
The Android Open Source Project | 8b23a6c | 2009-03-03 19:30:32 -0800 | [diff] [blame] | 124 | #endif |
| 125 | } |
| 126 | |
| 127 | /* alloc shared memory pages */ |
| 128 | void *qemu_vmalloc(size_t size) |
| 129 | { |
David 'Digit' Turner | 5d8f37a | 2009-09-14 14:32:27 -0700 | [diff] [blame] | 130 | return qemu_memalign(getpagesize(), size); |
The Android Open Source Project | 8b23a6c | 2009-03-03 19:30:32 -0800 | [diff] [blame] | 131 | } |
| 132 | |
| 133 | void qemu_vfree(void *ptr) |
| 134 | { |
The Android Open Source Project | 8b23a6c | 2009-03-03 19:30:32 -0800 | [diff] [blame] | 135 | free(ptr); |
| 136 | } |
| 137 | |
| 138 | #endif |
| 139 | |
| 140 | int qemu_create_pidfile(const char *filename) |
| 141 | { |
| 142 | char buffer[128]; |
| 143 | int len; |
| 144 | #ifndef _WIN32 |
| 145 | int fd; |
| 146 | |
David Turner | f7dd220 | 2010-09-10 10:59:22 +0200 | [diff] [blame] | 147 | fd = qemu_open(filename, O_RDWR | O_CREAT, 0600); |
The Android Open Source Project | 8b23a6c | 2009-03-03 19:30:32 -0800 | [diff] [blame] | 148 | if (fd == -1) |
| 149 | return -1; |
| 150 | |
| 151 | if (lockf(fd, F_TLOCK, 0) == -1) |
| 152 | return -1; |
| 153 | |
| 154 | len = snprintf(buffer, sizeof(buffer), "%ld\n", (long)getpid()); |
| 155 | if (write(fd, buffer, len) != len) |
| 156 | return -1; |
| 157 | #else |
| 158 | HANDLE file; |
The Android Open Source Project | 8b23a6c | 2009-03-03 19:30:32 -0800 | [diff] [blame] | 159 | OVERLAPPED overlap; |
| 160 | BOOL ret; |
David Turner | f7dd220 | 2010-09-10 10:59:22 +0200 | [diff] [blame] | 161 | memset(&overlap, 0, sizeof(overlap)); |
The Android Open Source Project | 8b23a6c | 2009-03-03 19:30:32 -0800 | [diff] [blame] | 162 | |
David Turner | f7dd220 | 2010-09-10 10:59:22 +0200 | [diff] [blame] | 163 | file = CreateFile(filename, GENERIC_WRITE, FILE_SHARE_READ, NULL, |
The Android Open Source Project | 8b23a6c | 2009-03-03 19:30:32 -0800 | [diff] [blame] | 164 | OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); |
| 165 | |
| 166 | if (file == INVALID_HANDLE_VALUE) |
| 167 | return -1; |
| 168 | |
The Android Open Source Project | 8b23a6c | 2009-03-03 19:30:32 -0800 | [diff] [blame] | 169 | len = snprintf(buffer, sizeof(buffer), "%ld\n", (long)getpid()); |
| 170 | ret = WriteFileEx(file, (LPCVOID)buffer, (DWORD)len, |
| 171 | &overlap, NULL); |
| 172 | if (ret == 0) |
| 173 | return -1; |
| 174 | #endif |
| 175 | return 0; |
| 176 | } |
| 177 | |
| 178 | #ifdef _WIN32 |
| 179 | |
David Turner | f7dd220 | 2010-09-10 10:59:22 +0200 | [diff] [blame] | 180 | /* mingw32 needs ffs for compilations without optimization. */ |
| 181 | int ffs(int i) |
| 182 | { |
| 183 | /* Use gcc's builtin ffs. */ |
| 184 | return __builtin_ffs(i); |
| 185 | } |
| 186 | |
The Android Open Source Project | 8b23a6c | 2009-03-03 19:30:32 -0800 | [diff] [blame] | 187 | /* Offset between 1/1/1601 and 1/1/1970 in 100 nanosec units */ |
| 188 | #define _W32_FT_OFFSET (116444736000000000ULL) |
| 189 | |
| 190 | int qemu_gettimeofday(qemu_timeval *tp) |
| 191 | { |
| 192 | union { |
| 193 | unsigned long long ns100; /*time since 1 Jan 1601 in 100ns units */ |
| 194 | FILETIME ft; |
| 195 | } _now; |
| 196 | |
| 197 | if(tp) |
| 198 | { |
| 199 | GetSystemTimeAsFileTime (&_now.ft); |
| 200 | tp->tv_usec=(long)((_now.ns100 / 10ULL) % 1000000ULL ); |
| 201 | tp->tv_sec= (long)((_now.ns100 - _W32_FT_OFFSET) / 10000000ULL); |
| 202 | } |
| 203 | /* Always return 0 as per Open Group Base Specifications Issue 6. |
| 204 | Do not set errno on error. */ |
| 205 | return 0; |
| 206 | } |
The Android Open Source Project | 8b23a6c | 2009-03-03 19:30:32 -0800 | [diff] [blame] | 207 | #endif /* _WIN32 */ |
| 208 | |
| 209 | |
David Turner | f7dd220 | 2010-09-10 10:59:22 +0200 | [diff] [blame] | 210 | #ifdef _WIN32 |
| 211 | #ifndef CONFIG_ANDROID |
| 212 | void socket_set_nonblock(int fd) |
| 213 | { |
| 214 | unsigned long opt = 1; |
| 215 | ioctlsocket(fd, FIONBIO, &opt); |
| 216 | } |
| 217 | #endif |
| 218 | |
| 219 | int inet_aton(const char *cp, struct in_addr *ia) |
| 220 | { |
| 221 | uint32_t addr = inet_addr(cp); |
| 222 | if (addr == 0xffffffff) |
| 223 | return 0; |
| 224 | ia->s_addr = addr; |
| 225 | return 1; |
| 226 | } |
| 227 | |
| 228 | void qemu_set_cloexec(int fd) |
| 229 | { |
| 230 | } |
| 231 | |
| 232 | #else |
| 233 | |
| 234 | #ifndef CONFIG_ANDROID |
| 235 | void socket_set_nonblock(int fd) |
| 236 | { |
| 237 | int f; |
| 238 | f = fcntl(fd, F_GETFL); |
| 239 | fcntl(fd, F_SETFL, f | O_NONBLOCK); |
| 240 | } |
| 241 | #endif |
| 242 | |
| 243 | void qemu_set_cloexec(int fd) |
| 244 | { |
| 245 | int f; |
| 246 | f = fcntl(fd, F_GETFD); |
| 247 | fcntl(fd, F_SETFD, f | FD_CLOEXEC); |
| 248 | } |
| 249 | |
| 250 | #endif |
| 251 | |
| 252 | /* |
| 253 | * Opens a file with FD_CLOEXEC set |
| 254 | */ |
| 255 | int qemu_open(const char *name, int flags, ...) |
| 256 | { |
| 257 | int ret; |
| 258 | int mode = 0; |
| 259 | |
| 260 | if (flags & O_CREAT) { |
| 261 | va_list ap; |
| 262 | |
| 263 | va_start(ap, flags); |
| 264 | mode = va_arg(ap, int); |
| 265 | va_end(ap); |
| 266 | } |
| 267 | |
| 268 | #ifdef O_CLOEXEC |
| 269 | ret = open(name, flags | O_CLOEXEC, mode); |
| 270 | #else |
| 271 | ret = open(name, flags, mode); |
| 272 | if (ret >= 0) { |
| 273 | qemu_set_cloexec(ret); |
| 274 | } |
| 275 | #endif |
| 276 | |
| 277 | return ret; |
| 278 | } |
| 279 | |
| 280 | /* |
| 281 | * A variant of write(2) which handles partial write. |
| 282 | * |
| 283 | * Return the number of bytes transferred. |
| 284 | * Set errno if fewer than `count' bytes are written. |
| 285 | * |
| 286 | * This function don't work with non-blocking fd's. |
| 287 | * Any of the possibilities with non-bloking fd's is bad: |
| 288 | * - return a short write (then name is wrong) |
| 289 | * - busy wait adding (errno == EAGAIN) to the loop |
| 290 | */ |
| 291 | ssize_t qemu_write_full(int fd, const void *buf, size_t count) |
| 292 | { |
| 293 | ssize_t ret = 0; |
| 294 | ssize_t total = 0; |
| 295 | |
| 296 | while (count) { |
| 297 | ret = write(fd, buf, count); |
| 298 | if (ret < 0) { |
| 299 | if (errno == EINTR) |
| 300 | continue; |
| 301 | break; |
| 302 | } |
| 303 | |
| 304 | count -= ret; |
| 305 | buf += ret; |
| 306 | total += ret; |
| 307 | } |
| 308 | |
| 309 | return total; |
| 310 | } |
| 311 | |
| 312 | #ifndef _WIN32 |
| 313 | /* |
| 314 | * Creates an eventfd that looks like a pipe and has EFD_CLOEXEC set. |
| 315 | */ |
| 316 | int qemu_eventfd(int fds[2]) |
| 317 | { |
| 318 | #ifdef CONFIG_EVENTFD |
| 319 | int ret; |
| 320 | |
| 321 | ret = eventfd(0, 0); |
| 322 | if (ret >= 0) { |
| 323 | fds[0] = ret; |
| 324 | qemu_set_cloexec(ret); |
| 325 | if ((fds[1] = dup(ret)) == -1) { |
| 326 | close(ret); |
| 327 | return -1; |
| 328 | } |
| 329 | qemu_set_cloexec(fds[1]); |
| 330 | return 0; |
| 331 | } |
| 332 | |
| 333 | if (errno != ENOSYS) { |
| 334 | return -1; |
| 335 | } |
| 336 | #endif |
| 337 | |
| 338 | return qemu_pipe(fds); |
| 339 | } |
| 340 | |
| 341 | /* |
| 342 | * Creates a pipe with FD_CLOEXEC set on both file descriptors |
| 343 | */ |
| 344 | int qemu_pipe(int pipefd[2]) |
| 345 | { |
| 346 | int ret; |
| 347 | |
| 348 | #ifdef CONFIG_PIPE2 |
| 349 | ret = pipe2(pipefd, O_CLOEXEC); |
| 350 | if (ret != -1 || errno != ENOSYS) { |
| 351 | return ret; |
| 352 | } |
| 353 | #endif |
| 354 | ret = pipe(pipefd); |
| 355 | if (ret == 0) { |
| 356 | qemu_set_cloexec(pipefd[0]); |
| 357 | qemu_set_cloexec(pipefd[1]); |
| 358 | } |
| 359 | |
| 360 | return ret; |
| 361 | } |
| 362 | #endif |
| 363 | |
| 364 | /* |
| 365 | * Opens a socket with FD_CLOEXEC set |
| 366 | */ |
| 367 | int qemu_socket(int domain, int type, int protocol) |
| 368 | { |
| 369 | int ret; |
| 370 | |
| 371 | #ifdef SOCK_CLOEXEC |
| 372 | ret = socket(domain, type | SOCK_CLOEXEC, protocol); |
| 373 | if (ret != -1 || errno != EINVAL) { |
| 374 | return ret; |
| 375 | } |
| 376 | #endif |
| 377 | ret = socket(domain, type, protocol); |
| 378 | if (ret >= 0) { |
| 379 | qemu_set_cloexec(ret); |
| 380 | } |
| 381 | |
| 382 | return ret; |
| 383 | } |
| 384 | |
| 385 | /* |
| 386 | * Accept a connection and set FD_CLOEXEC |
| 387 | */ |
| 388 | int qemu_accept(int s, struct sockaddr *addr, socklen_t *addrlen) |
| 389 | { |
| 390 | int ret; |
| 391 | |
| 392 | #ifdef CONFIG_ACCEPT4 |
| 393 | ret = accept4(s, addr, addrlen, SOCK_CLOEXEC); |
| 394 | if (ret != -1 || errno != ENOSYS) { |
| 395 | return ret; |
| 396 | } |
| 397 | #endif |
| 398 | ret = accept(s, addr, addrlen); |
| 399 | if (ret >= 0) { |
| 400 | qemu_set_cloexec(ret); |
| 401 | } |
| 402 | |
| 403 | return ret; |
| 404 | } |
David Turner | b919805 | 2010-09-10 11:50:34 +0200 | [diff] [blame] | 405 | |
| 406 | #ifdef WIN32 |
| 407 | int asprintf( char **, char *, ... ); |
| 408 | int vasprintf( char **, char *, va_list ); |
| 409 | |
| 410 | int vasprintf( char **sptr, char *fmt, va_list argv ) |
| 411 | { |
| 412 | int wanted = vsnprintf( *sptr = NULL, 0, fmt, argv ); |
| 413 | if( (wanted > 0) && ((*sptr = malloc( 1 + wanted )) != NULL) ) |
| 414 | return vsprintf( *sptr, fmt, argv ); |
| 415 | |
| 416 | return wanted; |
| 417 | } |
| 418 | |
| 419 | int asprintf( char **sptr, char *fmt, ... ) |
| 420 | { |
| 421 | int retval; |
| 422 | va_list argv; |
| 423 | va_start( argv, fmt ); |
| 424 | retval = vasprintf( sptr, fmt, argv ); |
| 425 | va_end( argv ); |
| 426 | return retval; |
| 427 | } |
| 428 | #endif |