swayaway
a drop-in replacement for swayidle(1)
log.c
2791 bytes raw
1#include "swayaway.h"
2
3#include <errno.h>
4#include <signal.h>
5#include <stdarg.h>
6#include <stdio.h>
7#include <stdlib.h>
8#include <string.h>
9#include <sys/wait.h>
10#include <time.h>
11#include <unistd.h>
12
13static bool debug_enabled = false;
14
15void log_init(bool debug)
16{
17 debug_enabled = debug;
18}
19
20void sway_log(const char *fmt, ...)
21{
22 time_t t = time(NULL);
23 struct tm tm_buf;
24 struct tm *tm_info = localtime_r(&t, &tm_buf);
25 char ts[32];
26 if (tm_info) {
27 strftime(ts, sizeof(ts), "%F %T", tm_info);
28 } else {
29 strcpy(ts, "??????????");
30 }
31
32 va_list args;
33 va_start(args, fmt);
34 fprintf(stderr, "%s - ", ts);
35 vfprintf(stderr, fmt, args);
36 fprintf(stderr, "\n");
37 va_end(args);
38}
39
40void sway_log_debug(const char *fmt, ...)
41{
42 if (!debug_enabled) {
43 return;
44 }
45 time_t t = time(NULL);
46 struct tm tm_buf;
47 struct tm *tm_info = localtime_r(&t, &tm_buf);
48 char ts[32];
49 if (tm_info) {
50 strftime(ts, sizeof(ts), "%F %T", tm_info);
51 } else {
52 strcpy(ts, "??????????");
53 }
54 va_list args;
55 va_start(args, fmt);
56 fprintf(stderr, "%s - [debug] ", ts);
57 vfprintf(stderr, fmt, args);
58 fprintf(stderr, "\n");
59 va_end(args);
60}
61
62/* prepare the current process to run a user command: unblock signals that
63 * were blocked for signalfd, restore default dispositions, and drop every fd
64 * inherited from the daemon so long-running commands don't hold sockets
65 * open. */
66static void child_prepare_exec(void)
67{
68 sigset_t set;
69 sigemptyset(&set);
70 sigprocmask(SIG_SETMASK, &set, NULL);
71 signal(SIGINT, SIG_DFL);
72 signal(SIGTERM, SIG_DFL);
73 signal(SIGUSR1, SIG_DFL);
74
75 long max = sysconf(_SC_OPEN_MAX);
76 if (max < 0 || max > 4096) {
77 max = 4096;
78 }
79 for (long fd = 3; fd < max; fd++) {
80 close((int)fd);
81 }
82}
83
84/* run `cmd` through the shell ("sh -c")
85 * with state.wait, double-fork and block until the command exits; otherwise
86 * double-fork and return immediately, leaving the command running detached */
87void cmd_exec(const char *cmd)
88{
89 if (!cmd) {
90 return;
91 }
92 sway_log_debug("exec: %s", cmd);
93
94 pid_t pid = fork();
95 if (pid == 0) {
96 if (!state.wait) {
97 // intermediate child: fork the grandchild and exit
98 pid = fork();
99 if (pid > 0) {
100 _exit(0);
101 }
102 }
103 if (pid == 0) {
104 child_prepare_exec();
105 char *const argv[] = { "sh", "-c", (char *)cmd, NULL };
106 execvp(argv[0], argv);
107 sway_log("exec failed: %s", strerror(errno));
108 _exit(1);
109 }
110 _exit(0);
111 } else if (pid < 0) {
112 sway_log("fork failed: %s", strerror(errno));
113 return;
114 }
115
116 if (state.wait) {
117 int status;
118 sway_log_debug("waiting for command to finish");
119 while (waitpid(pid, &status, 0) < 0) {
120 if (errno != EINTR) {
121 break;
122 }
123 }
124 if (WIFEXITED(status)) {
125 sway_log_debug("command exited: %d", WEXITSTATUS(status));
126 }
127 }
128 // non-wait: reap the intermediate child
129 else {
130 waitpid(pid, NULL, 0);
131 }
132}