X-Git-Url: https://vcs.maemo.org/git/?a=blobdiff_plain;f=src%2Ftailhead.c;h=f0488cbc184f9de878b383b35017a184a09248d6;hb=7a8c1e45c8d53a3b84a712c09c1fbdf9eaaa3e5a;hp=b9e24cb0603ae9b0aaf534799d100ebbf497fbcb;hpb=867a842b3fa4494f531b63902953c14707b89eeb;p=monky diff --git a/src/tailhead.c b/src/tailhead.c index b9e24cb..f0488cb 100644 --- a/src/tailhead.c +++ b/src/tailhead.c @@ -1,4 +1,7 @@ -/* Conky, a system monitor, based on torsmo +/* -*- mode: c; c-basic-offset: 4; tab-width: 4; indent-tabs-mode: t -*- + * vim: ts=4 sw=4 noet ai cindent syntax=c + * + * Conky, a system monitor, based on torsmo * * Any original torsmo code is licensed under the BSD license * @@ -7,7 +10,7 @@ * Please see COPYING for details * * Copyright (c) 2004, Hannu Saransaari and Lauri Hakkarainen - * Copyright (c) 2005-2009 Brenden Matthews, Philip Kovacs, et. al. + * Copyright (c) 2005-2010 Brenden Matthews, Philip Kovacs, et. al. * (see AUTHORS) * All rights reserved. * @@ -24,399 +27,212 @@ * along with this program. If not, see . * */ -#include "config.h" -#include "conky.h" -#include "logging.h" -#include "tailhead.h" -#include "text_object.h" -#include +#define _GNU_SOURCE +#include "common.h" +#include "text_object.h" +#include "logging.h" +#include +#include #include +#include #include -#include -#include - -#ifndef HAVE_MEMRCHR -static const void *memrchr(const void *buffer, char c, size_t n) -{ - const unsigned char *p = buffer; - for (p += n; n; n--) { - if (*--p == c) { - return p; +#define MAX_HEADTAIL_LINES 30 +#define DEFAULT_MAX_HEADTAIL_USES 2 + +struct headtail { + int wantedlines; + char *logfile; + char *buffer; + int current_use; + int max_uses; + int reported; +}; + +static void tailstring(char *string, int endofstring, int wantedlines) { + int i, linescounted = 0; + + string[endofstring] = 0; + if(endofstring > 0) { + if(string[endofstring-1] == '\n') { //work with or without \n at end of file + string[endofstring-1] = 0; + } + for(i = endofstring - 1; i >= 0 && linescounted < wantedlines; i--) { + if(string[i] == '\n') { + linescounted++; + } + } + if(i > 0) { + strfold(string, i+2); } } - return NULL; } -#endif -int init_tailhead_object(enum tailhead_type type, - struct text_object *obj, const char *arg) +void free_tailhead(struct text_object *obj) { - char buf[128]; - int n1, n2; - struct stat st; - FILE *fp = NULL; - int fd; - int numargs; - const char *me; - - /* FIXME: use #define for that */ - me = (type == TAIL) ? "tail" : "head"; - - if (!arg) { - ERR("%s needs arguments", me); - return 1; - } + struct headtail *ht = obj->data.opaque; + if (!ht) + return; + if (ht->logfile) + free(ht->logfile); + if (ht->buffer) + free(ht->buffer); + free(obj->data.opaque); + obj->data.opaque = NULL; +} - numargs = sscanf(arg, "%127s %i %i", buf, &n1, &n2); +void init_tailhead(const char* type, const char* arg, struct text_object *obj, void* free_at_crash) { + unsigned int args; + struct headtail *ht; - if (numargs < 2 || numargs > 3) { - ERR("incorrect number of arguments given to %s object", me); - return 1; - } + ht = malloc(sizeof(struct headtail)); + memset(ht, 0, sizeof(struct headtail)); - if (n1 < 1 || n1 > MAX_TAIL_LINES) { - ERR("invalid arg for %s, number of lines must be " - "between 1 and %i", me, MAX_TAIL_LINES); - return 1; - } + ht->logfile = malloc(DEFAULT_TEXT_BUFFER_SIZE); + memset(ht->logfile, 0, DEFAULT_TEXT_BUFFER_SIZE); - obj->data.tail.fd = -1; + ht->max_uses = DEFAULT_MAX_HEADTAIL_USES; - if (type == HEAD) { - goto NO_FIFO; + args = sscanf(arg, "%s %d %d", ht->logfile, &ht->wantedlines, &ht->max_uses); + if (args < 2 || args > 3) { + free_tailhead(obj); + CRIT_ERR(obj, free_at_crash, "%s needs a file as 1st and a number of lines as 2nd argument", type); } - to_real_path(buf, buf); - if (stat(buf, &st) == 0) { - if (S_ISFIFO(st.st_mode)) { - fd = open(buf, O_RDONLY | O_NONBLOCK); - - if (fd == -1) { - ERR("%s logfile does not exist, or you do " - "not have correct permissions", me); - return 1; - } - - obj->data.tail.fd = fd; - } else { -NO_FIFO: - fp = fopen(buf, "r"); - } + if (ht->max_uses < 1) { + free_tailhead(obj); + CRIT_ERR(obj, free_at_crash, "invalid arg for %s, next_check must be larger than 0", type); } - - if (fp || obj->data.tail.fd != -1) { - obj->data.tail.logfile = malloc(text_buffer_size); - strcpy(obj->data.tail.logfile, buf); - obj->data.tail.wantedlines = n1; - obj->data.tail.interval = update_interval * 2; - - if (obj->data.tail.fd == -1) { - fclose(fp); - } + if (ht->wantedlines > 0 && ht->wantedlines <= MAX_HEADTAIL_LINES) { + to_real_path(ht->logfile, ht->logfile); + ht->buffer = NULL; + ht->current_use = 0; } else { - // fclose(fp); - ERR("%s logfile does not exist, or you do not have " - "correct permissions", me); - return 1; + free_tailhead(obj); + CRIT_ERR(obj, free_at_crash, "invalid arg for %s, number of lines must be between 1 and %d", type, MAX_HEADTAIL_LINES); } - /* XXX: the following implies update_interval >= 1 ?! */ - if (numargs == 3 && (n2 < 1 || n2 < update_interval)) { - ERR("%s interval must be greater than " - "0 and "PACKAGE_NAME"'s interval, ignoring", me); - } else if (numargs == 3) { - obj->data.tail.interval = n2; - } - /* asumming all else worked */ - obj->data.tail.buffer = malloc(text_buffer_size * 20); - return 0; + obj->data.opaque = ht; } -/* Allows reading from a FIFO (i.e., /dev/xconsole). - * The file descriptor is set to non-blocking which makes this possible. - * - * FIXME: Since lseek cannot seek a file descriptor long lines will break. */ -static void tail_pipe(struct text_object *obj, char *dst, size_t dst_size) -{ -#define TAIL_PIPE_BUFSIZE 4096 - int lines = 0; - int line_len = 0; - int last_line = 0; - int fd = obj->data.tail.fd; - - while (1) { - char buf[TAIL_PIPE_BUFSIZE]; - ssize_t len = read(fd, buf, sizeof(buf)); - int i; - - if (len == -1) { - if (errno != EAGAIN) { - strcpy(obj->data.tail.buffer, "Logfile Read Error"); - snprintf(dst, dst_size, "Logfile Read Error"); - } - - break; - } else if (len == 0) { - strcpy(obj->data.tail.buffer, "Logfile Empty"); - snprintf(dst, dst_size, "Logfile Empty"); - break; - } - - for (line_len = 0, i = 0; i < len; i++) { - int pos = 0; - char *p; - - if (buf[i] == '\n') { - lines++; - - if (obj->data.tail.readlines > 0) { - int n; - int olines = 0; - int first_line = 0; +void print_tailhead(const char* type, struct text_object *obj, char *p, int p_max_size) { + int fd, i, endofstring = 0, linescounted = 0; + FILE *fp; + struct stat st; + struct headtail *ht = obj->data.opaque; - for (n = 0; obj->data.tail.buffer[n]; n++) { - if (obj->data.tail.buffer[n] == '\n') { - if (!first_line) { - first_line = n + 1; - } + if (!ht) + return; - if (++olines < obj->data.tail.wantedlines) { - pos = n + 1; - continue; + //empty the buffer and reset the counter if we used it the max number of times + if(ht->buffer && ht->current_use >= ht->max_uses - 1) { + free(ht->buffer); + ht->buffer = NULL; + ht->current_use = 0; + } + //use the buffer if possible + if(ht->buffer) { + strcpy(p, ht->buffer); + ht->current_use++; + }else{ //otherwise find the needed data + if(stat(ht->logfile, &st) == 0) { + if (S_ISFIFO(st.st_mode)) { + fd = open_fifo(ht->logfile, &ht->reported); + if(fd != -1) { + if(strcmp(type, "head") == 0) { + for(i = 0; linescounted < ht->wantedlines; i++) { + read(fd, p + i, 1); + if(p[i] == '\n') { + linescounted++; } - - n++; - p = obj->data.tail.buffer + first_line; - pos = n - first_line; - memmove(obj->data.tail.buffer, - obj->data.tail.buffer + first_line, strlen(p)); - obj->data.tail.buffer[pos] = 0; - break; } + p[i] = 0; + } else if(strcmp(type, "tail") == 0) { + i = read(fd, p, p_max_size - 1); + tailstring(p, i, ht->wantedlines); + } else { + CRIT_ERR(NULL, NULL, "If you are seeing this then there is a bug in the code, report it !"); } } - - p = buf + last_line; - line_len++; - memcpy(&(obj->data.tail.buffer[pos]), p, line_len); - obj->data.tail.buffer[pos + line_len] = 0; - last_line = i + 1; - line_len = 0; - obj->data.tail.readlines = lines; - continue; - } - - line_len++; - } - } - - snprintf(dst, dst_size, "%s", obj->data.tail.buffer); -} - -static long rev_fcharfind(FILE *fp, char val, unsigned int step) -{ -#define BUFSZ 0x1000 - long ret = -1; - unsigned int count = 0; - static char buf[BUFSZ]; - long orig_pos = ftell(fp); - long buf_pos = -1; - long file_pos = orig_pos; - long buf_size = BUFSZ; - const char *cur_found; - - while (count < step) { - if (buf_pos <= 0) { - if (file_pos > BUFSZ) { - fseek(fp, file_pos - BUFSZ, SEEK_SET); + close(fd); } else { - buf_size = file_pos; - fseek(fp, 0, SEEK_SET); + fp = open_file(ht->logfile, &ht->reported); + if(fp != NULL) { + if(strcmp(type, "head") == 0) { + for(i = 0; i < ht->wantedlines; i++) { + fgets(p + endofstring, p_max_size - endofstring, fp); + endofstring = strlen(p); + } + } else if(strcmp(type, "tail") == 0) { + fseek(fp, - p_max_size, SEEK_END); + i = fread(p, 1, p_max_size - 1, fp); + tailstring(p, i, ht->wantedlines); + } else { + CRIT_ERR(NULL, NULL, "If you are seeing this then there is a bug in the code, report it !"); + } + fclose(fp); + } } - file_pos = ftell(fp); - buf_pos = fread(buf, 1, buf_size, fp); - } - cur_found = memrchr(buf, val, (size_t) buf_pos); - if (cur_found != NULL) { - buf_pos = cur_found - buf; - count++; + ht->buffer = strdup(p); } else { - buf_pos = -1; - if (file_pos == 0) { - break; - } + CRIT_ERR(NULL, NULL, "$%s can't find information about %s", type, ht->logfile); } } - fseek(fp, orig_pos, SEEK_SET); - if (count == step) { - ret = file_pos + buf_pos; - } - return ret; + return; } -int print_tail_object(struct text_object *obj, char *p, size_t p_max_size) -{ - FILE *fp; - long nl = 0, bsize; - int iter; - - if (current_update_time - obj->data.tail.last_update < obj->data.tail.interval) { - snprintf(p, p_max_size, "%s", obj->data.tail.buffer); - return 0; - } - - obj->data.tail.last_update = current_update_time; +/* FIXME: use something more general (see also tail.c, head.c */ +#define BUFSZ 0x1000 - if (obj->data.tail.fd != -1) { - tail_pipe(obj, p, p_max_size); - return 0; +void print_lines(struct text_object *obj, char *p, int p_max_size) +{ + static int rep = 0; + FILE *fp = open_file(obj->data.s, &rep); + char buf[BUFSZ]; + int j, lines; + + if (!fp) { + snprintf(p, p_max_size, "File Unreadable"); + return; } - fp = fopen(obj->data.tail.logfile, "rt"); - if (fp == NULL) { - /* Send one message, but do not consistently spam - * on missing logfiles. */ - if (obj->data.tail.readlines != 0) { - ERR("tail logfile failed to open"); - strcpy(obj->data.tail.buffer, "Logfile Missing"); - } - obj->data.tail.readlines = 0; - snprintf(p, p_max_size, "Logfile Missing"); - } else { - obj->data.tail.readlines = 0; - /* -1 instead of 0 to avoid counting a trailing - * newline */ - fseek(fp, -1, SEEK_END); - bsize = ftell(fp) + 1; - for (iter = obj->data.tail.wantedlines; iter > 0; - iter--) { - nl = rev_fcharfind(fp, '\n', iter); - if (nl >= 0) { - break; + lines = 0; + while(fgets(buf, BUFSZ, fp) != NULL){ + for(j = 0; buf[j] != 0; j++) { + if(buf[j] == '\n') { + lines++; } } - obj->data.tail.readlines = iter; - if (obj->data.tail.readlines - < obj->data.tail.wantedlines) { - fseek(fp, 0, SEEK_SET); - } else { - fseek(fp, nl + 1, SEEK_SET); - bsize -= ftell(fp); - } - /* Make sure bsize is at least 1 byte smaller than the - * buffer max size. */ - if (bsize > (long) ((text_buffer_size * 20) - 1)) { - fseek(fp, bsize - text_buffer_size * 20 - 1, - SEEK_CUR); - bsize = text_buffer_size * 20 - 1; - } - bsize = fread(obj->data.tail.buffer, 1, bsize, fp); - fclose(fp); - if (bsize > 0) { - /* Clean up trailing newline, make sure the - * buffer is null terminated. */ - if (obj->data.tail.buffer[bsize - 1] == '\n') { - obj->data.tail.buffer[bsize - 1] = '\0'; - } else { - obj->data.tail.buffer[bsize] = '\0'; - } - snprintf(p, p_max_size, "%s", - obj->data.tail.buffer); - } else { - strcpy(obj->data.tail.buffer, "Logfile Empty"); - snprintf(p, p_max_size, "Logfile Empty"); - } /* bsize > 0 */ - } /* fp == NULL */ - return 0; -} - -long fwd_fcharfind(FILE *fp, char val, unsigned int step) -{ -#define BUFSZ 0x1000 - long ret = -1; - unsigned int count = 0; - static char buf[BUFSZ]; - long orig_pos = ftell(fp); - long buf_pos = -1; - long buf_size = BUFSZ; - char *cur_found = NULL; - - while (count < step) { - if (cur_found == NULL) { - buf_size = fread(buf, 1, buf_size, fp); - buf_pos = 0; - } - cur_found = memchr(buf + buf_pos, val, buf_size - buf_pos); - if (cur_found != NULL) { - buf_pos = cur_found - buf + 1; - count++; - } else { - if (feof(fp)) { - break; - } - } - } - if (count == step) { - ret = ftell(fp) - buf_size + buf_pos - 1; - } - fseek(fp, orig_pos, SEEK_SET); - return ret; + } + snprintf(p, p_max_size, "%d", lines); + fclose(fp); } -int print_head_object(struct text_object *obj, char *p, size_t p_max_size) +void print_words(struct text_object *obj, char *p, int p_max_size) { - FILE *fp; - long nl = 0; - int iter; - - if (current_update_time - obj->data.tail.last_update < obj->data.tail.interval) { - snprintf(p, p_max_size, "%s", obj->data.tail.buffer); - return 0; + static int rep = 0; + FILE *fp = open_file(obj->data.s, &rep); + char buf[BUFSZ]; + int j, words; + char inword = 0; + + if(!fp) { + snprintf(p, p_max_size, "File Unreadable"); + return; } - obj->data.tail.last_update = current_update_time; - - fp = fopen(obj->data.tail.logfile, "rt"); - if (fp == NULL) { - /* Send one message, but do not consistently spam - * on missing logfiles. */ - if (obj->data.tail.readlines != 0) { - ERR("head logfile failed to open"); - strcpy(obj->data.tail.buffer, "Logfile Missing"); - } - obj->data.tail.readlines = 0; - snprintf(p, p_max_size, "Logfile Missing"); - } else { - obj->data.tail.readlines = 0; - for (iter = obj->data.tail.wantedlines; iter > 0; - iter--) { - nl = fwd_fcharfind(fp, '\n', iter); - if (nl >= 0) { - break; - } - } - obj->data.tail.readlines = iter; - /* Make sure nl is at least 1 byte smaller than the - * buffer max size. */ - if (nl > (long) ((text_buffer_size * 20) - 1)) { - nl = text_buffer_size * 20 - 1; - } - nl = fread(obj->data.tail.buffer, 1, nl, fp); - fclose(fp); - if (nl > 0) { - /* Clean up trailing newline, make sure the buffer - * is null terminated. */ - if (obj->data.tail.buffer[nl - 1] == '\n') { - obj->data.tail.buffer[nl - 1] = '\0'; + words = 0; + while(fgets(buf, BUFSZ, fp) != NULL){ + for(j = 0; buf[j] != 0; j++) { + if(!isspace(buf[j])) { + if(!inword) { + words++; + inword = 1; + } } else { - obj->data.tail.buffer[nl] = '\0'; + inword = 0; } - snprintf(p, p_max_size, "%s", - obj->data.tail.buffer); - } else { - strcpy(obj->data.tail.buffer, "Logfile Empty"); - snprintf(p, p_max_size, "Logfile Empty"); - } /* nl > 0 */ - } /* if fp == null */ - return 0; + } + } + snprintf(p, p_max_size, "%d", words); + fclose(fp); }