98 lines
2.3 KiB
C
98 lines
2.3 KiB
C
#include <errno.h>
|
|
#include <stdbool.h>
|
|
#include <stdio.h> /* fprintf(3) */
|
|
#include <stdlib.h> /* exit(3) */
|
|
#include <sysexits.h>
|
|
#include <unistd.h> /* access(2), chdir(2) */
|
|
|
|
#include "libshell.h" /* getpaths(3) */
|
|
|
|
void
|
|
usage(char *name){
|
|
fprintf(stderr, "Usage: %s (-a) [name]\n", name);
|
|
exit(EX_USAGE);
|
|
}
|
|
|
|
int
|
|
which(char *program, char **paths, char *name, bool breakonfirst){
|
|
char **q;
|
|
int retval;
|
|
retval = 0;
|
|
|
|
for(q = paths; *q != NULL; ++q){
|
|
if(chdir(*q) != 0)
|
|
switch(retval = errno){
|
|
/* Non-issues in the context of this program */
|
|
case EACCES: /* Access denied */
|
|
case ELOOP: /* Too many symlinks in path */
|
|
case ENAMETOOLONG: /* Name too long */
|
|
case ENOENT: /* Directory doesn't exist */
|
|
case ENOTDIR: /* Not a directory */
|
|
continue;
|
|
case EFAULT:
|
|
goto apology;
|
|
case EIO:
|
|
goto ioerr;
|
|
}
|
|
/* Changed dir, now check for file in dir */
|
|
if(access(program, R_OK | X_OK) != 0)
|
|
switch(retval = errno){
|
|
case EACCES:
|
|
case ELOOP:
|
|
case ENAMETOOLONG:
|
|
case ENOENT:
|
|
case EROFS:
|
|
continue;
|
|
case EFAULT:
|
|
goto apology;
|
|
case EIO:
|
|
goto ioerr;
|
|
}
|
|
else{
|
|
fprintf(stdout, "%s%s\n", *q, program);
|
|
if(breakonfirst != 0)
|
|
break;
|
|
}
|
|
}
|
|
end:
|
|
return retval;
|
|
apology:
|
|
fprintf(stderr,
|
|
/* EFAULT means the pointer passed to either chdir(2) or access(2) was outside
|
|
* of the address space available to the program. This means something's Very
|
|
* Wrong with getpaths(3) and libshell has to be fixed. That'd be a serious,
|
|
* common error, so try to reassure the user and solicit a bug report. */
|
|
"%s: EFAULT\n"
|
|
"You the user did nothing to invoke this error message. This is an error in\n"
|
|
"which, a program you or another program executed. PLEASE e-mail the creator\n"
|
|
"of this program (the address can be found in the corresponding manual page)\n"
|
|
"and tell them you got this error and what you were doing when it happened.\n"
|
|
"Sorry!\n", name);
|
|
goto end;
|
|
ioerr:
|
|
fprintf(stderr, "%s: filesystem I/O error\n", name);
|
|
goto end;
|
|
}
|
|
|
|
int main(int argc, char *argv[]){
|
|
int i;
|
|
char **paths;
|
|
int retval;
|
|
|
|
if(argc <= 1)
|
|
usage(argv[0]);
|
|
|
|
if((paths = getpaths()) == NULL){
|
|
fprintf(stderr, "%s: Could not get the value of $PATH\n", argv[0]);
|
|
exit(1);
|
|
}
|
|
|
|
for(i = 1; i < argc; ++i)
|
|
if((retval = which(argv[i], paths, argv[0], 1)) != 0)
|
|
break;
|
|
|
|
free(*paths);
|
|
free(paths);
|
|
return retval;
|
|
}
|