Statistics
| Branch: | Revision:

root / os-posix.c @ f64622c4

History | View | Annotate | Download (8.7 kB)

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
#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

    
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

    
65
static void termsig_handler(int signal, siginfo_t *info, void *c)
66
{
67
    qemu_system_killed(info->si_signo, info->si_pid);
68
}
69

    
70
static void sigchld_handler(int signal)
71
{
72
    waitpid(-1, NULL, WNOHANG);
73
}
74

    
75
void os_setup_signal_handling(void)
76
{
77
    struct sigaction act;
78

    
79
    memset(&act, 0, sizeof(act));
80
    act.sa_sigaction = termsig_handler;
81
    act.sa_flags = SA_SIGINFO;
82
    sigaction(SIGINT,  &act, NULL);
83
    sigaction(SIGHUP,  &act, NULL);
84
    sigaction(SIGTERM, &act, NULL);
85

    
86
    act.sa_handler = sigchld_handler;
87
    act.sa_flags = SA_NOCLDSTOP;
88
    sigaction(SIGCHLD, &act, NULL);
89
}
90

    
91
/* Find a likely location for support files using the location of the binary.
92
   For installed binaries this will be "$bindir/../share/qemu".  When
93
   running from the build tree this will be "$bindir/../pc-bios".  */
94
#define SHARE_SUFFIX "/share/qemu"
95
#define BUILD_SUFFIX "/pc-bios"
96
char *os_find_datadir(const char *argv0)
97
{
98
    char *dir;
99
    char *p = NULL;
100
    char *res;
101
    char buf[PATH_MAX];
102
    size_t max_len;
103

    
104
#if defined(__linux__)
105
    {
106
        int len;
107
        len = readlink("/proc/self/exe", buf, sizeof(buf) - 1);
108
        if (len > 0) {
109
            buf[len] = 0;
110
            p = buf;
111
        }
112
    }
113
#elif defined(__FreeBSD__)
114
    {
115
        static int mib[4] = {CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME, -1};
116
        size_t len = sizeof(buf) - 1;
117

    
118
        *buf = '\0';
119
        if (!sysctl(mib, ARRAY_SIZE(mib), buf, &len, NULL, 0) &&
120
            *buf) {
121
            buf[sizeof(buf) - 1] = '\0';
122
            p = buf;
123
        }
124
    }
125
#endif
126
    /* If we don't have any way of figuring out the actual executable
127
       location then try argv[0].  */
128
    if (!p) {
129
        p = realpath(argv0, buf);
130
        if (!p) {
131
            return NULL;
132
        }
133
    }
134
    dir = dirname(p);
135
    dir = dirname(dir);
136

    
137
    max_len = strlen(dir) +
138
        MAX(strlen(SHARE_SUFFIX), strlen(BUILD_SUFFIX)) + 1;
139
    res = qemu_mallocz(max_len);
140
    snprintf(res, max_len, "%s%s", dir, SHARE_SUFFIX);
141
    if (access(res, R_OK)) {
142
        snprintf(res, max_len, "%s%s", dir, BUILD_SUFFIX);
143
        if (access(res, R_OK)) {
144
            qemu_free(res);
145
            res = NULL;
146
        }
147
    }
148

    
149
    return res;
150
}
151
#undef SHARE_SUFFIX
152
#undef BUILD_SUFFIX
153

    
154
void os_set_proc_name(const char *s)
155
{
156
#if defined(PR_SET_NAME)
157
    char name[16];
158
    if (!s)
159
        return;
160
    name[sizeof(name) - 1] = 0;
161
    strncpy(name, s, sizeof(name));
162
    /* Could rewrite argv[0] too, but that's a bit more complicated.
163
       This simple way is enough for `top'. */
164
    if (prctl(PR_SET_NAME, name)) {
165
        perror("unable to change process name");
166
        exit(1);
167
    }
168
#else
169
    fprintf(stderr, "Change of process name not supported by your OS\n");
170
    exit(1);
171
#endif
172
}
173

    
174
/*
175
 * Parse OS specific command line options.
176
 * return 0 if option handled, -1 otherwise
177
 */
