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, sizeof(mib)/sizeof(*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 } 332