Move chroot handling to OS specific files.
[sdk/emulator/qemu.git] / os-posix.c
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 #include <pwd.h>
32 #include <libgen.h>
33
34 /* Needed early for CONFIG_BSD etc. */
35 #include "config-host.h"
36 #include "sysemu.h"
37 #include "net/slirp.h"
38 #include "qemu-options.h"
39
40 static struct passwd *user_pwd;
41 static const char *chroot_dir;
42
43 void os_setup_early_signal_handling(void)
44 {
45     struct sigaction act;
46     sigfillset(&act.sa_mask);
47     act.sa_flags = 0;
48     act.sa_handler = SIG_IGN;
49     sigaction(SIGPIPE, &act, NULL);
50 }
51
52 static void termsig_handler(int signal)
53 {
54     qemu_system_shutdown_request();
55 }
56
57 static void sigchld_handler(int signal)
58 {
59     waitpid(-1, NULL, WNOHANG);
60 }
61
62 void os_setup_signal_handling(void)
63 {
64     struct sigaction act;
65
66     memset(&act, 0, sizeof(act));
67     act.sa_handler = termsig_handler;
68     sigaction(SIGINT,  &act, NULL);
69     sigaction(SIGHUP,  &act, NULL);
70     sigaction(SIGTERM, &act, NULL);
71
72     act.sa_handler = sigchld_handler;
73     act.sa_flags = SA_NOCLDSTOP;
74     sigaction(SIGCHLD, &act, NULL);
75 }
76
77 /* Find a likely location for support files using the location of the binary.
78    For installed binaries this will be "$bindir/../share/qemu".  When
79    running from the build tree this will be "$bindir/../pc-bios".  */
80 #define SHARE_SUFFIX "/share/qemu"
81 #define BUILD_SUFFIX "/pc-bios"
82 char *os_find_datadir(const char *argv0)
83 {
84     char *dir;
85     char *p = NULL;
86     char *res;
87     char buf[PATH_MAX];
88     size_t max_len;
89
90 #if defined(__linux__)
91     {
92         int len;
93         len = readlink("/proc/self/exe", buf, sizeof(buf) - 1);
94         if (len > 0) {
95             buf[len] = 0;
96             p = buf;
97         }
98     }
99 #elif defined(__FreeBSD__)
100     {
101         static int mib[4] = {CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME, -1};
102         size_t len = sizeof(buf) - 1;
103
104         *buf = '\0';
105         if (!sysctl(mib, sizeof(mib)/sizeof(*mib), buf, &len, NULL, 0) &&
106             *buf) {
107             buf[sizeof(buf) - 1] = '\0';
108             p = buf;
109         }
110     }
111 #endif
112     /* If we don't have any way of figuring out the actual executable
113        location then try argv[0].  */
114     if (!p) {
115         p = realpath(argv0, buf);
116         if (!p) {
117             return NULL;
118         }
119     }
120     dir = dirname(p);
121     dir = dirname(dir);
122
123     max_len = strlen(dir) +
124         MAX(strlen(SHARE_SUFFIX), strlen(BUILD_SUFFIX)) + 1;
125     res = qemu_mallocz(max_len);
126     snprintf(res, max_len, "%s%s", dir, SHARE_SUFFIX);
127     if (access(res, R_OK)) {
128         snprintf(res, max_len, "%s%s", dir, BUILD_SUFFIX);
129         if (access(res, R_OK)) {
130             qemu_free(res);
131             res = NULL;
132         }
133     }
134
135     return res;
136 }
137 #undef SHARE_SUFFIX
138 #undef BUILD_SUFFIX
139
140 /*
141  * Parse OS specific command line options.
142  * return 0 if option handled, -1 otherwise
143  */
144 void os_parse_cmd_args(int index, const char *optarg)
145 {
146     switch (index) {
147 #ifdef CONFIG_SLIRP
148     case QEMU_OPTION_smb:
149         if (net_slirp_smb(optarg) < 0)
150             exit(1);
151         break;
152 #endif
153     case QEMU_OPTION_runas:
154         user_pwd = getpwnam(optarg);
155         if (!user_pwd) {
156             fprintf(stderr, "User \"%s\" doesn't exist\n", optarg);
157             exit(1);
158         }
159         break;
160     case QEMU_OPTION_chroot:
161         chroot_dir = optarg;
162         break;
163     }
164     return;
165 }
166
167 void os_change_process_uid(void)
168 {
169     if (user_pwd) {
170         if (setgid(user_pwd->pw_gid) < 0) {
171             fprintf(stderr, "Failed to setgid(%d)\n", user_pwd->pw_gid);
172             exit(1);
173         }
174         if (setuid(user_pwd->pw_uid) < 0) {
175             fprintf(stderr, "Failed to setuid(%d)\n", user_pwd->pw_uid);
176             exit(1);
177         }
178         if (setuid(0) != -1) {
179             fprintf(stderr, "Dropping privileges failed\n");
180             exit(1);
181         }
182     }
183 }
184
185 void os_change_root(void)
186 {
187     if (chroot_dir) {
188         if (chroot(chroot_dir) < 0) {
189             fprintf(stderr, "chroot failed\n");
190             exit(1);
191         }
192         if (chdir("/")) {
193             perror("not able to chdir to /");
194             exit(1);
195         }
196     }
197
198 }