[hackers] [sbase] Refactor and audit which(1) || FRIGN

From: <git_AT_suckless.org>
Date: Mon, 27 Apr 2015 20:34:02 +0200 (CEST)

commit b333176b8c82859ae5a2dbfc8018f7284949f6b0
Author: FRIGN <dev_AT_frign.de>
Date: Mon Apr 27 20:01:30 2015 +0200

    Refactor and audit which(1)
    
    Use the *at functions instead of building paths manually. We do
    still have path-building in recurse() and other areas, but the
    long-term goal is to rid most interfaces of that for practical
    and security reasons.
    In this case, it's more or less trivial.
    
    Also, refactor the manpage to be more consistent with the others.
    
    BUGFIX: Return exit status 3 on error.

diff --git a/README b/README
index 46b2bf7..1259808 100644
--- a/README
+++ b/README
_AT_@ -91,7 +91,7 @@ The following tools are implemented:
 =*|o uudecode .
 =*|o uuencode .
 #*|o wc .
-=* x which .
+=*|x which .
 =*|o xargs (-p)
 =*|x yes .
 
diff --git a/which.1 b/which.1
index 05989ae..ed98d26 100644
--- a/which.1
+++ b/which.1
_AT_@ -3,33 +3,42 @@
 .Os sbase
 .Sh NAME
 .Nm which
-.Nd locate a program file (or files) in the path
+.Nd locate programs in the path
 .Sh SYNOPSIS
 .Nm
 .Op Fl a
-.Op Ar name ...
+.Ar name ...
 .Sh DESCRIPTION
 .Nm
-looks for programs in
+looks for each
+.Ar name
+in the
 .Ev PATH
-.
-.Pp
-If
-.Fl a
-is specified it will display all matches and not stop at the first match.
+directories, stopping at the first match and printing
+the full path to stdout.
+.Sh OPTIONS
+.Bl -tag -width Ds
+.It Fl a
+Don't stop at the first match and search all
+.Ev PATH
+directories.
+.El
 .Sh EXIT STATUS
-The
-.Nm
-utility exits with one of the following values:
 .Bl -tag -width Ds
 .It 0
-All names were successfully resolved.
+Each
+.Ar name
+was found.
 .It 1
-Some names were resolved but not all.
+At least one
+.Ar name
+was not found.
 .It 2
-No names were resolved.
+No
+.Ar name
+was found.
+.It 3
+An error occurred.
 .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
index ed09e07..f3f296b 100644
--- a/which.c
+++ b/which.c
_AT_@ -1,5 +1,7 @@
 #include <sys/stat.h>
+#include <sys/types.h>
 
+#include <fcntl.h>
 #include <limits.h>
 #include <stdio.h>
 #include <stdlib.h>
_AT_@ -14,30 +16,34 @@ static int aflag;
 static int
 which(const char *path, const char *name)
 {
- char file[PATH_MAX], *p, *s, *ptr;
- size_t len;
+ char *ptr, *p;
+ size_t i, len;
         struct stat st;
- int found = 0;
+ int dirfd, 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;
+ ptr = p = enstrdup(3, path);
+ len = strlen(p);
+ for (i = 0; i < len + 1; i++) {
+ if (ptr[i] != ':' && ptr[i] != '\0')
+ continue;
+ ptr[i] = '\0';
+ if ((dirfd = open(p, O_RDONLY, 0)) >= 0) {
+ if (!fstatat(dirfd, name, &st, 0) &&
+ S_ISREG(st.st_mode) &&
+ !faccessat(dirfd, name, X_OK, 0)) {
+ found = 1;
+ fputs(p, stdout);
+ if (i && ptr[i - 1] != '/')
+ fputc('/', stdout);
+ puts(name);
+ if (!aflag) {
+ close(dirfd);
+ break;
+ }
+ }
+ close(dirfd);
                 }
+ p = ptr + i + 1;
         }
         free(ptr);
 
_AT_@ -47,14 +53,14 @@ which(const char *path, const char *name)
 static void
 usage(void)
 {
- eprintf("usage: %s [-a] name...\n", argv0);
+ eprintf("usage: %s [-a] name ...\n", argv0);
 }
 
 int
 main(int argc, char *argv[])
 {
         char *path;
- int i, found;
+ int found = 0, foundall = 1;
 
         ARGBEGIN {
         case 'a':
_AT_@ -68,13 +74,16 @@ main(int argc, char *argv[])
                 usage();
 
         if (!(path = getenv("PATH")))
- eprintf("$PATH not set\n");
+ enprintf(3, "$PATH is 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]);
+ for (; *argv; argc--, argv++) {
+ if (which(path, *argv)) {
+ found = 1;
+ } else {
+ weprintf("%s: command not found.\n", *argv);
+ foundall = 0;
+ }
         }
- return !found ? 2 : found == argc ? 0 : 1;
+
+ return found ? foundall ? 0 : 1 : 2;
 }
Received on Mon Apr 27 2015 - 20:34:02 CEST

This archive was generated by hypermail 2.3.0 : Mon Apr 27 2015 - 20:36:18 CEST