Home | History | Annotate | Download | only in qemu
      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 <libgen.h>
     35 
     36 /* Needed early for CONFIG_BSD etc. */
     37 #include "config-host.h"
     38 #include "sysemu.h"
     39 #include "net.h"
     40 #include "qemu-options.h"
     41 
     42 #ifdef CONFIG_LINUX
     43 #include <sys/prctl.h>
     44 #include <sys/syscall.h>
     45 #endif
     46 
     47 #ifdef CONFIG_EVENTFD
     48 #include <sys/eventfd.h>
     49 #endif
     50 
     51 static struct passwd *user_pwd;
     52 static const char *chroot_dir;
     53 static int daemonize;
     54 static int fds[2];
     55 
     56 void os_setup_early_signal_handling(void)
     57 {
     58     struct sigaction act;
     59     sigfillset(&act.sa_mask);
     60     act.sa_flags = 0;
     61     act.sa_handler = SIG_IGN;
     62     sigaction(SIGPIPE, &act, NULL);
     63 }
     64 
     65 static void termsig_handler(int signal)
     66 {
     67     qemu_system_shutdown_request();
     68 }
     69 
     70 static void sigchld_handler(int signal)
     71 {
     72     waitpid(-1, NULL, WNOHANG);
     73 }
     74 
     75 void os_setup_signal_handling(void)
     76 {
     77     struct sigaction act;
     78 
     79     memset(&act, 0, sizeof(act));
     80     act.sa_handler = termsig_handler;
     81     sigaction(SIGINT,  &act, NULL);
     82     sigaction(SIGHUP,  &act, NULL);
     83     sigaction(SIGTERM, &act, NULL);
     84 
     85     act.sa_handler = sigchld_handler;
     86     act.sa_flags = SA_NOCLDSTOP;
     87     sigaction(SIGCHLD, &act, NULL);
     88 }
     89 
     90 /* Find a likely location for support files using the location of the binary.
     91    For installed binaries this will be "$bindir/../share/qemu".  When
     92    running from the build tree this will be "$bindir/../pc-bios".  */
     93 #define SHARE_SUFFIX "/share/qemu"
     94 #define BUILD_SUFFIX "/pc-bios"
     95 char *os_find_datadir(const char *argv0)
     96 {
     97     char *dir;
     98     char *p = NULL;
     99     char *res;
    100     char buf[PATH_MAX];
    101     size_t max_len;
    102 
    103 #if defined(__linux__)
    104     {
    105         int len;
    106         len = readlink("/proc/self/exe", buf, sizeof(buf) - 1);
    107         if (len > 0) {
    108             buf[len] = 0;
    109             p = buf;
    110         }
    111     }
    112 #elif defined(__FreeBSD__)
    113     {
    114         static int mib[4] = {CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME, -1};
    115         size_t len = sizeof(buf) - 1;
    116 
    117         *buf = '\0';
    118         if (!sysctl(mib, ARRAY_SIZE(mib), buf, &len, NULL, 0) &&
    119             *buf) {
    120             buf[sizeof(buf) - 1] = '\0';
    121             p = buf;
    122         }
    123     }
    124 #endif
    125     /* If we don't have any way of figuring out the actual executable
    126        location then try argv[0].  */
    127     if (!p) {
    128         p = realpath(argv0, buf);
    129         if (!p) {
    130             return NULL;
    131         }
    132     }
    133     dir = dirname(p);
    134     dir = dirname(dir);
    135 
    136     max_len = strlen(dir) +
    137         MAX(strlen(SHARE_SUFFIX), strlen(BUILD_SUFFIX)) + 1;
    138     res = qemu_mallocz(max_len);
    139     snprintf(res, max_len, "%s%s", dir, SHARE_SUFFIX);
    140     if (access(res, R_OK)) {
    141         snprintf(res, max_len, "%s%s", dir, BUILD_SUFFIX);
    142         if (access(res, R_OK)) {
    143             qemu_free(res);
    144             res = NULL;
    145         }
    146     }
    147 
    148     return res;
    149 }
    150 #undef SHARE_SUFFIX
    151 #undef BUILD_SUFFIX
    152 
    153 void os_set_proc_name(const char *s)
    154 {
    155 #if defined(PR_SET_NAME)
    156     char name[16];
    157     if (!s)
    158         return;
    159     name[sizeof(name) - 1] = 0;
    160     strncpy(name, s, sizeof(name));
    161     /* Could rewrite argv[0] too, but that's a bit more complicated.
    162        This simple way is enough for `top'. */
    163     if (prctl(PR_SET_NAME, name)) {
    164         perror("unable to change process name");
    165         exit(1);
    166     }
    167 #else
    168     fprintf(stderr, "Change of process name not supported by your OS\n");
    169     exit(1);
    170 #endif
    171 }
    172 
    173 /*
    174  * Parse OS specific command line options.
    175  * return 0 if option handled, -1 otherwise
    176  */
    177 void os_parse_cmd_args(int index, const char *optarg)
    178 {
    179     switch (index) {
    180 #ifdef CONFIG_SLIRP
    181     case QEMU_OPTION_smb:
    182 #if 1
    183         net_slirp_smb(optarg);
    184 #else
    185         if (net_slirp_smb(optarg) < 0)
    186             exit(1);
    187 #endif
    188         break;
    189 #endif
    190     case QEMU_OPTION_runas:
    191         user_pwd = getpwnam(optarg);
    192         if (!user_pwd) {
    193             fprintf(stderr, "User \"%s\" doesn't exist\n", optarg);
    194             exit(1);
    195         }
    196         break;
    197     case QEMU_OPTION_chroot:
    198         chroot_dir = optarg;
    199         break;
    200     case QEMU_OPTION_daemonize:
    201         daemonize = 1;
    202         break;
    203     }
    204     return;
    205 }
    206 
    207 static void change_process_uid(void)
    208 {
    209     if (user_pwd) {
    210         if (setgid(user_pwd->pw_gid) < 0) {
    211             fprintf(stderr, "Failed to setgid(%d)\n", user_pwd->pw_gid);
    212             exit(1);
    213         }
    214         if (setuid(user_pwd->pw_uid) < 0) {
    215             fprintf(stderr, "Failed to setuid(%d)\n", user_pwd->pw_uid);
    216             exit(1);
    217         }
    218         if (setuid(0) != -1) {
    219             fprintf(stderr, "Dropping privileges failed\n");
    220             exit(1);
    221         }
    222     }
    223 }
    224 
    225 static void change_root(void)
    226 {
    227     if (chroot_dir) {
    228         if (chroot(chroot_dir) < 0) {
    229             fprintf(stderr, "chroot failed\n");
    230             exit(1);
    231         }
    232         if (chdir("/")) {
    233             perror("not able to chdir to /");
    234             exit(1);
    235         }
    236     }
    237 
    238 }
    239 
    240 void os_daemonize(void)
    241 {
    242     if (daemonize) {
    243 	pid_t pid;
    244 
    245 	if (pipe(fds) == -1)
    246 	    exit(1);
    247 
    248 	pid = fork();
    249 	if (pid > 0) {
    250 	    uint8_t status;
    251 	    ssize_t len;
    252 
    253 	    close(fds[1]);
    254 
    255 	again:
    256             len = read(fds[0], &status, 1);
    257             if (len == -1 && (errno == EINTR))
    258                 goto again;
    259 
    260             if (len != 1)
    261                 exit(1);
    262             else if (status == 1) {
    263                 fprintf(stderr, "Could not acquire pidfile: %s\n", strerror(errno));
    264                 exit(1);
    265             } else
    266                 exit(0);
    267 	} else if (pid < 0)
    268             exit(1);
    269 
    270 	close(fds[0]);
    271 	qemu_set_cloexec(fds[1]);
    272 
    273 	setsid();
    274 
    275 	pid = fork();
    276 	if (pid > 0)
    277 	    exit(0);
    278 	else if (pid < 0)
    279 	    exit(1);
    280 
    281 	umask(027);
    282 
    283         signal(SIGTSTP, SIG_IGN);
    284         signal(SIGTTOU, SIG_IGN);
    285         signal(SIGTTIN, SIG_IGN);
    286     }
    287 }
    288 
    289 void os_setup_post(void)
    290 {
    291     int fd = 0;
    292 
    293     if (daemonize) {
    294 	uint8_t status = 0;
    295 	ssize_t len;
    296 
    297     again1:
    298 	len = write(fds[1], &status, 1);
    299 	if (len == -1 && (errno == EINTR))
    300 	    goto again1;
    301 
    302 	if (len != 1)
    303 	    exit(1);
    304 
    305         if (chdir("/")) {
    306             perror("not able to chdir to /");
    307             exit(1);
    308         }
    309 	TFR(fd = qemu_open("/dev/null", O_RDWR));
    310 	if (fd == -1)
    311 	    exit(1);
    312     }
    313 
    314     change_root();
    315     change_process_uid();
    316 
    317     if (daemonize) {
    318         dup2(fd, 0);
    319         dup2(fd, 1);
    320         dup2(fd, 2);
    321 
    322         close(fd);
    323     }
    324 }
    325 
    326 void os_pidfile_error(void)
    327 {
    328     if (daemonize) {
    329         uint8_t status = 1;
    330         if (write(fds[1], &status, 1) != 1) {
    331             perror("daemonize. Writing to pipe\n");
    332         }
    333     } else
    334         fprintf(stderr, "Could not acquire pid file: %s\n", strerror(errno));
    335 }
    336 
    337 void os_set_line_buffering(void)
    338 {
    339     setvbuf(stdout, NULL, _IOLBF, 0);
    340 }
    341 
    342 /*
    343  * Creates an eventfd that looks like a pipe and has EFD_CLOEXEC set.
    344  */
    345 int qemu_eventfd(int fds[2])
    346 {
    347 #ifdef CONFIG_EVENTFD
    348     int ret;
    349 
    350     ret = eventfd(0, 0);
    351     if (ret >= 0) {
    352         fds[0] = ret;
    353         qemu_set_cloexec(ret);
    354         if ((fds[1] = dup(ret)) == -1) {
    355             close(ret);
    356             return -1;
    357         }
    358         qemu_set_cloexec(fds[1]);
    359         return 0;
    360     }
    361 
    362     if (errno != ENOSYS) {
    363         return -1;
    364     }
    365 #endif
    366 
    367     return qemu_pipe(fds);
    368 }
    369 
    370 int qemu_create_pidfile(const char *filename)
    371 {
    372     char buffer[128];
    373     int len;
    374     int fd;
    375 
    376     fd = qemu_open(filename, O_RDWR | O_CREAT, 0600);
    377     if (fd == -1) {
    378         return -1;
    379     }
    380     if (lockf(fd, F_TLOCK, 0) == -1) {
    381         return -1;
    382     }
    383     len = snprintf(buffer, sizeof(buffer), "%ld\n", (long)getpid());
    384     if (write(fd, buffer, len) != len) {
    385         return -1;
    386     }
    387 
    388     return 0;
    389 }
    390 
    391 int qemu_get_thread_id(void)
    392 {
    393 #if defined (__linux__)
    394     return syscall(SYS_gettid);
    395 #else
    396     return getpid();
    397 #endif
    398 }
    399