Back to home page

OSCL-LXR

 
 

    


0001 /* SPDX-License-Identifier: GPL-2.0 */
0002 #include <dirent.h>
0003 #include <errno.h>
0004 #include <fcntl.h>
0005 #include <linux/ctype.h>
0006 #include <linux/kernel.h>
0007 #include <linux/string.h>
0008 #include <linux/zalloc.h>
0009 #include <string.h>
0010 #include <stdlib.h>
0011 #include <sys/types.h>
0012 #include <unistd.h>
0013 #include <subcmd/exec-cmd.h>
0014 #include <subcmd/parse-options.h>
0015 #include <sys/wait.h>
0016 #include <sys/stat.h>
0017 #include "builtin.h"
0018 #include "builtin-test-list.h"
0019 #include "color.h"
0020 #include "debug.h"
0021 #include "hist.h"
0022 #include "intlist.h"
0023 #include "string2.h"
0024 #include "symbol.h"
0025 #include "tests.h"
0026 #include "util/rlimit.h"
0027 
0028 
0029 /*
0030  * As this is a singleton built once for the run of the process, there is
0031  * no value in trying to free it and just let it stay around until process
0032  * exits when it's cleaned up.
0033  */
0034 static size_t files_num = 0;
0035 static struct script_file *files = NULL;
0036 static int files_max_width = 0;
0037 
0038 static const char *shell_tests__dir(char *path, size_t size)
0039 {
0040     const char *devel_dirs[] = { "./tools/perf/tests", "./tests", };
0041     char *exec_path;
0042     unsigned int i;
0043 
0044     for (i = 0; i < ARRAY_SIZE(devel_dirs); ++i) {
0045         struct stat st;
0046 
0047         if (!lstat(devel_dirs[i], &st)) {
0048             scnprintf(path, size, "%s/shell", devel_dirs[i]);
0049             if (!lstat(devel_dirs[i], &st))
0050                 return path;
0051         }
0052     }
0053 
0054     /* Then installed path. */
0055     exec_path = get_argv_exec_path();
0056     scnprintf(path, size, "%s/tests/shell", exec_path);
0057     free(exec_path);
0058     return path;
0059 }
0060 
0061 static const char *shell_test__description(char *description, size_t size,
0062                                            const char *path, const char *name)
0063 {
0064     FILE *fp;
0065     char filename[PATH_MAX];
0066     int ch;
0067 
0068     path__join(filename, sizeof(filename), path, name);
0069     fp = fopen(filename, "r");
0070     if (!fp)
0071         return NULL;
0072 
0073     /* Skip first line - should be #!/bin/sh Shebang */
0074     do {
0075         ch = fgetc(fp);
0076     } while (ch != EOF && ch != '\n');
0077 
0078     description = fgets(description, size, fp);
0079     fclose(fp);
0080 
0081     /* Assume first char on line is omment everything after that desc */
0082     return description ? strim(description + 1) : NULL;
0083 }
0084 
0085 /* Is this full file path a shell script */
0086 static bool is_shell_script(const char *path)
0087 {
0088     const char *ext;
0089 
0090     ext = strrchr(path, '.');
0091     if (!ext)
0092         return false;
0093     if (!strcmp(ext, ".sh")) { /* Has .sh extension */
0094         if (access(path, R_OK | X_OK) == 0) /* Is executable */
0095             return true;
0096     }
0097     return false;
0098 }
0099 
0100 /* Is this file in this dir a shell script (for test purposes) */
0101 static bool is_test_script(const char *path, const char *name)
0102 {
0103     char filename[PATH_MAX];
0104 
0105     path__join(filename, sizeof(filename), path, name);
0106     if (!is_shell_script(filename)) return false;
0107     return true;
0108 }
0109 
0110 /* Duplicate a string and fall over and die if we run out of memory */
0111 static char *strdup_check(const char *str)
0112 {
0113     char *newstr;
0114 
0115     newstr = strdup(str);
0116     if (!newstr) {
0117         pr_err("Out of memory while duplicating test script string\n");
0118         abort();
0119     }
0120     return newstr;
0121 }
0122 
0123 static void append_script(const char *dir, const char *file, const char *desc)
0124 {
0125     struct script_file *files_tmp;
0126     size_t files_num_tmp;
0127     int width;
0128 
0129     files_num_tmp = files_num + 1;
0130     if (files_num_tmp >= SIZE_MAX) {
0131         pr_err("Too many script files\n");
0132         abort();
0133     }
0134     /* Realloc is good enough, though we could realloc by chunks, not that
0135      * anyone will ever measure performance here */
0136     files_tmp = realloc(files,
0137                 (files_num_tmp + 1) * sizeof(struct script_file));
0138     if (files_tmp == NULL) {
0139         pr_err("Out of memory while building test list\n");
0140         abort();
0141     }
0142     /* Add file to end and NULL terminate the struct array */
0143     files = files_tmp;
0144     files_num = files_num_tmp;
0145     files[files_num - 1].dir = strdup_check(dir);
0146     files[files_num - 1].file = strdup_check(file);
0147     files[files_num - 1].desc = strdup_check(desc);
0148     files[files_num].dir = NULL;
0149     files[files_num].file = NULL;
0150     files[files_num].desc = NULL;
0151 
0152     width = strlen(desc); /* Track max width of desc */
0153     if (width > files_max_width)
0154         files_max_width = width;
0155 }
0156 
0157 static void append_scripts_in_dir(const char *path)
0158 {
0159     struct dirent **entlist;
0160     struct dirent *ent;
0161     int n_dirs, i;
0162     char filename[PATH_MAX];
0163 
0164     /* List files, sorted by alpha */
0165     n_dirs = scandir(path, &entlist, NULL, alphasort);
0166     if (n_dirs == -1)
0167         return;
0168     for (i = 0; i < n_dirs && (ent = entlist[i]); i++) {
0169         if (ent->d_name[0] == '.')
0170             continue; /* Skip hidden files */
0171         if (is_test_script(path, ent->d_name)) { /* It's a test */
0172             char bf[256];
0173             const char *desc = shell_test__description
0174                 (bf, sizeof(bf), path, ent->d_name);
0175 
0176             if (desc) /* It has a desc line - valid script */
0177                 append_script(path, ent->d_name, desc);
0178         } else if (is_directory(path, ent)) { /* Scan the subdir */
0179             path__join(filename, sizeof(filename),
0180                    path, ent->d_name);
0181             append_scripts_in_dir(filename);
0182         }
0183     }
0184     for (i = 0; i < n_dirs; i++) /* Clean up */
0185         zfree(&entlist[i]);
0186     free(entlist);
0187 }
0188 
0189 const struct script_file *list_script_files(void)
0190 {
0191     char path_dir[PATH_MAX];
0192     const char *path;
0193 
0194     if (files)
0195         return files; /* Singleton - we already know our list */
0196 
0197     path = shell_tests__dir(path_dir, sizeof(path_dir)); /* Walk  dir */
0198     append_scripts_in_dir(path);
0199 
0200     return files;
0201 }
0202 
0203 int list_script_max_width(void)
0204 {
0205     list_script_files(); /* Ensure we have scanned all scripts */
0206     return files_max_width;
0207 }