rasd: Parse config file for events to enable

The file 'rasd.cfg' is parsed for options:
 .the events to enable are stored line by line. The format is 'sys:name',
 .a line starting with '#' is a comment and is ignored,
 .a line full of spaces and/or tabs is empty and is ignored.

Boris: rewrite cfg_valid_line() to use regex(3). We want to select only
the "interesting" lines and ignore everything else.

Signed-off-by: Jean Pihet <jean.pihet@linaro.org>
Link: http://lkml.kernel.org/r/1412933690-25576-4-git-send-email-jean.pihet@linaro.org
Signed-off-by: Borislav Petkov <bp@suse.de>
diff --git a/src/rasd.c b/src/rasd.c
index 9147d65..593e5b0 100644
--- a/src/rasd.c
+++ b/src/rasd.c
@@ -4,13 +4,37 @@
 #include "ras.h"
 #include "debugfs.h"
 
+#include <regex.h>
+
 #define EVENT_STR_MAX_LENGTH	1024
 #define SYS_NAME_SEPARATOR	":"
+#define RASD_CFG_FILE		"rasd.cfg"
 
 unsigned int page_size;
-struct perf_evlist evlist;
+struct perf_evlist *evlist;
 struct perf_rasd rasd;
 
+/* Check if the read line is a valid config file line.*/
+static bool cfg_valid_line(char *str)
+{
+	regex_t reg;
+	int ret;
+
+	ret = regcomp(&reg, "^[:space:]*[a-z]+:[a-z_]+[:space:]*$",
+		      REG_EXTENDED |
+		      REG_NEWLINE); /* for matching $ */
+	if (ret)
+		err("compiling cfg regex");
+
+	ret = regexec(&reg, str, 0, NULL, 0);
+	if (ret) {
+		if (ret != REG_NOMATCH)
+			printf("error matching %s\n", str);
+		return false;
+	}
+	return true;
+}
+
 /*
  * Extract the event subsystem and event names from the command
  * line argument. The syntax is 'sys:name'.
@@ -55,7 +79,38 @@
 		err("init tracepoint evsel");
 
 	/* Add the event to the lists of events */
-	list_add_tail(&tp->node, &evlist.entries);
+	list_add_tail(&tp->node, &evlist->entries);
+
+	return ret;
+}
+
+/*
+ * Read the config file for events to enable
+ */
+static int read_config_file(void)
+{
+	FILE *file;
+	char *event_str;
+	int ret = 0;
+
+	file = fopen(RASD_CFG_FILE, "r");
+	if (!file)
+		return -ENODEV;
+
+	event_str = malloc(EVENT_STR_MAX_LENGTH);
+	if (!event_str)
+		return -ENOMEM;
+
+	/* Read config file, line by line */
+	while (fgets(event_str, EVENT_STR_MAX_LENGTH, file))
+		if (cfg_valid_line(event_str))
+			add_tp_event(event_str);
+
+	if (ferror(file))
+		ret = -EINVAL;
+
+	free(event_str);
+	fclose(file);
 
 	return ret;
 }
@@ -63,7 +118,6 @@
 int main()
 {
 	struct perf_evsel *c;
-	char *ev_name = strdup("mce:mce_record");
 
 	page_size = sysconf(_SC_PAGE_SIZE);
 
@@ -73,25 +127,29 @@
 	if (!debugfs_mount(NULL))
 		err("mounting debugfs");
 
-	INIT_LIST_HEAD(&evlist.entries);
+	/* Initialize evlist */
+	evlist = perf_evlist__new();
+	if (!evlist)
+		err("allocating evlist");
 
-	/* Add event from the name string */
-	add_tp_event(ev_name);
+	/* Read config file */
+	if (read_config_file())
+		err("error reading config file");
 
-	evlist__for_each(&evlist, c) {
+	evlist__for_each(evlist, c) {
 		/*
 		 * On all online cpus by default.
 		 */
 		if (perf_evsel__open(c, cpu_map__new(NULL), NULL) < 0)
-			err("opening counter");
+			err("opening tracepoint, are you root?");
 	}
 
-        if (perf_evlist__mmap(&evlist, 4 /* opts->mmap_pages */, false) < 0)
-                err("Failed to mmap with %d (%s)\n", errno, strerror(errno));
+	if (perf_evlist__mmap(evlist, 4 /* opts->mmap_pages */, false) < 0)
+		err("Failed to mmap with %d (%s)\n", errno, strerror(errno));
 
 	/* mmap it and all that, consume it */
 
-	perf_evlist__delete(&evlist);
+	perf_evlist__delete(evlist);
 
 	free(rasd.name);
 	free(rasd.sys);