diff --git a/src/Makefile.am b/src/Makefile.am index ac6f1b8a..6c415f06 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -50,11 +50,11 @@ endif # BUILD_CONFIG_OUTPUT # source files always needed for compiling mandatory_sources = colours.c colours.h common.c common.h conky.c conky.h \ - core.c core.h diskio.c diskio.h fs.c fs.h logging.h mail.c mail.h \ - mixer.c mixer.h template.c template.h timed_thread.c timed_thread.h \ - mboxscan.c mboxscan.h specials.c specials.h tailhead.c tailhead.h \ - temphelper.c temphelper.h text_object.c text_object.h timeinfo.c \ - timeinfo.h algebra.c algebra.h + core.c core.h diskio.c diskio.h exec.c exec.h fs.c fs.h logging.h \ + mail.c mail.h mixer.c mixer.h template.c template.h timed_thread.c \ + timed_thread.h mboxscan.c mboxscan.h specials.c specials.h tailhead.c \ + tailhead.h temphelper.c temphelper.h text_object.c text_object.h \ + timeinfo.c timeinfo.h algebra.c algebra.h # source files only needed when the apropriate option is enabled audacious = audacious.c audacious.h diff --git a/src/conky.c b/src/conky.c index 60c62282..bfd0f80b 100644 --- a/src/conky.c +++ b/src/conky.c @@ -76,6 +76,7 @@ #include "build.h" #include "colours.h" #include "diskio.h" +#include "exec.h" #ifdef X11 #include "fonts.h" #endif @@ -163,7 +164,6 @@ double update_interval; double update_interval_old; double update_interval_bat; void *global_cpu = NULL; -pid_t childpid = 0; int argc_copy; char** argv_copy; @@ -631,107 +631,6 @@ static void human_readable(long long num, char *buf, int size) /* global object list root element */ static struct text_object global_root_object; -//our own implementation of popen, the difference : the value of 'childpid' will be filled with -//the pid of the running 'command'. This is useful if want to kill it when it hangs while reading -//or writing to it. We have to kill it because pclose will wait until the process dies by itself -FILE* pid_popen(const char *command, const char *mode, pid_t *child) { - int ends[2]; - int parentend, childend; - - //by running pipe after the strcmp's we make sure that we don't have to create a pipe - //and close the ends if mode is something illegal - if(strcmp(mode, "r") == 0) { - if(pipe(ends) != 0) { - return NULL; - } - parentend = ends[0]; - childend = ends[1]; - } else if(strcmp(mode, "w") == 0) { - if(pipe(ends) != 0) { - return NULL; - } - parentend = ends[1]; - childend = ends[0]; - } else { - return NULL; - } - *child = fork(); - if(*child == -1) { - close(parentend); - close(childend); - return NULL; - } else if(*child > 0) { - close(childend); - waitpid(*child, NULL, 0); - } else { - //don't read from both stdin and pipe or write to both stdout and pipe - if(childend == ends[0]) { - close(0); - } else { - close(1); - } - dup(childend); //by dupping childend, the returned fd will have close-on-exec turned off - execl("/bin/sh", "sh", "-c", command, (char *) NULL); - _exit(EXIT_FAILURE); //child should die here, (normally execl will take care of this but it can fail) - } - return fdopen(parentend, mode); -} - -static inline void read_exec(const char *data, char *buf, const int size) -{ - FILE *fp; - - alarm(update_interval); - fp = pid_popen(data, "r", &childpid); - if(fp) { - int length; - - length = fread(buf, 1, size, fp); - pclose(fp); - buf[length] = '\0'; - if (length > 0 && buf[length - 1] == '\n') { - buf[length - 1] = '\0'; - } - } else { - buf[0] = '\0'; - } - alarm(0); -} - -void do_read_exec(const char *data, char *buf, const int size) -{ - read_exec(data, buf, size); -} - -void *threaded_exec(void *) __attribute__((noreturn)); - -void *threaded_exec(void *arg) -{ - char *buff, *p2; - struct text_object *obj = (struct text_object *)arg; - - while (1) { - buff = malloc(text_buffer_size); - read_exec(obj->data.texeci.cmd, buff, - text_buffer_size); - p2 = buff; - while (*p2) { - if (*p2 == '\001') { - *p2 = ' '; - } - p2++; - } - timed_thread_lock(obj->data.texeci.p_timed_thread); - strncpy(obj->data.texeci.buffer, buff, text_buffer_size); - timed_thread_unlock(obj->data.texeci.p_timed_thread); - free(buff); - if (timed_thread_test(obj->data.texeci.p_timed_thread, 0)) { - timed_thread_exit(obj->data.texeci.p_timed_thread); - } - } - /* never reached */ -} - static long current_text_color; void set_current_text_color(long colour) @@ -893,21 +792,6 @@ char *format_time(unsigned long timeval, const int width) return strndup("", text_buffer_size); } -//remove backspaced chars, example: "dog^H^H^Hcat" becomes "cat" -//string has to end with \0 and it's length should fit in a int -#define BACKSPACE 8 -void remove_deleted_chars(char *string){ - int i = 0; - while(string[i] != 0){ - if(string[i] == BACKSPACE){ - if(i != 0){ - strcpy( &(string[i-1]), &(string[i+1]) ); - i--; - }else strcpy( &(string[i]), &(string[i+1]) ); //necessary for ^H's at the start of a string - }else i++; - } -} - static inline void format_media_player_time(char *buf, const int size, int seconds) { @@ -931,31 +815,6 @@ static inline void format_media_player_time(char *buf, const int size, } } -static inline double get_barnum(char *buf) -{ - char *c = buf; - double barnum; - - while (*c) { - if (*c == '\001') { - *c = ' '; - } - c++; - } - - if (sscanf(buf, "%lf", &barnum) == 0) { - NORM_ERR("reading exec value failed (perhaps it's not the " - "correct format?)"); - return -1; - } - if (barnum > 100.0 || barnum < 0.0) { - NORM_ERR("your exec value is not between 0 and 100, " - "therefore it will be ignored"); - return -1; - } - return barnum; -} - /* substitutes all occurrences of '\n' with SECRIT_MULTILINE_CHAR, which allows * multiline objects like $exec work with $align[rc] and friends */ @@ -1503,206 +1362,43 @@ static void generate_text_internal(char *p, int p_max_size, evaluate(obj->data.s, p); } OBJ(exec) { - read_exec(obj->data.s, p, text_buffer_size); - remove_deleted_chars(p); + print_exec(obj, p, p_max_size); } OBJ(execp) { - struct information *tmp_info; - struct text_object subroot; - - read_exec(obj->data.s, p, text_buffer_size); - - tmp_info = malloc(sizeof(struct information)); - memcpy(tmp_info, cur, sizeof(struct information)); - parse_conky_vars(&subroot, p, p, tmp_info); - - free_text_objects(&subroot, 1); - free(tmp_info); + print_execp(obj, p, p_max_size); } #ifdef X11 OBJ(execgauge) { - double barnum; - - read_exec(obj->data.s, p, text_buffer_size); - barnum = get_barnum(p); /*using the same function*/ - - if (barnum >= 0.0) { - barnum /= 100; - new_gauge(p, obj->a, obj->b, round_to_int(barnum * 255.0)); - } + print_execgauge(obj, p, p_max_size); } #endif /* X11 */ OBJ(execbar) { - double barnum; - - read_exec(obj->data.s, p, text_buffer_size); - barnum = get_barnum(p); - - if (barnum >= 0.0) { -#ifdef X11 - if(output_methods & TO_X) { - barnum /= 100; - new_bar(p, obj->a, obj->b, round_to_int(barnum * 255.0)); - }else{ -#endif /* X11 */ - if(!obj->a) obj->a = DEFAULT_BAR_WIDTH_NO_X; - new_bar_in_shell(p, p_max_size, barnum, obj->a); -#ifdef X11 - } -#endif /* X11 */ - } + print_execbar(obj, p, p_max_size); } #ifdef X11 OBJ(execgraph) { - char showaslog = FALSE; - char tempgrad = FALSE; - double barnum; - char *cmd = obj->data.s; - - if (strstr(cmd, " "TEMPGRAD) && strlen(cmd) > strlen(" "TEMPGRAD)) { - tempgrad = TRUE; - cmd += strlen(" "TEMPGRAD); - } - if (strstr(cmd, " "LOGGRAPH) && strlen(cmd) > strlen(" "LOGGRAPH)) { - showaslog = TRUE; - cmd += strlen(" "LOGGRAPH); - } - read_exec(cmd, p, text_buffer_size); - barnum = get_barnum(p); - - if (barnum > 0) { - new_graph(p, obj->a, obj->b, obj->c, obj->d, round_to_int(barnum), - 100, 1, showaslog, tempgrad); - } + print_execgraph(obj, p, p_max_size); } #endif /* X11 */ OBJ(execibar) { - if (current_update_time - obj->data.execi.last_update - >= obj->data.execi.interval) { - double barnum; - - read_exec(obj->data.execi.cmd, p, text_buffer_size); - barnum = get_barnum(p); - - if (barnum >= 0.0) { - obj->f = barnum; - } - obj->data.execi.last_update = current_update_time; - } -#ifdef X11 - if(output_methods & TO_X) { - new_bar(p, obj->a, obj->b, round_to_int(obj->f * 2.55)); - } else { -#endif /* X11 */ - if(!obj->a) obj->a = DEFAULT_BAR_WIDTH_NO_X; - new_bar_in_shell(p, p_max_size, round_to_int(obj->f), obj->a); -#ifdef X11 - } -#endif /* X11 */ + print_execibar(obj, p, p_max_size); } #ifdef X11 OBJ(execigraph) { - if (current_update_time - obj->data.execi.last_update - >= obj->data.execi.interval) { - double barnum; - char showaslog = FALSE; - char tempgrad = FALSE; - char *cmd = obj->data.execi.cmd; - - if (strstr(cmd, " "TEMPGRAD) && strlen(cmd) > strlen(" "TEMPGRAD)) { - tempgrad = TRUE; - cmd += strlen(" "TEMPGRAD); - } - if (strstr(cmd, " "LOGGRAPH) && strlen(cmd) > strlen(" "LOGGRAPH)) { - showaslog = TRUE; - cmd += strlen(" "LOGGRAPH); - } - obj->char_a = showaslog; - obj->char_b = tempgrad; - read_exec(cmd, p, text_buffer_size); - barnum = get_barnum(p); - - if (barnum >= 0.0) { - obj->f = barnum; - } - obj->data.execi.last_update = current_update_time; - } - new_graph(p, obj->a, obj->b, obj->c, obj->d, (int) (obj->f), 100, 1, obj->char_a, obj->char_b); + print_execigraph(obj, p, p_max_size); } OBJ(execigauge) { - if (current_update_time - obj->data.execi.last_update - >= obj->data.execi.interval) { - double barnum; - - read_exec(obj->data.execi.cmd, p, text_buffer_size); - barnum = get_barnum(p); - - if (barnum >= 0.0) { - obj->f = 255 * barnum / 100.0; - } - obj->data.execi.last_update = current_update_time; - } - new_gauge(p, obj->a, obj->b, round_to_int(obj->f)); + print_execigauge(obj, p, p_max_size); } #endif /* X11 */ OBJ(execi) { - if (current_update_time - obj->data.execi.last_update - >= obj->data.execi.interval - && obj->data.execi.interval != 0) { - read_exec(obj->data.execi.cmd, obj->data.execi.buffer, - text_buffer_size); - obj->data.execi.last_update = current_update_time; - } - snprintf(p, text_buffer_size, "%s", obj->data.execi.buffer); + print_execi(obj, p, p_max_size); } OBJ(execpi) { - struct text_object subroot; - struct information *tmp_info = - malloc(sizeof(struct information)); - memcpy(tmp_info, cur, sizeof(struct information)); - - if (current_update_time - obj->data.execi.last_update - < obj->data.execi.interval - || obj->data.execi.interval == 0) { - parse_conky_vars(&subroot, obj->data.execi.buffer, p, tmp_info); - } else { - char *output = obj->data.execi.buffer; - FILE *fp = pid_popen(obj->data.execi.cmd, "r", &childpid); - int length = fread(output, 1, text_buffer_size, fp); - - pclose(fp); - - output[length] = '\0'; - if (length > 0 && output[length - 1] == '\n') { - output[length - 1] = '\0'; - } - - parse_conky_vars(&subroot, obj->data.execi.buffer, p, tmp_info); - obj->data.execi.last_update = current_update_time; - } - free_text_objects(&subroot, 1); - free(tmp_info); + print_execpi(obj, p); } OBJ(texeci) { - if (!obj->data.texeci.p_timed_thread) { - obj->data.texeci.p_timed_thread = - timed_thread_create(&threaded_exec, - (void *) obj, obj->data.texeci.interval * 1000000); - if (!obj->data.texeci.p_timed_thread) { - NORM_ERR("Error creating texeci timed thread"); - } - /* - * note that we don't register this thread with the - * timed_thread list, because we destroy it manually - */ - if (timed_thread_run(obj->data.texeci.p_timed_thread)) { - NORM_ERR("Error running texeci timed thread"); - } - } else { - timed_thread_lock(obj->data.texeci.p_timed_thread); - snprintf(p, text_buffer_size, "%s", obj->data.texeci.buffer); - timed_thread_unlock(obj->data.texeci.p_timed_thread); - } + print_texeci(obj, p, p_max_size); } OBJ(imap_unseen) { struct mail_s *mail = ensure_mail_thread(obj, imap_thread, "imap"); diff --git a/src/conky.h b/src/conky.h index f0a850f6..fa8c5b29 100644 --- a/src/conky.h +++ b/src/conky.h @@ -336,9 +336,6 @@ extern unsigned int max_user_text; /* path to config file */ extern char *current_config; -/* just a wrapper for read_exec() defined in conky.c */ -void do_read_exec(const char *data, char *buf, const int size); - #ifdef X11 #define TO_X 1 #endif /* X11 */ @@ -367,4 +364,7 @@ void set_update_interval(double interval); #define UNUSED(a) (void)a #define UNUSED_ATTR __attribute__ ((unused)) +void parse_conky_vars(struct text_object *, const char *, + char *, struct information *); + #endif /* _conky_h_ */ diff --git a/src/core.c b/src/core.c index 42d4a8af..f245be86 100644 --- a/src/core.c +++ b/src/core.c @@ -35,6 +35,7 @@ #include "build.h" #include "colours.h" #include "diskio.h" +#include "exec.h" #ifdef X11 #include "fonts.h" #endif @@ -596,117 +597,39 @@ struct text_object *construct_text_object(const char *s, const char *arg, long obj->data.s = strndup(arg ? arg : "", text_buffer_size); #endif /* IMLIB2 */ END OBJ(exec, 0) - obj->data.s = strndup(arg ? arg : "", text_buffer_size); + scan_exec_arg(obj, arg); END OBJ(execp, 0) - obj->data.s = strndup(arg ? arg : "", text_buffer_size); + scan_exec_arg(obj, arg); END OBJ(execbar, 0) SIZE_DEFAULTS(bar); - obj->data.s = strndup(arg ? arg : "", text_buffer_size); + scan_exec_arg(obj, arg); #ifdef X11 END OBJ(execgauge, 0) SIZE_DEFAULTS(gauge); - obj->data.s = strndup(arg ? arg : "", text_buffer_size); + scan_exec_arg(obj, arg); END OBJ(execgraph, 0) SIZE_DEFAULTS(graph); - obj->data.s = strndup(arg ? arg : "", text_buffer_size); + scan_exec_arg(obj, arg); #endif /* X11 */ - END OBJ(execibar, 0) - int n; + END OBJ_ARG(execibar, 0, "execibar needs arguments") SIZE_DEFAULTS(bar); - - if (!arg || sscanf(arg, "%f %n", &obj->data.execi.interval, &n) <= 0) { - char buf[256]; - - NORM_ERR("${execibar command}"); - obj->type = OBJ_text; - snprintf(buf, 256, "${%s}", s); - obj->data.s = strndup(buf, text_buffer_size); - } else { - obj->data.execi.cmd = strndup(arg + n, text_buffer_size); - } + scan_execi_arg(obj, arg); #ifdef X11 - END OBJ(execigraph, 0) - int n; + END OBJ_ARG(execigraph, 0, "execigraph needs arguments") SIZE_DEFAULTS(graph); - - if (!arg || sscanf(arg, "%f %n", &obj->data.execi.interval, &n) <= 0) { - char buf[256]; - - NORM_ERR("${execigraph command}"); - obj->type = OBJ_text; - snprintf(buf, 256, "${%s}", s); - obj->data.s = strndup(buf, text_buffer_size); - } else { - obj->data.execi.cmd = strndup(arg + n, text_buffer_size); - } - END OBJ(execigauge, 0) - int n; + scan_execi_arg(obj, arg); + END OBJ_ARG(execigauge, 0, "execigauge needs arguments") SIZE_DEFAULTS(gauge); - - if (!arg || sscanf(arg, "%f %n", &obj->data.execi.interval, &n) <= 0) { - char buf[256]; - - NORM_ERR("${execigauge command}"); - obj->type = OBJ_text; - snprintf(buf, 256, "${%s}", s); - obj->data.s = strndup(buf, text_buffer_size); - } else { - obj->data.execi.cmd = strndup(arg + n, text_buffer_size); - } + scan_execi_arg(obj, arg); #endif /* X11 */ - END OBJ(execi, 0) - int n; - - if (!arg || sscanf(arg, "%f %n", &obj->data.execi.interval, &n) <= 0) { - char buf[256]; - - NORM_ERR("${execi command}"); - obj->type = OBJ_text; - snprintf(buf, 256, "${%s}", s); - obj->data.s = strndup(buf, text_buffer_size); - } else { - obj->data.execi.cmd = strndup(arg + n, text_buffer_size); - obj->data.execi.buffer = malloc(text_buffer_size); - } - END OBJ(execpi, 0) - int n; - - if (!arg || sscanf(arg, "%f %n", &obj->data.execi.interval, &n) <= 0) { - char buf[256]; - - NORM_ERR("${execi command}"); - obj->type = OBJ_text; - snprintf(buf, 256, "${%s}", s); - obj->data.s = strndup(buf, text_buffer_size); - } else { - obj->data.execi.cmd = strndup(arg + n, text_buffer_size); - obj->data.execi.buffer = malloc(text_buffer_size); - } - END OBJ(texeci, 0) - int n; - - if (!arg || sscanf(arg, "%f %n", &obj->data.texeci.interval, &n) <= 0) { - char buf[256]; - - NORM_ERR("${texeci command}"); - obj->type = OBJ_text; - snprintf(buf, 256, "${%s}", s); - obj->data.s = strndup(buf, text_buffer_size); - } else { - obj->data.texeci.cmd = strndup(arg + n, text_buffer_size); - obj->data.texeci.buffer = malloc(text_buffer_size); - } - obj->data.texeci.p_timed_thread = NULL; + END OBJ_ARG(execi, 0, "execi needs arguments") + scan_execi_arg(obj, arg); + END OBJ_ARG(execpi, 0, "execpi needs arguments") + scan_execi_arg(obj, arg); + END OBJ_ARG(texeci, 0, "texeci needs arguments") + scan_execi_arg(obj, arg); END OBJ(pre_exec, 0) - obj->type = OBJ_text; - if (arg) { - char buf[2048]; - - do_read_exec(arg, buf, sizeof(buf)); - obj->data.s = strndup(buf, text_buffer_size); - } else { - obj->data.s = strndup("", text_buffer_size); - } + scan_pre_exec_arg(obj, arg); END OBJ(fs_bar, &update_fs_stats) init_fs_bar(obj, arg); END OBJ(fs_bar_free, &update_fs_stats) @@ -1956,7 +1879,7 @@ void free_text_objects(struct text_object *root, int internal) case OBJ_execgraph: #endif case OBJ_execp: - free(data.s); + free_exec(obj); break; #ifdef HAVE_ICONV case OBJ_iconv_start: @@ -2118,17 +2041,12 @@ void free_text_objects(struct text_object *root, int internal) case OBJ_execpi: case OBJ_execi: case OBJ_execibar: + case OBJ_texeci: #ifdef X11 case OBJ_execigraph: case OBJ_execigauge: #endif /* X11 */ - free(data.execi.cmd); - free(data.execi.buffer); - break; - case OBJ_texeci: - if (data.texeci.p_timed_thread) timed_thread_destroy(data.texeci.p_timed_thread, &data.texeci.p_timed_thread); - free(data.texeci.cmd); - free(data.texeci.buffer); + free_execi(obj); break; case OBJ_nameserver: free_dns_data(); diff --git a/src/exec.c b/src/exec.c new file mode 100644 index 00000000..1867176d --- /dev/null +++ b/src/exec.c @@ -0,0 +1,455 @@ +/* -*- 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 + * + * All code written since the fork of torsmo is licensed under the GPL + * + * Please see COPYING for details + * + * Copyright (c) 2004, Hannu Saransaari and Lauri Hakkarainen + * Copyright (c) 2005-2009 Brenden Matthews, Philip Kovacs, et. al. + * (see AUTHORS) + * All rights reserved. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +#include "conky.h" +#include "core.h" +#include "logging.h" +#include "specials.h" +#include "text_object.h" +#include +#include +#include + +/* FIXME: this will probably not work, since the variable is being reused + * between different text objects. So when a process really hangs, it's PID + * will be overwritten at the next iteration. */ +pid_t childpid = 0; + +//our own implementation of popen, the difference : the value of 'childpid' will be filled with +//the pid of the running 'command'. This is useful if want to kill it when it hangs while reading +//or writing to it. We have to kill it because pclose will wait until the process dies by itself +static FILE* pid_popen(const char *command, const char *mode, pid_t *child) { + int ends[2]; + int parentend, childend; + + //by running pipe after the strcmp's we make sure that we don't have to create a pipe + //and close the ends if mode is something illegal + if(strcmp(mode, "r") == 0) { + if(pipe(ends) != 0) { + return NULL; + } + parentend = ends[0]; + childend = ends[1]; + } else if(strcmp(mode, "w") == 0) { + if(pipe(ends) != 0) { + return NULL; + } + parentend = ends[1]; + childend = ends[0]; + } else { + return NULL; + } + *child = fork(); + if(*child == -1) { + close(parentend); + close(childend); + return NULL; + } else if(*child > 0) { + close(childend); + waitpid(*child, NULL, 0); + } else { + //don't read from both stdin and pipe or write to both stdout and pipe + if(childend == ends[0]) { + close(0); + } else { + close(1); + } + dup(childend); //by dupping childend, the returned fd will have close-on-exec turned off + execl("/bin/sh", "sh", "-c", command, (char *) NULL); + _exit(EXIT_FAILURE); //child should die here, (normally execl will take care of this but it can fail) + } + return fdopen(parentend, mode); +} + +//remove backspaced chars, example: "dog^H^H^Hcat" becomes "cat" +//string has to end with \0 and it's length should fit in a int +#define BACKSPACE 8 +static void remove_deleted_chars(char *string){ + int i = 0; + while(string[i] != 0){ + if(string[i] == BACKSPACE){ + if(i != 0){ + strcpy( &(string[i-1]), &(string[i+1]) ); + i--; + }else strcpy( &(string[i]), &(string[i+1]) ); //necessary for ^H's at the start of a string + }else i++; + } +} + +static inline double get_barnum(char *buf) +{ + char *c = buf; + double barnum; + + while (*c) { + if (*c == '\001') { + *c = ' '; + } + c++; + } + + if (sscanf(buf, "%lf", &barnum) == 0) { + NORM_ERR("reading exec value failed (perhaps it's not the " + "correct format?)"); + return -1; + } + if (barnum > 100.0 || barnum < 0.0) { + NORM_ERR("your exec value is not between 0 and 100, " + "therefore it will be ignored"); + return -1; + } + return barnum; +} + +static inline void read_exec(const char *data, char *buf, const int size) +{ + FILE *fp; + + memset(buf, 0, size); + + if (!data) + return; + + alarm(update_interval); + fp = pid_popen(data, "r", &childpid); + if(fp) { + int length; + + length = fread(buf, 1, size, fp); + pclose(fp); + buf[length] = '\0'; + if (length > 0 && buf[length - 1] == '\n') { + buf[length - 1] = '\0'; + } + } else { + buf[0] = '\0'; + } + alarm(0); +} + +static void *threaded_exec(void *) __attribute__((noreturn)); + +static void *threaded_exec(void *arg) +{ + char *buff, *p2; + struct text_object *obj = arg; + + while (1) { + buff = malloc(text_buffer_size); + read_exec(obj->data.execi.cmd, buff, text_buffer_size); + p2 = buff; + while (*p2) { + if (*p2 == '\001') { + *p2 = ' '; + } + p2++; + } + timed_thread_lock(obj->data.execi.p_timed_thread); + if (obj->data.execi.buffer) + free(obj->data.execi.buffer); + obj->data.execi.buffer = buff; + timed_thread_unlock(obj->data.execi.p_timed_thread); + if (timed_thread_test(obj->data.execi.p_timed_thread, 0)) { + timed_thread_exit(obj->data.execi.p_timed_thread); + } + } + /* never reached */ +} + +/* check the execi fields and return true if the given interval has passed */ +static int time_to_update(struct text_object *obj) +{ + if (!obj->data.execi.interval) + return 0; + if (current_update_time - obj->data.execi.last_update >= obj->data.execi.interval) + return 1; + return 0; +} + +void scan_exec_arg(struct text_object *obj, const char *arg) +{ + obj->data.s = strndup(arg ? arg : "", text_buffer_size); +} + +void scan_pre_exec_arg(struct text_object *obj, const char *arg) +{ + char buf[2048]; + + obj->type = OBJ_text; + read_exec(arg, buf, sizeof(buf)); + obj->data.s = strndup(buf, text_buffer_size); +} + +void scan_execi_arg(struct text_object *obj, const char *arg) +{ + int n; + + if (sscanf(arg, "%f %n", &obj->data.execi.interval, &n) <= 0) { + NORM_ERR("${execi* command}"); + return; + } + obj->data.execi.cmd = strndup(arg + n, text_buffer_size); +} + +void print_exec(struct text_object *obj, char *p, int p_max_size) +{ + read_exec(obj->data.s, p, p_max_size); + remove_deleted_chars(p); +} + +void print_execp(struct text_object *obj, char *p, int p_max_size) +{ + struct information *tmp_info; + struct text_object subroot; + + read_exec(obj->data.s, p, p_max_size); + + tmp_info = malloc(sizeof(struct information)); + memcpy(tmp_info, &info, sizeof(struct information)); + parse_conky_vars(&subroot, p, p, tmp_info); + + free_text_objects(&subroot, 1); + free(tmp_info); +} + +void print_execi(struct text_object *obj, char *p, int p_max_size) +{ + if (time_to_update(obj)) { + if (!obj->data.execi.buffer) + obj->data.execi.buffer = malloc(text_buffer_size); + read_exec(obj->data.execi.cmd, obj->data.execi.buffer, text_buffer_size); + obj->data.execi.last_update = current_update_time; + } + snprintf(p, p_max_size, "%s", obj->data.execi.buffer); +} + +void print_execpi(struct text_object *obj, char *p) +{ + struct text_object subroot; + struct information *tmp_info; + + tmp_info = malloc(sizeof(struct information)); + memcpy(tmp_info, &info, sizeof(struct information)); + + if (!time_to_update(obj)) { + parse_conky_vars(&subroot, obj->data.execi.buffer, p, tmp_info); + } else { + char *output; + int length; + FILE *fp = pid_popen(obj->data.execi.cmd, "r", &childpid); + + if (!obj->data.execi.buffer) + obj->data.execi.buffer = malloc(text_buffer_size); + + length = fread(obj->data.execi.buffer, 1, text_buffer_size, fp); + pclose(fp); + + output = obj->data.execi.buffer; + output[length] = '\0'; + if (length > 0 && output[length - 1] == '\n') { + output[length - 1] = '\0'; + } + + parse_conky_vars(&subroot, obj->data.execi.buffer, p, tmp_info); + obj->data.execi.last_update = current_update_time; + } + free_text_objects(&subroot, 1); + free(tmp_info); +} + +void print_texeci(struct text_object *obj, char *p, int p_max_size) +{ + if (!obj->data.execi.p_timed_thread) { + obj->data.execi.p_timed_thread = + timed_thread_create(&threaded_exec, + (void *) obj, obj->data.execi.interval * 1000000); + if (!obj->data.execi.p_timed_thread) { + NORM_ERR("Error creating texeci timed thread"); + } + /* + * note that we don't register this thread with the + * timed_thread list, because we destroy it manually + */ + if (timed_thread_run(obj->data.execi.p_timed_thread)) { + NORM_ERR("Error running texeci timed thread"); + } + } else { + timed_thread_lock(obj->data.execi.p_timed_thread); + snprintf(p, p_max_size, "%s", obj->data.execi.buffer); + timed_thread_unlock(obj->data.execi.p_timed_thread); + } +} + +#ifdef X11 +void print_execgauge(struct text_object *obj, char *p, int p_max_size) +{ + double barnum; + + read_exec(obj->data.s, p, p_max_size); + barnum = get_barnum(p); /*using the same function*/ + + if (barnum >= 0.0) { + barnum /= 100; + new_gauge(p, obj->a, obj->b, round_to_int(barnum * 255.0)); + } +} + +void print_execgraph(struct text_object *obj, char *p, int p_max_size) +{ + char showaslog = FALSE; + char tempgrad = FALSE; + double barnum; + char *cmd = obj->data.execi.cmd; + + if (strstr(cmd, " "TEMPGRAD) && strlen(cmd) > strlen(" "TEMPGRAD)) { + tempgrad = TRUE; + cmd += strlen(" "TEMPGRAD); + } + if (strstr(cmd, " "LOGGRAPH) && strlen(cmd) > strlen(" "LOGGRAPH)) { + showaslog = TRUE; + cmd += strlen(" "LOGGRAPH); + } + read_exec(cmd, p, p_max_size); + barnum = get_barnum(p); + + if (barnum > 0) { + new_graph(p, obj->a, obj->b, obj->c, obj->d, round_to_int(barnum), + 100, 1, showaslog, tempgrad); + } +} + +void print_execigraph(struct text_object *obj, char *p, int p_max_size) +{ + if (time_to_update(obj)) { + double barnum; + char showaslog = FALSE; + char tempgrad = FALSE; + char *cmd = obj->data.execi.cmd; + + if (strstr(cmd, " "TEMPGRAD) && strlen(cmd) > strlen(" "TEMPGRAD)) { + tempgrad = TRUE; + cmd += strlen(" "TEMPGRAD); + } + if (strstr(cmd, " "LOGGRAPH) && strlen(cmd) > strlen(" "LOGGRAPH)) { + showaslog = TRUE; + cmd += strlen(" "LOGGRAPH); + } + obj->char_a = showaslog; + obj->char_b = tempgrad; + read_exec(cmd, p, p_max_size); + barnum = get_barnum(p); + + if (barnum >= 0.0) { + obj->f = barnum; + } + obj->data.execi.last_update = current_update_time; + } + new_graph(p, obj->a, obj->b, obj->c, obj->d, (int) (obj->f), 100, 1, obj->char_a, obj->char_b); +} + +void print_execigauge(struct text_object *obj, char *p, int p_max_size) +{ + if (time_to_update(obj)) { + double barnum; + + read_exec(obj->data.execi.cmd, p, p_max_size); + barnum = get_barnum(p); + + if (barnum >= 0.0) { + obj->f = 255 * barnum / 100.0; + } + obj->data.execi.last_update = current_update_time; + } + new_gauge(p, obj->a, obj->b, round_to_int(obj->f)); +} +#endif /* X11 */ + +void print_execbar(struct text_object *obj, char *p, int p_max_size) +{ + double barnum; + read_exec(obj->data.s, p, p_max_size); + barnum = get_barnum(p); + + if (barnum >= 0.0) { +#ifdef X11 + if(output_methods & TO_X) { + barnum /= 100; + new_bar(p, obj->a, obj->b, round_to_int(barnum * 255.0)); + }else +#endif /* X11 */ + { + if(!obj->a) obj->a = DEFAULT_BAR_WIDTH_NO_X; + new_bar_in_shell(p, p_max_size, barnum, obj->a); + } + } +} + +void print_execibar(struct text_object *obj, char *p, int p_max_size) +{ + double barnum; + + if (time_to_update(obj)) { + read_exec(obj->data.execi.cmd, p, p_max_size); + barnum = get_barnum(p); + + if (barnum >= 0.0) { + obj->f = barnum; + } + obj->data.execi.last_update = current_update_time; + } +#ifdef X11 + if(output_methods & TO_X) { + new_bar(p, obj->a, obj->b, round_to_int(obj->f * 2.55)); + } else +#endif /* X11 */ + { + if(!obj->a) obj->a = DEFAULT_BAR_WIDTH_NO_X; + new_bar_in_shell(p, p_max_size, round_to_int(obj->f), obj->a); + } +} + +void free_exec(struct text_object *obj) +{ + if (obj->data.s) { + free(obj->data.s); + obj->data.s = NULL; + } +} + +void free_execi(struct text_object *obj) +{ + if (obj->data.execi.p_timed_thread) + timed_thread_destroy(obj->data.execi.p_timed_thread, &obj->data.execi.p_timed_thread); + if (obj->data.execi.cmd) + free(obj->data.execi.cmd); + if (obj->data.execi.buffer) + free(obj->data.execi.buffer); + memset(&obj->data.execi, 0, sizeof(obj->data.execi)); +} diff --git a/src/exec.h b/src/exec.h new file mode 100644 index 00000000..1a174772 --- /dev/null +++ b/src/exec.h @@ -0,0 +1,54 @@ +/* -*- 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 + * + * All code written since the fork of torsmo is licensed under the GPL + * + * Please see COPYING for details + * + * Copyright (c) 2004, Hannu Saransaari and Lauri Hakkarainen + * Copyright (c) 2005-2009 Brenden Matthews, Philip Kovacs, et. al. + * (see AUTHORS) + * All rights reserved. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +#ifndef _EXEC_H +#define _EXEC_H + +extern pid_t childpid; + +void scan_exec_arg(struct text_object *, const char *); +void scan_pre_exec_arg(struct text_object *, const char *); +void scan_execi_arg(struct text_object *, const char *); +void print_exec(struct text_object *, char *, int); +void print_execp(struct text_object *, char *, int); +void print_execi(struct text_object *, char *, int); +void print_execpi(struct text_object *, char *); +void print_texeci(struct text_object *, char *, int); +#ifdef X11 +void print_execgauge(struct text_object *, char *, int); +void print_execgraph(struct text_object *, char *, int); +void print_execigraph(struct text_object *, char *, int); +void print_execigauge(struct text_object *, char *, int); +#endif /* X11 */ +void print_execbar(struct text_object *, char *, int); +void print_execibar(struct text_object *, char *, int); +void free_exec(struct text_object *); +void free_execi(struct text_object *); +#endif /* _EXEC_H */ diff --git a/src/text_object.h b/src/text_object.h index b9c96fbc..2bc36696 100644 --- a/src/text_object.h +++ b/src/text_object.h @@ -511,15 +511,8 @@ struct text_object { char *cmd; char *buffer; double data; - } execi; /* 5 */ - - struct { - float interval; - char *cmd; - char *buffer; - double data; timed_thread *p_timed_thread; - } texeci; + } execi; /* 5 */ struct { int a, b;