Linux Audio

Check our new training course

Loading...
Note: File does not exist in v4.6.
  1/* SPDX-License-Identifier: GPL-2.0 */
  2#include <dirent.h>
  3#include <errno.h>
  4#include <fcntl.h>
  5#include <linux/ctype.h>
  6#include <linux/kernel.h>
  7#include <linux/string.h>
  8#include <linux/zalloc.h>
  9#include <string.h>
 10#include <stdlib.h>
 11#include <sys/types.h>
 12#include <unistd.h>
 13#include <subcmd/exec-cmd.h>
 14#include <subcmd/parse-options.h>
 15#include <sys/wait.h>
 16#include <sys/stat.h>
 17#include "builtin.h"
 18#include "builtin-test-list.h"
 19#include "color.h"
 20#include "debug.h"
 21#include "hist.h"
 22#include "intlist.h"
 23#include "string2.h"
 24#include "symbol.h"
 25#include "tests.h"
 26#include "util/rlimit.h"
 27
 28
 29/*
 30 * As this is a singleton built once for the run of the process, there is
 31 * no value in trying to free it and just let it stay around until process
 32 * exits when it's cleaned up.
 33 */
 34static size_t files_num = 0;
 35static struct script_file *files = NULL;
 36static int files_max_width = 0;
 37
 38static const char *shell_tests__dir(char *path, size_t size)
 39{
 40	const char *devel_dirs[] = { "./tools/perf/tests", "./tests", };
 41	char *exec_path;
 42	unsigned int i;
 43
 44	for (i = 0; i < ARRAY_SIZE(devel_dirs); ++i) {
 45		struct stat st;
 46
 47		if (!lstat(devel_dirs[i], &st)) {
 48			scnprintf(path, size, "%s/shell", devel_dirs[i]);
 49			if (!lstat(devel_dirs[i], &st))
 50				return path;
 51		}
 52	}
 53
 54	/* Then installed path. */
 55	exec_path = get_argv_exec_path();
 56	scnprintf(path, size, "%s/tests/shell", exec_path);
 57	free(exec_path);
 58	return path;
 59}
 60
 61static const char *shell_test__description(char *description, size_t size,
 62                                           const char *path, const char *name)
 63{
 64	FILE *fp;
 65	char filename[PATH_MAX];
 66	int ch;
 67
 68	path__join(filename, sizeof(filename), path, name);
 69	fp = fopen(filename, "r");
 70	if (!fp)
 71		return NULL;
 72
 73	/* Skip first line - should be #!/bin/sh Shebang */
 74	do {
 75		ch = fgetc(fp);
 76	} while (ch != EOF && ch != '\n');
 77
 78	description = fgets(description, size, fp);
 79	fclose(fp);
 80
 81	/* Assume first char on line is omment everything after that desc */
 82	return description ? strim(description + 1) : NULL;
 83}
 84
 85/* Is this full file path a shell script */
 86static bool is_shell_script(const char *path)
 87{
 88	const char *ext;
 89
 90	ext = strrchr(path, '.');
 91	if (!ext)
 92		return false;
 93	if (!strcmp(ext, ".sh")) { /* Has .sh extension */
 94		if (access(path, R_OK | X_OK) == 0) /* Is executable */
 95			return true;
 96	}
 97	return false;
 98}
 99
100/* Is this file in this dir a shell script (for test purposes) */
101static bool is_test_script(const char *path, const char *name)
102{
103	char filename[PATH_MAX];
104
105	path__join(filename, sizeof(filename), path, name);
106	if (!is_shell_script(filename)) return false;
107	return true;
108}
109
110/* Duplicate a string and fall over and die if we run out of memory */
111static char *strdup_check(const char *str)
112{
113	char *newstr;
114
115	newstr = strdup(str);
116	if (!newstr) {
117		pr_err("Out of memory while duplicating test script string\n");
118		abort();
119	}
120	return newstr;
121}
122
123static void append_script(const char *dir, const char *file, const char *desc)
124{
125	struct script_file *files_tmp;
126	size_t files_num_tmp;
127	int width;
128
129	files_num_tmp = files_num + 1;
130	if (files_num_tmp >= SIZE_MAX) {
131		pr_err("Too many script files\n");
132		abort();
133	}
134	/* Realloc is good enough, though we could realloc by chunks, not that
135	 * anyone will ever measure performance here */
136	files_tmp = realloc(files,
137			    (files_num_tmp + 1) * sizeof(struct script_file));
138	if (files_tmp == NULL) {
139		pr_err("Out of memory while building test list\n");
140		abort();
141	}
142	/* Add file to end and NULL terminate the struct array */
143	files = files_tmp;
144	files_num = files_num_tmp;
145	files[files_num - 1].dir = strdup_check(dir);
146	files[files_num - 1].file = strdup_check(file);
147	files[files_num - 1].desc = strdup_check(desc);
148	files[files_num].dir = NULL;
149	files[files_num].file = NULL;
150	files[files_num].desc = NULL;
151
152	width = strlen(desc); /* Track max width of desc */
153	if (width > files_max_width)
154		files_max_width = width;
155}
156
157static void append_scripts_in_dir(const char *path)
158{
159	struct dirent **entlist;
160	struct dirent *ent;
161	int n_dirs, i;
162	char filename[PATH_MAX];
163
164	/* List files, sorted by alpha */
165	n_dirs = scandir(path, &entlist, NULL, alphasort);
166	if (n_dirs == -1)
167		return;
168	for (i = 0; i < n_dirs && (ent = entlist[i]); i++) {
169		if (ent->d_name[0] == '.')
170			continue; /* Skip hidden files */
171		if (is_test_script(path, ent->d_name)) { /* It's a test */
172			char bf[256];
173			const char *desc = shell_test__description
174				(bf, sizeof(bf), path, ent->d_name);
175
176			if (desc) /* It has a desc line - valid script */
177				append_script(path, ent->d_name, desc);
178		} else if (is_directory(path, ent)) { /* Scan the subdir */
179			path__join(filename, sizeof(filename),
180				   path, ent->d_name);
181			append_scripts_in_dir(filename);
182		}
183	}
184	for (i = 0; i < n_dirs; i++) /* Clean up */
185		zfree(&entlist[i]);
186	free(entlist);
187}
188
189const struct script_file *list_script_files(void)
190{
191	char path_dir[PATH_MAX];
192	const char *path;
193
194	if (files)
195		return files; /* Singleton - we already know our list */
196
197	path = shell_tests__dir(path_dir, sizeof(path_dir)); /* Walk  dir */
198	append_scripts_in_dir(path);
199
200	return files;
201}
202
203int list_script_max_width(void)
204{
205	list_script_files(); /* Ensure we have scanned all scripts */
206	return files_max_width;
207}