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