/** Signal handler callback for writing signals to pipe * * @param sig the signal number to pass to mainloop via pipe */ static void mce_tx_signal_cb(int sig) { /* NOTE: this function must be kept async-signal-safe! */ static volatile int exit_tries = 0; static const char msg[] = "\n*** BREAK ***\n"; static const char die[] = "\n*** UNRECOVERABLE FAILURE ***\n"; switch( sig ) { case SIGUSR1: case SIGUSR2: case SIGHUP: /* Just pass to mainloop */ break; case SIGINT: case SIGQUIT: case SIGTERM: /* Make sure that a stuck or non-existing mainloop does * not stop us from handling at least repeated terminating signals ... */ #ifdef ENABLE_WAKELOCKS /* We are on exit path -> block suspend for good */ wakelock_block_suspend_until_exit(); #endif no_error_check_write(STDERR_FILENO, msg, sizeof msg - 1); if( !mainloop || ++exit_tries >= 2 ) { mce_abort(); } break; default: /* Assume unrecoverable failure that can't be handled in * the mainloop - disable autosuspend and then terminate * via default signal handler. */ no_error_check_write(STDERR_FILENO, die, sizeof die - 1); mce_exit_via_signal(sig); break; } /* transfer the signal to mainloop via pipe */ int did = TEMP_FAILURE_RETRY(write(signal_pipe[1], &sig, sizeof sig)); if( did != (int)sizeof sig ) { mce_abort(); } }
/** * Daemonize the program * * @return TRUE if MCE is started during boot, FALSE otherwise */ static gboolean daemonize(void) { gint retries = 0; gint i = 0; gchar str[10]; if (getppid() == 1) goto EXIT; /* Already daemonized */ /* Detach from process group */ switch (fork()) { case -1: /* Parent - Failure */ mce_log(LL_CRIT, "daemonize: fork failed: %s", g_strerror(errno)); exit(EXIT_FAILURE); case 0: /* Child */ break; default: /* Parent -- Success */ /* One main() one exit() - in this case the parent * must not call atexit handlers etc */ _exit(EXIT_SUCCESS); } /* Detach TTY */ setsid(); /* Close all file descriptors and redirect stdio to /dev/null */ if ((i = getdtablesize()) == -1) i = 256; while (--i >= 0) { if (close(i) == -1) { if (retries > 10) { mce_log(LL_CRIT, "close() was interrupted more than " "10 times. Exiting."); exit(EXIT_FAILURE); } if (errno == EINTR) { mce_log(LL_INFO, "close() was interrupted; retrying."); errno = 0; i++; retries++; } else if (errno == EBADF) { /* Ignore invalid file descriptors */ errno = 0; } else { mce_log(LL_CRIT, "Failed to close() fd %d; %s. " "Exiting.", i + 1, g_strerror(errno)); exit(EXIT_FAILURE); } } else { retries = 0; } } if ((i = open("/dev/null", O_RDWR)) == -1) { mce_log(LL_CRIT, "Cannot open `/dev/null'; %s. Exiting.", g_strerror(errno)); exit(EXIT_FAILURE); } if ((dup(i) == -1)) { mce_log(LL_CRIT, "Failed to dup() `/dev/null'; %s. Exiting.", g_strerror(errno)); exit(EXIT_FAILURE); } if ((dup(i) == -1)) { mce_log(LL_CRIT, "Failed to dup() `/dev/null'; %s. Exiting.", g_strerror(errno)); exit(EXIT_FAILURE); } /* Set umask */ umask(022); /* Set working directory */ if ((chdir("/tmp") == -1)) { mce_log(LL_CRIT, "Failed to chdir() to `/tmp'; %s. Exiting.", g_strerror(errno)); exit(EXIT_FAILURE); } /* Single instance */ if ((i = open(MCE_LOCKFILE, O_RDWR | O_CREAT, 0640)) == -1) { mce_log(LL_CRIT, "Cannot open lockfile; %s. Exiting.", g_strerror(errno)); exit(EXIT_FAILURE); } if (lockf(i, F_TLOCK, 0) == -1) { mce_log(LL_CRIT, "Already running. Exiting."); exit(EXIT_FAILURE); } sprintf(str, "%d\n", getpid()); no_error_check_write(i, str, strlen(str)); close(i); /* Ignore TTY signals */ signal(SIGTSTP, SIG_IGN); signal(SIGTTOU, SIG_IGN); signal(SIGTTIN, SIG_IGN); /* Ignore child terminate signal */ signal(SIGCHLD, SIG_IGN); EXIT: return 0; }
/** Signal handler callback for writing signals to pipe * * @param sig the signal number to pass to mainloop via pipe */ static void mce_tx_signal_cb(int sig) { /* NOTE: this function must be kept async-signal-safe! */ static volatile int exit_tries = 0; static const char msg[] = "\n*** BREAK ***\n"; #ifdef ENABLE_WAKELOCKS static const char die[] = "\n*** UNRECOVERABLE FAILURE ***\n"; #endif /* FIXME: Should really use sigaction() to avoid having * the default handler active until we manage to restore * our handler here ... */ signal(sig, mce_tx_signal_cb); switch( sig ) { case SIGINT: case SIGQUIT: case SIGTERM: /* Make sure that a stuck or non-existing mainloop does * not stop us from handling at least repeated terminating signals ... */ #ifdef ENABLE_WAKELOCKS /* We are on exit path -> block suspend for good */ wakelock_block_suspend_until_exit(); #endif no_error_check_write(STDERR_FILENO, msg, sizeof msg - 1); if( !mainloop || ++exit_tries >= 2 ) { mce_abort(); } break; #ifdef ENABLE_WAKELOCKS case SIGABRT: case SIGILL: case SIGFPE: case SIGSEGV: case SIGALRM: case SIGBUS: /* Unrecoverable failures can't be handled in the mainloop * Terminate but disable suspend first */ no_error_check_write(STDERR_FILENO, die, sizeof die - 1); mce_exit_via_signal(sig); break; case SIGTSTP: /* Stopping mce could also lead to unrecoverable suspend */ break; #endif default: break; } /* transfer the signal to mainloop via pipe */ int did = TEMP_FAILURE_RETRY(write(signal_pipe[1], &sig, sizeof sig)); if( did != (int)sizeof sig ) { mce_abort(); } }