From patchwork Mon Feb 12 18:58:56 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ian Rogers X-Patchwork-Id: 200003 Return-Path: Delivered-To: ouuuleilei@gmail.com Received: by 2002:a05:7300:bc8a:b0:106:860b:bbdd with SMTP id dn10csp109651dyb; Mon, 12 Feb 2024 11:00:55 -0800 (PST) X-Forwarded-Encrypted: i=3; AJvYcCWZa4cXhiUNzX7+x0tK52c6unBvl0vqsu56AC9Vetzm/5DWM58GE7jjW0Ees1w8IQC1Unh/9QAKoJdN9gkurIrMxQDm1A== X-Google-Smtp-Source: AGHT+IHLOEEL8iID1S4SFSol7YZ/acmZXR23nuBj7K/NYCfaIgEzVoQtFMKEB72ULD3UsxUKRDZN X-Received: by 2002:a17:906:3416:b0:a3c:cebd:2d7c with SMTP id c22-20020a170906341600b00a3ccebd2d7cmr1404384ejb.5.1707764455323; Mon, 12 Feb 2024 11:00:55 -0800 (PST) ARC-Seal: i=2; a=rsa-sha256; t=1707764455; cv=pass; d=google.com; s=arc-20160816; b=qzENdv7lBBYzCWRLhCo/IKT4EUnrYRhwIEcpC9mk/91del9GkxL7PyfE+o4mTzCDRv neByG8E+NEiKN2Jk4i07NTAreE/SV2KvF4Ztm/d3/QXrSddKWxNK49ZyTyHlZfoaJFPp JSaFZIrW5oY92fabwAM6sNcjDChyzlCEJ8VMXA5LZM+smiTLE4U5s4G3CuYHhoKUseJI 90JLqrTKhmsbNzTvbkNvLLd2LqLEuX9LmLE2NJ8d74sRlLprzmWUxygL+/wd5EUrSxci P9lqb0d5HjhHWBxc04/gMrL//qo/tyaP7E+uSulgKjTDEWXmvHrmMltn+gD/QEe89g2w TXuw== ARC-Message-Signature: i=2; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=to:from:subject:references:mime-version:list-unsubscribe :list-subscribe:list-id:precedence:message-id:in-reply-to:date :dkim-signature; bh=mEeFv0uon5WQC9cFYvgD6Kwx90gDUxQUuXbCDfN9dJU=; fh=3USEa3mPzR8ide6bkw7xk1KX62T/r9m6RoKKzb5dT7I=; b=Q0k2YJUcjQrINA9SL7SAC8bH5vOUosd9qrOZbtDUf9qha7uIHFasW3YdGT3cRZwRfJ JfE4lrP10GDXETfclDXVW0hsk9IU0jFLi6x/+48o4dyBFGFrS96alHQ4tVCjmlEz4sKm 0BT5e+eKJdH6tu9aSjrP5aSjaYx97BJb4Hg301vZ2YebhhEt5UsLmNGgKbPGNO7EqKj1 g2eWxg7V9s3w4nDaZn18C6REvTN2tIcogADcSDGk3RyZxqZHF2EwIJUWVv48T2AetuuB Wd7iBV816eCDmK8d01TK/UerVUpD+JiQaOEAajw+PnCgYC6c2tVzVG/fjn4c/esmRp7g VpJg==; dara=google.com ARC-Authentication-Results: i=2; mx.google.com; dkim=pass header.i=@google.com header.s=20230601 header.b=VJyBcTrZ; arc=pass (i=1 spf=pass spfdomain=flex--irogers.bounces.google.com dkim=pass dkdomain=google.com dmarc=pass fromdomain=google.com); spf=pass (google.com: domain of linux-kernel+bounces-62245-ouuuleilei=gmail.com@vger.kernel.org designates 147.75.80.249 as permitted sender) smtp.mailfrom="linux-kernel+bounces-62245-ouuuleilei=gmail.com@vger.kernel.org"; dmarc=pass (p=REJECT sp=REJECT dis=NONE) header.from=google.com X-Forwarded-Encrypted: i=2; AJvYcCVMKsWPFAnhU0cBMVvp2zbG5IK/13ZlyYu3kHM/PE9tOFXIFuOcKZM0ZWZtFrP2vrHKr1f1lZhIV8wqBxjSZ9NZH2VYWg== Received: from am.mirrors.kernel.org (am.mirrors.kernel.org. [147.75.80.249]) by mx.google.com with ESMTPS id b20-20020a1709062b5400b00a3cd089a96asi427687ejg.145.2024.02.12.11.00.55 for (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 12 Feb 2024 11:00:55 -0800 (PST) Received-SPF: pass (google.com: domain of linux-kernel+bounces-62245-ouuuleilei=gmail.com@vger.kernel.org designates 147.75.80.249 as permitted sender) client-ip=147.75.80.249; Authentication-Results: mx.google.com; dkim=pass header.i=@google.com header.s=20230601 header.b=VJyBcTrZ; arc=pass (i=1 spf=pass spfdomain=flex--irogers.bounces.google.com dkim=pass dkdomain=google.com dmarc=pass fromdomain=google.com); spf=pass (google.com: domain of linux-kernel+bounces-62245-ouuuleilei=gmail.com@vger.kernel.org designates 147.75.80.249 as permitted sender) smtp.mailfrom="linux-kernel+bounces-62245-ouuuleilei=gmail.com@vger.kernel.org"; dmarc=pass (p=REJECT sp=REJECT dis=NONE) header.from=google.com Received: from smtp.subspace.kernel.org (wormhole.subspace.kernel.org [52.25.139.140]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by am.mirrors.kernel.org (Postfix) with ESMTPS id BF6821F24B9D for ; Mon, 12 Feb 2024 19:00:54 +0000 (UTC) Received: from localhost.localdomain (localhost.localdomain [127.0.0.1]) by smtp.subspace.kernel.org (Postfix) with ESMTP id 1C6794CB22; Mon, 12 Feb 2024 18:59:28 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="VJyBcTrZ" Received: from mail-yb1-f201.google.com (mail-yb1-f201.google.com [209.85.219.201]) (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 B379645C14 for ; Mon, 12 Feb 2024 18:59:21 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.219.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1707764363; cv=none; b=O8LveCVco4WECY+Gn0/f/GDQBHB6Y7lH4l6qmn7ZBoUV5uDNB/lY66e16lat7/gi8C1ZxHC8xF4I4A96iy56wxf6PgWP2pLyr7fJPiDAkMq8yIWK4mOc4dBHv/QsGxSKxKQMtHLbVW08R+BoVZayxul55Yxe9J/qUZJgFAz2edM= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1707764363; c=relaxed/simple; bh=pokSEbOrag3uWdO1RhTKTOPvPSFp8ZMJI6bQo7DbnNA=; h=Date:In-Reply-To:Message-Id:Mime-Version:References:Subject:From: To:Content-Type; b=uMHXqw0eEuHizsqctw5M8nudd3E4BNoUhVR8n6eGdFfxYepdHWB/b4yEQndgNRhERZTlwqpT9T2g9/1TvEoMpVL/B8QbsrYa29TCfsaigTxvvHRQ2k5z0W261y3yXN8+k9JoHDZrIfjfUS966BvsdkFj5JGl9CCWe3KVrJ3fwmY= 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=VJyBcTrZ; arc=none smtp.client-ip=209.85.219.201 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 Received: by mail-yb1-f201.google.com with SMTP id 3f1490d57ef6-dc6b269b172so5768206276.1 for ; Mon, 12 Feb 2024 10:59:21 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20230601; t=1707764361; x=1708369161; 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=mEeFv0uon5WQC9cFYvgD6Kwx90gDUxQUuXbCDfN9dJU=; b=VJyBcTrZUBi5oZMBg6/NziPWTE5l63C+eegMy4hvn2u1fzJdXhxZXJynWerDIdnnsm hGqsnsBA+/P5Tvs5P4HBWph2ELiMM6DwNz3tz7JeYbwylImdmlvmKWzNC9El0oVUQwKP kFyWDi3mF0ZQpk9AtKrwePZQ6+fFRH7v50t7KX6eQzIpWqRJpwfMs+uN7bHcKcSd6B3F d5qowv4SL1d2wE3qnsaUY0EzzmrnDklS7nXsRiVaLNOpL11MzDOYJcXODklmGWQPq6OA jeZLHMkINn6/iMHZC+t1zNSs0zWP3f0IKOpyZ0NPQRwBZH4oN6kYZMIuve336JSLb0ui eNWQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1707764361; x=1708369161; 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=mEeFv0uon5WQC9cFYvgD6Kwx90gDUxQUuXbCDfN9dJU=; b=qY57+J+spqBP/V9f51rwVDwbXKZYF9ggOq/PZMmf99WKgSYz3hRXTArCO0WU64h2HJ mIn43h5U3MlWK1Oqv4TZxkQyQCGEus8dKIJ7ffp5zf8OVpyD1h8u4xcFVnlpFNA7Zibn lz85f+tG/9L5shrVkI5idZLCIhTlFgC7aF769tEDAt9t1o7NsGNoW9KsxkNEGtMQWlr7 jjpB/k7BKPQE5hbKOAIAVKOoah1UQwdrPGNwifm/JI3MPcO0odJicyuOOm69mX25GU4T FoV23MEIXAEhRuruPPj8ReZqItIEP2anbOq59FhvMA/1RkTL1RCRmciruQsXBdKCtIh+ /XMg== X-Forwarded-Encrypted: i=1; AJvYcCVvsFibKk7WDCbXDLGJS8AwqL1B+nlQh6e0g2AzExLVp1KYwKN1KZtbuuIlfuQd9PVD9/YKRcVX0h6B/xdW33S3L8P4DawaMsSqT9Pc X-Gm-Message-State: AOJu0Yzh6NQIpYxBpBlqUEWb94qdKFJw20Pm+nB+4nFrUQSb+7SxVudg IaEPaC0KmhtjAQ1na+kDYbey4Mx3PnIOBkNUU1fO7KH1RbFH7JCsPFtzr6x/GvAPdWUVRzA+q6w eX4JlBw== X-Received: from irogers.svl.corp.google.com ([2620:15c:2a3:200:125c:bcda:4fe2:b6e6]) (user=irogers job=sendgmr) by 2002:a05:6902:1209:b0:dc7:7655:46ce with SMTP id s9-20020a056902120900b00dc7765546cemr64080ybu.2.1707764360768; Mon, 12 Feb 2024 10:59:20 -0800 (PST) Date: Mon, 12 Feb 2024 10:58:56 -0800 In-Reply-To: <20240212185858.68189-1-irogers@google.com> Message-Id: <20240212185858.68189-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: <20240212185858.68189-1-irogers@google.com> X-Mailer: git-send-email 2.43.0.687.g38aa6559b0-goog Subject: [PATCH v3 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 , James Clark , Athira Jajeev , Kan Liang , Yang Jihong , linux-kernel@vger.kernel.org, linux-perf-users@vger.kernel.org, llvm@lists.linux.dev X-getmail-retrieved-from-mailbox: INBOX X-GMAIL-THRID: 1790720821196783438 X-GMAIL-MSGID: 1790720821196783438 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 | 21 ++--- tools/perf/tests/tests-scripts.c | 144 ++++++++++++++++++------------- 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-test.c index eff3c62e9b47..6d5001daaf63 100644 --- a/tools/perf/tests/builtin-test.c +++ b/tools/perf/tests/builtin-test.c @@ -300,22 +300,20 @@ static int test_and_print(struct test_suite *t, int subtest) } struct shell_test { - const char *dir; const char *file; }; static int shell_test__run(struct test_suite *test, int subdir __maybe_unused) { int err; - char script[PATH_MAX]; struct shell_test *st = test->priv; + char *cmd; - path__join(script, sizeof(script) - 3, st->dir, st->file); - - if (verbose > 0) - strncat(script, " -v", sizeof(script) - strlen(script) - 1); - - err = system(script); + asprintf(&cmd, "%s%s", st->file, verbose ? " -v" : ""); + if (!cmd) + return TEST_FAIL; + err = system(cmd); + free(cmd); if (!err) return TEST_OK; @@ -331,7 +329,7 @@ static int run_shell_tests(int argc, const char *argv[], int i, int width, files = list_script_files(); if (!files) return 0; - for (file = files; file->dir; file++) { + for (file = files; file->file; file++) { int curr = i++; struct test_case test_cases[] = { { @@ -345,13 +343,12 @@ static int run_shell_tests(int argc, const char *argv[], int i, int width, .test_cases = test_cases, .priv = &st, }; - st.dir = file->dir; + st.file = file->file; if (test_suite.desc == NULL || !perf_test__matches(test_suite.desc, curr, argc, argv)) continue; - st.file = file->file; pr_info("%3d: %-*s:", i, width, test_suite.desc); if (intlist__find(skiplist, i)) { @@ -455,7 +452,7 @@ static int perf_test__list_shell(int argc, const char **argv, int i) files = list_script_files(); if (!files) return 0; - for (file = files; file->dir; file++) { + for (file = files; file->file; file++) { int curr = i++; struct test_suite t = { .desc = file->desc diff --git a/tools/perf/tests/tests-scripts.c b/tools/perf/tests/tests-scripts.c index 4ebd841da05b..9b3b66dd5508 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" @@ -35,55 +36,69 @@ static size_t files_num = 0; static struct script_file *files = NULL; static int files_max_width = 0; -static const char *shell_tests__dir(char *path, size_t size) +static int shell_tests__dir_fd(void) { - const char *devel_dirs[] = { "./tools/perf/tests", "./tests", }; - char *exec_path; - unsigned int i; + char path[PATH_MAX], *exec_path; + static const char * const devel_dirs[] = { "./tools/perf/tests/shell", "./tests/shell", }; - for (i = 0; i < ARRAY_SIZE(devel_dirs); ++i) { - struct stat st; + for (size_t i = 0; i < ARRAY_SIZE(devel_dirs); ++i) { + int fd = open(devel_dirs[i], O_PATH); - if (!lstat(devel_dirs[i], &st)) { - scnprintf(path, size, "%s/shell", devel_dirs[i]); - if (!lstat(devel_dirs[i], &st)) - return path; - } + if (fd >= 0) + return fd; } /* Then installed path. */ exec_path = 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); } -static const char *shell_test__description(char *description, size_t size, - const char *path, const char *name) +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 = 0; - path__join(filename, sizeof(filename), path, name); - fp = fopen(filename, "r"); - if (!fp) + io__init(&io, openat(dir_fd, name, O_RDONLY), buf, sizeof(buf)); + if (io.fd < 0) return NULL; /* Skip first line - should be #!/bin/sh Shebang */ + if (io__get_char(&io) != '#') + goto err_out; + if (io__get_char(&io) != '!') + goto err_out; do { - ch = fgetc(fp); - } while (ch != EOF && ch != '\n'); - - description = fgets(description, size, fp); - fclose(fp); + ch = io__get_char(&io); + if (ch < 0) + goto err_out; + } while (ch != '\n'); - /* Assume first char on line is omment everything after that desc */ - return description ? strim(description + 1) : NULL; + do { + ch = io__get_char(&io); + if (ch < 0) + goto err_out; + } while (ch == '#' || isspace(ch)); + while (ch > 0 && ch != '\n') { + desc[pos++] = ch; + if (pos >= (int)sizeof(desc) - 1) + break; + ch = io__get_char(&io); + } + while (pos > 0 && isspace(desc[--pos])) + ; + desc[++pos] = '\0'; + close(io.fd); + return strdup(desc); +err_out: + close(io.fd); + return NULL; } /* 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; @@ -91,20 +106,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) == 0) /* Is executable */ + if (faccessat(dir_fd, path, R_OK | X_OK, 0) == 0) /* Is executable */ return true; } return false; } /* 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); } /* Duplicate a string and fall over and die if we run out of memory */ @@ -120,12 +131,21 @@ static char *strdup_check(const char *str) return newstr; } -static void append_script(const char *dir, const char *file, const char *desc) +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; + snprintf(link, sizeof(link), "/proc/%d/fd/%d", getpid(), dir_fd); + len = readlink(link, filename, sizeof(filename)); + if (len < 0) { + pr_err("Failed to readlink %s", link); + return; + } + filename[len++] = '/'; + strcpy(&filename[len], name); files_num_tmp = files_num + 1; if (files_num_tmp >= SIZE_MAX) { pr_err("Too many script files\n"); @@ -142,10 +162,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 = files_tmp; files_num = files_num_tmp; - files[files_num - 1].dir = strdup_check(dir); - files[files_num - 1].file = strdup_check(file); - files[files_num - 1].desc = strdup_check(desc); - files[files_num].dir = NULL; + files[files_num - 1].file = strdup_check(filename); + files[files_num - 1].desc = desc; files[files_num].file = NULL; files[files_num].desc = NULL; @@ -154,32 +172,39 @@ static void append_script(const char *dir, const char *file, const char *desc) files_max_width = width; } -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]; /* List files, sorted by alpha */ - n_dirs = scandir(path, &entlist, NULL, alphasort); + n_dirs = scandirat(dir_fd, ".", &entlist, NULL, alphasort); if (n_dirs == -1) return; for (i = 0; i < n_dirs && (ent = entlist[i]); i++) { + int fd; + if (ent->d_name[0] == '.') continue; /* Skip hidden files */ - if (is_test_script(path, ent->d_name)) { /* It's a test */ - char bf[256]; - const char *desc = 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 = shell_test__description(dir_fd, ent->d_name); 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 != DT_DIR) { + struct stat st; + + if (ent->d_type != DT_UNKNOWN) + continue; + fstatat(dir_fd, ent->d_name, &st, 0); + if (!S_ISDIR(st.st_mode)) + continue; } + fd = openat(dir_fd, ent->d_name, O_PATH); + append_scripts_in_dir(fd); } for (i = 0; i < n_dirs; i++) /* Clean up */ zfree(&entlist[i]); @@ -188,14 +213,17 @@ static void append_scripts_in_dir(const char *path) const struct script_file *list_script_files(void) { - char path_dir[PATH_MAX]; - const char *path; + int dir_fd; if (files) return files; /* Singleton - we already know our list */ - path = shell_tests__dir(path_dir, sizeof(path_dir)); /* Walk dir */ - append_scripts_in_dir(path); + dir_fd = shell_tests__dir_fd(); /* Walk dir */ + if (dir_fd < 0) + return NULL; + + append_scripts_in_dir(dir_fd); + close(dir_fd); return files; } diff --git a/tools/perf/tests/tests-scripts.h b/tools/perf/tests/tests-scripts.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 struct script_file { - char *dir; char *file; char *desc; };