189 lines
5.1 KiB
C
189 lines
5.1 KiB
C
#include <stdio.h>
|
|
#include <unistd.h>
|
|
#include <stdlib.h>
|
|
#include <stdbool.h>
|
|
#include <stdint.h>
|
|
#include <string.h>
|
|
#include <signal.h>
|
|
#include <sys/inotify.h>
|
|
#include <assert.h>
|
|
|
|
#include <netinet/in.h>
|
|
#include <sys/socket.h>
|
|
|
|
#include <libflex.h>
|
|
|
|
struct daemon_state {
|
|
bool running;
|
|
int inotify_fd;
|
|
int inotify_wd;
|
|
};
|
|
static struct daemon_state g_state = {
|
|
.running = true
|
|
};
|
|
|
|
void daemon_deinit(struct daemon_state *state) {
|
|
inotify_rm_watch(g_state.inotify_fd, g_state.inotify_wd);
|
|
}
|
|
|
|
void signal_handler(int signal) {
|
|
g_state.running = false;
|
|
printf("Stoping daemon\n");
|
|
daemon_deinit(&g_state);
|
|
exit(0);
|
|
}
|
|
|
|
#define PORT 12345
|
|
|
|
int main() {
|
|
int server_fd = socket(AF_INET, SOCK_STREAM, 0);
|
|
if (server_fd == -1) {
|
|
perror("socket");
|
|
return -1;
|
|
}
|
|
|
|
int on = 1;
|
|
setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
|
|
|
|
struct sockaddr_in server_addr;
|
|
server_addr.sin_family = AF_INET;
|
|
server_addr.sin_addr.s_addr = htonl(INADDR_ANY);
|
|
server_addr.sin_port = htons(PORT);
|
|
|
|
if (bind(server_fd, (struct sockaddr*)&server_addr, sizeof(server_addr)) == -1) {
|
|
perror("bind");
|
|
return -1;
|
|
}
|
|
|
|
if (listen(server_fd, 1) == -1) {
|
|
perror("listen");
|
|
return -1;
|
|
}
|
|
|
|
printf("listening on 0.0.0.0:%d...\n", PORT);
|
|
|
|
struct sockaddr_storage client_addr;
|
|
socklen_t client_addrlen;
|
|
int client_fd = accept(server_fd, (struct sockaddr*)&client_addr, &client_addrlen);
|
|
if (client_fd == -1) {
|
|
perror("accept");
|
|
return -1;
|
|
}
|
|
|
|
printf("Accepted connection!\n");
|
|
|
|
char *path = NULL;
|
|
|
|
struct flx_msg read_msg = { 0 };
|
|
uint8_t read_buffer[255] = { 0 };
|
|
size_t read_buffer_size = 0;
|
|
while (true) {
|
|
int msg_size = flx_read(read_buffer, sizeof(read_buffer), &read_buffer_size, client_fd, &read_msg);
|
|
if (msg_size == 0) {
|
|
break;
|
|
}
|
|
if (msg_size < 0) {
|
|
continue;
|
|
}
|
|
|
|
|
|
if (read_msg.action == FLX_ACT_WATCH && read_msg.option == FLX_WATCH_ADD) {
|
|
path = char_slice_dupe(read_msg.data[0]);
|
|
assert(path != NULL);
|
|
}
|
|
|
|
memmove(read_buffer, read_buffer + msg_size, sizeof(read_buffer) - msg_size);
|
|
read_buffer_size -= msg_size;
|
|
|
|
if (path != NULL) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
printf("Watching path: %s\n", path);
|
|
|
|
int inotify_fd = inotify_init();
|
|
if (inotify_fd == -1) {
|
|
perror("inotify_init");
|
|
return -1;
|
|
}
|
|
|
|
int inotify_wd = inotify_add_watch(inotify_fd, path, IN_CREATE | IN_DELETE | IN_ACCESS | IN_CLOSE_WRITE | IN_MODIFY | IN_MOVE_SELF);
|
|
if (inotify_fd == -1) {
|
|
perror("inotify_add_watch");
|
|
return -1;
|
|
}
|
|
|
|
char *base_path = strrchr(path, '/');
|
|
if (base_path == NULL) {
|
|
base_path = path;
|
|
} else {
|
|
base_path += 1;
|
|
}
|
|
|
|
signal(SIGPIPE, SIG_IGN);
|
|
signal(SIGABRT, signal_handler);
|
|
signal(SIGINT, signal_handler);
|
|
signal(SIGTERM, signal_handler);
|
|
|
|
uint8_t buffer[4096];
|
|
while (g_state.running) {
|
|
printf("Waiting for inotify event.\n");
|
|
|
|
int read_length = read(inotify_fd, buffer, sizeof(buffer));
|
|
if (read_length == -1) {
|
|
perror("read");
|
|
return -1;
|
|
}
|
|
|
|
int buffer_used = 0;
|
|
while (buffer_used < read_length) {
|
|
struct inotify_event *event = (struct inotify_event*)&buffer[buffer_used];
|
|
buffer_used += sizeof(struct inotify_event) + event->len;
|
|
|
|
struct flx_msg msg = { 0 };
|
|
|
|
if (event->mask & IN_CREATE) {
|
|
flx_msg_init_notify(&msg, FLX_NOTIFY_CREATE, base_path, path);
|
|
if (flx_write(client_fd, &msg) <= 0) {
|
|
g_state.running = false;
|
|
}
|
|
}
|
|
if (event->mask & IN_DELETE) {
|
|
flx_msg_init_notify(&msg, FLX_NOTIFY_DELETE, base_path, path);
|
|
if (flx_write(client_fd, &msg) <= 0) {
|
|
g_state.running = false;
|
|
}
|
|
}
|
|
if (event->mask & IN_ACCESS) {
|
|
flx_msg_init_notify(&msg, FLX_NOTIFY_ACCESS, base_path, path);
|
|
if (flx_write(client_fd, &msg) <= 0) {
|
|
g_state.running = false;
|
|
}
|
|
}
|
|
if (event->mask & IN_CLOSE_WRITE) {
|
|
flx_msg_init_notify(&msg, FLX_NOTIFY_CLOSE, base_path, path);
|
|
if (flx_write(client_fd, &msg) <= 0) {
|
|
g_state.running = false;
|
|
}
|
|
}
|
|
if (event->mask & IN_MODIFY) {
|
|
flx_msg_init_notify(&msg, FLX_NOTIFY_MODIFY, base_path, path);
|
|
if (flx_write(client_fd, &msg) <= 0) {
|
|
g_state.running = false;
|
|
}
|
|
}
|
|
if (event->mask & IN_MOVE_SELF) {
|
|
flx_msg_init_notify(&msg, FLX_NOTIFY_MOVE, base_path, path);
|
|
if (flx_write(client_fd, &msg) <= 0) {
|
|
g_state.running = false;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
daemon_deinit(&g_state);
|
|
|
|
return 0;
|
|
}
|