summaryrefslogtreecommitdiffstats
path: root/src/lib
diff options
context:
space:
mode:
authorKarel Klic <kklic@redhat.com>2011-03-09 16:49:41 +0100
committerKarel Klic <kklic@redhat.com>2011-03-09 16:58:28 +0100
commit43d84e3f11e46b7c9a042ff338024dfc41bb4f22 (patch)
tree783b1122556f15345290ff8b1623812b6e864827 /src/lib
parent6ec12db137f2d0fe18f059fcef2390512d0b2c3f (diff)
parentc2f2a9f310e7b3bc3725cc8dc7e805fd38c7fbbd (diff)
downloadabrt-43d84e3f11e46b7c9a042ff338024dfc41bb4f22.tar.gz
abrt-43d84e3f11e46b7c9a042ff338024dfc41bb4f22.tar.xz
abrt-43d84e3f11e46b7c9a042ff338024dfc41bb4f22.zip
Merge branch 'master' of ssh://git.fedorahosted.org/git/abrt
Diffstat (limited to 'src/lib')
-rw-r--r--src/lib/Makefile.am23
-rw-r--r--src/lib/crash_data.c13
-rw-r--r--src/lib/event_config.c135
-rw-r--r--src/lib/event_xml_parser.c203
-rw-r--r--src/lib/load_plugin_settings.c52
-rw-r--r--src/lib/run_event.c46
-rw-r--r--src/lib/spawn.c12
-rw-r--r--src/lib/xfuncs.c14
8 files changed, 437 insertions, 61 deletions
diff --git a/src/lib/Makefile.am b/src/lib/Makefile.am
index bad3e63a..36fe7b4b 100644
--- a/src/lib/Makefile.am
+++ b/src/lib/Makefile.am
@@ -43,16 +43,19 @@ libreport_la_SOURCES = \
hooklib.c hooklib.h \
parse_release.c \
parse_options.c parse_options.h \
- steal_directory.c
+ steal_directory.c \
+ event_xml_parser.c \
+ event_config.c
libreport_la_CPPFLAGS = \
- -Wall -Werror \
+ -Wall -Wwrite-strings -Werror \
-I$(srcdir)/../include/report -I$(srcdir)/../include \
+ -DLOCALSTATEDIR='"$(localstatedir)"' \
+ -DVAR_RUN=\"$(VAR_RUN)\" \
-DDEBUG_DUMPS_DIR=\"$(DEBUG_DUMPS_DIR)\" \
-DPLUGINS_LIB_DIR=\"$(PLUGINS_LIB_DIR)\" \
-DPLUGINS_CONF_DIR=\"$(PLUGINS_CONF_DIR)\" \
- -DLOCALSTATEDIR='"$(localstatedir)"' \
-DCONF_DIR=\"$(CONF_DIR)\" \
- -DVAR_RUN=\"$(VAR_RUN)\" \
+ -DEVENTS_DIR=\"$(EVENTS_DIR)\" \
$(GLIB_CFLAGS) \
-D_GNU_SOURCE
libreport_la_LDFLAGS = \
@@ -64,14 +67,16 @@ libabrt_dbus_la_SOURCES = \
abrt_dbus.c abrt_dbus.h
libabrt_dbus_la_CPPFLAGS = \
-I$(srcdir)/../include/report -I$(srcdir)/../include \
+ -DLOCALSTATEDIR='"$(localstatedir)"' \
+ -DVAR_RUN=\"$(VAR_RUN)\" \
-DDEBUG_DUMPS_DIR=\"$(DEBUG_DUMPS_DIR)\" \
-DPLUGINS_LIB_DIR=\"$(PLUGINS_LIB_DIR)\" \
-DPLUGINS_CONF_DIR=\"$(PLUGINS_CONF_DIR)\" \
-DCONF_DIR=\"$(CONF_DIR)\" \
- -DVAR_RUN=\"$(VAR_RUN)\" \
+ -DEVENTS_DIR=\"$(EVENTS_DIR)\" \
$(GLIB_CFLAGS) \
$(DBUS_CFLAGS) \
- -Wall -Werror \
+ -Wall -Wwrite-strings -Werror \
-D_GNU_SOURCE
libabrt_dbus_la_LDFLAGS = \
-version-info 0:1:0
@@ -83,13 +88,15 @@ libabrt_web_la_SOURCES = \
abrt_curl.h abrt_curl.c \
abrt_xmlrpc.h abrt_xmlrpc.cpp
libabrt_web_la_CPPFLAGS = \
- -Wall -Werror \
+ -Wall -Wwrite-strings -Werror \
-I$(srcdir)/../include/report -I$(srcdir)/../include \
+ -DLOCALSTATEDIR='"$(localstatedir)"' \
+ -DVAR_RUN=\"$(VAR_RUN)\" \
-DDEBUG_DUMPS_DIR=\"$(DEBUG_DUMPS_DIR)\" \
-DPLUGINS_LIB_DIR=\"$(PLUGINS_LIB_DIR)\" \
-DPLUGINS_CONF_DIR=\"$(PLUGINS_CONF_DIR)\" \
-DCONF_DIR=\"$(CONF_DIR)\" \
- -DVAR_RUN=\"$(VAR_RUN)\" \
+ -DEVENTS_DIR=\"$(EVENTS_DIR)\" \
$(GLIB_CFLAGS) \
$(CURL_CFLAGS) \
$(LIBXML_CFLAGS) \
diff --git a/src/lib/crash_data.c b/src/lib/crash_data.c
index 63b0a7a5..7f23c52f 100644
--- a/src/lib/crash_data.c
+++ b/src/lib/crash_data.c
@@ -233,10 +233,21 @@ void load_crash_data_from_dump_dir(crash_data_t *crash_data, struct dump_dir *dd
content = dd_load_text(dd, short_name);
}
+ int flags = 0;
+
+ if (editable)
+ flags |= CD_FLAG_TXT | CD_FLAG_ISEDITABLE;
+ else
+ flags |= CD_FLAG_TXT | CD_FLAG_ISNOTEDITABLE;
+
+ int oneline = strchr(content, '\n') == NULL;
+ if (oneline)
+ flags |= CD_FLAG_ONELINE;
+
add_to_crash_data_ext(crash_data,
short_name,
content,
- (editable ? CD_FLAG_TXT + CD_FLAG_ISEDITABLE : CD_FLAG_TXT + CD_FLAG_ISNOTEDITABLE)
+ flags
);
free(short_name);
free(full_name);
diff --git a/src/lib/event_config.c b/src/lib/event_config.c
new file mode 100644
index 00000000..a79ee40c
--- /dev/null
+++ b/src/lib/event_config.c
@@ -0,0 +1,135 @@
+#include "abrtlib.h"
+
+GHashTable *g_event_config_list;
+
+event_option_t *new_event_option(void)
+{
+ return xzalloc(sizeof(event_option_t));
+}
+
+event_config_t *new_event_config(void)
+{
+ return xzalloc(sizeof(event_config_t));
+}
+
+void free_event_option(event_option_t *p)
+{
+ if (!p)
+ return;
+ free(p->name);
+ free(p->value);
+ free(p->label);
+ free(p->description);
+ free(p->allowed_value);
+ free(p);
+}
+
+void free_event_config(event_config_t *p)
+{
+ if (!p)
+ return;
+ free(p->name);
+ free(p->title);
+ free(p->action);
+ free(p->description);
+ for (GList *opt = p->options; opt; opt = opt->next)
+ free_event_option(opt->data);
+ g_list_free(p->options);
+ free(p);
+}
+
+
+// (Re)loads data from /etc/abrt/events/*.{conf,xml}
+void load_event_config_data(void)
+{
+ free_event_config_data();
+
+ DIR *dir = opendir(EVENTS_DIR);
+ if (!dir)
+ return;
+
+ if (!g_event_config_list)
+ g_event_config_list = g_hash_table_new_full(
+ /*hash_func*/ g_str_hash,
+ /*key_equal_func:*/ g_str_equal,
+ /*key_destroy_func:*/ free,
+ /*value_destroy_func:*/ (GDestroyNotify) free_event_config
+ );
+
+ struct dirent *dent;
+ while ((dent = readdir(dir)) != NULL)
+ {
+ char *ext = strrchr(dent->d_name, '.');
+ if (!ext)
+ continue;
+ bool conf = strcmp(ext + 1, "conf") == 0;
+ bool xml = strcmp(ext + 1, "xml") == 0;
+ if (!conf && !xml)
+ continue;
+
+ char *fullname = concat_path_file(EVENTS_DIR, dent->d_name);
+
+ *ext = '\0';
+ event_config_t *event_config = get_event_config(dent->d_name);
+ bool new_config = (!event_config);
+ if (new_config)
+ event_config = new_event_config();
+
+ if (xml)
+ load_event_description_from_file(event_config, fullname);
+ if (conf)
+ {
+ map_string_h *keys_and_values = new_map_string();
+
+ load_conf_file(fullname, keys_and_values, /*skipKeysWithoutValue:*/ false);
+
+ /* Insert or replace every key/value from keys_and_values to event_config->option */
+ GHashTableIter iter;
+ char *name;
+ char *value;
+ g_hash_table_iter_init(&iter, keys_and_values);
+ while (g_hash_table_iter_next(&iter, (void**)&name, (void**)&value))
+ {
+ event_option_t *opt;
+ GList *elem = g_list_find(event_config->options, name);
+ if (elem)
+ {
+ opt = elem->data;
+ free(opt->value);
+ }
+ else
+ {
+ opt = new_event_option();
+ opt->name = xstrdup(name);
+ }
+ opt->value = xstrdup(value);
+ if (!elem)
+ event_config->options = g_list_append(event_config->options, opt);
+ }
+
+ free_map_string(keys_and_values);
+ }
+
+ free(fullname);
+
+ if (new_config)
+ g_hash_table_replace(g_event_config_list, xstrdup(dent->d_name), event_config);
+ }
+}
+
+/* Frees all loaded data */
+void free_event_config_data(void)
+{
+ if (g_event_config_list)
+ {
+ g_hash_table_destroy(g_event_config_list);
+ g_event_config_list = NULL;
+ }
+}
+
+event_config_t *get_event_config(const char *name)
+{
+ if (!g_event_config_list)
+ return NULL;
+ return g_hash_table_lookup(g_event_config_list, name);
+}
diff --git a/src/lib/event_xml_parser.c b/src/lib/event_xml_parser.c
new file mode 100644
index 00000000..be4a9e09
--- /dev/null
+++ b/src/lib/event_xml_parser.c
@@ -0,0 +1,203 @@
+#include "abrtlib.h"
+#include "event_config.h"
+
+#define EVENT_ELEMENT "event"
+#define LABEL_ELEMENT "label"
+#define DESCRIPTION_ELEMENT "description"
+#define ALLOW_EMPTY_ELEMENT "allow-empty"
+#define OPTION_ELEMENT "option"
+#define ACTION_ELEMENT "action"
+#define NAME_ELEMENT "name"
+
+static int in_option = 0; //FIXME
+
+static const char *const option_types[] =
+{
+ "text",
+ "bool",
+ "password",
+ "number",
+ NULL
+};
+
+// Called for open tags <foo bar="baz">
+static void start_element(GMarkupParseContext *context,
+ const gchar *element_name,
+ const gchar **attribute_names,
+ const gchar **attribute_values,
+ gpointer user_data,
+ GError **error)
+{
+ //g_print("start: %s\n", element_name);
+
+ event_config_t *ui = user_data;
+
+ if (strcmp(element_name, OPTION_ELEMENT) == 0)
+ {
+ if (in_option == 0)
+ {
+ in_option = 1;
+ event_option_t *option = new_event_option();
+ //we need to prepend, so ui->options always points to the last created option
+ VERB2 log("adding option");
+ ui->options = g_list_prepend(ui->options, option);
+
+ int i;
+ for (i = 0; attribute_names[i] != NULL; ++i)
+ {
+ VERB2 log("attr: %s:%s", attribute_names[i], attribute_values[i]);
+ if (strcmp(attribute_names[i], "name") == 0)
+ {
+ free(option->name);
+ option->name = xstrdup(attribute_values[i]);
+ }
+ else if (strcmp(attribute_names[i], "type") == 0)
+ {
+ option_type_t type;
+ for (type = OPTION_TYPE_TEXT; type < OPTION_TYPE_INVALID; ++type)
+ {
+ if (strcmp(option_types[type], attribute_values[i]) == 0)
+ option->type = type;
+ }
+ }
+ }
+ }
+ else
+ {
+ error_msg("error, option nested in option");
+ }
+ }
+
+}
+
+// Called for close tags </foo>
+static void end_element(GMarkupParseContext *context,
+ const gchar *element_name,
+ gpointer user_data,
+ GError **error)
+{
+ event_config_t *ui = user_data;
+ if (strcmp(element_name, OPTION_ELEMENT) == 0)
+ {
+ in_option = 0;
+ }
+ if (strcmp(element_name, EVENT_ELEMENT) == 0)
+ {
+ //we need to reverse the list, because we we're prepending
+ ui->options = g_list_reverse(ui->options);
+ in_option = 0;
+ }
+}
+
+// Called for character data
+// text is not nul-terminated
+static void text(GMarkupParseContext *context,
+ const gchar *text,
+ gsize text_len,
+ gpointer user_data,
+ GError **error)
+{
+ event_config_t *ui = user_data;
+ const gchar * inner_element = g_markup_parse_context_get_element(context);
+ char *_text = xstrndup(text, text_len);
+ if (in_option == 1)
+ {
+ event_option_t *option = ui->options->data;
+ if (strcmp(inner_element, LABEL_ELEMENT) == 0)
+ {
+ VERB2 log("new label:'%s'", _text);
+ free(option->label);
+ option->label = _text;
+ return;
+ }
+ if (strcmp(inner_element, DESCRIPTION_ELEMENT) == 0)
+ {
+ VERB2 log("tooltip:'%s'", _text);
+ free(option->description);
+ option->description = _text;
+ return;
+ }
+ }
+ else
+ {
+ /* we're not in option, so the description is for the event */
+ if (strcmp(inner_element, ACTION_ELEMENT) == 0)
+ {
+ VERB2 log("action description:'%s'", _text);
+ free(ui->action);
+ ui->action = _text;
+ return;
+ }
+ if (strcmp(inner_element, NAME_ELEMENT) == 0)
+ {
+ VERB2 log("event name:'%s'", _text);
+ free(ui->name);
+ ui->name = _text;
+ return;
+ }
+ if (strcmp(inner_element, DESCRIPTION_ELEMENT) == 0)
+ {
+ VERB2 log("event description:'%s'", _text);
+ free(ui->description);
+ ui->description = _text;
+ return;
+ }
+ }
+ free(_text);
+}
+
+ // Called for strings that should be re-saved verbatim in this same
+ // position, but are not otherwise interpretable. At the moment
+ // this includes comments and processing instructions.
+ // text is not nul-terminated
+static void passthrough(GMarkupParseContext *context,
+ const gchar *passthrough_text,
+ gsize text_len,
+ gpointer user_data,
+ GError **error)
+{
+ VERB2 log("passthrough");
+}
+
+// Called on error, including one set by other
+// methods in the vtable. The GError should not be freed.
+static void error(GMarkupParseContext *context,
+ GError *error,
+ gpointer user_data)
+{
+ error_msg("error in XML parsing");
+}
+
+/* this function takes 2 parameters
+ * ui -> pointer to event_config_t
+ * filename -> filename to read
+ * event_config_t contains list of options, which is malloced by hits function
+ * and must be freed by the caller
+ */
+
+void load_event_description_from_file(event_config_t *event_config, const char* filename)
+{
+ GMarkupParser parser;
+ parser.start_element = &start_element;
+ parser.end_element = &end_element;
+ parser.text = &text;
+ parser.passthrough = &passthrough;
+ parser.error = &error;
+ GMarkupParseContext *context = g_markup_parse_context_new(
+ &parser, G_MARKUP_TREAT_CDATA_AS_TEXT,
+ event_config, /*GDestroyNotify:*/ NULL);
+
+ FILE* fin = fopen(filename, "r");
+ if (fin != NULL)
+ {
+ size_t read_bytes = 0;
+ char buff[1024];
+ while ((read_bytes = fread(buff, 1, 1024, fin)) != 0)
+ {
+ g_markup_parse_context_parse(context, buff, read_bytes, NULL);
+ }
+ fclose(fin);
+ }
+
+ g_markup_parse_context_free(context);
+}
diff --git a/src/lib/load_plugin_settings.c b/src/lib/load_plugin_settings.c
index 1e6b31e7..1b6086f9 100644
--- a/src/lib/load_plugin_settings.c
+++ b/src/lib/load_plugin_settings.c
@@ -34,47 +34,47 @@ bool load_conf_file(const char *pPath, map_string_h *settings, bool skipKeysWith
char *line;
while ((line = xmalloc_fgetline(fp)) != NULL)
{
- unsigned ii;
- bool valid = false;
bool in_quote = false;
/* We are reusing line buffer to form temporary
* "key\0value\0..." in its beginning
*/
- char *key = line;
- char *value = line;
- char *cur = line;
-
- for (ii = 0; line[ii] != '\0'; ii++)
+ char *value = NULL;
+ char *src;
+ char *dst;
+ for (src = dst = line; *src; src++)
{
- if (line[ii] == '"')
+ char c = *src;
+ if (c == '"')
{
in_quote = !in_quote;
}
- if (isspace(line[ii]) && !in_quote)
- {
- continue;
- }
- if (line[ii] == '#' && !in_quote && cur == line)
- {
- break;
- }
- if (line[ii] == '=' && !in_quote)
+ if (!in_quote)
{
- valid = true;
- *cur++ = '\0'; /* terminate key */
- value = cur; /* remember where value starts */
- continue;
+ if (isspace(c))
+ {
+ continue;
+ }
+ if (c == '#' && dst == line)
+ {
+ break;
+ }
+ if (c == '=')
+ {
+ *dst++ = '\0'; /* terminate key */
+ value = dst; /* remember where value starts */
+ continue;
+ }
}
- *cur++ = line[ii]; /* store next key or value char */
+ *dst++ = c; /* store next key or value char */
}
- *cur++ = '\0'; /* terminate value */
+ *dst = '\0'; /* terminate value */
/* Skip broken or empty lines. */
- if (!valid)
+ if (!value)
goto free_line;
/* Skip lines with empty key. */
- if (key[0] == '\0')
+ if (line[0] == '\0')
goto free_line;
if (skipKeysWithoutValue && value[0] == '\0')
@@ -84,7 +84,7 @@ bool load_conf_file(const char *pPath, map_string_h *settings, bool skipKeysWith
if (in_quote)
goto free_line;
- g_hash_table_replace(settings, xstrdup(key), xstrdup(value));
+ g_hash_table_replace(settings, xstrdup(line), xstrdup(value));
free_line:
free(line);
}
diff --git a/src/lib/run_event.c b/src/lib/run_event.c
index a2bbc76b..45facffd 100644
--- a/src/lib/run_event.c
+++ b/src/lib/run_event.c
@@ -93,7 +93,7 @@ static GList *load_event_config(GList *list,
if (*p == '\0' || *p == '#')
goto next_line; /* empty or comment line, skip */
- VERB3 log("%s: line '%s'", __func__, p);
+ //VERB3 log("%s: line '%s'", __func__, p);
if (strncmp(p, "include", strlen("include")) == 0 && isblank(p[strlen("include")]))
{
@@ -117,15 +117,15 @@ static GList *load_event_config(GList *list,
glob_t globbuf;
memset(&globbuf, 0, sizeof(globbuf));
- VERB3 log("%s: globbing '%s'", __func__, name_to_glob);
+ //VERB3 log("%s: globbing '%s'", __func__, name_to_glob);
glob(name_to_glob, 0, NULL, &globbuf);
free(name_to_glob);
char **name = globbuf.gl_pathv;
if (name) while (*name)
{
- VERB3 log("%s: recursing into '%s'", __func__, *name);
+ //VERB3 log("%s: recursing into '%s'", __func__, *name);
list = load_event_config(list, dump_dir_name, event, *name);
- VERB3 log("%s: returned from '%s'", __func__, *name);
+ //VERB3 log("%s: returned from '%s'", __func__, *name);
name++;
}
globfree(&globbuf);
@@ -174,10 +174,10 @@ static GList *load_event_config(GList *list,
/* Does VAL match? */
if (strcmp(real_val, line_val) != 0)
{
- VERB3 log("var '%s': '%.*s'!='%s', skipping line",
- p,
- (int)(strchrnul(real_val, '\n') - real_val), real_val,
- line_val);
+ //VERB3 log("var '%s': '%.*s'!='%s', skipping line",
+ // p,
+ // (int)(strchrnul(real_val, '\n') - real_val), real_val,
+ // line_val);
free(malloced_val);
goto next_line; /* no */
}
@@ -245,18 +245,19 @@ int spawn_next_command(struct run_event_state *state,
VERB1 log("Executing '%s'", cmd);
/* Export some useful environment variables for children */
+ char *env_vec[3];
/* Just exporting dump_dir_name isn't always ok: it can be "."
* and some children want to cd to other directory but still
* be able to find dump directory by using $DUMP_DIR...
*/
char *full_name = realpath(dump_dir_name, NULL);
- setenv("DUMP_DIR", (full_name ? full_name : dump_dir_name), 1);
+ env_vec[0] = xasprintf("DUMP_DIR=%s", (full_name ? full_name : dump_dir_name));
free(full_name);
- setenv("EVENT", event, 1);
-//FIXME: set vars in the child, not here! Need to improve fork_execv_on_steroids...
+ env_vec[1] = xasprintf("EVENT=%s", event);
+ env_vec[2] = NULL;
char *argv[4];
- argv[0] = (char*)"/bin/sh";
+ argv[0] = (char*)"/bin/sh"; // TODO: honor $SHELL?
argv[1] = (char*)"-c";
argv[2] = cmd;
argv[3] = NULL;
@@ -266,12 +267,15 @@ int spawn_next_command(struct run_event_state *state,
EXECFLG_INPUT_NUL + EXECFLG_OUTPUT + EXECFLG_ERR2OUT,
argv,
pipefds,
- /* unsetenv_vec: */ NULL,
+ /* env_vec: */ env_vec,
/* dir: */ dump_dir_name,
/* uid(unused): */ 0
);
state->command_out_fd = pipefds[0];
+ free(env_vec[0]);
+ free(env_vec[1]);
+
state->commands = g_list_remove(state->commands, cmd);
return 0;
@@ -396,7 +400,7 @@ static int list_possible_events_helper(struct strbuf *result,
if (*p == '\0' || *p == '#')
goto next_line; /* empty or comment line, skip */
- VERB3 log("%s: line '%s'", __func__, p);
+ //VERB3 log("%s: line '%s'", __func__, p);
if (strncmp(p, "include", strlen("include")) == 0 && isblank(p[strlen("include")]))
{
@@ -420,15 +424,15 @@ static int list_possible_events_helper(struct strbuf *result,
glob_t globbuf;
memset(&globbuf, 0, sizeof(globbuf));
- VERB3 log("%s: globbing '%s'", __func__, name_to_glob);
+ //VERB3 log("%s: globbing '%s'", __func__, name_to_glob);
glob(name_to_glob, 0, NULL, &globbuf);
free(name_to_glob);
char **name = globbuf.gl_pathv;
if (name) while (*name)
{
- VERB3 log("%s: recursing into '%s'", __func__, *name);
+ //VERB3 log("%s: recursing into '%s'", __func__, *name);
error = list_possible_events_helper(result, dd, dump_dir_name, pfx, *name);
- VERB3 log("%s: returned from '%s'", __func__, *name);
+ //VERB3 log("%s: returned from '%s'", __func__, *name);
if (error)
break;
name++;
@@ -480,10 +484,10 @@ static int list_possible_events_helper(struct strbuf *result,
/* Does VAL match? */
if (strcmp(real_val, line_val) != 0)
{
- VERB3 log("var '%s': '%.*s'!='%s', skipping line",
- p,
- (int)(strchrnul(real_val, '\n') - real_val), real_val,
- line_val);
+ //VERB3 log("var '%s': '%.*s'!='%s', skipping line",
+ // p,
+ // (int)(strchrnul(real_val, '\n') - real_val), real_val,
+ // line_val);
free(real_val);
goto next_line; /* no */
}
diff --git a/src/lib/spawn.c b/src/lib/spawn.c
index f6b7263c..188b63bd 100644
--- a/src/lib/spawn.c
+++ b/src/lib/spawn.c
@@ -32,7 +32,7 @@ static char *concat_str_vector(char **strings)
pid_t fork_execv_on_steroids(int flags,
char **argv,
int *pipefds,
- char **unsetenv_vec,
+ char **env_vec,
const char *dir,
uid_t uid)
{
@@ -69,9 +69,11 @@ pid_t fork_execv_on_steroids(int flags,
xsetreuid(uid, uid);
}
- if (unsetenv_vec) {
- while (*unsetenv_vec)
- unsetenv(*unsetenv_vec++);
+ if (env_vec) {
+ /* Note: we use the glibc extension that putenv("var")
+ * *unsets* $var if "var" string has no '=' */
+ while (*env_vec)
+ putenv(*env_vec++);
}
/* Play with stdio descriptors */
@@ -134,7 +136,7 @@ char *run_in_shell_and_save_output(int flags,
const char *argv[] = { "/bin/sh", "-c", cmd, NULL };
int pipeout[2];
pid_t child = fork_execv_on_steroids(flags, (char **)argv, pipeout,
- /*unsetenv_vec:*/ NULL, dir, /*uid (unused):*/ 0);
+ /*env_vec:*/ NULL, dir, /*uid (unused):*/ 0);
size_t pos = 0;
char *result = NULL;
diff --git a/src/lib/xfuncs.c b/src/lib/xfuncs.c
index f451693a..3766d231 100644
--- a/src/lib/xfuncs.c
+++ b/src/lib/xfuncs.c
@@ -215,6 +215,20 @@ void xsetenv(const char *key, const char *value)
die_out_of_memory();
}
+void safe_unsetenv(const char *var_val)
+{
+ //char *name = xstrndup(var_val, strchrnul(var_val, '=') - var_val);
+ //unsetenv(name);
+ //free(name);
+
+ /* Avoid malloc/free (name is usually very short) */
+ unsigned len = strchrnul(var_val, '=') - var_val;
+ char name[len + 1];
+ memcpy(name, var_val, len);
+ name[len] = '\0';
+ unsetenv(name);
+}
+
// Die with an error message if we can't open a new socket.
int xsocket(int domain, int type, int protocol)
{