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 <unistd.h>
  27#include <fcntl.h>
  28#include <signal.h>
  29#include <sys/types.h>
  30#include <sys/wait.h>
  31/*needed for MAP_POPULATE before including qemu-options.h */
  32#include <sys/mman.h>
  33#include <pwd.h>
  34#include <grp.h>
  35#include <libgen.h>
  36
  37/* Needed early for CONFIG_BSD etc. */
  38#include "config-host.h"
  39#include "sysemu/sysemu.h"
  40#include "net/slirp.h"
  41#include "qemu-options.h"
  42
  43#ifdef CONFIG_LINUX
  44#include <sys/prctl.h>
  45#endif
  46
  47static struct passwd *user_pwd;
  48static const char *chroot_dir;
  49static int daemonize;
  50static int fds[2];
  51
  52void os_setup_early_signal_handling(void)
  53{
  54    struct sigaction act;
  55    sigfillset(&act.sa_mask);
  56    act.sa_flags = 0;
  57    act.sa_handler = SIG_IGN;
  58    sigaction(SIGPIPE, &act, NULL);
  59}
  60
  61static void termsig_handler(int signal, siginfo_t *info, void *c)
  62{
  63    qemu_system_killed(info->si_signo, info->si_pid);
  64}
  65
  66void os_setup_signal_handling(void)
  67{
  68    struct sigaction act;
  69
  70    memset(&act, 0, sizeof(act));
  71    act.sa_sigaction = termsig_handler;
  72    act.sa_flags = SA_SIGINFO;
  73    sigaction(SIGINT,  &act, NULL);
  74    sigaction(SIGHUP,  &act, NULL);
  75    sigaction(SIGTERM, &act, NULL);
  76}
  77
  78/* Find a likely location for support files using the location of the binary.
  79   For installed binaries this will be "$bindir/../share/qemu".  When
  80   running from the build tree this will be "$bindir/../pc-bios".  */
  81#define SHARE_SUFFIX "/share/qemu"
  82#define BUILD_SUFFIX "/pc-bios"
  83char *os_find_datadir(void)
  84{
  85    char *dir, *exec_dir;
  86    char *res;
  87    size_t max_len;
  88
  89    exec_dir = qemu_get_exec_dir();
  90    if (exec_dir == NULL) {
  91        return NULL;
  92    }
  93    dir = dirname(exec_dir);
  94
  95    max_len = strlen(dir) +
  96        MAX(strlen(SHARE_SUFFIX), strlen(BUILD_SUFFIX)) + 1;
  97    res = g_malloc0(max_len);
  98    snprintf(res, max_len, "%s%s", dir, SHARE_SUFFIX);
  99    if (access(res, R_OK)) {
 100        snprintf(res, max_len, "%s%s", dir, BUILD_SUFFIX);
 101        if (access(res, R_OK)) {
 102            g_free(res);
 103            res = NULL;
 104        }
 105    }
 106
 107    g_free(exec_dir);
 108    return res;
 109}
 110#undef SHARE_SUFFIX
 111#undef BUILD_SUFFIX
 112
 113void os_set_proc_name(const char *s)
 114{
 115#if defined(PR_SET_NAME)
 116    char name[16];
 117    if (!s)
 118        return;
 119    pstrcpy(name, sizeof(name), s);
 120    /* Could rewrite argv[0] too, but that's a bit more complicated.
 121       This simple way is enough for `top'. */
 122    if (prctl(PR_SET_NAME, name)) {
 123        perror("unable to change process name");
 124        exit(1);
 125    }
 126#else
 127    fprintf(stderr, "Change of process name not supported by your OS\n");
 128    exit(1);
 129#endif
 130}
 131
 132/*
 133 * Parse OS specific command line options.
 134 * return 0 if option handled, -1 otherwise
 135 */
 136void os_parse_cmd_args(int index, const char *optarg)
 137{
 138    switch (index) {
 139#ifdef CONFIG_SLIRP
 140    case QEMU_OPTION_smb:
 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
 209        if (pipe(fds) == -1)
 210            exit(1);
 211
 212        pid = fork();
 213        if (pid > 0) {
 214            uint8_t status;
 215            ssize_t len;
 216
 217            close(fds[1]);
 218
 219        again:
 220            len = read(fds[0], &status, 1);
 221            if (len == -1 && (errno == EINTR))
 222                goto again;
 223
 224            if (len != 1)
 225                exit(1);
 226            else if (status == 1) {
 227                fprintf(stderr, "Could not acquire pidfile: %s\n", strerror(errno));
 228                exit(1);
 229            } else
 230                exit(0);
 231        } else if (pid < 0)
 232            exit(1);
 233
 234        close(fds[0]);
 235        qemu_set_cloexec(fds[1]);
 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        uint8_t status = 0;
 259        ssize_t len;
 260
 261    again1:
 262        len = write(fds[1], &status, 1);
 263        if (len == -1 && (errno == EINTR))
 264            goto again1;
 265
 266        if (len != 1)
 267            exit(1);
 268
 269        if (chdir("/")) {
 270            perror("not able to chdir to /");
 271            exit(1);
 272        }
 273        TFR(fd = qemu_open("/dev/null", O_RDWR));
 274        if (fd == -1)
 275            exit(1);
 276    }
 277
 278    change_root();
 279    change_process_uid();
 280
 281    if (daemonize) {
 282        dup2(fd, 0);
 283        dup2(fd, 1);
 284        dup2(fd, 2);
 285
 286        close(fd);
 287    }
 288}
 289
 290void os_pidfile_error(void)
 291{
 292    if (daemonize) {
 293        uint8_t status = 1;
 294        if (write(fds[1], &status, 1) != 1) {
 295            perror("daemonize. Writing to pipe\n");
 296        }
 297    } else
 298        fprintf(stderr, "Could not acquire pid file: %s\n", strerror(errno));
 299}
 300
 301void os_set_line_buffering(void)
 302{
 303    setvbuf(stdout, NULL, _IOLBF, 0);
 304}
 305
 306int qemu_create_pidfile(const char *filename)
 307{
 308    char buffer[128];
 309    int len;
 310    int fd;
 311
 312    fd = qemu_open(filename, O_RDWR | O_CREAT, 0600);
 313    if (fd == -1) {
 314        return -1;
 315    }
 316    if (lockf(fd, F_TLOCK, 0) == -1) {
 317        close(fd);
 318        return -1;
 319    }
 320    len = snprintf(buffer, sizeof(buffer), FMT_pid "\n", getpid());
 321    if (write(fd, buffer, len) != len) {
 322        close(fd);
 323        return -1;
 324    }
 325
 326    /* keep pidfile open & locked forever */
 327    return 0;
 328}
 329
 330bool is_daemonized(void)
 331{
 332    return daemonize;
 333}
 334
 335int os_mlock(void)
 336{
 337    int ret = 0;
 338
 339    ret = mlockall(MCL_CURRENT | MCL_FUTURE);
 340    if (ret < 0) {
 341        perror("mlockall");
 342    }
 343
 344    return ret;
 345}
 346