| //===----------------------------------------------------------------------===// | |
| // | |
| // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | |
| // See https://llvm.org/LICENSE.txt for license information. | |
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | |
| // | |
| //===----------------------------------------------------------------------===// | |
| /// | |
| /// \file | |
| /// Integration test for program_invocation_name. | |
| /// | |
| //===----------------------------------------------------------------------===// | |
| #include "src/__support/CPP/string_view.h" | |
| #include "src/errno/program_invocation_name.h" | |
| #include "src/errno/program_invocation_short_name.h" | |
| #include "src/unistd/execve.h" | |
| #include "test/IntegrationTest/test.h" | |
| TEST_MAIN(int argc, char **argv, char **envp) { | |
| ASSERT_TRUE(argc >= 1); | |
| ASSERT_TRUE(LIBC_NAMESPACE::program_invocation_name != nullptr); | |
| ASSERT_TRUE(LIBC_NAMESPACE::program_invocation_short_name != nullptr); | |
| ASSERT_TRUE(LIBC_NAMESPACE::program_invocation_name == argv[0]); | |
| LIBC_NAMESPACE::cpp::string_view arg1 = argc > 1 ? argv[1] : ""; | |
| if (arg1 == "reexec1") { | |
| // Step 1: Executed with an absolute path containing slashes. | |
| ASSERT_STREQ(LIBC_NAMESPACE::program_invocation_name, | |
| "/known/path/to/invocation_name"); | |
| ASSERT_STREQ(LIBC_NAMESPACE::program_invocation_short_name, | |
| "invocation_name"); | |
| ASSERT_EQ(argc, 3); | |
| const char *self_path = argv[2]; | |
| char *const child_argv[] = { | |
| const_cast<char *>("./relative/path/to/invocation_name"), | |
| const_cast<char *>("reexec2"), | |
| const_cast<char *>(self_path), | |
| nullptr, | |
| }; | |
| LIBC_NAMESPACE::execve(self_path, child_argv, envp); | |
| ASSERT_TRUE(false); | |
| } | |
| if (arg1 == "reexec2") { | |
| // Step 2: Executed with a relative path containing slashes. | |
| ASSERT_STREQ(LIBC_NAMESPACE::program_invocation_name, | |
| "./relative/path/to/invocation_name"); | |
| ASSERT_STREQ(LIBC_NAMESPACE::program_invocation_short_name, | |
| "invocation_name"); | |
| ASSERT_EQ(argc, 3); | |
| const char *self_path = argv[2]; | |
| char *const child_argv[] = { | |
| const_cast<char *>(""), | |
| const_cast<char *>("reexec3"), | |
| const_cast<char *>(self_path), | |
| nullptr, | |
| }; | |
| LIBC_NAMESPACE::execve(self_path, child_argv, envp); | |
| ASSERT_TRUE(false); | |
| } | |
| if (arg1 == "reexec3") { | |
| // Step 3: Executed with an empty string. | |
| ASSERT_TRUE(LIBC_NAMESPACE::program_invocation_name == | |
| LIBC_NAMESPACE::program_invocation_short_name); | |
| ASSERT_STREQ(LIBC_NAMESPACE::program_invocation_name, ""); | |
| ASSERT_STREQ(LIBC_NAMESPACE::program_invocation_short_name, ""); | |
| ASSERT_EQ(argc, 3); | |
| const char *self_path = argv[2]; | |
| char *const child_argv[] = { | |
| const_cast<char *>("/known/path/to/dir/"), | |
| const_cast<char *>("reexec4"), | |
| const_cast<char *>(self_path), | |
| nullptr, | |
| }; | |
| LIBC_NAMESPACE::execve(self_path, child_argv, envp); | |
| ASSERT_TRUE(false); | |
| } | |
| if (arg1 == "reexec4") { | |
| // Step 4: Executed with a path ending in a slash. | |
| ASSERT_STREQ(LIBC_NAMESPACE::program_invocation_name, | |
| "/known/path/to/dir/"); | |
| ASSERT_STREQ(LIBC_NAMESPACE::program_invocation_short_name, ""); | |
| ASSERT_EQ(argc, 3); | |
| const char *self_path = argv[2]; | |
| char *const child_argv[] = { | |
| const_cast<char *>("invocation_name_no_slash"), | |
| const_cast<char *>("reexec5"), | |
| const_cast<char *>(self_path), | |
| nullptr, | |
| }; | |
| LIBC_NAMESPACE::execve(self_path, child_argv, envp); | |
| ASSERT_TRUE(false); | |
| } | |
| if (arg1 == "reexec5") { | |
| // Step 5: Executed with a path without slashes. | |
| ASSERT_TRUE(LIBC_NAMESPACE::program_invocation_name == | |
| LIBC_NAMESPACE::program_invocation_short_name); | |
| ASSERT_STREQ(LIBC_NAMESPACE::program_invocation_name, | |
| "invocation_name_no_slash"); | |
| ASSERT_STREQ(LIBC_NAMESPACE::program_invocation_short_name, | |
| "invocation_name_no_slash"); | |
| ASSERT_EQ(argc, 3); | |
| const char *self_path = argv[2]; | |
| char *const child_argv[] = { | |
| nullptr, | |
| }; | |
| LIBC_NAMESPACE::execve(self_path, child_argv, envp); | |
| ASSERT_TRUE(false); | |
| } | |
| if (argc == 1 && LIBC_NAMESPACE::cpp::string_view(argv[0]) == "") { | |
| // Step 6: Executed with an empty (zero-length) argv. The kernel adds an | |
| // empty string for argv[0]. | |
| ASSERT_STREQ(LIBC_NAMESPACE::program_invocation_name, ""); | |
| ASSERT_STREQ(LIBC_NAMESPACE::program_invocation_short_name, ""); | |
| return 0; | |
| } | |
| // Step 0: Initial run. Re-exec self with known argv[0] values. | |
| const char *self_path = argv[0]; | |
| char *const child_argv[] = { | |
| const_cast<char *>("/known/path/to/invocation_name"), | |
| const_cast<char *>("reexec1"), | |
| const_cast<char *>(self_path), | |
| nullptr, | |
| }; | |
| LIBC_NAMESPACE::execve(self_path, child_argv, envp); | |
| ASSERT_TRUE(false); | |
| return 1; | |
| } |