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