log: enable filtering on functions

Up to now we could only use log level, category, and file for filtering.
Allow filtering on a list of functions.

Signed-off-by: Heinrich Schuchardt <heinrich.schuchardt@canonical.com>
diff --git a/cmd/log.c b/cmd/log.c
index 519ec76..64add6d 100644
--- a/cmd/log.c
+++ b/cmd/log.c
@@ -115,30 +115,27 @@
 		return CMD_RET_FAILURE;
 	}
 
-	/*      <3> < 6  > <2+1 + 7 > <      16      > < unbounded... */
-	printf("num policy level            categories files\n");
 	list_for_each_entry(filt, &ldev->filter_head, sibling_node) {
-		printf("%3d %6.6s %s %-7.7s ", filt->filter_num,
-		       filt->flags & LOGFF_DENY ? "deny" : "allow",
+		printf("%-3d: %s %s %s\n", filt->filter_num,
+		       filt->flags & LOGFF_DENY ? "DENY" : "ALLOW",
 		       filt->flags & LOGFF_LEVEL_MIN ? ">=" : "<=",
 		       log_get_level_name(filt->level));
 
 		if (filt->flags & LOGFF_HAS_CAT) {
-			int i;
-
-			if (filt->cat_list[0] != LOGC_END)
-				printf("%16.16s %s\n",
-				       log_get_cat_name(filt->cat_list[0]),
-				       filt->file_list ? filt->file_list : "");
-
-			for (i = 1; i < LOGF_MAX_CATEGORIES &&
-				    filt->cat_list[i] != LOGC_END; i++)
-				printf("%21c %16.16s\n", ' ',
+			printf("     Categories:");
+			for (int i = 0;
+			     i < LOGF_MAX_CATEGORIES &&
+			     filt->cat_list[i] != LOGC_END;
+			     ++i) {
+				printf(" %s",
 				       log_get_cat_name(filt->cat_list[i]));
-		} else {
-			printf("%16c %s\n", ' ',
-			       filt->file_list ? filt->file_list : "");
+			}
+			printf("\n");
 		}
+		if (filt->file_list)
+			printf("     Files: %s\n", filt->file_list);
+		if (filt->func_list)
+			printf("     Functions: %s\n", filt->func_list);
 	}
 
 	return CMD_RET_SUCCESS;
@@ -151,6 +148,7 @@
 	bool print_num = false;
 	bool type_set = false;
 	char *file_list = NULL;
+	char *func_list = NULL;
 	const char *drv_name = "console";
 	int opt, err;
 	int cat_count = 0;
@@ -160,7 +158,7 @@
 	struct getopt_state gs;
 
 	getopt_init_state(&gs);
-	while ((opt = getopt(&gs, argc, argv, "Ac:d:Df:l:L:p")) > 0) {
+	while ((opt = getopt(&gs, argc, argv, "Ac:d:Df:F:l:L:p")) > 0) {
 		switch (opt) {
 		case 'A':
 #define do_type() do { \
@@ -199,6 +197,9 @@
 		case 'f':
 			file_list = gs.arg;
 			break;
+		case 'F':
+			func_list = gs.arg;
+			break;
 		case 'l':
 #define do_level() do { \
 			if (level_set) { \
@@ -229,7 +230,7 @@
 
 	cat_list[cat_count] = LOGC_END;
 	err = log_add_filter_flags(drv_name, cat_count ? cat_list : NULL, level,
-				   file_list, flags);
+				   file_list, func_list, flags);
 	if (err < 0) {
 		printf("Could not add filter (err = %d)\n", err);
 		return CMD_RET_FAILURE;
@@ -388,7 +389,8 @@
 	"\t-d <driver> - Specify the log driver to add the filter to; defaults\n"
 	"\t              to console\n"
 	"\t-D - Deny messages matching this filter; mutually exclusive with -A\n"
-	"\t-f <files_list> - A comma-separated list of files to match\n"
+	"\t-f <file_list> - A comma-separated list of files to match\n"
+	"\t-F <func_list> - A comma-separated list of functions to match\n"
 	"\t-l <level> - Match log levels less than or equal to <level>;\n"
 	"\t             mutually-exclusive with -L\n"
 	"\t-L <level> - Match log levels greather than or equal to <level>;\n"