This is an automated email from the git hooks/post-receive script. guillem pushed a commit to branch main in repository dpkg.
View the commit online: https://git.dpkg.org/cgit/dpkg/dpkg.git/commit/?id=0fba5af0f97f8e28c4712a0b886069ab0e2c3e13 commit 0fba5af0f97f8e28c4712a0b886069ab0e2c3e13 Author: Guillem Jover <guil...@debian.org> AuthorDate: Thu Aug 24 12:11:14 2023 +0200 libdpkg: Generalize command_in_path() from find_command() This is useful for external users too. --- lib/dpkg/Makefile.am | 6 ++ lib/dpkg/command.c | 45 +++++++++++ lib/dpkg/command.h | 2 + lib/dpkg/libdpkg.map | 1 + .../postinst => lib/dpkg/t/data/command/path-a/cmd | 2 - .../dpkg/t/data/command/path-a/cmd-a | 2 - .../postinst => lib/dpkg/t/data/command/path-b/cmd | 2 - .../dpkg/t/data/command/path-b/cmd-b | 2 - .../dpkg/t/data/command/path-noexec/cmd | 2 - .../dpkg/t/data/command/path-noexec/cmd-noexec | 2 - lib/dpkg/t/t-command.c | 88 +++++++++++++++++++++- src/main/help.c | 39 +--------- src/main/main.h | 1 - src/main/unpack.c | 3 +- 14 files changed, 145 insertions(+), 52 deletions(-) diff --git a/lib/dpkg/Makefile.am b/lib/dpkg/Makefile.am index 3403338ce..9482e3261 100644 --- a/lib/dpkg/Makefile.am +++ b/lib/dpkg/Makefile.am @@ -254,6 +254,12 @@ test_scripts = \ # EOL test_data = \ + t/data/command/path-a/cmd \ + t/data/command/path-a/cmd-a \ + t/data/command/path-b/cmd \ + t/data/command/path-b/cmd-b \ + t/data/command/path-noexec/cmd \ + t/data/command/path-noexec/cmd-noexec \ t/data/meminfo-no-data \ t/data/meminfo-no-info \ t/data/meminfo-no-unit \ diff --git a/lib/dpkg/command.c b/lib/dpkg/command.c index 73f58f61a..8f6934425 100644 --- a/lib/dpkg/command.c +++ b/lib/dpkg/command.c @@ -28,6 +28,8 @@ #include <dpkg/dpkg.h> #include <dpkg/i18n.h> #include <dpkg/string.h> +#include <dpkg/varbuf.h> +#include <dpkg/file.h> #include <dpkg/path.h> #include <dpkg/command.h> @@ -209,3 +211,46 @@ command_shell(const char *cmd, const char *name) execlp(shell, shell, mode, "--", cmd, NULL); ohshite(_("unable to execute %s (%s)"), name, cmd); } + +/** + * Check whether a command can be found in PATH. + * + * @param cmd The command name to check. This is a relative pathname. + * + * @return A boolean denoting whether the command has been found. + */ +bool +command_in_path(const char *cmd) +{ + struct varbuf filename = VARBUF_INIT; + const char *path_list; + const char *path, *path_end; + + if (cmd[0] == '/') + return file_is_exec(cmd); + + path_list = getenv("PATH"); + if (!path_list) + ohshit(_("PATH is not set")); + + for (path = path_list; path; path = *path_end ? path_end + 1 : NULL) { + size_t path_len; + + path_end = strchrnul(path, ':'); + path_len = (size_t)(path_end - path); + + varbuf_set_buf(&filename, path, path_len); + if (path_len) + varbuf_add_char(&filename, '/'); + varbuf_add_str(&filename, cmd); + varbuf_end_str(&filename); + + if (file_is_exec(filename.buf)) { + varbuf_destroy(&filename); + return true; + } + } + + varbuf_destroy(&filename); + return false; +} diff --git a/lib/dpkg/command.h b/lib/dpkg/command.h index 09ec92ac7..768aba437 100644 --- a/lib/dpkg/command.h +++ b/lib/dpkg/command.h @@ -58,6 +58,8 @@ void command_exec(struct command *cmd) DPKG_ATTR_NORET; void command_shell(const char *cmd, const char *name) DPKG_ATTR_NORET; +bool command_in_path(const char *cmd); + /** @} */ DPKG_END_DECLS diff --git a/lib/dpkg/libdpkg.map b/lib/dpkg/libdpkg.map index fa4329bb1..e0b11520d 100644 --- a/lib/dpkg/libdpkg.map +++ b/lib/dpkg/libdpkg.map @@ -202,6 +202,7 @@ LIBDPKG_PRIVATE { command_add_args; command_exec; command_shell; + command_in_path; command_destroy; pager_get_exec; diff --git a/tests/t-predepends-no-triggers/pkg-trigger/DEBIAN/postinst b/lib/dpkg/t/data/command/path-a/cmd similarity index 55% copy from tests/t-predepends-no-triggers/pkg-trigger/DEBIAN/postinst copy to lib/dpkg/t/data/command/path-a/cmd index c52d3c26b..1a2485251 100755 --- a/tests/t-predepends-no-triggers/pkg-trigger/DEBIAN/postinst +++ b/lib/dpkg/t/data/command/path-a/cmd @@ -1,3 +1 @@ #!/bin/sh - -exit 0 diff --git a/tests/t-predepends-no-triggers/pkg-trigger/DEBIAN/postinst b/lib/dpkg/t/data/command/path-a/cmd-a similarity index 55% copy from tests/t-predepends-no-triggers/pkg-trigger/DEBIAN/postinst copy to lib/dpkg/t/data/command/path-a/cmd-a index c52d3c26b..1a2485251 100755 --- a/tests/t-predepends-no-triggers/pkg-trigger/DEBIAN/postinst +++ b/lib/dpkg/t/data/command/path-a/cmd-a @@ -1,3 +1 @@ #!/bin/sh - -exit 0 diff --git a/tests/t-predepends-no-triggers/pkg-trigger/DEBIAN/postinst b/lib/dpkg/t/data/command/path-b/cmd similarity index 55% copy from tests/t-predepends-no-triggers/pkg-trigger/DEBIAN/postinst copy to lib/dpkg/t/data/command/path-b/cmd index c52d3c26b..1a2485251 100755 --- a/tests/t-predepends-no-triggers/pkg-trigger/DEBIAN/postinst +++ b/lib/dpkg/t/data/command/path-b/cmd @@ -1,3 +1 @@ #!/bin/sh - -exit 0 diff --git a/tests/t-predepends-no-triggers/pkg-trigger/DEBIAN/postinst b/lib/dpkg/t/data/command/path-b/cmd-b similarity index 55% copy from tests/t-predepends-no-triggers/pkg-trigger/DEBIAN/postinst copy to lib/dpkg/t/data/command/path-b/cmd-b index c52d3c26b..1a2485251 100755 --- a/tests/t-predepends-no-triggers/pkg-trigger/DEBIAN/postinst +++ b/lib/dpkg/t/data/command/path-b/cmd-b @@ -1,3 +1 @@ #!/bin/sh - -exit 0 diff --git a/tests/t-predepends-no-triggers/pkg-trigger/DEBIAN/postinst b/lib/dpkg/t/data/command/path-noexec/cmd old mode 100755 new mode 100644 similarity index 55% copy from tests/t-predepends-no-triggers/pkg-trigger/DEBIAN/postinst copy to lib/dpkg/t/data/command/path-noexec/cmd index c52d3c26b..1a2485251 --- a/tests/t-predepends-no-triggers/pkg-trigger/DEBIAN/postinst +++ b/lib/dpkg/t/data/command/path-noexec/cmd @@ -1,3 +1 @@ #!/bin/sh - -exit 0 diff --git a/tests/t-predepends-no-triggers/pkg-trigger/DEBIAN/postinst b/lib/dpkg/t/data/command/path-noexec/cmd-noexec old mode 100755 new mode 100644 similarity index 55% copy from tests/t-predepends-no-triggers/pkg-trigger/DEBIAN/postinst copy to lib/dpkg/t/data/command/path-noexec/cmd-noexec index c52d3c26b..1a2485251 --- a/tests/t-predepends-no-triggers/pkg-trigger/DEBIAN/postinst +++ b/lib/dpkg/t/data/command/path-noexec/cmd-noexec @@ -1,3 +1 @@ #!/bin/sh - -exit 0 diff --git a/lib/dpkg/t/t-command.c b/lib/dpkg/t/t-command.c index 33e002e12..3a2e64bda 100644 --- a/lib/dpkg/t/t-command.c +++ b/lib/dpkg/t/t-command.c @@ -185,6 +185,91 @@ test_command_exec(void) command_destroy(&cmd); } +static void +test_command_in_path(void) +{ + char *path_a, *path_b, *path_noexec; + char *oldpath, *newpath = NULL; + bool ret; + int rc; + + path_a = test_data_file("command/path-a"); + path_b = test_data_file("command/path-b"); + path_noexec = test_data_file("command/path-noexec"); + + oldpath = getenv("PATH"); + + setenv("PATH", "", 1); + ret = command_in_path("cmd"); + test_pass(ret == false); + ret = command_in_path("cmd-a"); + test_pass(ret == false); + ret = command_in_path("cmd-b"); + test_pass(ret == false); + ret = command_in_path("cmd-noexec"); + test_pass(ret == false); + + setenv("PATH", "/nonexistent", 1); + ret = command_in_path("cmd"); + test_pass(ret == false); + ret = command_in_path("cmd-a"); + test_pass(ret == false); + ret = command_in_path("cmd-b"); + test_pass(ret == false); + ret = command_in_path("cmd-noexec"); + test_pass(ret == false); + + setenv("PATH", path_a, 1); + ret = command_in_path("cmd"); + test_pass(ret == true); + ret = command_in_path("cmd-a"); + test_pass(ret == true); + ret = command_in_path("cmd-b"); + test_pass(ret == false); + ret = command_in_path("cmd-noexec"); + test_pass(ret == false); + + setenv("PATH", path_b, 1); + ret = command_in_path("cmd"); + test_pass(ret == true); + ret = command_in_path("cmd-a"); + test_pass(ret == false); + ret = command_in_path("cmd-b"); + test_pass(ret == true); + ret = command_in_path("cmd-noexec"); + test_pass(ret == false); + + setenv("PATH", path_noexec, 1); + ret = command_in_path("cmd"); + test_pass(ret == false); + ret = command_in_path("cmd-a"); + test_pass(ret == false); + ret = command_in_path("cmd-b"); + test_pass(ret == false); + ret = command_in_path("cmd-noexec"); + test_pass(ret == false); + + rc = asprintf(&newpath, "/nonexistent:%s:%s:%s", path_a, path_b, path_noexec); + if (rc < 0) + test_bail("cannot allocate new PATH variable"); + setenv("PATH", newpath, 1); + ret = command_in_path("cmd"); + test_pass(ret == true); + ret = command_in_path("cmd-a"); + test_pass(ret == true); + ret = command_in_path("cmd-b"); + test_pass(ret == true); + ret = command_in_path("cmd-noexec"); + test_pass(ret == false); + + setenv("PATH", oldpath, 1); + + free(path_a); + free(path_b); + free(path_noexec); + free(newpath); +} + static void test_command_shell(void) { @@ -213,7 +298,7 @@ test_command_shell(void) TEST_ENTRY(test) { - test_plan(49); + test_plan(73); test_command_init(); test_command_grow_argv(); @@ -221,5 +306,6 @@ TEST_ENTRY(test) test_command_add_argl(); test_command_add_args(); test_command_exec(); + test_command_in_path(); test_command_shell(); } diff --git a/src/main/help.c b/src/main/help.c index cfce1bbce..e81466938 100644 --- a/src/main/help.c +++ b/src/main/help.c @@ -35,6 +35,7 @@ #include <dpkg/dpkg-db.h> #include <dpkg/path.h> #include <dpkg/file.h> +#include <dpkg/command.h> #include <dpkg/db-fsys.h> #include "main.h" @@ -75,42 +76,6 @@ namenodetouse(struct fsys_namenode *namenode, struct pkginfo *pkg, return fnn; } -bool -find_command(const char *prog) -{ - struct varbuf filename = VARBUF_INIT; - const char *path_list; - const char *path, *path_end; - - if (prog[0] == '/') - return file_is_exec(prog); - - path_list = getenv("PATH"); - if (!path_list) - ohshit(_("PATH is not set")); - - for (path = path_list; path; path = *path_end ? path_end + 1 : NULL) { - size_t path_len; - - path_end = strchrnul(path, ':'); - path_len = (size_t)(path_end - path); - - varbuf_set_buf(&filename, path, path_len); - if (path_len) - varbuf_add_char(&filename, '/'); - varbuf_add_str(&filename, prog); - varbuf_end_str(&filename); - - if (file_is_exec(filename.buf)) { - varbuf_destroy(&filename); - return true; - } - } - - varbuf_destroy(&filename); - return false; -} - /** * Verify that some programs can be found in the PATH. */ @@ -139,7 +104,7 @@ void checkpath(void) { int warned= 0; for (prog = prog_list; *prog; prog++) { - if (!find_command(*prog)) { + if (!command_in_path(*prog)) { warning(_("'%s' not found in PATH or not executable"), *prog); warned++; } diff --git a/src/main/main.h b/src/main/main.h index 9b7d896bd..f841e8d46 100644 --- a/src/main/main.h +++ b/src/main/main.h @@ -223,7 +223,6 @@ bool force_conflicts(struct deppossi *possi); void conffile_mark_obsolete(struct pkginfo *pkg, struct fsys_namenode *namenode); void pkg_conffiles_mark_old(struct pkginfo *pkg); -bool find_command(const char *prog); void checkpath(void); struct fsys_namenode * diff --git a/src/main/unpack.c b/src/main/unpack.c index be0a41765..97dd0a0d1 100644 --- a/src/main/unpack.c +++ b/src/main/unpack.c @@ -46,6 +46,7 @@ #include <dpkg/pkg.h> #include <dpkg/pkg-queue.h> #include <dpkg/path.h> +#include <dpkg/command.h> #include <dpkg/buffer.h> #include <dpkg/subproc.h> #include <dpkg/dir.h> @@ -132,7 +133,7 @@ deb_verify(const char *filename) /* We have to check on every unpack, in case the debsig-verify package * gets installed or removed. */ - if (!find_command(DEBSIGVERIFY)) + if (!command_in_path(DEBSIGVERIFY)) return; printf(_("Authenticating %s ...\n"), filename); -- Dpkg.Org's dpkg