File:  [Qemu by Fabrice Bellard] / qemu / os-posix.c
Revision 1.1.1.2 (vendor branch): download - view: text, annotated - select for diffs
Tue Apr 24 18:33:44 2018 UTC (3 years, 3 months ago) by root
Branches: qemu, MAIN
CVS tags: qemu0150, qemu0141, qemu0140, HEAD
qemu 0.14.0

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

unix.superglobalmegacorp.com