#include <errno.h>
|
#include <fcntl.h>
|
#include <signal.h>
|
#include <spawn.h>
|
#include <stdarg.h>
|
#include <stdio.h>
|
#include <stdlib.h>
|
#include <string.h>
|
#include <sys/wait.h>
|
#include <time.h>
|
#include <unistd.h>
|
|
extern char **environ;
|
|
static const char *PYTHON = "/usr/bin/python3";
|
static const char *WATCHER = "/Users/ar/bin/daily_activity_watch.py";
|
static const char *APP_LOG = "/Users/ar/.daily-activity-watch.app.log";
|
static const char *CHILD_STDOUT = "/Users/ar/.daily-activity-watch.child.log";
|
static const char *CHILD_STDERR = "/Users/ar/.daily-activity-watch.err.log";
|
|
static volatile sig_atomic_t should_stop = 0;
|
static volatile sig_atomic_t child_pid = 0;
|
|
static void app_log(const char *fmt, ...) {
|
FILE *fh = fopen(APP_LOG, "a");
|
if (!fh) {
|
return;
|
}
|
|
time_t now = time(NULL);
|
struct tm local_tm;
|
localtime_r(&now, &local_tm);
|
|
char ts[32];
|
strftime(ts, sizeof(ts), "%Y-%m-%d %H:%M:%S", &local_tm);
|
fprintf(fh, "[%s] ", ts);
|
|
va_list args;
|
va_start(args, fmt);
|
vfprintf(fh, fmt, args);
|
va_end(args);
|
|
fputc('\n', fh);
|
fclose(fh);
|
}
|
|
static void handle_signal(int signo) {
|
should_stop = 1;
|
if (child_pid > 0) {
|
kill(child_pid, signo);
|
}
|
}
|
|
static int spawn_watcher(pid_t *pid) {
|
posix_spawn_file_actions_t actions;
|
posix_spawn_file_actions_init(&actions);
|
posix_spawn_file_actions_addopen(&actions, STDOUT_FILENO, CHILD_STDOUT,
|
O_CREAT | O_APPEND | O_WRONLY, 0644);
|
posix_spawn_file_actions_addopen(&actions, STDERR_FILENO, CHILD_STDERR,
|
O_CREAT | O_APPEND | O_WRONLY, 0644);
|
|
char *argv[] = {(char *)PYTHON, (char *)WATCHER, NULL};
|
int rc = posix_spawn(pid, PYTHON, &actions, NULL, argv, environ);
|
posix_spawn_file_actions_destroy(&actions);
|
return rc;
|
}
|
|
int main(void) {
|
signal(SIGTERM, handle_signal);
|
signal(SIGINT, handle_signal);
|
signal(SIGHUP, handle_signal);
|
|
app_log("DailyActivityWatch app started");
|
|
while (!should_stop) {
|
pid_t pid = 0;
|
int rc = spawn_watcher(&pid);
|
if (rc != 0) {
|
app_log("failed to start watcher: %s", strerror(rc));
|
sleep(5);
|
continue;
|
}
|
|
child_pid = pid;
|
app_log("started watcher pid=%d", pid);
|
|
int status = 0;
|
while (waitpid(pid, &status, 0) < 0) {
|
if (errno == EINTR && should_stop) {
|
break;
|
}
|
if (errno != EINTR) {
|
app_log("waitpid failed: %s", strerror(errno));
|
break;
|
}
|
}
|
|
child_pid = 0;
|
if (should_stop) {
|
break;
|
}
|
|
app_log("watcher exited status=%d; restarting in 5s", status);
|
sleep(5);
|
}
|
|
app_log("DailyActivityWatch app stopped");
|
return 0;
|
}
|