178
void os_parse_cmd_args(int index, const char *optarg)
179
{
180
    switch (index) {
181
#ifdef CONFIG_SLIRP
182
    case QEMU_OPTION_smb:
183
        if (net_slirp_smb(optarg) < 0)
184
            exit(1);
185
        break;
186
#endif
187
    case QEMU_OPTION_runas:
188
        user_pwd = getpwnam(optarg);
189
        if (!user_pwd) {
190
            fprintf(stderr, "User \"%s\" doesn't exist\n", optarg);
191
            exit(1);
192
        }
193
        break;
194
    case QEMU_OPTION_chroot:
195
        chroot_dir = optarg;
196
        break;
197
    case QEMU_OPTION_daemonize:
198
        daemonize = 1;
199
        break;
200
    }
201
    return;
202
}
203

    
204
static void change_process_uid(void)
205
{
206
    if (user_pwd) {
207
        if (setgid(user_pwd->pw_gid) < 0) {
208
            fprintf(stderr, "Failed to setgid(%d)\n", user_pwd->pw_gid);
209
            exit(1);
210
        }
211
        if (setuid(user_pwd->pw_uid) < 0) {
212
            fprintf(stderr, "Failed to setuid(%d)\n", user_pwd->pw_uid);
213
            exit(1);
214
        }
215
        if (setuid(0) != -1) {
216
            fprintf(stderr, "Dropping privileges failed\n");
217
            exit(1);
218
        }
219
    }
220
}
221

    
222
static void change_root(void)
223
{
224
    if (chroot_dir) {
225
        if (chroot(chroot_dir) < 0) {
226
            fprintf(stderr, "chroot failed\n");
227
            exit(1);
228
        }
229
        if (chdir("/")) {
230
            perror("not able to chdir to /");
231
            exit(1);
232
        }
233
    }
234

    
235
}
236

    
237
void os_daemonize(void)
238
{
239
    if (daemonize) {
240
        pid_t pid;
241

    
242
        if (pipe(fds) == -1)
243
            exit(1);
244

    
245
        pid = fork();
246
        if (pid > 0) {
247
            uint8_t status;
248
            ssize_t len;
249

    
250
            close(fds[1]);
251

    
252
        again:
253
            len = read(fds[0], &status, 1);
254
            if (len == -1 && (errno == EINTR))
255
                goto again;
256

    
257
            if (len != 1)
258
                exit(1);
259
            else if (status == 1) {
260
                fprintf(stderr, "Could not acquire pidfile: %s\n", strerror(errno));
261
                exit(1);
262
            } else
263
                exit(0);
264
        } else if (pid < 0)
265
            exit(1);
266

    
267
        close(fds[0]);
268
        qemu_set_cloexec(fds[1]);
269

    
270
        setsid();
271

    
272
        pid = fork();
273
        if (pid > 0)
274
            exit(0);
275
        else if (pid < 0)
276
            exit(1);
277

    
278
        umask(027);
279

    
280
        signal(SIGTSTP, SIG_IGN);
281
        signal(SIGTTOU, SIG_IGN);
282
        signal(SIGTTIN, SIG_IGN);
283
    }
284
}
285

    
286
void os_setup_post(void)
287
{
288
    int fd = 0;
289

    
290
    if (daemonize) {
291
        uint8_t status = 0;
292
        ssize_t len;
293

    
294
    again1:
295
        len = write(fds[1], &status, 1);
296
        if (len == -1 && (errno == EINTR))
297
            goto again1;
298

    
299
        if (len != 1)
300
            exit(1);
301

    
302
        if (chdir("/")) {
303
            perror("not able to chdir to /");
304
            exit(1);
305
        }
306
        TFR(fd = qemu_open("/dev/null", O_RDWR));
307
        if (fd == -1)
308
            exit(1);
309
    }
310

    
311
    change_root();
312
    change_process_uid();
313

    
314
    if (daemonize) {
315
        dup2(fd, 0);
316
        dup2(fd, 1);
317
        dup2(fd, 2);
318

    
319
        close(fd);
320
    }
321
}
322

    
323
void os_pidfile_error(void)
324
{
325
    if (daemonize) {
326
        uint8_t status = 1;
327
        if (write(fds[1], &status, 1) != 1) {
328
            perror("daemonize. Writing to pipe\n");
329
        }
330
    } else
331
        fprintf(stderr, "Could not acquire pid file: %s\n", strerror(errno));
332
}
333

    
334
void os_set_line_buffering(void)
335
{
336
    setvbuf(stdout, NULL, _IOLBF, 0);
337
}
338

    
339
/*
340
 * Creates an eventfd that looks like a pipe and has EFD_CLOEXEC set.
341
 */
342
int qemu_eventfd(int fds[2])
343
{
344
#ifdef CONFIG_EVENTFD
345
    int ret;
346

    
347
    ret = eventfd(0, 0);
348
    if (ret >= 0) {
349
        fds[0] = ret;
350
        qemu_set_cloexec(ret);
351
        if ((fds[1] = dup(ret)) == -1) {
352
            close(ret);
353
            return -1;
354
        }
355
        qemu_set_cloexec(fds[1]);
356
        return 0;
357
    }
358

    
359
    if (errno != ENOSYS) {
360
        return -1;
361
    }
362
#endif
363

    
364
    return qemu_pipe(fds);
365
}
366

    
367
int qemu_create_pidfile(const char *filename)
368
{
369
    char buffer[128];
370
    int len;
371
    int fd;
372

    
373
    fd = qemu_open(filename, O_RDWR | O_CREAT, 0600);
374
    if (fd == -1) {
375
        return -1;
376
    }
377
    if (lockf(fd, F_TLOCK, 0) == -1) {
378
        return -1;
379
    }
380
    len = snprintf(buffer, sizeof(buffer), "%ld\n", (long)getpid());
381
    if (write(fd, buffer, len) != len) {
382
        return -1;
383
    }
384

    
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
}