Update.
This commit is contained in:
parent
d7d699059f
commit
304f469a27
146
main.c
146
main.c
@ -25,6 +25,7 @@
|
||||
#define APP_LOG_FILE "rproc.log"
|
||||
#define PID_LOCK_FILE "/tmp/rproc.pid"
|
||||
#define MAX_LOG_LINE_LEN 4096
|
||||
#define TAIL_LINE_COUNT 300
|
||||
|
||||
typedef struct Process {
|
||||
pid_t pid;
|
||||
@ -128,6 +129,11 @@ static void terminate_process(pid_t pid, const char* script_name) {
|
||||
if (kill(pid, SIGTERM) == -1) {
|
||||
if (errno == ESRCH) {
|
||||
app_log("Process %d for '%s' did not exist. Removing from tracking.", pid, script_name);
|
||||
char pid_filename[FILENAME_MAX];
|
||||
snprintf(pid_filename, sizeof(pid_filename), "%s.pid", script_name);
|
||||
if (access(pid_filename, F_OK) == 0) {
|
||||
unlink(pid_filename);
|
||||
}
|
||||
remove_process_by_pid(pid);
|
||||
}
|
||||
return;
|
||||
@ -138,6 +144,11 @@ static void terminate_process(pid_t pid, const char* script_name) {
|
||||
const pid_t result = waitpid(pid, &status, WNOHANG);
|
||||
if (result == pid) {
|
||||
app_log("Process %d for '%s' terminated gracefully.", pid, script_name);
|
||||
char pid_filename[FILENAME_MAX];
|
||||
snprintf(pid_filename, sizeof(pid_filename), "%s.pid", script_name);
|
||||
if (access(pid_filename, F_OK) == 0) {
|
||||
unlink(pid_filename);
|
||||
}
|
||||
remove_process_by_pid(pid);
|
||||
return;
|
||||
}
|
||||
@ -153,6 +164,11 @@ static void terminate_process(pid_t pid, const char* script_name) {
|
||||
app_log("Process %d for '%s' disappeared before SIGKILL.", pid, script_name);
|
||||
}
|
||||
waitpid(pid, NULL, 0);
|
||||
char pid_filename[FILENAME_MAX];
|
||||
snprintf(pid_filename, sizeof(pid_filename), "%s.pid", script_name);
|
||||
if (access(pid_filename, F_OK) == 0) {
|
||||
unlink(pid_filename);
|
||||
}
|
||||
remove_process_by_pid(pid);
|
||||
}
|
||||
|
||||
@ -215,6 +231,16 @@ static void start_script(const char* script_name) {
|
||||
exit(127);
|
||||
}
|
||||
|
||||
char pid_filename[FILENAME_MAX];
|
||||
snprintf(pid_filename, sizeof(pid_filename), "%s.pid", script_name);
|
||||
FILE* pid_fp = fopen(pid_filename, "w");
|
||||
if (pid_fp) {
|
||||
fprintf(pid_fp, "%d", pid);
|
||||
fclose(pid_fp);
|
||||
} else {
|
||||
app_log("Warning: could not create pid file for %s", script_name);
|
||||
}
|
||||
|
||||
add_process(pid, script_name);
|
||||
app_log("Started '%s' with PID %d", script_name, pid);
|
||||
}
|
||||
@ -235,16 +261,28 @@ static void handle_sigchld(int sig) {
|
||||
while ((pid = waitpid(-1, &status, WNOHANG)) > 0) {
|
||||
Process* p = find_process_by_pid(pid);
|
||||
if (p) {
|
||||
char pid_filename[FILENAME_MAX];
|
||||
snprintf(pid_filename, sizeof(pid_filename), "%s.pid", p->script_name);
|
||||
|
||||
if (WIFEXITED(status) && WEXITSTATUS(status) != 0) {
|
||||
app_log("Script '%s' (PID: %d) crashed with status %d.", p->script_name, pid, WEXITSTATUS(status));
|
||||
if (access(pid_filename, F_OK) == 0) {
|
||||
unlink(pid_filename);
|
||||
}
|
||||
p->crashed_at = time(NULL);
|
||||
p->pid = -1;
|
||||
} else if (WIFSIGNALED(status)) {
|
||||
app_log("Script '%s' (PID: %d) terminated by signal %d.", p->script_name, pid, WTERMSIG(status));
|
||||
if (access(pid_filename, F_OK) == 0) {
|
||||
unlink(pid_filename);
|
||||
}
|
||||
p->crashed_at = time(NULL);
|
||||
p->pid = -1;
|
||||
} else {
|
||||
app_log("Script '%s' (PID: %d) exited cleanly.", p->script_name, pid);
|
||||
if (access(pid_filename, F_OK) == 0) {
|
||||
unlink(pid_filename);
|
||||
}
|
||||
remove_process_by_pid(pid);
|
||||
}
|
||||
}
|
||||
@ -278,7 +316,43 @@ static void setup_signal_handlers(void) {
|
||||
}
|
||||
}
|
||||
|
||||
static void adopt_existing_processes(void) {
|
||||
DIR* d = opendir(".");
|
||||
if (!d) return;
|
||||
|
||||
struct dirent* dir;
|
||||
while ((dir = readdir(d)) != NULL) {
|
||||
size_t len = strlen(dir->d_name);
|
||||
if (len > 4 && strcmp(dir->d_name + len - 4, ".pid") == 0) {
|
||||
FILE* fp = fopen(dir->d_name, "r");
|
||||
if (!fp) continue;
|
||||
|
||||
pid_t pid = 0;
|
||||
if (fscanf(fp, "%d", &pid) == 1 && pid > 0) {
|
||||
fclose(fp);
|
||||
if (kill(pid, 0) == 0 || errno == EPERM) {
|
||||
char script_name[FILENAME_MAX];
|
||||
strncpy(script_name, dir->d_name, len - 4);
|
||||
script_name[len - 4] = '\0';
|
||||
app_log("Adopting existing process '%s' with PID %d", script_name, pid);
|
||||
add_process(pid, script_name);
|
||||
} else {
|
||||
app_log("Found stale pid file '%s'. Removing.", dir->d_name);
|
||||
if (access(dir->d_name, F_OK) == 0) {
|
||||
unlink(dir->d_name);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
fclose(fp);
|
||||
}
|
||||
}
|
||||
}
|
||||
closedir(d);
|
||||
}
|
||||
|
||||
static void run_daemon(void) {
|
||||
adopt_existing_processes();
|
||||
|
||||
DIR* d = opendir(".");
|
||||
if (d) {
|
||||
struct dirent* dir;
|
||||
@ -363,9 +437,57 @@ static void run_daemon(void) {
|
||||
typedef struct LogFile {
|
||||
char* name;
|
||||
off_t offset;
|
||||
int color_index;
|
||||
struct LogFile* next;
|
||||
} LogFile;
|
||||
|
||||
static off_t get_tail_offset(const char* filename, int line_count) {
|
||||
FILE* fp = fopen(filename, "rb");
|
||||
if (!fp) return 0;
|
||||
|
||||
char buf[4096];
|
||||
off_t file_size;
|
||||
long pos;
|
||||
int newlines = 0;
|
||||
|
||||
if (fseek(fp, 0, SEEK_END) != 0) {
|
||||
fclose(fp);
|
||||
return 0;
|
||||
}
|
||||
file_size = ftell(fp);
|
||||
if (file_size <= 0) {
|
||||
fclose(fp);
|
||||
return 0;
|
||||
}
|
||||
pos = file_size;
|
||||
|
||||
while (pos > 0) {
|
||||
long seek_to = pos - sizeof(buf);
|
||||
if (seek_to < 0) seek_to = 0;
|
||||
|
||||
if (fseek(fp, seek_to, SEEK_SET) != 0) break;
|
||||
|
||||
size_t bytes_read = fread(buf, 1, pos - seek_to, fp);
|
||||
if (bytes_read == 0) break;
|
||||
|
||||
for (long i = bytes_read - 1; i >= 0; --i) {
|
||||
if (buf[i] == '\n' && (seek_to + i) != (file_size - 1)) {
|
||||
newlines++;
|
||||
if (newlines >= line_count) {
|
||||
pos = seek_to + i + 1;
|
||||
fclose(fp);
|
||||
return pos;
|
||||
}
|
||||
}
|
||||
}
|
||||
pos = seek_to;
|
||||
}
|
||||
|
||||
fclose(fp);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static void run_monitor(void) {
|
||||
char cwd[PATH_MAX] = {0};
|
||||
char line_buffer[PATH_MAX];
|
||||
@ -386,7 +508,7 @@ static void run_monitor(void) {
|
||||
}
|
||||
|
||||
printf("Another instance is running in %s. Attaching as a live monitor...\n", cwd);
|
||||
printf("--- Tailing all *.log files. Press Ctrl+C to exit. ---\n");
|
||||
printf("--- Tailing last %d lines from all *.log files. Press Ctrl+C to exit. ---\n", TAIL_LINE_COUNT);
|
||||
|
||||
LogFile* log_list = NULL;
|
||||
int fd = inotify_init();
|
||||
@ -394,6 +516,19 @@ static void run_monitor(void) {
|
||||
|
||||
inotify_add_watch(fd, ".", IN_CREATE | IN_MODIFY);
|
||||
|
||||
static const char* colors[] = {
|
||||
"\033[0;32m", /* Green */
|
||||
"\033[0;33m", /* Yellow */
|
||||
"\033[0;34m", /* Blue */
|
||||
"\033[0;36m", /* Cyan */
|
||||
"\033[0;35m", /* Magenta */
|
||||
"\033[0;31m", /* Red */
|
||||
};
|
||||
static const int num_colors = sizeof(colors) / sizeof(colors[0]);
|
||||
static const char* color_reset = "\033[0m";
|
||||
static int next_color_index = 0;
|
||||
|
||||
|
||||
while(1) {
|
||||
DIR* d = opendir(".");
|
||||
if (d) {
|
||||
@ -411,7 +546,9 @@ static void run_monitor(void) {
|
||||
if (!found) {
|
||||
LogFile* new_log = malloc(sizeof(LogFile));
|
||||
new_log->name = strdup(dir->d_name);
|
||||
new_log->offset = 0;
|
||||
new_log->offset = get_tail_offset(dir->d_name, TAIL_LINE_COUNT);
|
||||
new_log->color_index = next_color_index;
|
||||
next_color_index = (next_color_index + 1) % num_colors;
|
||||
new_log->next = log_list;
|
||||
log_list = new_log;
|
||||
}
|
||||
@ -426,7 +563,8 @@ static void run_monitor(void) {
|
||||
fseek(fp, l->offset, SEEK_SET);
|
||||
char line[MAX_LOG_LINE_LEN];
|
||||
while (fgets(line, sizeof(line), fp)) {
|
||||
printf("[%s] %s", l->name, line);
|
||||
line[strcspn(line, "\r\n")] = 0;
|
||||
printf("%s[%s] %s%s\n", colors[l->color_index], l->name, line, color_reset);
|
||||
}
|
||||
l->offset = ftell(fp);
|
||||
fclose(fp);
|
||||
@ -488,8 +626,10 @@ int main(void) {
|
||||
cleanup_lock:
|
||||
flock(pid_fd, LOCK_UN);
|
||||
close(pid_fd);
|
||||
if (access(PID_LOCK_FILE, F_OK) == 0) {
|
||||
unlink(PID_LOCK_FILE);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user