#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"); struct flx_msg *read_msg = malloc(sizeof(struct flx_msg)); struct flx_msg *send_msg = malloc(sizeof(struct flx_msg)); struct flx_serialize_result result; flx_msg_init(read_msg); flx_msg_init(send_msg); flx_serialize_result_init(&result); uint8_t socket_buffer[FLX_PKT_MAXIMUM_SIZE]; while (true) { int bytes_read = recv(client_fd, socket_buffer, sizeof(socket_buffer), 0); if (bytes_read == 0 || bytes_read == -1) { perror("recv"); return -1; } flx_deserialize(socket_buffer, read_msg, &result); if (result.reply != FLX_REPLY_VALID) { printf("Received error %x from client\n", result.reply); send_msg->action = FLX_ACT_REPLY; send_msg->option = result.reply; send_msg = 0; flx_serialize(socket_buffer, send_msg, &result); write(client_fd, socket_buffer, result.size); continue; } if (read_msg->action != FLX_ACT_WATCH) { continue; } break; } char *path = strdup(read_msg->data[0]); 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(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]; if (event->mask & IN_CREATE) { send_msg->option = FLX_NOTIFY_CREATE; } if (event->mask & IN_DELETE) { send_msg->option = FLX_NOTIFY_DELETE; } if (event->mask & IN_ACCESS) { send_msg->option = FLX_NOTIFY_ACCESS; } if (event->mask & IN_CLOSE_WRITE) { send_msg->option = FLX_NOTIFY_CLOSE; } if (event->mask & IN_MODIFY) { send_msg->option = FLX_NOTIFY_MODIFY; } if (event->mask & IN_MOVE_SELF) { send_msg->option = FLX_NOTIFY_MOVE; } buffer_used += sizeof(struct inotify_event) + event->len; if (send_msg->option == FLX_UNSET_UNSET) { continue; } send_msg->action = FLX_ACT_NOTIFY; send_msg->data_len = FLX_DLEN_NOTIFY; send_msg->data = malloc(sizeof(char*) * FLX_DLEN_NOTIFY); send_msg->data[0] = base_path; send_msg->data[1] = path; flx_serialize(socket_buffer, send_msg, &result); } } daemon_deinit(&g_state); return 0; }