Skip site navigation (1)Skip section navigation (2)
Date:      Sun, 30 Dec 2001 08:21:50 -0700
From:      Peter Sanchez <fut0n@linuxforlesbians.org>
To:        Sheldon Hearn <sheldonh@starjuice.net>
Cc:        freebsd-bugs@freebsd.org
Subject:   Re: bin/32807: which utility replacement in C
Message-ID:  <20011230082150.C17916@sushi.linuxforlesbians.org>
In-Reply-To: <89022.1009717138@axl.seasidesoftware.co.za>; from sheldonh@starjuice.net on Sun, Dec 30, 2001 at 02:58:58PM %2B0200
References:  <xzpzo4lwer4.fsf@flood.ping.uio.no> <89022.1009717138@axl.seasidesoftware.co.za>

next in thread | previous in thread | raw e-mail | index | archive | help
> On 15 Dec 2001 00:42:07 +0100, Dag-Erling Smorgrav wrote:
>
> Since you've been driving the review process, will you don an asbestos
> suit and use this one to kill the existing perl script? :-)

LOL. Im the one being killed over here ;)

> Note that there's a malloc() that isn't tested for failure, but it's
> hidden in a strdup().  This is in findprog().
> 
> Ciao,
> Sheldon.

Here ya go...

Peter

/*
 * which - a which utility for Unix
 *
 * SYNOPSIS: For FreeBSD-4.x and later
 *
 * DESCRIPTION:
 * Utility to get the full system path of an executable in the 
 * users PATH environment variable.
 *
 * Works for:
 *      FreeBSD 4.x and probably most earlier versions
 *
 * AUTHOR:      Peter Sanchez <psanchez@packet-addiction.org>
 */

#ifndef lint
static const char rcsid[] = "$FreeBSD$";
#endif /* not lint */

#include <sys/types.h>
#include <sys/stat.h>

#include <err.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <pwd.h>
#include <sysexits.h>

#define NGROUPS 15

struct pathinfo {
        struct  pathinfo *next;
        char    *path;
};

struct pathinfo *all = NULL;
int found = 1;

void
usage(void)
{
        (void)fprintf(stderr, "usage: which [-a] [-s] program ...\n");
        exit(EX_USAGE);
}

int
file_exists(char *file)
{
        struct stat info;
        int check;

        check = stat(file, &info);
        if (check == -1)
                return check; /* file doesnt exist */

        return (info.st_mode & S_IFREG && access(file, X_OK) == 0) ? check : -1;
}

void
losepath(void)
{
        struct pathinfo *tmp;

        while (all != NULL) {
                tmp = all->next;
                free(all);
                all = tmp;
        }
}

void
findpath(void)
{
        struct pathinfo *cur = NULL;
        char *userpath = getenv("PATH");
    
        if (userpath == NULL || strlen(userpath) == 0)
                errx(EX_OSERR, "No PATH variable.");

        all = (struct pathinfo *)malloc(sizeof(struct pathinfo));
        if (all == NULL)
                err(EX_OSERR, (char *)NULL);
                /* NOTREACHED */

        cur = all;

        while ((cur->path = strsep(&userpath, ":")) != NULL) {
                cur->next = (struct pathinfo *)malloc(sizeof(struct pathinfo));
                if (cur->next == NULL) {
                        losepath();
                        err(EX_OSERR, (char *)NULL);
                        /* NOTREACHED */
                }

                if (strlen(cur->path) == 0)
                        warnx("PATH element of 0 length.");

                cur = cur->next;
        }
        cur->next = NULL;
        cur = all;
}

void
findprog(char *prog, int aflag, int sflag)
{
        struct pathinfo *tmp;
        char *tmpbuf;

        tmp = all;
        while (all != NULL) {
                if (all->path == NULL)
                        break;
                if (strchr(prog, '/')) {
                        tmpbuf = strdup(prog);
                        if (tmpbuf == NULL) {
                                losepath();
                                err(EX_OSERR, (char *)NULL);
                                /* NOTREACHED */
                        }
                }
                else {
                        tmpbuf = malloc(strlen(all->path) + (strlen(prog) + 1));
                        if (tmpbuf == NULL) {
                                losepath();
                                err(EX_OSERR, (char *)NULL);
                                /* NOTREACHED */
                        }
                        sprintf(tmpbuf, "%s/%s", all->path, prog);
                }

                if (file_exists(tmpbuf) == 0) {
                        found = 0;
                        if (sflag && aflag) ;
                        else if (sflag && !aflag) {
                                all = tmp;
                                free(tmpbuf);
                                return;
                        }
                        else if (aflag && !sflag)
                                (void)printf("%s\n", tmpbuf);
                        else {
                                (void)printf("%s\n", tmpbuf);
                                all = tmp;
                                free(tmpbuf);
                                return;
                        }
                }
                all = all->next;
                free(tmpbuf);
        }
        all = tmp;
}

int
main(int argc, char *argv[])
{
        char ch;
        int aflag, sflag, i;

        aflag = sflag = 0;
        if (argc < 2)
                exit(EX_USAGE);
       
        while ((ch = getopt(argc, argv, "ash?")) != -1) {
                switch (ch) {
                        case 'a':
                                aflag = 1;
                                break;
                        case 's':
                                sflag = 1;
                                break;
                        case 'h':
                        case '?':
                        default:
                                usage();
                                /* NOTREACHED */
                }
        }
        argc -= optind;
        argv += optind;
    
        findpath();
        for (i = 0; i < argc; i++)
                findprog(argv[i], aflag, sflag);
    
        losepath();
        return sflag ? found : 0;
}

-- 
Peter Sanchez, aka fut0n	|	"The ability to read is what
 - fut0n@linuxforlesbians.org	|	 distinguishes Unix users from
 - www.linuxforlesbians.org	|	 those of more popular platforms."
 - FreeBSD or DIE		|			- John Lasser

To Unsubscribe: send mail to majordomo@FreeBSD.org
with "unsubscribe freebsd-bugs" in the body of the message




Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?20011230082150.C17916>