aboutsummaryrefslogtreecommitdiffstats
path: root/which.c
diff options
context:
space:
mode:
Diffstat (limited to 'which.c')
-rw-r--r--which.c92
1 files changed, 92 insertions, 0 deletions
diff --git a/which.c b/which.c
new file mode 100644
index 0000000..96a3ece
--- /dev/null
+++ b/which.c
@@ -0,0 +1,92 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+#ifndef TEST
+
+
+const char *
+libsimple_which(const char *file, int cwdfd, const char *path, char **free_this_out)
+{
+ const char *p, *q;
+ char *buf = NULL;
+ size_t bufsize, len, filelen;
+ int got_eacces = 0, saved_errno = errno;
+
+ free_this_out = NULL;
+
+ if (!file || !free_this_out) {
+ errno = EINVAL;
+ return NULL;
+ }
+
+ if (strchr(file, '/'))
+ return file;
+
+ if (!path) {
+ path = getenv("PATH");
+ if (!path)
+ path = "";
+ }
+ if (!*path) {
+ errno = ENOENT;
+ return NULL;
+ }
+
+ bufsize = 0;
+ for (p = path; p; p = q) {
+ q = strchr(p, ':');
+ if (q)
+ len = (size_t)(q++ - p);
+ else
+ len = strlen(p);
+ if (len > bufsize)
+ bufsize = len;
+ }
+ if (bufsize) {
+ filelen = strlen(file) + 1U;
+ bufsize += 1U + filelen;
+ buf = malloc(bufsize);
+ if (!buf)
+ return NULL;
+ }
+
+ for (p = path; p; p = q) {
+ q = strchr(p, ':');
+ if (q)
+ len = (size_t)(q++ - p);
+ else
+ len = strlen(p);
+ if (len) {
+ memcpy(buf, p, len);
+ buf[len] = '/';
+ memcpy(&buf[len + 1], file, filelen);
+ if (!faccessat(cwdfd, buf, X_OK, AT_EACCESS)) {
+ *free_this_out = buf;
+ errno = saved_errno;
+ return buf;
+ }
+ } else {
+ if (!faccessat(cwdfd, file, X_OK, AT_EACCESS)) {
+ errno = saved_errno;
+ return file;
+ }
+ }
+ if (errno == EACCES)
+ got_eacces = 1;
+ }
+
+ free(buf);
+ errno = got_eacces ? EACCES : ENOENT;
+ return NULL;
+}
+
+
+#else
+#include "test.h"
+
+int
+main(void)
+{
+ return 0;
+}
+
+#endif