From nobody Thu Sep 19 01:52:11 2024 Received: from mail-yb1-f202.google.com (mail-yb1-f202.google.com [209.85.219.202]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id ACD4E3AC24 for ; Wed, 21 Feb 2024 03:42:18 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.219.202 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1708486941; cv=none; b=e5ayDNHQ7cgTLBCUfvw9H5udlx0+AOgbjxyj+zO58isrBU1r/XI8jLkLOX1Wxv8RCnplz02+TlbYnPOM7HNG/l66UkgwiFKH6k4VsNuBp+WZEg2LK8TzmssYDDaYIrqBrJlfd8H/K3WUsreLxtfZXkXUxjrfFycIuEwscoGMuno= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1708486941; c=relaxed/simple; bh=qUA5FgB5jKzfSy9eC0WQ2ZcQSsUjX037xNJTVpjXWhQ=; h=Date:In-Reply-To:Message-Id:Mime-Version:References:Subject:From: To:Content-Type; b=dwQq4/4U8Mg0MSjjE99lOIZOy8MttWLpFw5JMlGWyvLDZyoupP31Qwd6V4xypjM3+5WZ9nLipM1SHZup3OA73OURdJk5Va5pAqxmpspe6OOYDQ44HhXaE1rD4/Em1+emfO093TSgzuYGGC+N13OotxO663oH8rtc9NClCKb9K7k= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com; spf=pass smtp.mailfrom=flex--irogers.bounces.google.com; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b=otD3bOGC; arc=none smtp.client-ip=209.85.219.202 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=flex--irogers.bounces.google.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="otD3bOGC" Received: by mail-yb1-f202.google.com with SMTP id 3f1490d57ef6-dc743cc50a6so8447909276.2 for ; Tue, 20 Feb 2024 19:42:18 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20230601; t=1708486938; x=1709091738; darn=vger.kernel.org; h=to:from:subject:references:mime-version:message-id:in-reply-to:date :from:to:cc:subject:date:message-id:reply-to; bh=o0/Grl7GyHkKiOIRnltfxI/fRhIGN1eYIXPhWGdq1Pc=; b=otD3bOGCDWeBoipbjDFK7uTEbhxBm636UDYzVJm/8xXNkU1RoGr6wW433TAjxKuo1i kksppxBOlIG9vnzsXOeEd9cxzvb6899nq3XbX2Lf/JU18uvWNdvPEEoSIkqMePYmE+RW 2Lmcy0pV3Yv/DrYQty9hKjqBVoB04+E1ZTm6Gp6vFMf6IILi2MeynyOSt0lJ0Fj55z51 i+IoZTe1IzV7zRREcjVSkNwqrdzNJfFewj02314vV7OJBf/y9MvN62uM3DW6AiTM0hNq 1iXCkYM66kIh8HDcggg/FARusyQoMAYEnF76J/tB9jSzks0GqE73l+PyXlUe0MafFVnE QrlQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1708486938; x=1709091738; h=to:from:subject:references:mime-version:message-id:in-reply-to:date :x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=o0/Grl7GyHkKiOIRnltfxI/fRhIGN1eYIXPhWGdq1Pc=; b=snn+iMIrShp079vqOhMV3Ieu6VZpg+GFTLEzHsjmSAXPieohYqeT38X2QruJQ/Z/NQ LthWxn1aCQPBbm1ZG209wWyJmv8xzjIGCSRdcP/ZI7zCijYhBFAvuX9rGgzn57YPkVDf V7EOkYMQc4HgD6bHHD0Xf5RRt9FspyxVbK3Pc+9brxXFM24SxaUiZfrwAz5wBWN6Tv2N LBIgjakOE3I7baMd3tEUqUyui7KKlydTRuwas2KeJ64lvogYZ1j09MGHq6Uq9I8DAQ/b rJ6kM23ZibP9XnupuY3zRsj6GaBT0Xz2jT6f28km4NtsI/ncR9fpAqxuBI8Ivry074lX QD8A== X-Forwarded-Encrypted: i=1; AJvYcCVuIIjVxNK0xckS//fM+jVp1g/cWm3UmugV0AU/rJQqsXrT4/kr0PJ1JDfjoVQBtGGswVjZOQ+ebVfNJirQTOFWjSv25Tumn1mklZgQ X-Gm-Message-State: AOJu0YxcdgqBhU7NNngwwt2VowYEzX14FrJraXwlNtU3SmtrfE/rxqsn mJddl8iR3M6c3Tcf2e0R4uTUKS/Fe5AJJ9QenIepgPW9aQX67W5UQULo5GBFfbUqNL0IFK18upp Z+u0/RA== X-Google-Smtp-Source: AGHT+IGjW09WyJmx19DJMMPJcFp8ZN/kWIXhC7Wx1m2/fsfOH/Oon5EbuHZGxLl9Vax9I5wDRGDMDMA3WEZE X-Received: from irogers.svl.corp.google.com ([2620:15c:2a3:200:3c02:f882:5876:b7ab]) (user=irogers job=sendgmr) by 2002:a05:6902:18d4:b0:dcd:2f2d:7a0f with SMTP id ck20-20020a05690218d400b00dcd2f2d7a0fmr605043ybb.9.1708486937727; Tue, 20 Feb 2024 19:42:17 -0800 (PST) Date: Tue, 20 Feb 2024 19:41:53 -0800 In-Reply-To: <20240221034155.1500118-1-irogers@google.com> Message-Id: <20240221034155.1500118-7-irogers@google.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: Mime-Version: 1.0 References: <20240221034155.1500118-1-irogers@google.com> X-Mailer: git-send-email 2.44.0.rc0.258.g7320e95886-goog Subject: [PATCH v6 6/8] perf tests: Use scandirat for shell script finding From: Ian Rogers To: Peter Zijlstra , Ingo Molnar , Arnaldo Carvalho de Melo , Namhyung Kim , Mark Rutland , Alexander Shishkin , Jiri Olsa , Ian Rogers , Adrian Hunter , Nathan Chancellor , Nick Desaulniers , Bill Wendling , Justin Stitt , Athira Jajeev , James Clark , Kan Liang , Yang Jihong , linux-kernel@vger.kernel.org, linux-perf-users@vger.kernel.org, llvm@lists.linux.dev Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Avoid filename appending buffers by using openat, faccessat and scandirat more widely. Turn the script's path back to a file name using readlink from /proc//fd/. Read the script's description using api/io.h to avoid fdopen conversions. Whilst reading perform additional sanity checks on the script's contents. Signed-off-by: Ian Rogers --- tools/perf/tests/builtin-test.c | 20 ++--- tools/perf/tests/tests-scripts.c | 145 ++++++++++++++++++------------- tools/perf/tests/tests-scripts.h | 1 - 3 files changed, 95 insertions(+), 71 deletions(-) diff --git a/tools/perf/tests/builtin-test.c b/tools/perf/tests/builtin-tes= t.c index eff3c62e9b47..162f9eb090ac 100644 --- a/tools/perf/tests/builtin-test.c +++ b/tools/perf/tests/builtin-test.c @@ -300,22 +300,19 @@ static int test_and_print(struct test_suite *t, int s= ubtest) } =20 struct shell_test { - const char *dir; const char *file; }; =20 static int shell_test__run(struct test_suite *test, int subdir __maybe_unu= sed) { int err; - char script[PATH_MAX]; struct shell_test *st =3D test->priv; + char *cmd =3D NULL; =20 - path__join(script, sizeof(script) - 3, st->dir, st->file); - - if (verbose > 0) - strncat(script, " -v", sizeof(script) - strlen(script) - 1); - - err =3D system(script); + if (asprintf(&cmd, "%s%s", st->file, verbose ? " -v" : "") < 0) + return TEST_FAIL; + err =3D system(cmd); + free(cmd); if (!err) return TEST_OK; =20 @@ -331,7 +328,7 @@ static int run_shell_tests(int argc, const char *argv[]= , int i, int width, files =3D list_script_files(); if (!files) return 0; - for (file =3D files; file->dir; file++) { + for (file =3D files; file->file; file++) { int curr =3D i++; struct test_case test_cases[] =3D { { @@ -345,13 +342,12 @@ static int run_shell_tests(int argc, const char *argv= [], int i, int width, .test_cases =3D test_cases, .priv =3D &st, }; - st.dir =3D file->dir; + st.file =3D file->file; =20 if (test_suite.desc =3D=3D NULL || !perf_test__matches(test_suite.desc, curr, argc, argv)) continue; =20 - st.file =3D file->file; pr_info("%3d: %-*s:", i, width, test_suite.desc); =20 if (intlist__find(skiplist, i)) { @@ -455,7 +451,7 @@ static int perf_test__list_shell(int argc, const char *= *argv, int i) files =3D list_script_files(); if (!files) return 0; - for (file =3D files; file->dir; file++) { + for (file =3D files; file->file; file++) { int curr =3D i++; struct test_suite t =3D { .desc =3D file->desc diff --git a/tools/perf/tests/tests-scripts.c b/tools/perf/tests/tests-scri= pts.c index 4ebd841da05b..c21f7a425da9 100644 --- a/tools/perf/tests/tests-scripts.c +++ b/tools/perf/tests/tests-scripts.c @@ -14,6 +14,7 @@ #include #include #include +#include #include "builtin.h" #include "tests-scripts.h" #include "color.h" @@ -24,6 +25,7 @@ #include "symbol.h" #include "tests.h" #include "util/rlimit.h" +#include "util/util.h" =20 =20 /* @@ -35,55 +37,69 @@ static size_t files_num =3D 0; static struct script_file *files =3D NULL; static int files_max_width =3D 0; =20 -static const char *shell_tests__dir(char *path, size_t size) +static int shell_tests__dir_fd(void) { - const char *devel_dirs[] =3D { "./tools/perf/tests", "./tests", }; - char *exec_path; - unsigned int i; + char path[PATH_MAX], *exec_path; + static const char * const devel_dirs[] =3D { "./tools/perf/tests/shell", = "./tests/shell", }; =20 - for (i =3D 0; i < ARRAY_SIZE(devel_dirs); ++i) { - struct stat st; + for (size_t i =3D 0; i < ARRAY_SIZE(devel_dirs); ++i) { + int fd =3D open(devel_dirs[i], O_PATH); =20 - if (!lstat(devel_dirs[i], &st)) { - scnprintf(path, size, "%s/shell", devel_dirs[i]); - if (!lstat(devel_dirs[i], &st)) - return path; - } + if (fd >=3D 0) + return fd; } =20 /* Then installed path. */ exec_path =3D get_argv_exec_path(); - scnprintf(path, size, "%s/tests/shell", exec_path); + scnprintf(path, sizeof(path), "%s/tests/shell", exec_path); free(exec_path); - return path; + return open(path, O_PATH); } =20 -static const char *shell_test__description(char *description, size_t size, - const char *path, const char *n= ame) +static char *shell_test__description(int dir_fd, const char *name) { - FILE *fp; - char filename[PATH_MAX]; - int ch; + struct io io; + char buf[128], desc[256]; + int ch, pos =3D 0; =20 - path__join(filename, sizeof(filename), path, name); - fp =3D fopen(filename, "r"); - if (!fp) + io__init(&io, openat(dir_fd, name, O_RDONLY), buf, sizeof(buf)); + if (io.fd < 0) return NULL; =20 /* Skip first line - should be #!/bin/sh Shebang */ + if (io__get_char(&io) !=3D '#') + goto err_out; + if (io__get_char(&io) !=3D '!') + goto err_out; do { - ch =3D fgetc(fp); - } while (ch !=3D EOF && ch !=3D '\n'); - - description =3D fgets(description, size, fp); - fclose(fp); + ch =3D io__get_char(&io); + if (ch < 0) + goto err_out; + } while (ch !=3D '\n'); =20 - /* Assume first char on line is omment everything after that desc */ - return description ? strim(description + 1) : NULL; + do { + ch =3D io__get_char(&io); + if (ch < 0) + goto err_out; + } while (ch =3D=3D '#' || isspace(ch)); + while (ch > 0 && ch !=3D '\n') { + desc[pos++] =3D ch; + if (pos >=3D (int)sizeof(desc) - 1) + break; + ch =3D io__get_char(&io); + } + while (pos > 0 && isspace(desc[--pos])) + ; + desc[++pos] =3D '\0'; + close(io.fd); + return strdup(desc); +err_out: + close(io.fd); + return NULL; } =20 /* Is this full file path a shell script */ -static bool is_shell_script(const char *path) +static bool is_shell_script(int dir_fd, const char *path) { const char *ext; =20 @@ -91,20 +107,16 @@ static bool is_shell_script(const char *path) if (!ext) return false; if (!strcmp(ext, ".sh")) { /* Has .sh extension */ - if (access(path, R_OK | X_OK) =3D=3D 0) /* Is executable */ + if (faccessat(dir_fd, path, R_OK | X_OK, 0) =3D=3D 0) /* Is executable */ return true; } return false; } =20 /* Is this file in this dir a shell script (for test purposes) */ -static bool is_test_script(const char *path, const char *name) +static bool is_test_script(int dir_fd, const char *name) { - char filename[PATH_MAX]; - - path__join(filename, sizeof(filename), path, name); - if (!is_shell_script(filename)) return false; - return true; + return is_shell_script(dir_fd, name); } =20 /* Duplicate a string and fall over and die if we run out of memory */ @@ -120,12 +132,21 @@ static char *strdup_check(const char *str) return newstr; } =20 -static void append_script(const char *dir, const char *file, const char *d= esc) +static void append_script(int dir_fd, const char *name, char *desc) { + char filename[PATH_MAX], link[128]; struct script_file *files_tmp; - size_t files_num_tmp; + size_t files_num_tmp, len; int width; =20 + snprintf(link, sizeof(link), "/proc/%d/fd/%d", getpid(), dir_fd); + len =3D readlink(link, filename, sizeof(filename)); + if (len < 0) { + pr_err("Failed to readlink %s", link); + return; + } + filename[len++] =3D '/'; + strcpy(&filename[len], name); files_num_tmp =3D files_num + 1; if (files_num_tmp >=3D SIZE_MAX) { pr_err("Too many script files\n"); @@ -142,10 +163,8 @@ static void append_script(const char *dir, const char = *file, const char *desc) /* Add file to end and NULL terminate the struct array */ files =3D files_tmp; files_num =3D files_num_tmp; - files[files_num - 1].dir =3D strdup_check(dir); - files[files_num - 1].file =3D strdup_check(file); - files[files_num - 1].desc =3D strdup_check(desc); - files[files_num].dir =3D NULL; + files[files_num - 1].file =3D strdup_check(filename); + files[files_num - 1].desc =3D desc; files[files_num].file =3D NULL; files[files_num].desc =3D NULL; =20 @@ -154,32 +173,39 @@ static void append_script(const char *dir, const char= *file, const char *desc) files_max_width =3D width; } =20 -static void append_scripts_in_dir(const char *path) +static void append_scripts_in_dir(int dir_fd) { struct dirent **entlist; struct dirent *ent; int n_dirs, i; - char filename[PATH_MAX]; =20 /* List files, sorted by alpha */ - n_dirs =3D scandir(path, &entlist, NULL, alphasort); + n_dirs =3D scandirat(dir_fd, ".", &entlist, NULL, alphasort); if (n_dirs =3D=3D -1) return; for (i =3D 0; i < n_dirs && (ent =3D entlist[i]); i++) { + int fd; + if (ent->d_name[0] =3D=3D '.') continue; /* Skip hidden files */ - if (is_test_script(path, ent->d_name)) { /* It's a test */ - char bf[256]; - const char *desc =3D shell_test__description - (bf, sizeof(bf), path, ent->d_name); + if (is_test_script(dir_fd, ent->d_name)) { /* It's a test */ + char *desc =3D shell_test__description(dir_fd, ent->d_name); =20 if (desc) /* It has a desc line - valid script */ - append_script(path, ent->d_name, desc); - } else if (is_directory(path, ent)) { /* Scan the subdir */ - path__join(filename, sizeof(filename), - path, ent->d_name); - append_scripts_in_dir(filename); + append_script(dir_fd, ent->d_name, desc); + continue; + } + if (ent->d_type !=3D DT_DIR) { + struct stat st; + + if (ent->d_type !=3D DT_UNKNOWN) + continue; + fstatat(dir_fd, ent->d_name, &st, 0); + if (!S_ISDIR(st.st_mode)) + continue; } + fd =3D openat(dir_fd, ent->d_name, O_PATH); + append_scripts_in_dir(fd); } for (i =3D 0; i < n_dirs; i++) /* Clean up */ zfree(&entlist[i]); @@ -188,14 +214,17 @@ static void append_scripts_in_dir(const char *path) =20 const struct script_file *list_script_files(void) { - char path_dir[PATH_MAX]; - const char *path; + int dir_fd; =20 if (files) return files; /* Singleton - we already know our list */ =20 - path =3D shell_tests__dir(path_dir, sizeof(path_dir)); /* Walk dir */ - append_scripts_in_dir(path); + dir_fd =3D shell_tests__dir_fd(); /* Walk dir */ + if (dir_fd < 0) + return NULL; + + append_scripts_in_dir(dir_fd); + close(dir_fd); =20 return files; } diff --git a/tools/perf/tests/tests-scripts.h b/tools/perf/tests/tests-scri= pts.h index 3a3ec6191848..3508a293aaf9 100644 --- a/tools/perf/tests/tests-scripts.h +++ b/tools/perf/tests/tests-scripts.h @@ -3,7 +3,6 @@ #define TESTS_SCRIPTS_H =20 struct script_file { - char *dir; char *file; char *desc; }; --=20 2.44.0.rc0.258.g7320e95886-goog