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);
}