diff --git a/kirill/rgz/daemon.c b/kirill/rgz/daemon.c index b43a735..a922df3 100644 --- a/kirill/rgz/daemon.c +++ b/kirill/rgz/daemon.c @@ -3,7 +3,10 @@ // В КАЖДОЙ СТРОКЕ заменяет пробелом каждый 3-й байт, который НЕ '\n'. // '\n' сохраняется и сбрасывает счётчик позиции внутри строки. // Пишет результат в FIFO_RESPONSE и дописывает "\nREPLACEMENTS:\n". -// Логирует ошибки в syslog, игнорирует SIGPIPE (чтобы write() не убивал процесс). [web:21][web:28] +// Реально использует argv[1] как max_replacements (лимит замен): после достижения лимита +// перестаёт делать замены, но продолжает копировать вход как есть. +// Если лимит превышен (т.е. были потенциальные замены дальше), логирует это в syslog. +// Логирует ошибки в syslog, игнорирует SIGPIPE (write() вернёт EPIPE вместо завершения). #include // fprintf, snprintf #include // malloc, free, strtoll @@ -28,7 +31,7 @@ static void signal_handler(int sig) { } // разбор неотрицательного long long -static long long parse_ll(const char *s) { +static long long parse_ll_nonneg(const char *s) { char *end = NULL; errno = 0; long long v = strtoll(s, &end, 10); @@ -36,13 +39,31 @@ static long long parse_ll(const char *s) { return v; } -// В каждой строке: заменить каждый 3-й НЕ '\n' байт на пробел. -// Возвращает количество замен. -static long long process_data(const char *input, size_t input_len, - char *output, size_t output_size) { - if (!input || !output || input_len == 0 || output_size == 0) { - return 0; +// Надёжная запись "всё или ошибка" +static int write_all(int fd, const void *buf, size_t len) { + const char *p = (const char *) buf; + size_t left = len; + while (left > 0) { + ssize_t n = write(fd, p, left); + if (n < 0) { + if (errno == EINTR) continue; + return -1; + } + if (n == 0) return -1; + p += (size_t) n; + left -= (size_t) n; } + return 0; +} + +// В каждой строке: заменить каждый 3-й НЕ '\n' байт на пробел до max_replacements. +// Возвращает фактическое количество замен; устанавливает *would_exceed=1 если лимит был бы превышен. +static long long process_data_limited(const char *input, size_t input_len, + char *output, size_t output_size, + long long max_replacements, + int *would_exceed) { + if (would_exceed) *would_exceed = 0; + if (!input || !output || input_len == 0 || output_size == 0) return 0; long long replacements = 0; size_t out_pos = 0; @@ -60,8 +81,13 @@ static long long process_data(const char *input, size_t input_len, pos_in_line++; if (pos_in_line % 3 == 0) { - output[out_pos++] = ' '; - replacements++; + if (replacements < max_replacements) { + output[out_pos++] = ' '; + replacements++; + } else { + if (would_exceed) *would_exceed = 1; + output[out_pos++] = (char) c; // лимит достигнут: больше не заменяем + } } else { output[out_pos++] = (char) c; } @@ -72,40 +98,40 @@ static long long process_data(const char *input, size_t input_len, } int main(int argc, char *argv[]) { - // Аргумент оставлен для совместимости с вашим запуском, но больше не влияет на обработку. if (argc != 2) { - fprintf(stderr, "Usage: %s \n", argv[0]); + fprintf(stderr, "Usage: %s \n", argv[0]); return 1; } - long long ignored = parse_ll(argv[1]); - if (ignored < 0) { + long long max_replacements = parse_ll_nonneg(argv[1]); + if (max_replacements < 0) { fprintf(stderr, "ERROR: Invalid argument (must be non-negative integer)\n"); return 1; } - openlog("fifo_server_daemon", LOG_PID | LOG_NDELAY, LOG_DAEMON); - syslog(LOG_INFO, "Server started (systemd), arg(ignored)=%lld", ignored); // syslog via openlog/syslog [web:28] + openlog("fifo_server_daemon", LOG_PID | LOG_NDELAY, LOG_DAEMON); // openlog/syslog/closelog + syslog(LOG_INFO, "Server started (systemd), max_replacements=%lld", max_replacements); struct sigaction sa; memset(&sa, 0, sizeof(sa)); sa.sa_handler = signal_handler; sigemptyset(&sa.sa_mask); - sigaction(SIGINT, &sa, NULL); - sigaction(SIGTERM, &sa, NULL); - signal(SIGPIPE, SIG_IGN); // игнор SIGPIPE, обработка ошибок через write() [web:21] + (void) sigaction(SIGINT, &sa, NULL); + (void) sigaction(SIGTERM, &sa, NULL); + + signal(SIGPIPE, SIG_IGN); // ignore SIGPIPE => write() fails with EPIPE unlink(FIFO_REQUEST); unlink(FIFO_RESPONSE); if (mkfifo(FIFO_REQUEST, 0666) == -1) { - syslog(LOG_ERR, "mkfifo request failed: %s", strerror(errno)); // mkfifo creates FIFO special file [web:37] + syslog(LOG_ERR, "mkfifo request failed: %s", strerror(errno)); closelog(); return 1; } if (mkfifo(FIFO_RESPONSE, 0666) == -1) { - syslog(LOG_ERR, "mkfifo response failed: %s", strerror(errno)); // mkfifo creates FIFO special file [web:37] + syslog(LOG_ERR, "mkfifo response failed: %s", strerror(errno)); unlink(FIFO_REQUEST); closelog(); return 1; @@ -115,7 +141,6 @@ int main(int argc, char *argv[]) { while (running) { int fd_req = open(FIFO_REQUEST, O_RDONLY); - // open FIFO for reading can block until writer connects [web:26][web:35] if (!running) { if (fd_req != -1) close(fd_req); break; @@ -145,21 +170,35 @@ int main(int argc, char *argv[]) { break; } - if (bytes_read <= 0) { + if (bytes_read < 0) { + if (errno != EINTR) syslog(LOG_ERR, "read request FIFO failed: %s", strerror(errno)); + free(input_buffer); + free(output_buffer); + continue; + } + + if (bytes_read == 0) { + // EOF (writer closed) free(input_buffer); free(output_buffer); - if (!running) break; continue; } input_buffer[bytes_read] = '\0'; syslog(LOG_INFO, "Request received: %zd bytes", bytes_read); - long long replacements = - process_data(input_buffer, (size_t) bytes_read, output_buffer, BUFFER_SIZE); + int would_exceed = 0; + long long replacements = process_data_limited( + input_buffer, (size_t) bytes_read, output_buffer, BUFFER_SIZE, max_replacements, &would_exceed + ); + + if (would_exceed) { + syslog(LOG_WARNING, + "Replacement limit reached: max=%lld, actual=%lld (further replacements suppressed)", + max_replacements, replacements); + } int fd_resp = open(FIFO_RESPONSE, O_WRONLY); - // open FIFO for writing can block until reader connects [web:26][web:35] if (fd_resp == -1) { syslog(LOG_ERR, "open response FIFO failed: %s", strerror(errno)); free(input_buffer); @@ -169,18 +208,30 @@ int main(int argc, char *argv[]) { } size_t output_len = strlen(output_buffer); - ssize_t bytes_written = write(fd_resp, output_buffer, output_len); + if (write_all(fd_resp, output_buffer, output_len) < 0) { + syslog(LOG_ERR, "write response body failed: %s", strerror(errno)); // EPIPE possible + close(fd_resp); + free(input_buffer); + free(output_buffer); + continue; + } - char trailer[64]; - snprintf(trailer, sizeof(trailer), "\nREPLACEMENTS:%lld\n", replacements); - if (write(fd_resp, trailer, strlen(trailer)) < 0) { - syslog(LOG_WARNING, "write replacements trailer failed: %s", strerror(errno)); + char trailer[128]; + if (would_exceed) { + snprintf(trailer, sizeof(trailer), "\nREPLACEMENTS:%lld\nLIMIT_EXCEEDED:%lld\n", + replacements, max_replacements); + } else { + snprintf(trailer, sizeof(trailer), "\nREPLACEMENTS:%lld\n", replacements); + } + + if (write_all(fd_resp, trailer, strlen(trailer)) < 0) { + syslog(LOG_WARNING, "write trailer failed: %s", strerror(errno)); // EPIPE possible } close(fd_resp); - syslog(LOG_INFO, "Response sent: %zd bytes; replacements=%lld", - bytes_written, replacements); + syslog(LOG_INFO, "Response sent: body=%zu bytes; replacements=%lld; limit=%lld", + output_len, replacements, max_replacements); free(input_buffer); free(output_buffer);