commit 58cb564bbde24c758caf3707aa89fb9f27267beb
parent 5595af5742d6d9eb193a563d126c50626ee0fd71
Author: Hiltjo Posthuma <hiltjo@codemadness.org>
Date: Mon, 27 Apr 2015 16:24:43 +0200
add which
Diffstat:
M | Makefile | | | 1 | + |
M | README | | | 1 | + |
A | which.1 | | | 35 | +++++++++++++++++++++++++++++++++++ |
A | which.c | | | 80 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
4 files changed, 117 insertions(+), 0 deletions(-)
diff --git a/Makefile b/Makefile
@@ -152,6 +152,7 @@ BIN =\
uudecode\
uuencode\
wc\
+ which\
xargs\
yes
diff --git a/README b/README
@@ -91,6 +91,7 @@ The following tools are implemented:
=*|o uudecode .
=*|o uuencode .
#*|o wc .
+=* x which .
=*|o xargs (-p)
=*|x yes .
diff --git a/which.1 b/which.1
@@ -0,0 +1,35 @@
+.Dd April 27, 2015
+.Dt WHICH 1
+.Os sbase
+.Sh NAME
+.Nm which
+.Nd locate a program file (or files) in the path
+.Sh SYNOPSIS
+.Nm
+.Op Fl a
+.Op Ar name ...
+.Sh DESCRIPTION
+.Nm
+looks for programs in
+.Ev PATH
+.
+.Pp
+If
+.Fl a
+is specified it will display all matches and not stop at the first match.
+.Sh EXIT STATUS
+The
+.Nm
+utility exits with one of the following values:
+.Bl -tag -width Ds
+.It 0
+All names were successfully resolved.
+.It 1
+Some names were resolved but not all.
+.It 2
+No names were resolved.
+.El
+.Sh DIAGNOSTICS
+If a program is not found it will print "Command not found" to stderr.
+.Sh SEE ALSO
+.Xr environ 7
diff --git a/which.c b/which.c
@@ -0,0 +1,80 @@
+#include <sys/stat.h>
+
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "arg.h"
+#include "util.h"
+
+static int aflag;
+
+static int
+which(const char *path, const char *name)
+{
+ char file[PATH_MAX], *p, *s, *ptr;
+ size_t len;
+ struct stat st;
+ int found = 0;
+
+ p = ptr = estrdup(path);
+ for (s = p; (s = strsep(&p, ":")); ) {
+ if (!s[0])
+ s = ".";
+ len = strlen(s);
+
+ if (snprintf(file, sizeof(file), "%s%s%s",
+ s,
+ len > 0 && s[len - 1] != '/' ? "/" : "",
+ name) >= sizeof(file))
+ eprintf("path too long\n");
+
+ if (stat(file, &st) == 0 && S_ISREG(st.st_mode) &&
+ access(file, X_OK) == 0) {
+ found = 1;
+ puts(file);
+ if (!aflag)
+ break;
+ }
+ }
+ free(ptr);
+
+ return found;
+}
+
+static void
+usage(void)
+{
+ eprintf("usage: %s [-a] name...\n", argv0);
+}
+
+int
+main(int argc, char *argv[])
+{
+ char *path;
+ int i, found;
+
+ ARGBEGIN {
+ case 'a':
+ aflag = 1;
+ break;
+ default:
+ usage();
+ } ARGEND;
+
+ if (!argc)
+ usage();
+
+ if (!(path = getenv("PATH")))
+ eprintf("$PATH not set\n");
+
+ for (i = 0, found = 0; i < argc; i++) {
+ if (which(path, argv[i]))
+ found++;
+ else
+ weprintf("%s: Command not found.\n", argv[i]);
+ }
+ return !found ? 2 : found == argc ? 0 : 1;
+}