diff --git a/Makefile b/Makefile index 27ce5ef..9baecd8 100644 --- a/Makefile +++ b/Makefile @@ -152,6 +152,7 @@ BIN =\ uudecode\ uuencode\ wc\ + which\ xargs\ yes diff --git a/README b/README index 2009e49..46b2bf7 100644 --- 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 new file mode 100644 index 0000000..05989ae --- /dev/null +++ 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 new file mode 100644 index 0000000..ed09e07 --- /dev/null +++ b/which.c @@ -0,0 +1,80 @@ +#include + +#include +#include +#include +#include +#include + +#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; +}