qemu/os-posix.c
<<
>>
Prefs
   1/*
   2 * os-posix.c
   3 *
   4 * Copyright (c) 2003-2008 Fabrice Bellard
   5 * Copyright (c) 2010 Red Hat, Inc.
   6 *
   7 * Permission is hereby granted, free of charge, to any person obtaining a copy
   8 * of this software and associated documentation files (the "Software"), to deal
   9 * in the Software without restriction, including without limitation the rights
  10 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  11 * copies of the Software, and to permit persons to whom the Software is
  12 * furnished to do so, subject to the following conditions:
  13 *
  14 * The above copyright notice and this permission notice shall be included in
  15 * all copies or substantial portions of the Software.
  16 *
  17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  18 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
  20 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  21 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  22 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  23 * THE SOFTWARE.
  24 */
  25
  26#include "qemu/osdep.h"
  27#include <sys/wait.h>
  28#include <pwd.h>
  29#include <grp.h>
  30#include <libgen.h>
  31
  32/* Needed early for CONFIG_BSD etc. */
  33#include "sysemu/sysemu.h"
  34#include "net/slirp.h"
  35#include "qemu-options.h"
  36#include "qemu/error-report.h"
  37#include "qemu/log.h"
  38#include "qemu/cutils.h"
  39
  40#ifdef CONFIG_LINUX
  41#include <sys/prctl.h>
  42#endif
  43
  44static struct passwd *user_pwd;
  45static const char *chroot_dir;
  46static int daemonize;
  47static int daemon_pipe;
  48
  49void os_setup_early_signal_handling(void)
  50{
  51    struct sigaction act;
  52    sigfillset(&act.sa_mask);
  53    act.sa_flags = 0;
  54    act.sa_handler = SIG_IGN;
  55    sigaction(SIGPIPE, &act, NULL);
  56}
  57
  58static void termsig_handler(int signal, siginfo_t *info, void *c)
  59{
  60    qemu_system_killed(info->si_signo, info->si_pid);
  61}
  62
  63void os_setup_signal_handling(void)
  64{
  65    struct sigaction act;
  66
  67    memset(&act, 0, sizeof(act));
  68    act.sa_sigaction = termsig_handler;
  69    act.sa_flags = SA_SIGINFO;
  70    sigaction(SIGINT,  &act, NULL);
  71    sigaction(SIGHUP,  &act, NULL);
  72    sigaction(SIGTERM, &act, NULL);
  73}
  74
  75/* Find a likely location for support files using the location of the binary.
  76   For installed binaries this will be "$bindir/../share/qemu".  When
  77   running from the build tree this will be "$bindir/../pc-bios".  */
  78#define SHARE_SUFFIX "/share/qemu"
  79#define BUILD_SUFFIX "/pc-bios"
  80char *os_find_datadir(void)
  81{
  82    char *dir, *exec_dir;
  83    char *res;
  84    size_t max_len;
  85
  86    exec_dir = qemu_get_exec_dir();
  87    if (exec_dir == NULL) {
  88        return NULL;
  89    }
  90    dir = g_path_get_dirname(exec_dir);
  91
  92    max_len = strlen(dir) +
  93        MAX(strlen(SHARE_SUFFIX), strlen(BUILD_SUFFIX)) + 1;
  94    res = g_malloc0(max_len);
  95    snprintf(res, max_len, "%s%s", dir, SHARE_SUFFIX);
  96    if (access(res, R_OK)) {
  97        snprintf(res, max_len, "%s%s", dir, BUILD_SUFFIX);
  98        if (access(res, R_OK)) {
  99            g_free(res);
 100            res = NULL;
 101        }
 102    }
 103
 104    g_free(dir);
 105    g_free(exec_dir);
 106    return res;
 107}
 108#undef SHARE_SUFFIX
 109#undef BUILD_SUFFIX
 110
 111void os_set_proc_name(const char *s)
 112{
 113#if defined(PR_SET_NAME)
 114    char name[16];
 115    if (!s)
 116        return;
 117    pstrcpy(name, sizeof(name), s);
 118    /* Could rewrite argv[0] too, but that's a bit more complicated.
 119       This simple way is enough for `top'. */
 120    if (prctl(PR_SET_NAME, name)) {
 121        perror("unable to change process name");
 122        exit(1);
 123    }
 124#else
 125    fprintf(stderr, "Change of process name not supported by your OS\n");
 126    exit(1);
 127#endif
 128}
 129
 130/*
 131 * Parse OS specific command line options.
 132 * return 0 if option handled, -1 otherwise
 133 */
 134void os_parse_cmd_args(int index, const char *optarg)
 135{
 136    switch (index) {
 137#ifdef CONFIG_SLIRP
 138    case QEMU_OPTION_smb:
 139        error_report("The -smb option is deprecated. "
 140                     "Please use '-netdev user,smb=...' instead.");
 141        if (net_slirp_smb(optarg) < 0)
 142            exit(1);
 143        break;
 144#endif
 145    case QEMU_OPTION_runas:
 146        user_pwd = getpwnam(optarg);
 147        if (!user_pwd) {
 148            fprintf(stderr, "User \"%s\" doesn't exist\n", optarg);
 149            exit(1);
 150        }
 151        break;
 152    case QEMU_OPTION_chroot:
 153        chroot_dir = optarg;
 154        break;
 155    case QEMU_OPTION_daemonize:
 156        daemonize = 1;
 157        break;
 158#if defined(CONFIG_LINUX)
 159    case QEMU_OPTION_enablefips:
 160        fips_set_state(true);
 161        break;
 162#endif
 163    }
 164}
 165
 166static void change_process_uid(void)
 167{
 168    if (user_pwd) {
 169        if (setgid(user_pwd->pw_gid) < 0) {
 170            fprintf(stderr, "Failed to setgid(%d)\n", user_pwd->pw_gid);
 171            exit(1);
 172        }
 173        if (initgroups(user_pwd->pw_name, user_pwd->pw_gid) < 0) {
 174            fprintf(stderr, "Failed to initgroups(\"%s\", %d)\n",
 175                    user_pwd->pw_name, user_pwd->pw_gid);
 176            exit(1);
 177        }
 178        if (setuid(user_pwd->pw_uid) < 0) {
 179            fprintf(stderr, "Failed to setuid(%d)\n", user_pwd->pw_uid);
 180            exit(1);
 181        }
 182        if (setuid(0) != -1) {
 183            fprintf(stderr, "Dropping privileges failed\n");
 184            exit(1);
 185        }
 186    }
 187}
 188
 189static void change_root(void)
 190{
 191    if (chroot_dir) {
 192        if (chroot(chroot_dir) < 0) {
 193            fprintf(stderr, "chroot failed\n");
 194            exit(1);
 195        }
 196        if (chdir("/")) {
 197            perror("not able to chdir to /");
 198            exit(1);
 199        }
 200    }
 201
 202}
 203
 204void os_daemonize(void)
 205{
 206    if (daemonize) {
 207        pid_t pid;
 208        int fds[2];
 209
 210        if (pipe(fds) == -1) {
 211            exit(1);
 212        }
 213
 214        pid = fork();
 215        if (pid > 0) {
 216            uint8_t status;
 217            ssize_t len;
 218
 219            close(fds[1]);
 220
 221            do {
 222                len = read(fds[0], &status, 1);
 223            } while (len < 0 && errno == EINTR);
 224
 225            /* only exit successfully if our child actually wrote
 226             * a one-byte zero to our pipe, upon successful init */
 227            exit(len == 1 && status == 0 ? 0 : 1);
 228
 229        } else if (pid < 0) {
 230            exit(1);
 231        }
 232
 233        close(fds[0]);
 234        daemon_pipe = fds[1];
 235        qemu_set_cloexec(daemon_pipe);
 236
 237        setsid();
 238
 239        pid = fork();
 240        if (pid > 0) {
 241            exit(0);
 242        } else if (pid < 0) {
 243            exit(1);
 244        }
 245        umask(027);
 246
 247        signal(SIGTSTP, SIG_IGN);
 248        signal(SIGTTOU, SIG_IGN);
 249        signal(SIGTTIN, SIG_IGN);
 250    }
 251}
 252
 253void os_setup_post(void)
 254{
 255    int fd = 0;
 256
 257    if (daemonize) {
 258        if (chdir("/")) {
 259            perror("not able to chdir to /");
 260            exit(1);
 261        }
 262        TFR(fd = qemu_open("/dev/null", O_RDWR));
 263        if (fd == -1) {
 264            exit(1);
 265        }
 266    }
 267
 268    change_root();
 269    change_process_uid();
 270
 271    if (daemonize) {
 272        uint8_t status = 0;
 273        ssize_t len;
 274
 275        dup2(fd, 0);
 276        dup2(fd, 1);
 277        /* In case -D is given do not redirect stderr to /dev/null */
 278        if (!qemu_logfile) {
 279            dup2(fd, 2);
 280        }
 281
 282        close(fd);
 283
 284        do {        
 285            len = write(daemon_pipe, &status, 1);
 286        } while (len < 0 && errno == EINTR);
 287        if (len != 1) {
 288            exit(1);
 289        }
 290    }
 291}
 292
 293void os_set_line_buffering(void)
 294{
 295    setvbuf(stdout, NULL, _IOLBF, 0);
 296}
 297
 298int qemu_create_pidfile(const char *filename)
 299{
 300    char buffer[128];
 301    int len;
 302    int fd;
 303
 304    fd = qemu_open(filename, O_RDWR | O_CREAT, 0600);
 305    if (fd == -1) {
 306        return -1;
 307    }
 308    if (lockf(fd, F_TLOCK, 0) == -1) {
 309        close(fd);
 310        return -1;
 311    }
 312    len = snprintf(buffer, sizeof(buffer), FMT_pid "\n", getpid());
 313    if (write(fd, buffer, len) != len) {
 314        close(fd);
 315        return -1;
 316    }
 317
 318    /* keep pidfile open & locked forever */
 319    return 0;
 320}
 321
 322bool is_daemonized(void)
 323{
 324    return daemonize;
 325}
 326
 327int os_mlock(void)
 328{
 329    int ret = 0;
 330
 331    ret = mlockall(MCL_CURRENT | MCL_FUTURE);
 332    if (ret < 0) {
 333        perror("mlockall");
 334    }
 335
 336    return ret;
 337}
 338