diff --git a/AUTHORS b/AUTHORS index c7b6ba04..22c014a1 100644 --- a/AUTHORS +++ b/AUTHORS @@ -13,6 +13,9 @@ Alex affinity X-Mozilla-Status support +Blondak + diskio read & write patch + Bobby Beckmann Interface IP and Wireless Quality patch @@ -165,6 +168,9 @@ Roman Bogorodskiy FreeBSD support BMPx support +Ryan Twitchell + head/tail rewrite patch + Stepan Zastupov WiFi signal level detection support on FreeBSD diff --git a/ChangeLog b/ChangeLog index b85919c1..d730cecf 100644 --- a/ChangeLog +++ b/ChangeLog @@ -3,6 +3,8 @@ 2006-12-29 * Update svn ebuild to new sourceforge url scheme. - requires deletion of existing wc: rm -rf /usr/portage/distfile/svn-src/conky/ + * Added head/tail rewrite patch (thanks Ryan Twitchell) + * Added diskio read/write sf.net patch 1542880 (thanks Blondak) 2006-12-26 * Clear conky vars on disconnect/failure to open files. diff --git a/app-admin/conky/conky-1.4.2.ebuild b/app-admin/conky/conky-1.4.2.ebuild index fe6a833f..2e6b12c7 100644 --- a/app-admin/conky/conky-1.4.2.ebuild +++ b/app-admin/conky/conky-1.4.2.ebuild @@ -33,7 +33,7 @@ DEPEND_COMMON=" audacious? ( media-sound/audacious ) infopipe? ( media-plugins/xmms-infopipe ) xmms? ( media-sound/xmms ) - xmms2? ( medis-sound/xmms2 ) + xmms2? ( media-sound/xmms2 ) )" RDEPEND="${DEPEND_COMMON}" diff --git a/configure.ac.in b/configure.ac.in index 99c527ef..962b8b0f 100644 --- a/configure.ac.in +++ b/configure.ac.in @@ -432,6 +432,14 @@ dnl AC_CHECK_FUNCS([calloc malloc free popen sysinfo getloadavg]) AC_SEARCH_LIBS(clock_gettime, [rt], [], AC_MSG_ERROR([clock_gettime() not found])) +dnl +dnl Check for zlib +dnl + +AC_CHECK_HEADER(zlib.h, + [], + [AC_MSG_ERROR([zlib is missing; please install the headers first])]) + dnl dnl Check doc stuff diff --git a/doc/variables.xml b/doc/variables.xml index abd2ca96..df44c825 100644 --- a/doc/variables.xml +++ b/doc/variables.xml @@ -381,6 +381,44 @@ + + + + + + Displays current disk IO for reads. + + + + + + + + + + Disk IO graph for reads, colours defined in hex, minus the #. If scale is non-zero, it becomes the scale for the graph. + + + + + + + + + Displays current disk IO for writes. + + + + + + + + + + Disk IO graph for writes, colours defined in hex, minus the #. If scale is non-zero, it becomes the scale for the graph. + + + diff --git a/src/conky.c b/src/conky.c index 33277e1e..425cae3e 100644 --- a/src/conky.c +++ b/src/conky.c @@ -9,13 +9,11 @@ #include "conky.h" #include #include -#include #include #include #include #include #include -#include #include #include #include @@ -541,53 +539,79 @@ static struct special_t *new_special(char *buf, int t) return &specials[special_count++]; } -typedef struct tailstring_list { - char data[TEXT_BUFFER_SIZE]; - struct tailstring_list *next; - struct tailstring_list *first; -} tailstring; - -void addtail(tailstring ** head, char *data_in) -{ - tailstring *tmp; - if ((tmp = malloc(sizeof(*tmp))) == NULL) { - CRIT_ERR("malloc"); - } - if (*head == NULL) { - tmp->first = tmp; - } else { - tmp->first = (*head)->first; - } - strncpy(tmp->data, data_in, TEXT_BUFFER_SIZE); - tmp->next = *head; - *head = tmp; -} - -void freetail(tailstring * head) -{ - tailstring *tmp; - while (head != NULL) { - tmp = head->next; - free(head); - head = tmp; - } -} - -void freelasttail(tailstring * head) -{ - tailstring * tmp = head; - while(tmp != NULL) { - if (tmp->next == head->first) { - tmp->next = NULL; - break; +long fwd_fcharfind(FILE* fp, char val, unsigned int step) { +#define BUFSZ 0x1000 + long ret = -1; + long 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; } - tmp = tmp->next; } - free(head->first); - while(head != NULL && tmp != NULL) { - head->first = tmp; - head = head->next; + if(count == step) + ret = ftell(fp) - buf_size + buf_pos - 1; + fseek(fp, orig_pos, SEEK_SET); + return ret; +#undef BUFSZ +} + +long rev_fcharfind(FILE* fp, char val, unsigned int step) { +#define BUFSZ 0x1000 + long ret = -1; + long count = 0; + static char buf[BUFSZ]; + long orig_pos = ftell(fp); + long buf_pos = -1; + long file_pos = orig_pos; + long buf_size = BUFSZ; + char* cur_found; + while(count < step) { + if(buf_pos <= 0) { + if(file_pos > BUFSZ) { + fseek(fp, file_pos-BUFSZ, SEEK_SET); + } + 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, + (int)val, + (size_t)buf_pos); + if(cur_found != NULL) { + buf_pos = cur_found-buf; + count++; + } else { + buf_pos = -1; + if(file_pos == 0) { + break; + } + } } + fseek(fp, orig_pos, SEEK_SET); + if(count == step) + ret = file_pos + buf_pos; + return ret; +#undef BUFSZ } static void new_bar(char *buf, int w, int h, int usage) @@ -900,7 +924,11 @@ enum text_object_type { OBJ_cpubar, OBJ_cpugraph, OBJ_diskio, + OBJ_diskio_read, + OBJ_diskio_write, OBJ_diskiograph, + OBJ_diskiograph_read, + OBJ_diskiograph_write, OBJ_downspeed, OBJ_downspeedf, OBJ_downspeedgraph, @@ -2169,7 +2197,11 @@ static struct text_object *construct_text_object(const char *s, const char *arg, obj->data.cpu_index = 0; } END OBJ(diskio, INFO_DISKIO) - END OBJ(diskiograph, INFO_DISKIO) (void) scan_graph(arg, &obj->a, &obj->b, &obj->c, &obj->d, &obj->e); + END OBJ(diskio_read, INFO_DISKIO) + END OBJ(diskio_write, INFO_DISKIO) + END OBJ(diskiograph, INFO_DISKIO) (void) scan_graph(arg, &obj->a, &obj->b, &obj->c, &obj->d, &obj->e); + END OBJ(diskiograph_read, INFO_DISKIO) (void) scan_graph(arg, &obj->a, &obj->b, &obj->c, &obj->d, &obj->e); + END OBJ(diskiograph_write, INFO_DISKIO) (void) scan_graph(arg, &obj->a, &obj->b, &obj->c, &obj->d, &obj->e); END OBJ(color, 0) #ifdef X11 obj->data.l = arg ? get_x11_color(arg) : default_fg_color; @@ -2472,7 +2504,7 @@ static struct text_object *construct_text_object(const char *s, const char *arg, obj->data.tail.logfile = malloc(TEXT_BUFFER_SIZE); strcpy(obj->data.tail.logfile, buf); - obj->data.tail.wantedlines = n1 - 1; + obj->data.tail.wantedlines = n1; obj->data.tail.interval = update_interval * 2; fclose(fp); @@ -2497,7 +2529,7 @@ static struct text_object *construct_text_object(const char *s, const char *arg, obj->data.tail.logfile = malloc(TEXT_BUFFER_SIZE); strcpy(obj->data.tail.logfile, buf); - obj->data.tail.wantedlines = n1 - 1; + obj->data.tail.wantedlines = n1; obj->data.tail.interval = n2; fclose(fp); } else { @@ -2532,7 +2564,7 @@ static struct text_object *construct_text_object(const char *s, const char *arg, obj->data.tail.logfile = malloc(TEXT_BUFFER_SIZE); strcpy(obj->data.tail.logfile, buf); - obj->data.tail.wantedlines = n1 - 1; + obj->data.tail.wantedlines = n1; obj->data.tail.interval = update_interval * 2; fclose(fp); @@ -2557,7 +2589,7 @@ static struct text_object *construct_text_object(const char *s, const char *arg, obj->data.tail.logfile = malloc(TEXT_BUFFER_SIZE); strcpy(obj->data.tail.logfile, buf); - obj->data.tail.wantedlines = n1 - 1; + obj->data.tail.wantedlines = n1; obj->data.tail.interval = n2; fclose(fp); } else { @@ -3414,7 +3446,8 @@ static void generate_text_internal(char *p, int p_max_size, struct text_object * new_font(p, obj->data.s); } #endif /* X11 */ - OBJ(diskio) { + void format_diskio(unsigned int diskio_value) + { if (!use_spacer) { if (diskio_value > 1024*1024) { snprintf(p, p_max_size, "%.1fGiB", @@ -3441,12 +3474,30 @@ static void generate_text_internal(char *p, int p_max_size, struct text_object * } } } - OBJ(diskiograph) { - new_graph(p, obj->a, - obj->b, obj->c, obj->d, - diskio_value, obj->e, 1); + OBJ(diskio) { + format_diskio(diskio_value); } - + OBJ(diskio_write) { + format_diskio(diskio_write_value); + } + OBJ(diskio_read) { + format_diskio(diskio_read_value); + } + OBJ(diskiograph) { + new_graph(p, obj->a, + obj->b, obj->c, obj->d, + diskio_value, obj->e, 1); + } + OBJ(diskiograph_read) { + new_graph(p, obj->a, + obj->b, obj->c, obj->d, + diskio_read_value, obj->e, 1); + } + OBJ(diskiograph_write) { + new_graph(p, obj->a, + obj->b, obj->c, obj->d, + diskio_write_value, obj->e, 1); + } OBJ(downspeed) { if (!use_spacer) { snprintf(p, p_max_size, "%d", @@ -4593,108 +4644,112 @@ static void generate_text_internal(char *p, int p_max_size, struct text_object * } else { obj->data.tail.last_update = current_update_time; FILE *fp; - int i; - int added = 0; - tailstring *head = NULL; - tailstring *headtmp = NULL; - tailstring *freetmp = NULL; + long nl, bsize; + int iter; fp = fopen(obj->data.tail.logfile, "rt"); if (fp == NULL) { - ERR("tail logfile failed to open"); + /* 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; - - while (fgets(obj->data.tail.buffer, TEXT_BUFFER_SIZE*20, fp) != NULL) { - if (added >= 30) { - freelasttail(head); - } - else { - added++; - } - addtail(&head, obj->data.tail.buffer); - obj->data.tail.readlines++; + /* -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 > 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); - freetmp = head; - - if (obj->data.tail.readlines > 0) { - for (i = 0;i < obj->data.tail.wantedlines + 1 && i < obj->data.tail.readlines; i++) { - addtail(&headtmp, head->data); - head = head->next; - } - freetail(freetmp); - freetmp = headtmp; - strcpy(obj->data.tail.buffer, headtmp->data); - headtmp = headtmp->next; - for (i = 1;i < obj->data.tail.wantedlines + 1 && i < obj->data.tail.readlines; i++) { - if (headtmp) { - strncat(obj->data.tail.buffer, headtmp->data, (TEXT_BUFFER_SIZE * 20) - strlen(obj->data.tail.buffer)); /* without strlen() at the end this becomes a possible */ - headtmp = headtmp->next; - } - } - - /* get rid of any ugly newlines at the end */ - if (obj->data.tail.buffer[strlen(obj->data.tail.buffer)-1] == '\n') { - obj->data.tail.buffer[strlen(obj->data.tail.buffer)-1] = '\0'; - } + 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); - - freetail(freetmp); - } else { + } + else { strcpy(obj->data.tail.buffer, "Logfile Empty"); snprintf(p, p_max_size, "Logfile Empty"); - } /* if readlines */ + } /* bsize > 0 */ } /* fp == NULL */ } /* if cur_upd_time >= */ - + //parse_conky_vars(obj->data.tail.buffer, p, cur); } OBJ(head) { if (current_update_time -obj->data.tail.last_update < obj->data.tail.interval) { - snprintf(p, p_max_size, "%s", obj->data.tail.buffer); + snprintf(p, p_max_size, "%s", obj->data.tail.buffer); } else { obj->data.tail.last_update = current_update_time; FILE *fp; - tailstring *head = NULL; - tailstring *headtmp = NULL; - tailstring *freetmp = NULL; + long nl; + int iter; fp = fopen(obj->data.tail.logfile, "rt"); if (fp == NULL) { - ERR("head logfile failed to open"); + /* 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; - while (fgets(obj->data.tail.buffer, TEXT_BUFFER_SIZE*20, fp) != NULL && obj->data.tail.readlines <= obj->data.tail.wantedlines) { - addtail(&head, obj->data.tail.buffer); - obj->data.tail.readlines++; + 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 > TEXT_BUFFER_SIZE*20 - 1) { + nl = TEXT_BUFFER_SIZE*20 - 1; + } + nl = fread(obj->data.tail.buffer, 1, nl, fp); fclose(fp); - freetmp = head; - if (obj->data.tail.readlines > 0) { - while (head) { - addtail(&headtmp, head->data); - head = head->next; + 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'; } - freetail(freetmp); - freetmp = headtmp; - strcpy(obj->data.tail.buffer, headtmp->data); - headtmp = headtmp->next; - while (headtmp) { - strncat(obj->data.tail.buffer, headtmp->data, (TEXT_BUFFER_SIZE * 20) - strlen(obj->data.tail.buffer)); /* without strlen() at the end this becomes a possible */ - headtmp = headtmp->next; - } - freetail(freetmp); - /* get rid of any ugly newlines at the end */ - if (obj->data.tail.buffer[strlen(obj->data.tail.buffer)-1] == '\n') { - obj->data.tail.buffer[strlen(obj->data.tail.buffer)-1] = '\0'; + else { + obj->data.tail.buffer[nl] = '\0'; } snprintf(p, p_max_size, "%s", obj->data.tail.buffer); - } else { + } + else { strcpy(obj->data.tail.buffer, "Logfile Empty"); snprintf(p, p_max_size, "Logfile Empty"); - } /* if readlines > 0 */ + } /* nl > 0 */ } /* if fp == null */ } /* cur_upd_time >= */ @@ -4808,6 +4863,11 @@ static void generate_text() current_update_time = get_time(); update_stuff(cur); + /* fix diskio rates to b/s (use update_interval */ + diskio_read_value = diskio_read_value / update_interval; + diskio_write_value = diskio_write_value / update_interval; + diskio_value = diskio_value / update_interval; + /* add things to the buffer */ diff --git a/src/conky.h b/src/conky.h index 9c3693df..cccd9376 100644 --- a/src/conky.h +++ b/src/conky.h @@ -96,6 +96,8 @@ struct net_stat { }; unsigned int diskio_value; +unsigned int diskio_read_value; +unsigned int diskio_write_value; struct fs_stat { char *path; diff --git a/src/linux.c b/src/linux.c index 228011b2..086f314b 100644 --- a/src/linux.c +++ b/src/linux.c @@ -1521,25 +1521,27 @@ void update_top() void update_diskio() { static unsigned int last = UINT_MAX; + static unsigned int last_read = UINT_MAX; + static unsigned int last_write = UINT_MAX; FILE* fp; - static int rep=0; + static int rep=0; char buf[512]; int major, minor; unsigned int current = 0; + unsigned int current_read = 0; + unsigned int current_write = 0; unsigned int reads, writes = 0; int col_count = 0; - if (!(fp =open_file("/proc/diskstats", &rep))) - { - diskio_value=0; - return; - } + if (!(fp =open_file("/proc/diskstats", &rep))) { + diskio_value=0; + return; + } /* read reads and writes from all disks (minor = 0), including * cd-roms and floppies, and summ them up */ - current = 0; while (!feof(fp)) { fgets(buf, 512, fp); col_count = sscanf(buf, "%u %u %*s %*u %*u %u %*u %*u %*u %u", @@ -1553,6 +1555,8 @@ void update_diskio() major != LVM_BLK_MAJOR && major != NBD_MAJOR && major != RAMDISK_MAJOR && major != LOOP_MAJOR) { current += reads + writes; + current_read += reads; + current_write += writes; } } @@ -1561,6 +1565,14 @@ void update_diskio() * "sectors read", and we therefore have to divide by two to * get KB */ int tot = ((double)(current-last)/2); + int tot_read = ((double)(current_read-last_read)/2); + int tot_write = ((double)(current_write-last_write)/2); + + if (last_read > current_read) + tot_read = 0; + if (last_write > current_write) + tot_write = 0; + if (last > current) { /* we hit this either if it's the very first time we * run this, or when /proc/diskstats overflows; while @@ -1568,10 +1580,14 @@ void update_diskio() tot = 0; } last = current; + last_read = current_read; + last_write = current_write; diskio_value = tot; + diskio_read_value = tot_read; + diskio_write_value = tot_write; - fclose(fp); + fclose(fp); } /* Here come the IBM ACPI-specific things. For reference, see