#include "swayaway.h" #include #include #include #include #include #include #include #include #include static bool debug_enabled = false; void log_init(bool debug) { debug_enabled = debug; } void sway_log(const char *fmt, ...) { time_t t = time(NULL); struct tm tm_buf; struct tm *tm_info = localtime_r(&t, &tm_buf); char ts[32]; if (tm_info) { strftime(ts, sizeof(ts), "%F %T", tm_info); } else { strcpy(ts, "??????????"); } va_list args; va_start(args, fmt); fprintf(stderr, "%s - ", ts); vfprintf(stderr, fmt, args); fprintf(stderr, "\n"); va_end(args); } void sway_log_debug(const char *fmt, ...) { if (!debug_enabled) { return; } time_t t = time(NULL); struct tm tm_buf; struct tm *tm_info = localtime_r(&t, &tm_buf); char ts[32]; if (tm_info) { strftime(ts, sizeof(ts), "%F %T", tm_info); } else { strcpy(ts, "??????????"); } va_list args; va_start(args, fmt); fprintf(stderr, "%s - [debug] ", ts); vfprintf(stderr, fmt, args); fprintf(stderr, "\n"); va_end(args); } /* prepare the current process to run a user command: unblock signals that * were blocked for signalfd, restore default dispositions, and drop every fd * inherited from the daemon so long-running commands don't hold sockets * open. */ static void child_prepare_exec(void) { sigset_t set; sigemptyset(&set); sigprocmask(SIG_SETMASK, &set, NULL); signal(SIGINT, SIG_DFL); signal(SIGTERM, SIG_DFL); signal(SIGUSR1, SIG_DFL); long max = sysconf(_SC_OPEN_MAX); if (max < 0 || max > 4096) { max = 4096; } for (long fd = 3; fd < max; fd++) { close((int)fd); } } /* run `cmd` through the shell ("sh -c") * with state.wait, double-fork and block until the command exits; otherwise * double-fork and return immediately, leaving the command running detached */ void cmd_exec(const char *cmd) { if (!cmd) { return; } sway_log_debug("exec: %s", cmd); pid_t pid = fork(); if (pid == 0) { if (!state.wait) { // intermediate child: fork the grandchild and exit pid = fork(); if (pid > 0) { _exit(0); } } if (pid == 0) { child_prepare_exec(); char *const argv[] = { "sh", "-c", (char *)cmd, NULL }; execvp(argv[0], argv); sway_log("exec failed: %s", strerror(errno)); _exit(1); } _exit(0); } else if (pid < 0) { sway_log("fork failed: %s", strerror(errno)); return; } if (state.wait) { int status; sway_log_debug("waiting for command to finish"); while (waitpid(pid, &status, 0) < 0) { if (errno != EINTR) { break; } } if (WIFEXITED(status)) { sway_log_debug("command exited: %d", WEXITSTATUS(status)); } } // non-wait: reap the intermediate child else { waitpid(pid, NULL, 0); } }