# 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
#include "build.h"
#include "colours.h"
#include "diskio.h"
+#include "exec.h"
#ifdef X11
#include "fonts.h"
#endif
double update_interval_old;
double update_interval_bat;
void *global_cpu = NULL;
-pid_t childpid = 0;
int argc_copy;
char** argv_copy;
/* 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)
return strndup("<inf>", 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)
{
}
}
-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
*/
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");
/* 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 */
#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_ */
#include "build.h"
#include "colours.h"
#include "diskio.h"
+#include "exec.h"
#ifdef X11
#include "fonts.h"
#endif
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 <interval> 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 <interval> 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 <interval> 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 <interval> 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 <interval> 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 <interval> 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)
case OBJ_execgraph:
#endif
case OBJ_execp:
- free(data.s);
+ free_exec(obj);
break;
#ifdef HAVE_ICONV
case OBJ_iconv_start:
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();
--- /dev/null
+/* -*- 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 <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "conky.h"
+#include "core.h"
+#include "logging.h"
+#include "specials.h"
+#include "text_object.h"
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+
+/* 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* <interval> 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));
+}
--- /dev/null
+/* -*- 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 <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#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 */
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;