Skip site navigation (1)Skip section navigation (2)
Date:      Thu, 13 Dec 2001 09:39:02 -0800 (PST)
From:      Peter Sanchez <fut0n@linuxforlesbians.org>
To:        freebsd-gnats-submit@FreeBSD.org
Subject:   bin/32807: which utility replacement in C
Message-ID:  <200112131739.fBDHd2h30268@freefall.freebsd.org>

next in thread | raw e-mail | index | archive | help

>Number:         32807
>Category:       bin
>Synopsis:       which utility replacement in C
>Confidential:   no
>Severity:       non-critical
>Priority:       low
>Responsible:    freebsd-bugs
>State:          open
>Quarter:        
>Keywords:       
>Date-Required:
>Class:          change-request
>Submitter-Id:   current-users
>Arrival-Date:   Thu Dec 13 09:40:00 PST 2001
>Closed-Date:
>Last-Modified:
>Originator:     Peter Sanchez
>Release:        4.4-STABLE
>Organization:
>Environment:
FreeBSD char.linuxforlesbians.org 4.4-STABLE FreeBSD 4.4-STABLE #0: Thu Nov 22 14:19:15 MST 2001     root@char.linuxforlesbians.org:/usr/src/sys/compile/CHAR  i386
>Description:
Just a simple C program to replace the perl which utility that comes 
default at /usr/bin/which (/usr/src/usr.bin/which). Its slighly faster 
than the perl version.
>How-To-Repeat:
N/A
>Fix:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <pwd.h>

#define NGROUPS 15

struct pathinfo
{
    char path[1024];
    struct pathinfo *next;
};

struct pathinfo *all = NULL;
struct passwd *pw;
uid_t uid;
int found = 1, gfail = 0;
int groups[NGROUPS + 1], ngroups = (NGROUPS + 1);

void
printusage(bin)
    char *bin;
{
    fprintf(stderr,"usage: %s [-a] [-s] program ...\n",bin);
    return;
}

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

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

    if(S_ISDIR(info.st_mode))
        return -1; /* file is a directory */

    /* 
     * I did not use access() here cause of man page warnings that 
     * it is a potential security risk and shoule NEVER be used. Not 
     * quit sure on how it can be a security risk, but I worked around 
     * it anyways.
     */
    if(info.st_uid == uid && info.st_mode & S_IFREG && info.st_mode & S_IXUSR)
        return check; /* user executable */

    if(gfail)
    {
        if(info.st_gid == pw->pw_gid && info.st_mode & S_IFREG &&
           info.st_mode & S_IXGRP)
            return check; /* group executable */
    }
    else
    {
        for(i = 0; i < ngroups; i++)
        {
            if(info.st_gid == groups[i] && info.st_mode & S_IFREG &&
               info.st_mode & S_IXGRP)
                return check; /* group executable */
        }
    }
    
    if(info.st_mode & S_IFREG && info.st_mode & S_IXOTH)
        return check; /* other executable */
    else
        return -1;
}

void
losepath(void)
{
    struct pathinfo *tmp;

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

void
findpath(void)
{
    struct pathinfo *cur = NULL;
    char *userpath = getenv("PATH");
    int i, x;
    
    if(userpath == NULL)
        exit(1);

    all = (struct pathinfo *)malloc((unsigned)sizeof(struct pathinfo));
    if(all == NULL)
    {
        fprintf(stderr,"Out of memory, malloc() failed!\n");
        exit(1);
    }
    cur = all;

    for(i = 0, x = 0; i < strlen(userpath); i++)
    {
        if(userpath[i] == ':')
        {
            cur->path[x] = '\0';
            x = 0;
            cur->next = (struct pathinfo *)malloc((unsigned)sizeof(struct pathinfo));
            if(cur->next == NULL)
            {
                losepath();
                fprintf(stderr,"Out of memory, malloc() failed!\n");
                exit(1);
            }
            cur = cur->next;
        }
        else
            cur->path[x++] = userpath[i];
    }
    cur->path[x] = '\0';
    cur->next = NULL;
    cur = all;
    return;
}

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

    tmp = all;
    while(all != NULL)
    {
        if(strchr(prog,'/'))
            strncpy(tmpbuf,prog,2048);
        else
            snprintf(tmpbuf,2048,"%s/%s",all->path,prog);

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

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

    aflag = sflag = pass = 0;
    if(argc < 2)
        return 1;
       
    if(!strncmp(argv[1],"-h",2) || !strncmp(argv[1],"--h",3) || 
       !strcmp(argv[1],"?"))
    {
        printusage(argv[0]);
        return 1;
    }

    uid = getuid();
    pw = getpwuid(uid);
    if(getgrouplist(pw->pw_name,pw->pw_gid,groups,&ngroups) == -1)
        gfail = 1;

    findpath();
    for(i = 1; i < argc; i++)
    {
        if(!pass && *argv[i] == '-')
        {
            if(!strcmp(argv[i],"-a"))
                aflag = 1;
            else if(!strcmp(argv[i],"-s"))
                sflag = 1;
            else
            {
                printusage(argv[0]);
                return 1;
            }
            continue;
        }

        pass = 1;
        strncpy(buf,argv[i],1024);
        findprog(buf,aflag,sflag);      
    }

    losepath();
    return sflag ? found : 0;
}
>Release-Note:
>Audit-Trail:
>Unformatted:

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?200112131739.fBDHd2h30268>