Jes Sorensen | c1b0b93 | 2010-10-26 10:39:19 +0200 | [diff] [blame] | 1 | /* |
| 2 | * os-posix-lib.c |
| 3 | * |
| 4 | * Copyright (c) 2003-2008 Fabrice Bellard |
| 5 | * Copyright (c) 2010 Red Hat, Inc. |
| 6 | * |
| 7 | * QEMU library functions on POSIX which are shared between QEMU and |
| 8 | * the QEMU tools. |
| 9 | * |
| 10 | * Permission is hereby granted, free of charge, to any person obtaining a copy |
| 11 | * of this software and associated documentation files (the "Software"), to deal |
| 12 | * in the Software without restriction, including without limitation the rights |
| 13 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
| 14 | * copies of the Software, and to permit persons to whom the Software is |
| 15 | * furnished to do so, subject to the following conditions: |
| 16 | * |
| 17 | * The above copyright notice and this permission notice shall be included in |
| 18 | * all copies or substantial portions of the Software. |
| 19 | * |
| 20 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
| 21 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
| 22 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
| 23 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
| 24 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
| 25 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN |
| 26 | * THE SOFTWARE. |
| 27 | */ |
| 28 | |
Alexandre Raymond | f97742d | 2011-06-06 23:34:10 -0400 | [diff] [blame] | 29 | /* The following block of code temporarily renames the daemon() function so the |
| 30 | compiler does not see the warning associated with it in stdlib.h on OSX */ |
| 31 | #ifdef __APPLE__ |
| 32 | #define daemon qemu_fake_daemon_function |
| 33 | #include <stdlib.h> |
| 34 | #undef daemon |
| 35 | extern int daemon(int, int); |
| 36 | #endif |
| 37 | |
Peter Maydell | 2e07b29 | 2013-03-05 00:34:40 +0000 | [diff] [blame] | 38 | #if defined(__linux__) && (defined(__x86_64__) || defined(__arm__)) |
Stefan Weil | c2a8238 | 2011-10-31 21:29:46 +0100 | [diff] [blame] | 39 | /* Use 2 MiB alignment so transparent hugepages can be used by KVM. |
| 40 | Valgrind does not support alignments larger than 1 MiB, |
| 41 | therefore we need special code which handles running on Valgrind. */ |
Avi Kivity | 36b5862 | 2011-09-05 11:07:05 +0300 | [diff] [blame] | 42 | # define QEMU_VMALLOC_ALIGN (512 * 4096) |
Christian Borntraeger | fdec991 | 2012-06-15 05:10:30 +0000 | [diff] [blame] | 43 | #elif defined(__linux__) && defined(__s390x__) |
| 44 | /* Use 1 MiB (segment size) alignment so gmap can be used by KVM. */ |
| 45 | # define QEMU_VMALLOC_ALIGN (256 * 4096) |
Avi Kivity | 36b5862 | 2011-09-05 11:07:05 +0300 | [diff] [blame] | 46 | #else |
| 47 | # define QEMU_VMALLOC_ALIGN getpagesize() |
| 48 | #endif |
Paolo Bonzini | 3818331 | 2014-05-14 17:43:21 +0800 | [diff] [blame] | 49 | #define HUGETLBFS_MAGIC 0x958458f6 |
Avi Kivity | 36b5862 | 2011-09-05 11:07:05 +0300 | [diff] [blame] | 50 | |
Stefan Hajnoczi | 13401ba | 2013-11-14 11:54:16 +0100 | [diff] [blame] | 51 | #include <termios.h> |
| 52 | #include <unistd.h> |
Daniel P. Berrange | d57e4e4 | 2015-05-12 17:09:19 +0100 | [diff] [blame] | 53 | #include <termios.h> |
Stefan Hajnoczi | 13401ba | 2013-11-14 11:54:16 +0100 | [diff] [blame] | 54 | |
Laszlo Ersek | e2ea351 | 2013-05-18 06:31:48 +0200 | [diff] [blame] | 55 | #include <glib/gprintf.h> |
| 56 | |
Jes Sorensen | c1b0b93 | 2010-10-26 10:39:19 +0200 | [diff] [blame] | 57 | #include "config-host.h" |
Paolo Bonzini | 9c17d61 | 2012-12-17 18:20:04 +0100 | [diff] [blame] | 58 | #include "sysemu/sysemu.h" |
Jes Sorensen | c1b0b93 | 2010-10-26 10:39:19 +0200 | [diff] [blame] | 59 | #include "trace.h" |
Paolo Bonzini | 1de7afc | 2012-12-17 18:20:00 +0100 | [diff] [blame] | 60 | #include "qemu/sockets.h" |
Paolo Bonzini | 7dda5dc | 2013-04-09 17:43:43 +0200 | [diff] [blame] | 61 | #include <sys/mman.h> |
Fam Zheng | 10f5bff | 2014-02-10 14:48:51 +0800 | [diff] [blame] | 62 | #include <libgen.h> |
Paolo Bonzini | 3818331 | 2014-05-14 17:43:21 +0800 | [diff] [blame] | 63 | #include <setjmp.h> |
| 64 | #include <sys/signal.h> |
Jes Sorensen | c1b0b93 | 2010-10-26 10:39:19 +0200 | [diff] [blame] | 65 | |
Paolo Bonzini | cbcfa04 | 2011-09-12 16:20:11 +0200 | [diff] [blame] | 66 | #ifdef CONFIG_LINUX |
| 67 | #include <sys/syscall.h> |
Paolo Bonzini | 3818331 | 2014-05-14 17:43:21 +0800 | [diff] [blame] | 68 | #include <sys/vfs.h> |
Paolo Bonzini | cbcfa04 | 2011-09-12 16:20:11 +0200 | [diff] [blame] | 69 | #endif |
Paolo Bonzini | cbcfa04 | 2011-09-12 16:20:11 +0200 | [diff] [blame] | 70 | |
Andreas Färber | 41975b2 | 2014-03-13 14:27:59 +0100 | [diff] [blame] | 71 | #ifdef __FreeBSD__ |
| 72 | #include <sys/sysctl.h> |
| 73 | #endif |
| 74 | |
Paolo Bonzini | cbcfa04 | 2011-09-12 16:20:11 +0200 | [diff] [blame] | 75 | int qemu_get_thread_id(void) |
| 76 | { |
| 77 | #if defined(__linux__) |
| 78 | return syscall(SYS_gettid); |
| 79 | #else |
| 80 | return getpid(); |
| 81 | #endif |
| 82 | } |
Alexandre Raymond | f97742d | 2011-06-06 23:34:10 -0400 | [diff] [blame] | 83 | |
| 84 | int qemu_daemon(int nochdir, int noclose) |
| 85 | { |
| 86 | return daemon(nochdir, noclose); |
| 87 | } |
| 88 | |
Jes Sorensen | b152aa8 | 2010-10-26 10:39:26 +0200 | [diff] [blame] | 89 | void *qemu_oom_check(void *ptr) |
Jes Sorensen | c1b0b93 | 2010-10-26 10:39:19 +0200 | [diff] [blame] | 90 | { |
| 91 | if (ptr == NULL) { |
| 92 | fprintf(stderr, "Failed to allocate memory: %s\n", strerror(errno)); |
| 93 | abort(); |
| 94 | } |
| 95 | return ptr; |
| 96 | } |
Jes Sorensen | c1b0b93 | 2010-10-26 10:39:19 +0200 | [diff] [blame] | 97 | |
Kevin Wolf | 7d2a35c | 2014-05-20 12:24:05 +0200 | [diff] [blame] | 98 | void *qemu_try_memalign(size_t alignment, size_t size) |
Jes Sorensen | c1b0b93 | 2010-10-26 10:39:19 +0200 | [diff] [blame] | 99 | { |
| 100 | void *ptr; |
Kevin Wolf | e535465 | 2013-11-29 21:29:17 +0100 | [diff] [blame] | 101 | |
| 102 | if (alignment < sizeof(void*)) { |
| 103 | alignment = sizeof(void*); |
| 104 | } |
| 105 | |
Jes Sorensen | c1b0b93 | 2010-10-26 10:39:19 +0200 | [diff] [blame] | 106 | #if defined(_POSIX_C_SOURCE) && !defined(__sun__) |
| 107 | int ret; |
| 108 | ret = posix_memalign(&ptr, alignment, size); |
| 109 | if (ret != 0) { |
Kevin Wolf | 7d2a35c | 2014-05-20 12:24:05 +0200 | [diff] [blame] | 110 | errno = ret; |
| 111 | ptr = NULL; |
Jes Sorensen | c1b0b93 | 2010-10-26 10:39:19 +0200 | [diff] [blame] | 112 | } |
| 113 | #elif defined(CONFIG_BSD) |
Kevin Wolf | 7d2a35c | 2014-05-20 12:24:05 +0200 | [diff] [blame] | 114 | ptr = valloc(size); |
Jes Sorensen | c1b0b93 | 2010-10-26 10:39:19 +0200 | [diff] [blame] | 115 | #else |
Kevin Wolf | 7d2a35c | 2014-05-20 12:24:05 +0200 | [diff] [blame] | 116 | ptr = memalign(alignment, size); |
Jes Sorensen | c1b0b93 | 2010-10-26 10:39:19 +0200 | [diff] [blame] | 117 | #endif |
| 118 | trace_qemu_memalign(alignment, size, ptr); |
| 119 | return ptr; |
| 120 | } |
| 121 | |
Kevin Wolf | 7d2a35c | 2014-05-20 12:24:05 +0200 | [diff] [blame] | 122 | void *qemu_memalign(size_t alignment, size_t size) |
| 123 | { |
| 124 | return qemu_oom_check(qemu_try_memalign(alignment, size)); |
| 125 | } |
| 126 | |
Jes Sorensen | c1b0b93 | 2010-10-26 10:39:19 +0200 | [diff] [blame] | 127 | /* alloc shared memory pages */ |
Igor Mammedov | a2b257d | 2014-10-31 16:38:37 +0000 | [diff] [blame] | 128 | void *qemu_anon_ram_alloc(size_t size, uint64_t *alignment) |
Jes Sorensen | c1b0b93 | 2010-10-26 10:39:19 +0200 | [diff] [blame] | 129 | { |
Avi Kivity | 36b5862 | 2011-09-05 11:07:05 +0300 | [diff] [blame] | 130 | size_t align = QEMU_VMALLOC_ALIGN; |
Paolo Bonzini | 7dda5dc | 2013-04-09 17:43:43 +0200 | [diff] [blame] | 131 | size_t total = size + align - getpagesize(); |
| 132 | void *ptr = mmap(0, total, PROT_READ | PROT_WRITE, |
| 133 | MAP_ANONYMOUS | MAP_PRIVATE, -1, 0); |
| 134 | size_t offset = QEMU_ALIGN_UP((uintptr_t)ptr, align) - (uintptr_t)ptr; |
Avi Kivity | 36b5862 | 2011-09-05 11:07:05 +0300 | [diff] [blame] | 135 | |
Paolo Bonzini | 7dda5dc | 2013-04-09 17:43:43 +0200 | [diff] [blame] | 136 | if (ptr == MAP_FAILED) { |
Markus Armbruster | 3922825 | 2013-07-31 15:11:11 +0200 | [diff] [blame] | 137 | return NULL; |
Stefan Weil | c2a8238 | 2011-10-31 21:29:46 +0100 | [diff] [blame] | 138 | } |
Stefan Weil | c2a8238 | 2011-10-31 21:29:46 +0100 | [diff] [blame] | 139 | |
Igor Mammedov | a2b257d | 2014-10-31 16:38:37 +0000 | [diff] [blame] | 140 | if (alignment) { |
| 141 | *alignment = align; |
| 142 | } |
Paolo Bonzini | 7dda5dc | 2013-04-09 17:43:43 +0200 | [diff] [blame] | 143 | ptr += offset; |
| 144 | total -= offset; |
| 145 | |
| 146 | if (offset > 0) { |
| 147 | munmap(ptr - offset, offset); |
Avi Kivity | 36b5862 | 2011-09-05 11:07:05 +0300 | [diff] [blame] | 148 | } |
Paolo Bonzini | 7dda5dc | 2013-04-09 17:43:43 +0200 | [diff] [blame] | 149 | if (total > size) { |
| 150 | munmap(ptr + size, total - size); |
| 151 | } |
| 152 | |
Paolo Bonzini | 6eebf95 | 2013-05-13 16:19:55 +0200 | [diff] [blame] | 153 | trace_qemu_anon_ram_alloc(size, ptr); |
Jes Sorensen | c7f4111 | 2011-07-25 17:13:36 +0200 | [diff] [blame] | 154 | return ptr; |
Jes Sorensen | c1b0b93 | 2010-10-26 10:39:19 +0200 | [diff] [blame] | 155 | } |
| 156 | |
| 157 | void qemu_vfree(void *ptr) |
| 158 | { |
| 159 | trace_qemu_vfree(ptr); |
| 160 | free(ptr); |
| 161 | } |
Jes Sorensen | 9549e76 | 2010-10-26 10:39:20 +0200 | [diff] [blame] | 162 | |
Paolo Bonzini | e7a09b9 | 2013-05-13 16:19:56 +0200 | [diff] [blame] | 163 | void qemu_anon_ram_free(void *ptr, size_t size) |
| 164 | { |
| 165 | trace_qemu_anon_ram_free(ptr, size); |
| 166 | if (ptr) { |
| 167 | munmap(ptr, size); |
| 168 | } |
| 169 | } |
| 170 | |
Stefan Hajnoczi | f9e8cac | 2013-03-27 10:10:43 +0100 | [diff] [blame] | 171 | void qemu_set_block(int fd) |
Paolo Bonzini | 154b9a0 | 2011-10-05 09:17:32 +0200 | [diff] [blame] | 172 | { |
| 173 | int f; |
| 174 | f = fcntl(fd, F_GETFL); |
| 175 | fcntl(fd, F_SETFL, f & ~O_NONBLOCK); |
| 176 | } |
| 177 | |
Stefan Hajnoczi | f9e8cac | 2013-03-27 10:10:43 +0100 | [diff] [blame] | 178 | void qemu_set_nonblock(int fd) |
Jes Sorensen | 9549e76 | 2010-10-26 10:39:20 +0200 | [diff] [blame] | 179 | { |
| 180 | int f; |
| 181 | f = fcntl(fd, F_GETFL); |
| 182 | fcntl(fd, F_SETFL, f | O_NONBLOCK); |
| 183 | } |
| 184 | |
Sebastian Ottlik | 606600a | 2013-10-02 12:23:12 +0200 | [diff] [blame] | 185 | int socket_set_fast_reuse(int fd) |
| 186 | { |
| 187 | int val = 1, ret; |
| 188 | |
| 189 | ret = setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, |
| 190 | (const char *)&val, sizeof(val)); |
| 191 | |
| 192 | assert(ret == 0); |
| 193 | |
| 194 | return ret; |
| 195 | } |
| 196 | |
Jes Sorensen | 9549e76 | 2010-10-26 10:39:20 +0200 | [diff] [blame] | 197 | void qemu_set_cloexec(int fd) |
| 198 | { |
| 199 | int f; |
| 200 | f = fcntl(fd, F_GETFD); |
| 201 | fcntl(fd, F_SETFD, f | FD_CLOEXEC); |
| 202 | } |
Jes Sorensen | 70e72ce | 2010-10-26 10:39:21 +0200 | [diff] [blame] | 203 | |
| 204 | /* |
| 205 | * Creates a pipe with FD_CLOEXEC set on both file descriptors |
| 206 | */ |
| 207 | int qemu_pipe(int pipefd[2]) |
| 208 | { |
| 209 | int ret; |
| 210 | |
| 211 | #ifdef CONFIG_PIPE2 |
| 212 | ret = pipe2(pipefd, O_CLOEXEC); |
| 213 | if (ret != -1 || errno != ENOSYS) { |
| 214 | return ret; |
| 215 | } |
| 216 | #endif |
| 217 | ret = pipe(pipefd); |
| 218 | if (ret == 0) { |
| 219 | qemu_set_cloexec(pipefd[0]); |
| 220 | qemu_set_cloexec(pipefd[1]); |
| 221 | } |
| 222 | |
| 223 | return ret; |
| 224 | } |
Hidetoshi Seto | 3867142 | 2010-11-24 11:38:10 +0900 | [diff] [blame] | 225 | |
Paolo Bonzini | ae0f940 | 2011-11-21 09:29:11 +0100 | [diff] [blame] | 226 | int qemu_utimens(const char *path, const struct timespec *times) |
Hidetoshi Seto | 3867142 | 2010-11-24 11:38:10 +0900 | [diff] [blame] | 227 | { |
| 228 | struct timeval tv[2], tv_now; |
| 229 | struct stat st; |
| 230 | int i; |
| 231 | #ifdef CONFIG_UTIMENSAT |
| 232 | int ret; |
| 233 | |
Paolo Bonzini | ae0f940 | 2011-11-21 09:29:11 +0100 | [diff] [blame] | 234 | ret = utimensat(AT_FDCWD, path, times, AT_SYMLINK_NOFOLLOW); |
Hidetoshi Seto | 3867142 | 2010-11-24 11:38:10 +0900 | [diff] [blame] | 235 | if (ret != -1 || errno != ENOSYS) { |
| 236 | return ret; |
| 237 | } |
| 238 | #endif |
| 239 | /* Fallback: use utimes() instead of utimensat() */ |
| 240 | |
| 241 | /* happy if special cases */ |
| 242 | if (times[0].tv_nsec == UTIME_OMIT && times[1].tv_nsec == UTIME_OMIT) { |
| 243 | return 0; |
| 244 | } |
| 245 | if (times[0].tv_nsec == UTIME_NOW && times[1].tv_nsec == UTIME_NOW) { |
| 246 | return utimes(path, NULL); |
| 247 | } |
| 248 | |
| 249 | /* prepare for hard cases */ |
| 250 | if (times[0].tv_nsec == UTIME_NOW || times[1].tv_nsec == UTIME_NOW) { |
| 251 | gettimeofday(&tv_now, NULL); |
| 252 | } |
| 253 | if (times[0].tv_nsec == UTIME_OMIT || times[1].tv_nsec == UTIME_OMIT) { |
| 254 | stat(path, &st); |
| 255 | } |
| 256 | |
| 257 | for (i = 0; i < 2; i++) { |
| 258 | if (times[i].tv_nsec == UTIME_NOW) { |
| 259 | tv[i].tv_sec = tv_now.tv_sec; |
| 260 | tv[i].tv_usec = tv_now.tv_usec; |
| 261 | } else if (times[i].tv_nsec == UTIME_OMIT) { |
| 262 | tv[i].tv_sec = (i == 0) ? st.st_atime : st.st_mtime; |
| 263 | tv[i].tv_usec = 0; |
| 264 | } else { |
| 265 | tv[i].tv_sec = times[i].tv_sec; |
| 266 | tv[i].tv_usec = times[i].tv_nsec / 1000; |
| 267 | } |
| 268 | } |
| 269 | |
| 270 | return utimes(path, &tv[0]); |
| 271 | } |
Laszlo Ersek | e2ea351 | 2013-05-18 06:31:48 +0200 | [diff] [blame] | 272 | |
| 273 | char * |
| 274 | qemu_get_local_state_pathname(const char *relative_pathname) |
| 275 | { |
| 276 | return g_strdup_printf("%s/%s", CONFIG_QEMU_LOCALSTATEDIR, |
| 277 | relative_pathname); |
| 278 | } |
Stefan Hajnoczi | 13401ba | 2013-11-14 11:54:16 +0100 | [diff] [blame] | 279 | |
| 280 | void qemu_set_tty_echo(int fd, bool echo) |
| 281 | { |
| 282 | struct termios tty; |
| 283 | |
| 284 | tcgetattr(fd, &tty); |
| 285 | |
| 286 | if (echo) { |
| 287 | tty.c_lflag |= ECHO | ECHONL | ICANON | IEXTEN; |
| 288 | } else { |
| 289 | tty.c_lflag &= ~(ECHO | ECHONL | ICANON | IEXTEN); |
| 290 | } |
| 291 | |
| 292 | tcsetattr(fd, TCSANOW, &tty); |
| 293 | } |
Fam Zheng | 10f5bff | 2014-02-10 14:48:51 +0800 | [diff] [blame] | 294 | |
| 295 | static char exec_dir[PATH_MAX]; |
| 296 | |
| 297 | void qemu_init_exec_dir(const char *argv0) |
| 298 | { |
| 299 | char *dir; |
| 300 | char *p = NULL; |
| 301 | char buf[PATH_MAX]; |
| 302 | |
| 303 | assert(!exec_dir[0]); |
| 304 | |
| 305 | #if defined(__linux__) |
| 306 | { |
| 307 | int len; |
| 308 | len = readlink("/proc/self/exe", buf, sizeof(buf) - 1); |
| 309 | if (len > 0) { |
| 310 | buf[len] = 0; |
| 311 | p = buf; |
| 312 | } |
| 313 | } |
| 314 | #elif defined(__FreeBSD__) |
| 315 | { |
| 316 | static int mib[4] = {CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME, -1}; |
| 317 | size_t len = sizeof(buf) - 1; |
| 318 | |
| 319 | *buf = '\0'; |
| 320 | if (!sysctl(mib, ARRAY_SIZE(mib), buf, &len, NULL, 0) && |
| 321 | *buf) { |
| 322 | buf[sizeof(buf) - 1] = '\0'; |
| 323 | p = buf; |
| 324 | } |
| 325 | } |
| 326 | #endif |
| 327 | /* If we don't have any way of figuring out the actual executable |
| 328 | location then try argv[0]. */ |
| 329 | if (!p) { |
| 330 | if (!argv0) { |
| 331 | return; |
| 332 | } |
| 333 | p = realpath(argv0, buf); |
| 334 | if (!p) { |
| 335 | return; |
| 336 | } |
| 337 | } |
| 338 | dir = dirname(p); |
| 339 | |
| 340 | pstrcpy(exec_dir, sizeof(exec_dir), dir); |
| 341 | } |
| 342 | |
| 343 | char *qemu_get_exec_dir(void) |
| 344 | { |
| 345 | return g_strdup(exec_dir); |
| 346 | } |
Paolo Bonzini | 3818331 | 2014-05-14 17:43:21 +0800 | [diff] [blame] | 347 | |
| 348 | static sigjmp_buf sigjump; |
| 349 | |
| 350 | static void sigbus_handler(int signal) |
| 351 | { |
| 352 | siglongjmp(sigjump, 1); |
| 353 | } |
| 354 | |
| 355 | static size_t fd_getpagesize(int fd) |
| 356 | { |
| 357 | #ifdef CONFIG_LINUX |
| 358 | struct statfs fs; |
| 359 | int ret; |
| 360 | |
| 361 | if (fd != -1) { |
| 362 | do { |
| 363 | ret = fstatfs(fd, &fs); |
| 364 | } while (ret != 0 && errno == EINTR); |
| 365 | |
| 366 | if (ret == 0 && fs.f_type == HUGETLBFS_MAGIC) { |
| 367 | return fs.f_bsize; |
| 368 | } |
| 369 | } |
| 370 | #endif |
| 371 | |
| 372 | return getpagesize(); |
| 373 | } |
| 374 | |
| 375 | void os_mem_prealloc(int fd, char *area, size_t memory) |
| 376 | { |
Stefan Weil | b7bf8f5 | 2014-06-24 22:52:29 +0200 | [diff] [blame] | 377 | int ret; |
Paolo Bonzini | 3818331 | 2014-05-14 17:43:21 +0800 | [diff] [blame] | 378 | struct sigaction act, oldact; |
| 379 | sigset_t set, oldset; |
Paolo Bonzini | 3818331 | 2014-05-14 17:43:21 +0800 | [diff] [blame] | 380 | |
| 381 | memset(&act, 0, sizeof(act)); |
| 382 | act.sa_handler = &sigbus_handler; |
| 383 | act.sa_flags = 0; |
| 384 | |
| 385 | ret = sigaction(SIGBUS, &act, &oldact); |
| 386 | if (ret) { |
| 387 | perror("os_mem_prealloc: failed to install signal handler"); |
| 388 | exit(1); |
| 389 | } |
| 390 | |
| 391 | /* unblock SIGBUS */ |
| 392 | sigemptyset(&set); |
| 393 | sigaddset(&set, SIGBUS); |
| 394 | pthread_sigmask(SIG_UNBLOCK, &set, &oldset); |
| 395 | |
| 396 | if (sigsetjmp(sigjump, 1)) { |
Michal Privoznik | 404ac83 | 2014-10-16 15:13:32 +0200 | [diff] [blame] | 397 | fprintf(stderr, "os_mem_prealloc: Insufficient free host memory " |
| 398 | "pages available to allocate guest RAM\n"); |
Paolo Bonzini | 3818331 | 2014-05-14 17:43:21 +0800 | [diff] [blame] | 399 | exit(1); |
Stefan Weil | b7bf8f5 | 2014-06-24 22:52:29 +0200 | [diff] [blame] | 400 | } else { |
| 401 | int i; |
| 402 | size_t hpagesize = fd_getpagesize(fd); |
Stefan Weil | 2a0457b | 2015-03-01 13:52:06 +0100 | [diff] [blame] | 403 | size_t numpages = DIV_ROUND_UP(memory, hpagesize); |
Paolo Bonzini | 3818331 | 2014-05-14 17:43:21 +0800 | [diff] [blame] | 404 | |
Stefan Weil | b7bf8f5 | 2014-06-24 22:52:29 +0200 | [diff] [blame] | 405 | /* MAP_POPULATE silently ignores failures */ |
Stefan Weil | 2a0457b | 2015-03-01 13:52:06 +0100 | [diff] [blame] | 406 | for (i = 0; i < numpages; i++) { |
Stefan Weil | b7bf8f5 | 2014-06-24 22:52:29 +0200 | [diff] [blame] | 407 | memset(area + (hpagesize * i), 0, 1); |
| 408 | } |
Paolo Bonzini | 3818331 | 2014-05-14 17:43:21 +0800 | [diff] [blame] | 409 | |
Stefan Weil | b7bf8f5 | 2014-06-24 22:52:29 +0200 | [diff] [blame] | 410 | ret = sigaction(SIGBUS, &oldact, NULL); |
| 411 | if (ret) { |
| 412 | perror("os_mem_prealloc: failed to reinstall signal handler"); |
| 413 | exit(1); |
| 414 | } |
Paolo Bonzini | 3818331 | 2014-05-14 17:43:21 +0800 | [diff] [blame] | 415 | |
Stefan Weil | b7bf8f5 | 2014-06-24 22:52:29 +0200 | [diff] [blame] | 416 | pthread_sigmask(SIG_SETMASK, &oldset, NULL); |
| 417 | } |
Paolo Bonzini | 3818331 | 2014-05-14 17:43:21 +0800 | [diff] [blame] | 418 | } |
Daniel P. Berrange | d57e4e4 | 2015-05-12 17:09:19 +0100 | [diff] [blame] | 419 | |
| 420 | |
| 421 | static struct termios oldtty; |
| 422 | |
| 423 | static void term_exit(void) |
| 424 | { |
| 425 | tcsetattr(0, TCSANOW, &oldtty); |
| 426 | } |
| 427 | |
| 428 | static void term_init(void) |
| 429 | { |
| 430 | struct termios tty; |
| 431 | |
| 432 | tcgetattr(0, &tty); |
| 433 | oldtty = tty; |
| 434 | |
| 435 | tty.c_iflag &= ~(IGNBRK|BRKINT|PARMRK|ISTRIP |
| 436 | |INLCR|IGNCR|ICRNL|IXON); |
| 437 | tty.c_oflag |= OPOST; |
| 438 | tty.c_lflag &= ~(ECHO|ECHONL|ICANON|IEXTEN); |
| 439 | tty.c_cflag &= ~(CSIZE|PARENB); |
| 440 | tty.c_cflag |= CS8; |
| 441 | tty.c_cc[VMIN] = 1; |
| 442 | tty.c_cc[VTIME] = 0; |
| 443 | |
| 444 | tcsetattr(0, TCSANOW, &tty); |
| 445 | |
| 446 | atexit(term_exit); |
| 447 | } |
| 448 | |
| 449 | int qemu_read_password(char *buf, int buf_size) |
| 450 | { |
| 451 | uint8_t ch; |
| 452 | int i, ret; |
| 453 | |
| 454 | printf("password: "); |
| 455 | fflush(stdout); |
| 456 | term_init(); |
| 457 | i = 0; |
| 458 | for (;;) { |
| 459 | ret = read(0, &ch, 1); |
| 460 | if (ret == -1) { |
| 461 | if (errno == EAGAIN || errno == EINTR) { |
| 462 | continue; |
| 463 | } else { |
| 464 | break; |
| 465 | } |
| 466 | } else if (ret == 0) { |
| 467 | ret = -1; |
| 468 | break; |
| 469 | } else { |
Daniel P. Berrange | 6a11d51 | 2015-05-12 17:09:20 +0100 | [diff] [blame] | 470 | if (ch == '\r' || |
| 471 | ch == '\n') { |
Daniel P. Berrange | d57e4e4 | 2015-05-12 17:09:19 +0100 | [diff] [blame] | 472 | ret = 0; |
| 473 | break; |
| 474 | } |
| 475 | if (i < (buf_size - 1)) { |
| 476 | buf[i++] = ch; |
| 477 | } |
| 478 | } |
| 479 | } |
| 480 | term_exit(); |
| 481 | buf[i] = '\0'; |
| 482 | printf("\n"); |
| 483 | return ret; |
| 484 | } |