sbase

suckless unix tools
git clone git://git.2f30.org/sbase
Log | Files | Refs | README | LICENSE

commit 58cb564bbde24c758caf3707aa89fb9f27267beb
parent 5595af5742d6d9eb193a563d126c50626ee0fd71
Author: Hiltjo Posthuma <hiltjo@codemadness.org>
Date:   Mon, 27 Apr 2015 16:24:43 +0200

add which

Diffstat:
MMakefile | 1+
MREADME | 1+
Awhich.1 | 35+++++++++++++++++++++++++++++++++++
Awhich.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; +}