diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-09-17 03:51:28 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-09-17 03:51:28 +0000 |
commit | 2b07c041cb218eca6e548bac9c4347f8a90c474c (patch) | |
tree | 679142f3916fa927903c6f245896f5c0325a3254 /tools/src/qstail.c | |
parent | Initial commit. (diff) | |
download | libapache2-mod-qos-2b07c041cb218eca6e548bac9c4347f8a90c474c.tar.xz libapache2-mod-qos-2b07c041cb218eca6e548bac9c4347f8a90c474c.zip |
Adding upstream version 11.74.upstream/11.74upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'tools/src/qstail.c')
-rw-r--r-- | tools/src/qstail.c | 237 |
1 files changed, 237 insertions, 0 deletions
diff --git a/tools/src/qstail.c b/tools/src/qstail.c new file mode 100644 index 0000000..3d535e2 --- /dev/null +++ b/tools/src/qstail.c @@ -0,0 +1,237 @@ +/* -*-mode: c; indent-tabs-mode: nil; c-basic-offset: 2; -*- + */ +/** + * Utilities for the quality of service module mod_qos. + * + * qstail.c: Shows the end of a log file beginning at the + * provided pattern. + * + * See http://mod-qos.sourceforge.net/ for further + * details. + * + * Copyright (C) 2023 Pascal Buchbinder + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +static const char revision[] = "$Id: qstail.c 2654 2022-05-13 09:12:42Z pbuchbinder $"; + +#include <stdio.h> +#include <unistd.h> +#include <string.h> +#include <stdlib.h> +#include <signal.h> + +#include "qs_util.h" + +#define BUFFER 2048 + +static void usage(char *cmd, int man) { + if(man) { + //.TH [name of program] [section number] [center footer] [left footer] [center header] + printf(".TH %s 1 \"%s\" \"mod_qos utilities %s\" \"%s man page\"\n", qs_CMD(cmd), man_date, + man_version, cmd); + } + printf("\n"); + if(man) { + printf(".SH NAME\n"); + } + qs_man_print(man, "%s - an utility printing the end of a log file" + " starting at the specified pattern.\n", cmd); + printf("\n"); + if(man) { + printf(".SH SYNOPSIS\n"); + } + qs_man_print(man, "%s%s -i <path> -p <pattern>\n", man ? "" : "Usage: ", cmd); + printf("\n"); + if(man) { + printf(".SH DESCRIPTION\n"); + } else { + printf("Summary\n"); + } + qs_man_print(man, " %s shows the end of a log file beginning with the line containing the\n", cmd); + qs_man_print(man, " specified pattern. This may be used to show all lines which has been written\n"); + qs_man_print(man, " after a certain event (e.g., server restart) or time stamp.\n"); + printf("\n"); + if(man) { + printf(".SH OPTIONS\n"); + } else { + printf("Options\n"); + } + if(man) printf(".TP\n"); + qs_man_print(man, " -i <path>\n"); + if(man) printf("\n"); + qs_man_print(man, " Input file to read the data from.\n"); + if(man) printf("\n.TP\n"); + qs_man_print(man, " -p <pattern>\n"); + if(man) printf("\n"); + qs_man_print(man, " Search pattern (literal string).\n"); + printf("\n"); + if(man) { + printf(".SH SEE ALSO\n"); + printf("qsdt(1), qsexec(1), qsfilter2(1), qsgeo(1), qsgrep(1), qshead(1), qslog(1), qslogger(1), qspng(1), qsre(1), qsrespeed(1), qsrotate(1), qssign(1)\n"); + printf(".SH AUTHOR\n"); + printf("Pascal Buchbinder, http://mod-qos.sourceforge.net/\n"); + } else { + printf("See http://mod-qos.sourceforge.net/ for further details.\n"); + } + if(man) { + exit(0); + } else { + exit(1); + } +} + +/* search the beginning of the line starting at the provided position */ +static void qs_readline(long pos, FILE *f) { + size_t len; + long startpos = pos - BUFFER + 1; + long readlen = BUFFER; + char line[readlen + 1]; + if(startpos < 0) { + // we are at the beginning of the file + startpos = 0; + readlen = pos + 1; + } + fseek(f, startpos, SEEK_SET); + len = fread(&line, 1, readlen, f); + if(len > 0) { + char *s = &line[len-1]; + line[len] = '\0'; + while((s >= line) && (s[0] != CR) && (s[0] != LF)) { + s--; + } + if((s[0] == CR) || (s[0] == LF)) { + s++; + } + printf("%s", s); + } +} + +static int qs_tail(const char *cmd, FILE *f, const char *pattern) { + char *cont = NULL; + long search_win_len = (strlen(pattern) * 2) + 32; + char line[search_win_len + 10]; + long pos = 0; + size_t len; + char *startpattern = NULL; + fseek(f, 0L, SEEK_END); + pos = ftell(f); + while(pos > search_win_len) { + int offset = 0; + pos = pos - (search_win_len/2); + fseek(f, pos, SEEK_SET); + len = fread(&line, 1, search_win_len, f); + if(len <= 0) { + /* pattern not found / reached end */ + return 1; + } + line[len] = '\0'; + if((startpattern = strstr(line, pattern)) != NULL) { + int containsend = 0; + char *s = startpattern; + char *end; + offset = startpattern - line; + /* search the beginning of the line */ + while((s > line) && (s[0] != CR) && (s[0] != LF)) { + s--; + } + if((s[0] != CR) && (s[0] != LF)) { + // beginning of the line not in the buffer + qs_readline(pos, f); + } + s++; + end = startpattern; + /* search the end of the line */ + while((offset < search_win_len) && end[0] && end[0] != CR && end[0] != LF) { + end++; + offset++; + } + /* print the line containing the pattern */ + if((end[0] == CR) || (end[0] == LF)) { + end[0] = '\0'; + printf("%s\n", s); + containsend = 1; + } else { + printf("%s", s); + } + fseek(f, pos + offset, SEEK_SET); + if(containsend) { + // skip the line at the current position + cont = fgets(line, sizeof(line), f); + } else { + cont = line; + } + if(cont) { + while(fgets(line, sizeof(line), f) != NULL) { + printf("%s", line); + } + } + return 0; + } + } + return 1; +} + +int main(int argc, const char * const argv[]) { + FILE *f; + const char *filename = NULL; + const char *pattern = NULL; + char *cmd = strrchr(argv[0], '/'); + int status = 0; + if(cmd == NULL) { + cmd = (char *)argv[0]; + } else { + cmd++; + } + + argc--; + argv++; + while(argc >= 1) { + if(strcmp(*argv,"-i") == 0) { + if (--argc >= 1) { + filename = *(++argv); + } + } else if(strcmp(*argv,"-p") == 0) { + if (--argc >= 1) { + pattern = *(++argv); + } + } else if(strcmp(*argv,"-?") == 0) { + usage(cmd, 0); + } else if(strcmp(*argv,"-help") == 0) { + usage(cmd, 0); + } else if(strcmp(*argv,"--help") == 0) { + usage(cmd, 0); + } else if(strcmp(*argv,"--man") == 0) { + usage(cmd, 1); + } + argc--; + argv++; + } + + if(filename == NULL || pattern == NULL) { + usage(cmd, 0); + } + if((f = fopen(filename, "r")) == NULL) { + fprintf(stderr, "[%s]: ERROR, could not open file '%s'\n", cmd, filename); + exit(1); + } + + status = qs_tail(cmd, f, pattern); + + fclose(f); + return status; +} |