xref: /qemu/os-posix.c (revision 8847cfe8aa9d8f6b8648aafd5d929a57d836cc61)
186b645e7SJes Sorensen /*
286b645e7SJes Sorensen  * os-posix.c
386b645e7SJes Sorensen  *
486b645e7SJes Sorensen  * Copyright (c) 2003-2008 Fabrice Bellard
586b645e7SJes Sorensen  * Copyright (c) 2010 Red Hat, Inc.
686b645e7SJes Sorensen  *
786b645e7SJes Sorensen  * Permission is hereby granted, free of charge, to any person obtaining a copy
886b645e7SJes Sorensen  * of this software and associated documentation files (the "Software"), to deal
986b645e7SJes Sorensen  * in the Software without restriction, including without limitation the rights
1086b645e7SJes Sorensen  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
1186b645e7SJes Sorensen  * copies of the Software, and to permit persons to whom the Software is
1286b645e7SJes Sorensen  * furnished to do so, subject to the following conditions:
1386b645e7SJes Sorensen  *
1486b645e7SJes Sorensen  * The above copyright notice and this permission notice shall be included in
1586b645e7SJes Sorensen  * all copies or substantial portions of the Software.
1686b645e7SJes Sorensen  *
1786b645e7SJes Sorensen  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
1886b645e7SJes Sorensen  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
1986b645e7SJes Sorensen  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
2086b645e7SJes Sorensen  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
2186b645e7SJes Sorensen  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
2286b645e7SJes Sorensen  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
2386b645e7SJes Sorensen  * THE SOFTWARE.
2486b645e7SJes Sorensen  */
2586b645e7SJes Sorensen 
2686b645e7SJes Sorensen #include <unistd.h>
2786b645e7SJes Sorensen #include <fcntl.h>
2886b645e7SJes Sorensen #include <signal.h>
298d963e6aSJes Sorensen #include <sys/types.h>
308d963e6aSJes Sorensen #include <sys/wait.h>
31*8847cfe8SJes Sorensen #include <pwd.h>
326170540bSJes Sorensen #include <libgen.h>
3386b645e7SJes Sorensen 
3486b645e7SJes Sorensen /* Needed early for CONFIG_BSD etc. */
3586b645e7SJes Sorensen #include "config-host.h"
3686b645e7SJes Sorensen #include "sysemu.h"
3759a5264bSJes Sorensen #include "net/slirp.h"
3859a5264bSJes Sorensen #include "qemu-options.h"
3986b645e7SJes Sorensen 
40*8847cfe8SJes Sorensen static struct passwd *user_pwd;
41*8847cfe8SJes Sorensen 
42fe98ac14SJes Sorensen void os_setup_early_signal_handling(void)
4386b645e7SJes Sorensen {
4486b645e7SJes Sorensen     struct sigaction act;
4586b645e7SJes Sorensen     sigfillset(&act.sa_mask);
4686b645e7SJes Sorensen     act.sa_flags = 0;
4786b645e7SJes Sorensen     act.sa_handler = SIG_IGN;
4886b645e7SJes Sorensen     sigaction(SIGPIPE, &act, NULL);
4986b645e7SJes Sorensen }
508d963e6aSJes Sorensen 
518d963e6aSJes Sorensen static void termsig_handler(int signal)
528d963e6aSJes Sorensen {
538d963e6aSJes Sorensen     qemu_system_shutdown_request();
548d963e6aSJes Sorensen }
558d963e6aSJes Sorensen 
568d963e6aSJes Sorensen static void sigchld_handler(int signal)
578d963e6aSJes Sorensen {
588d963e6aSJes Sorensen     waitpid(-1, NULL, WNOHANG);
598d963e6aSJes Sorensen }
608d963e6aSJes Sorensen 
618d963e6aSJes Sorensen void os_setup_signal_handling(void)
628d963e6aSJes Sorensen {
638d963e6aSJes Sorensen     struct sigaction act;
648d963e6aSJes Sorensen 
658d963e6aSJes Sorensen     memset(&act, 0, sizeof(act));
668d963e6aSJes Sorensen     act.sa_handler = termsig_handler;
678d963e6aSJes Sorensen     sigaction(SIGINT,  &act, NULL);
688d963e6aSJes Sorensen     sigaction(SIGHUP,  &act, NULL);
698d963e6aSJes Sorensen     sigaction(SIGTERM, &act, NULL);
708d963e6aSJes Sorensen 
718d963e6aSJes Sorensen     act.sa_handler = sigchld_handler;
728d963e6aSJes Sorensen     act.sa_flags = SA_NOCLDSTOP;
738d963e6aSJes Sorensen     sigaction(SIGCHLD, &act, NULL);
748d963e6aSJes Sorensen }
756170540bSJes Sorensen 
766170540bSJes Sorensen /* Find a likely location for support files using the location of the binary.
776170540bSJes Sorensen    For installed binaries this will be "$bindir/../share/qemu".  When
786170540bSJes Sorensen    running from the build tree this will be "$bindir/../pc-bios".  */
796170540bSJes Sorensen #define SHARE_SUFFIX "/share/qemu"
806170540bSJes Sorensen #define BUILD_SUFFIX "/pc-bios"
816170540bSJes Sorensen char *os_find_datadir(const char *argv0)
826170540bSJes Sorensen {
836170540bSJes Sorensen     char *dir;
846170540bSJes Sorensen     char *p = NULL;
856170540bSJes Sorensen     char *res;
866170540bSJes Sorensen     char buf[PATH_MAX];
876170540bSJes Sorensen     size_t max_len;
886170540bSJes Sorensen 
896170540bSJes Sorensen #if defined(__linux__)
906170540bSJes Sorensen     {
916170540bSJes Sorensen         int len;
926170540bSJes Sorensen         len = readlink("/proc/self/exe", buf, sizeof(buf) - 1);
936170540bSJes Sorensen         if (len > 0) {
946170540bSJes Sorensen             buf[len] = 0;
956170540bSJes Sorensen             p = buf;
966170540bSJes Sorensen         }
976170540bSJes Sorensen     }
986170540bSJes Sorensen #elif defined(__FreeBSD__)
996170540bSJes Sorensen     {
1006170540bSJes Sorensen         static int mib[4] = {CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME, -1};
1016170540bSJes Sorensen         size_t len = sizeof(buf) - 1;
1026170540bSJes Sorensen 
1036170540bSJes Sorensen         *buf = '\0';
1046170540bSJes Sorensen         if (!sysctl(mib, sizeof(mib)/sizeof(*mib), buf, &len, NULL, 0) &&
1056170540bSJes Sorensen             *buf) {
1066170540bSJes Sorensen             buf[sizeof(buf) - 1] = '\0';
1076170540bSJes Sorensen             p = buf;
1086170540bSJes Sorensen         }
1096170540bSJes Sorensen     }
1106170540bSJes Sorensen #endif
1116170540bSJes Sorensen     /* If we don't have any way of figuring out the actual executable
1126170540bSJes Sorensen        location then try argv[0].  */
1136170540bSJes Sorensen     if (!p) {
1146170540bSJes Sorensen         p = realpath(argv0, buf);
1156170540bSJes Sorensen         if (!p) {
1166170540bSJes Sorensen             return NULL;
1176170540bSJes Sorensen         }
1186170540bSJes Sorensen     }
1196170540bSJes Sorensen     dir = dirname(p);
1206170540bSJes Sorensen     dir = dirname(dir);
1216170540bSJes Sorensen 
1226170540bSJes Sorensen     max_len = strlen(dir) +
1236170540bSJes Sorensen         MAX(strlen(SHARE_SUFFIX), strlen(BUILD_SUFFIX)) + 1;
1246170540bSJes Sorensen     res = qemu_mallocz(max_len);
1256170540bSJes Sorensen     snprintf(res, max_len, "%s%s", dir, SHARE_SUFFIX);
1266170540bSJes Sorensen     if (access(res, R_OK)) {
1276170540bSJes Sorensen         snprintf(res, max_len, "%s%s", dir, BUILD_SUFFIX);
1286170540bSJes Sorensen         if (access(res, R_OK)) {
1296170540bSJes Sorensen             qemu_free(res);
1306170540bSJes Sorensen             res = NULL;
1316170540bSJes Sorensen         }
1326170540bSJes Sorensen     }
1336170540bSJes Sorensen 
1346170540bSJes Sorensen     return res;
1356170540bSJes Sorensen }
1366170540bSJes Sorensen #undef SHARE_SUFFIX
1376170540bSJes Sorensen #undef BUILD_SUFFIX
13859a5264bSJes Sorensen 
13959a5264bSJes Sorensen /*
14059a5264bSJes Sorensen  * Parse OS specific command line options.
14159a5264bSJes Sorensen  * return 0 if option handled, -1 otherwise
14259a5264bSJes Sorensen  */
14359a5264bSJes Sorensen void os_parse_cmd_args(int index, const char *optarg)
14459a5264bSJes Sorensen {
14559a5264bSJes Sorensen     switch (index) {
14659a5264bSJes Sorensen #ifdef CONFIG_SLIRP
14759a5264bSJes Sorensen     case QEMU_OPTION_smb:
14859a5264bSJes Sorensen         if (net_slirp_smb(optarg) < 0)
14959a5264bSJes Sorensen             exit(1);
15059a5264bSJes Sorensen         break;
15159a5264bSJes Sorensen #endif
152*8847cfe8SJes Sorensen     case QEMU_OPTION_runas:
153*8847cfe8SJes Sorensen         user_pwd = getpwnam(optarg);
154*8847cfe8SJes Sorensen         if (!user_pwd) {
155*8847cfe8SJes Sorensen             fprintf(stderr, "User \"%s\" doesn't exist\n", optarg);
156*8847cfe8SJes Sorensen             exit(1);
157*8847cfe8SJes Sorensen         }
158*8847cfe8SJes Sorensen         break;
15959a5264bSJes Sorensen     }
16059a5264bSJes Sorensen     return;
16159a5264bSJes Sorensen }
162*8847cfe8SJes Sorensen 
163*8847cfe8SJes Sorensen void os_change_process_uid(void)
164*8847cfe8SJes Sorensen {
165*8847cfe8SJes Sorensen     if (user_pwd) {
166*8847cfe8SJes Sorensen         if (setgid(user_pwd->pw_gid) < 0) {
167*8847cfe8SJes Sorensen             fprintf(stderr, "Failed to setgid(%d)\n", user_pwd->pw_gid);
168*8847cfe8SJes Sorensen             exit(1);
169*8847cfe8SJes Sorensen         }
170*8847cfe8SJes Sorensen         if (setuid(user_pwd->pw_uid) < 0) {
171*8847cfe8SJes Sorensen             fprintf(stderr, "Failed to setuid(%d)\n", user_pwd->pw_uid);
172*8847cfe8SJes Sorensen             exit(1);
173*8847cfe8SJes Sorensen         }
174*8847cfe8SJes Sorensen         if (setuid(0) != -1) {
175*8847cfe8SJes Sorensen             fprintf(stderr, "Dropping privileges failed\n");
176*8847cfe8SJes Sorensen             exit(1);
177*8847cfe8SJes Sorensen         }
178*8847cfe8SJes Sorensen     }
179*8847cfe8SJes Sorensen }
180