File:  [Qemu by Fabrice Bellard] / qemu / os-posix.c
Revision 1.1.1.4 (vendor branch): download - view: text, annotated - select for diffs
Tue Apr 24 19:17:06 2018 UTC (3 years, 1 month ago) by root
Branches: qemu, MAIN
CVS tags: qemu1001, HEAD
qemu 1.0.1

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

unix.superglobalmegacorp.com