mirror of
https://github.com/Llewellynvdm/conky.git
synced 2024-11-20 03:51:18 +00:00
Fix bug with SF id 2808272 (tail and head)
To fix this bug the tail and head code was rewritten, everything should still work except tailing a FIFO instead of a normal head.
This commit is contained in:
parent
0c159ca440
commit
5a027864d5
@ -1261,12 +1261,12 @@
|
||||
<command>
|
||||
<option>head</option>
|
||||
</command>
|
||||
<option>logfile lines (interval)</option>
|
||||
<option>logfile lines (next_check)</option>
|
||||
</term>
|
||||
<listitem>Displays first N lines of supplied text text
|
||||
file. If interval is not supplied, Conky assumes 2x Conky's
|
||||
interval. Max of 30 lines can be displayed, or until the
|
||||
text buffer is filled.
|
||||
<listitem>Displays first N lines of supplied text file. The
|
||||
file is checked every 'next_check' update. If next_check
|
||||
is not supplied, Conky defaults to 2. Max of 30 lines can be
|
||||
displayed, or until the text buffer is filled.
|
||||
<para /></listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
@ -2794,12 +2794,12 @@
|
||||
<command>
|
||||
<option>tail</option>
|
||||
</command>
|
||||
<option>logfile lines (interval)</option>
|
||||
<option>logfile lines (next_check)</option>
|
||||
</term>
|
||||
<listitem>Displays last N lines of supplied text text file.
|
||||
If interval is not supplied, Conky assumes 2x Conky's
|
||||
interval. Max of 30 lines can be displayed, or until the
|
||||
text buffer is filled.
|
||||
<listitem>Displays last N lines of supplied text file. The
|
||||
file is checked every 'next_check' update. If next_check
|
||||
is not supplied, Conky defaults to 2. Max of 30 lines can be
|
||||
displayed, or until the text buffer is filled.
|
||||
<para /></listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
|
13
src/common.c
13
src/common.c
@ -51,6 +51,19 @@
|
||||
/* OS specific prototypes to be implemented by linux.c & Co. */
|
||||
void update_entropy(void);
|
||||
|
||||
/* folds a string over top of itself, like so:
|
||||
*
|
||||
* if start is "blah", and you call it with count = 1, the result will be "lah"
|
||||
*/
|
||||
void strfold(char *start, int count)
|
||||
{
|
||||
char *curplace;
|
||||
for (curplace = start + count; *curplace != 0; curplace++) {
|
||||
*(curplace - count) = *curplace;
|
||||
}
|
||||
*(curplace - count) = 0;
|
||||
}
|
||||
|
||||
#ifndef HAVE_STRNDUP
|
||||
// use our own strndup() if it's not available
|
||||
char *strndup(const char *s, size_t n)
|
||||
|
@ -6,6 +6,7 @@
|
||||
#include <string.h>
|
||||
#include <sys/socket.h>
|
||||
|
||||
void strfold(char *start, int count);
|
||||
int check_mount(char *s);
|
||||
void prepare_update(void);
|
||||
void update_uptime(void);
|
||||
|
40
src/conky.c
40
src/conky.c
@ -773,9 +773,12 @@ static void free_text_objects(struct text_object *root, int internal)
|
||||
free(data.ifblock.s);
|
||||
free(data.ifblock.str);
|
||||
break;
|
||||
case OBJ_head:
|
||||
case OBJ_tail:
|
||||
free(data.tail.logfile);
|
||||
free(data.tail.buffer);
|
||||
free(data.headtail.logfile);
|
||||
if(data.headtail.buffer) {
|
||||
free(data.headtail.buffer);
|
||||
}
|
||||
break;
|
||||
case OBJ_text:
|
||||
case OBJ_font:
|
||||
@ -2067,15 +2070,9 @@ static struct text_object *construct_text_object(const char *s,
|
||||
}
|
||||
#endif /* __linux__ */
|
||||
END OBJ(tail, 0)
|
||||
if (init_tail_object(obj, arg)) {
|
||||
obj->type = OBJ_text;
|
||||
obj->data.s = strndup("${tail}", text_buffer_size);
|
||||
}
|
||||
init_tailhead("tail", arg, obj, free_at_crash);
|
||||
END OBJ(head, 0)
|
||||
if (init_head_object(obj, arg)) {
|
||||
obj->type = OBJ_text;
|
||||
obj->data.s = strndup("${head}", text_buffer_size);
|
||||
}
|
||||
init_tailhead("head", arg, obj, free_at_crash);
|
||||
END OBJ(lines, 0)
|
||||
if (arg) {
|
||||
obj->data.s = strndup(arg, text_buffer_size);
|
||||
@ -3333,19 +3330,6 @@ static int text_contains_templates(const char *text)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* folds a string over top of itself, like so:
|
||||
*
|
||||
* if start is "blah", and you call it with count = 1, the result will be "lah"
|
||||
*/
|
||||
static void strfold(char *start, int count)
|
||||
{
|
||||
char *curplace;
|
||||
for (curplace = start + count; *curplace != 0; curplace++) {
|
||||
*(curplace - count) = *curplace;
|
||||
}
|
||||
*(curplace - count) = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* - assumes that *string is '#'
|
||||
* - removes the part from '#' to the end of line ('\n' or '\0')
|
||||
@ -5566,10 +5550,12 @@ static void generate_text_internal(char *p, int p_max_size,
|
||||
#endif
|
||||
}
|
||||
}
|
||||
OBJ(tail)
|
||||
print_tail_object(obj, p, p_max_size);
|
||||
OBJ(head)
|
||||
print_head_object(obj, p, p_max_size);
|
||||
OBJ(tail) {
|
||||
print_tailhead("tail", obj, p, p_max_size);
|
||||
}
|
||||
OBJ(head) {
|
||||
print_tailhead("head", obj, p, p_max_size);
|
||||
}
|
||||
OBJ(lines) {
|
||||
FILE *fp = open_file(obj->data.s, &obj->a);
|
||||
|
||||
|
438
src/tailhead.c
438
src/tailhead.c
@ -24,399 +24,83 @@
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
#include "config.h"
|
||||
#include "conky.h"
|
||||
#include "logging.h"
|
||||
#include "tailhead.h"
|
||||
|
||||
#include "text_object.h"
|
||||
#include "logging.h"
|
||||
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#define MAX_HEADTAIL_LINES 30
|
||||
#define DEFAULT_MAX_HEADTAIL_USES 2
|
||||
|
||||
#ifndef HAVE_MEMRCHR
|
||||
static const void *memrchr(const void *buffer, char c, size_t n)
|
||||
{
|
||||
const unsigned char *p = buffer;
|
||||
void init_tailhead(const char* type, const char* arg, struct text_object *obj, void* free_at_crash) {
|
||||
unsigned int args;
|
||||
|
||||
for (p += n; n; n--) {
|
||||
if (*--p == c) {
|
||||
return p;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
int init_tailhead_object(enum tailhead_type type,
|
||||
struct text_object *obj, const char *arg)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
numargs = sscanf(arg, "%127s %i %i", buf, &n1, &n2);
|
||||
|
||||
if (numargs < 2 || numargs > 3) {
|
||||
ERR("incorrect number of arguments given to %s object", me);
|
||||
return 1;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
obj->data.tail.fd = -1;
|
||||
|
||||
if (type == HEAD) {
|
||||
goto NO_FIFO;
|
||||
}
|
||||
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;
|
||||
if(arg) {
|
||||
obj->data.headtail.logfile=malloc(strlen(arg));
|
||||
obj->data.headtail.max_uses = DEFAULT_MAX_HEADTAIL_USES;
|
||||
args = sscanf(arg, "%s %d %d", obj->data.headtail.logfile, &obj->data.headtail.wantedlines, &obj->data.headtail.max_uses);
|
||||
if(args == 2 || args == 3) {
|
||||
if(obj->data.headtail.max_uses < 1) {
|
||||
free(obj->data.headtail.logfile);
|
||||
CRIT_ERR(obj, free_at_crash, "invalid arg for %s, next_check must be larger than 0", type);
|
||||
}
|
||||
if (obj->data.headtail.wantedlines > 0 && obj->data.headtail.wantedlines <= MAX_HEADTAIL_LINES) {
|
||||
to_real_path(obj->data.headtail.logfile, obj->data.headtail.logfile);
|
||||
obj->data.headtail.buffer = NULL;
|
||||
obj->data.headtail.current_use = 0;
|
||||
}else{
|
||||
free(obj->data.headtail.logfile);
|
||||
CRIT_ERR(obj, free_at_crash, "invalid arg for %s, number of lines must be between 1 and %d", type, MAX_HEADTAIL_LINES);
|
||||
}
|
||||
|
||||
obj->data.tail.fd = fd;
|
||||
} else {
|
||||
NO_FIFO:
|
||||
fp = fopen(buf, "r");
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
free(obj->data.headtail.logfile);
|
||||
CRIT_ERR(obj, free_at_crash, "%s needs a file as 1st and a number of lines as 2nd argument", type);
|
||||
}
|
||||
} else {
|
||||
// fclose(fp);
|
||||
ERR("%s logfile does not exist, or you do not have "
|
||||
"correct permissions", me);
|
||||
return 1;
|
||||
CRIT_ERR(obj, free_at_crash, "%s needs arguments", type);
|
||||
}
|
||||
/* 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;
|
||||
}
|
||||
|
||||
/* 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;
|
||||
void print_tailhead(const char* type, struct text_object *obj, char *p, int p_max_size) {
|
||||
int i, endofstring = 0, linescounted = 0;
|
||||
FILE *fp;
|
||||
|
||||
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;
|
||||
|
||||
for (n = 0; obj->data.tail.buffer[n]; n++) {
|
||||
if (obj->data.tail.buffer[n] == '\n') {
|
||||
if (!first_line) {
|
||||
first_line = n + 1;
|
||||
}
|
||||
|
||||
if (++olines < obj->data.tail.wantedlines) {
|
||||
pos = n + 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
if(obj->data.headtail.buffer && obj->data.headtail.current_use >= obj->data.headtail.max_uses - 1) {
|
||||
free(obj->data.headtail.buffer);
|
||||
obj->data.headtail.buffer = NULL;
|
||||
obj->data.headtail.current_use = 0;
|
||||
}
|
||||
if(obj->data.headtail.buffer) {
|
||||
strcpy(p, obj->data.headtail.buffer);
|
||||
obj->data.headtail.current_use++;
|
||||
}else{
|
||||
fp = open_file(obj->data.headtail.logfile, &obj->a);
|
||||
if(fp != NULL) {
|
||||
if(strcmp(type,"head") == 0) {
|
||||
for(i = 0; i < obj->data.headtail.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);
|
||||
fread(p, 1, p_max_size, fp);
|
||||
p[p_max_size - 1] = 0;
|
||||
if(p[strlen(p)-1] == '\n') { //work with or without \n at end of file
|
||||
p[strlen(p)-1] = 0;
|
||||
}
|
||||
for(i = strlen(p); i >= 0 && linescounted < obj->data.headtail.wantedlines; i--) {
|
||||
if(p[i] == '\n') {
|
||||
linescounted++;
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
if(i > 0) {
|
||||
strfold(p, i+2);
|
||||
}
|
||||
} else {
|
||||
buf_size = file_pos;
|
||||
fseek(fp, 0, SEEK_SET);
|
||||
}
|
||||
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++;
|
||||
} else {
|
||||
buf_pos = -1;
|
||||
if (file_pos == 0) {
|
||||
break;
|
||||
CRIT_ERR(NULL, NULL, "If you are seeing this then there is a bug in the code, report it !");
|
||||
}
|
||||
fclose(fp);
|
||||
obj->data.headtail.buffer = strdup(p);
|
||||
}
|
||||
}
|
||||
fseek(fp, orig_pos, SEEK_SET);
|
||||
if (count == step) {
|
||||
ret = file_pos + buf_pos;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
if (obj->data.tail.fd != -1) {
|
||||
tail_pipe(obj, p, p_max_size);
|
||||
return 0;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
int print_head_object(struct text_object *obj, char *p, size_t 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;
|
||||
}
|
||||
|
||||
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';
|
||||
} else {
|
||||
obj->data.tail.buffer[nl] = '\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;
|
||||
return;
|
||||
}
|
||||
|
@ -24,24 +24,6 @@
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
#ifndef _TAILHEAD_H
|
||||
#define _TAILHEAD_H
|
||||
|
||||
#include "text_object.h"
|
||||
|
||||
#define MAX_TAIL_LINES 100
|
||||
|
||||
enum tailhead_type {
|
||||
TAIL,
|
||||
HEAD,
|
||||
};
|
||||
|
||||
#define init_tail_object(o, a) init_tailhead_object(TAIL, o, a)
|
||||
#define init_head_object(o, a) init_tailhead_object(HEAD, o, a)
|
||||
|
||||
int init_tailhead_object(enum tailhead_type,
|
||||
struct text_object *, const char *);
|
||||
int print_head_object(struct text_object *, char *, size_t);
|
||||
int print_tail_object(struct text_object *, char *, size_t);
|
||||
|
||||
#endif /* _TAILHEAD_H */
|
||||
void init_tailhead(const char* type, const char* arg, struct text_object *obj, void* free_at_crash);
|
||||
void print_tailhead(const char* type, struct text_object *obj, char *p, int p_max_size);
|
||||
|
@ -493,15 +493,11 @@ struct text_object {
|
||||
|
||||
struct {
|
||||
int wantedlines;
|
||||
int readlines;
|
||||
char *logfile;
|
||||
double last_update;
|
||||
float interval;
|
||||
char *buffer;
|
||||
/* If not -1, a file descriptor to read from when
|
||||
* logfile is a FIFO. */
|
||||
int fd;
|
||||
} tail;
|
||||
int current_use;
|
||||
int max_uses;
|
||||
} headtail;
|
||||
|
||||
struct {
|
||||
double last_update;
|
||||
|
Loading…
Reference in New Issue
Block a user