#include #include #include #include #include #include #include #include #include #include #include #include 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; }