v10i064: which4 - supersedes fast which2.c

Maarten Litmaath maart at cs.vu.nl
Wed Feb 14 13:02:15 AEST 1990


Posting-number: Volume 10, Issue 64
Submitted-by: maart at cs.vu.nl (Maarten Litmaath)
Archive-name: which4

Dear moderator,
below is the latest version of which2.c, the fast form of the which(1)
command.  Besides aliases and executables, shell functions are now
recognized too.  Furthermore the output will be correct even if the
effective uid (gid) of the invoker doesn't equal the real uid (gid).

An updated manual is included.

I suggest the previous 2 versions (v04i010, v05i016) to be deleted from
the archives, or to be replaced with pointers to which4.

Thanks for your time,
				Maarten Litmaath @ VU Amsterdam:
				maart at cs.vu.nl, uunet!mcsun!botter!maart

: This is a shar archive.  Extract with sh, not csh.
: This archive ends with exit, so do not worry about trailing junk.
: --------------------------- cut here --------------------------
PATH=/bin:/usr/bin:/usr/ucb
echo Extracting 'which.1'
sed 's/^X//' > 'which.1' << '+ END-OF-FILE ''which.1'
X.TH WHICH 1 Sep\ 21\ 1989
X.SH NAME
Xwhich \- give alias, function or path expansion of command
X.SH SYNOPSIS
X.B which
X[
X.B \-i
X] [
X.B \-a
X] [
X.B \-\-
X] [
X.I command
X]
X.SH DESCRIPTION
X.I Which
Xprovides the user with the full expansion of the
X.I command
Xargument, be it either an \fIalias\fR, a \fIshell function\fR
Xor an executable file (default). To enable search for
X.I aliases
Xand \fIshell functions\fR
Xthe user should supply the `\fI\-i\fR'
X(= interactive) flag. In that case
X.I which
Xexpects as standard input the expansion of the \fIalias\fR
Xor \fIshell function\fR.
XIf the standard input is empty or the `\fI\-i\fR' flag has not been
Xgiven, \fIwhich\fR will try to locate \fIcommand\fR
Xin the user's \fIPATH\fR.
XThe interactive mode is easily used by setting an
X.I alias
Xlike the following:
X.ft B
X.nf
X
X	alias	which	alias !\\$ \\| /usr/local/bin/which \-i !\\*
X
X.fi
X.ft R
Xin \fIcsh\fR, or
X.ft B
X.nf
X
X	alias	which	eval alias '\\"\\$$#\\" |' \\
X			/usr/local/bin/which \-i '${1+"$@"}'
X
X.fi
X.ft R
Xin shells which are supersets of
X.I sh
Xand which know \fIaliases\fR. If your shell has \fIshell functions\fR, you
Xcan use the following function:
X.ft B
X.nf
X
X	which()
X	{
X		eval last=\\"\\$$#\\"
X		set | sed \-n "/^$last(){$/,/^}$/p" |
X			/usr/local/bin/which \-i ${1+"$@"}
X	}
X
X.fi
X.ft R
XIf the `\fI\-a\fR' (= all) flag is given,
X.I which
Xwill not stop after the first `match', but search for all occurrences of
X.I command
Xin the user's
X.I PATH.
XThe `\fI\-\-\fR'
Xflag can be used to end the list of options: the next argument (if present)
Xwill be taken as \fIcommand\fR, even if it starts with a `\-'.
X\fIWhich [\-i] [\-a] [\-\-]\fR
Xwithout further arguments prints the user's
X.I PATH
Xbroken up into its components,
Xone per line.
X.PP
XThis new version of the
X.I which
Xcommand is not a
X.I csh
Xscript.
XBeing an executable it is much faster, and not sourcing 
X.I .cshrc
Xit gives a true picture of one's
X.I aliases.
X.SH EXAMPLE
X.ft B
X.nf
X% alias
Xwhich	alias !$ | /usr/local/bin/which \-i !*
X% which which
Xwhich	alias !$ | /usr/local/bin/which \-i !*
X% which \-a which
Xwhich	alias !$ | /usr/local/bin/which \-i !*
X/usr/local/bin/which
X/usr/ucb/which
X%
X.fi
X.ft R
X.SH AUTHOR
XMaarten Litmaath @ VU Informatika Amsterdam
+ END-OF-FILE which.1
chmod 'u=rw,g=r,o=r' 'which.1'
set `wc -c 'which.1'`
count=$1
case $count in
2205)	:;;
*)	echo 'Bad character count in ''which.1' >&2
		echo 'Count should be 2205' >&2
esac
echo Extracting 'Makefile'
sed 's/^X//' > 'Makefile' << '+ END-OF-FILE ''Makefile'
X# Makefile for /usr/local/bin/which
X
Xwhich:		which4.c
X		cc -O which4.c -o which
X
Xinstall:	which
X		/bin/mv -f which /usr/local/bin
X
Xdoc:
X		nroff -man which.1 > which.man
+ END-OF-FILE Makefile
chmod 'u=rw,g=r,o=r' 'Makefile'
set `wc -c 'Makefile'`
count=$1
case $count in
169)	:;;
*)	echo 'Bad character count in ''Makefile' >&2
		echo 'Count should be 169' >&2
esac
echo Extracting 'which4.c'
sed 's/^X//' > 'which4.c' << '+ END-OF-FILE ''which4.c'
X/*
X * which [-i] [-a] [--] [<command>]
X * alias which alias !\$ \| /usr/local/bin/which -i !\*
X * alias which 'eval alias \$$# | /usr/local/bin/which -i ${1+"$@"}'
X * which()
X * {
X *	eval last=\"\$$#\"
X *	set | sed -n "/^$last(){$/,/^}$/p" |
X *		/usr/local/bin/which -i ${1+"$@"}
X * }
X *
X * author: Maarten Litmaath @ VU University Amsterdam (maart at cs.vu.nl)
X * first change:
X *	Emile LeBlanc (leblanc%math.Berkeley.EDU at ucbvax.berkeley.edu) notes
X *	the access() system call considering everything executable for
X *	root (!), so we give root a special treatment
X *	'which', 'which -i' and 'which -a' with no further arguments now
X *	return the PATH environment variable, split up into its components
X *	the aliases defined above are slightly different from the previous
X *	version - now it's the shell who's doing the alias checking
X * second change:
X *	added support for shell functions and multiline aliases, added the
X *	`--' option, changed the source style
X * third change:
X *	to hell with access()!
X *	now stat() is used to give the right answer even if the effective
X *	uid (gid) differs from the real uid (gid)
X *	we can't use setuid(geteuid()), because that's nonportable :-(
X */
X
X#include	<sys/types.h>
X#include	<sys/stat.h>
X#include	<stdio.h>
X
X#define		BUF_SIZE	512
X#define		M_USR		0700
X#define		M_GRP		0070
X#define		M_OTH		0007
X#define		X_ALL		0111
X#define		R_ALL		0444
X
Xchar	Version[] =
X	"@(#)which 4.0 90/01/24 Maarten Litmaath @ VU Informatika Amsterdam";
Xchar	*Prog;
X
X
Xvoid	usage()
X{
X	fprintf(stderr, "Usage: %s [-i] [-a] [--] [<command>]\n", Prog);
X	exit(1);
X}
X
X
Xmain(argc, argv) 
Xint	argc;
Xregister char	**argv;
X{
X	register char	*path, *s;
X	char	*save, *strcpy(), *getenv(), *fgets(), buf[BUF_SIZE];
X	int	all = 0, inter = 0, stop = 0, found = 0, uid, gid, mask,
X		xmask, rmask;
X	struct	stat	st;
X	void	usage(), convert();
X
X
X	Prog = *argv++;
X	--argc;
X
X	while (!stop && (s = *argv) && (*s == '-')) {
X		++argv;
X		--argc;
X		++s;
X		while (*s)
X			switch (*s++) {
X			case 'a':
X				all = 1;
X				break;
X			case 'i':
X				inter = 1;
X				break;
X			case '-':
X				stop = 1;
X				break;
X			default:
X				usage();
X			}
X	}
X
X	if (argc > 1)
X		usage();
X
X	if (inter && *argv) {
X		while (fgets(buf, sizeof buf, stdin)) {
X			if (!found) {
X				printf("%s", *argv);
X				found = 1;
X			}
X			printf("\t%s", buf);
X		}
X		if (found && !all)
X			exit(0);
X	}
X
X	if (!(save = path = getenv("PATH"))) {
X		fprintf(stderr, "%s: no PATH in environment!\n", Prog);
X		exit(1);
X	}
X
X	if (!*path)
X		save = path = ".";
X
X	if (!*argv) {
X		convert(path, buf);
X		puts(buf);
X		exit(0);
X	}
X
X	uid = geteuid();
X	gid = getegid();
X	if (uid == 0) {
X		xmask = X_ALL;
X		rmask = R_ALL;
X	}
X
X	while (*path) {
X		s = buf;
X		while ((*s++ = *path) && *path++ != ':')
X			;
X		if (*buf == ':') {
X			/*
X			 * to deal with the dubious convention that a
X			 * spurious colon is equivalent to a dot...
X			 */
X			*buf = '.';
X			++s;
X		}
X		(void) strcpy(s, *argv);
X		*--s = '/';
X
X		if (stat(buf, &st) != 0 || (st.st_mode & S_IFMT) != S_IFREG)
X			continue;
X
X		/* file exists and is regular */
X
X		if (uid != 0) {
X			mask = st.st_uid == uid ? M_USR :
X				st.st_gid == gid ? M_GRP : M_OTH;
X			xmask = X_ALL & mask;
X			rmask = R_ALL & mask;
X		}
X
X		if (!(st.st_mode & xmask))
X			continue;
X
X		/* file is executable */
X
X		*s = 0;
X		if (stat(buf, &st) != 0) {
X			perror(buf);
X			continue;
X		}
X
X		if (!(st.st_mode & rmask)) {
X			fprintf(stderr,
X				"%s: %s found in unreadable directory %s!\n",
X				Prog, *argv, buf);
X			found = 1;
X			continue;
X		}
X
X		/* directory is readable */
X
X		*s = '/';
X		puts(buf);
X		if (!all)
X			exit(0);
X		found = 1;
X	}
X
X	if (found)
X		exit(0);
X
X	convert(save, buf);
X	fprintf(stderr, "%s not found in\n%s\n", *argv, buf);
X	exit(1);
X}
X
X
Xvoid	convert(path, buf)
Xregister char	*path, *buf;
X{
X	for (;;) {
X		while ((*buf++ = *path) && *path++ != ':')
X			;
X		if (!*path)
X			break;
X		*buf++ = '\n';
X	}
X	*buf = '\0';		/* to cope with a PATH ending in ':' */
X}
+ END-OF-FILE which4.c
chmod 'u=rw,g=r,o=r' 'which4.c'
set `wc -c 'which4.c'`
count=$1
case $count in
3907)	:;;
*)	echo 'Bad character count in ''which4.c' >&2
		echo 'Count should be 3907' >&2
esac
exit 0



More information about the Comp.sources.misc mailing list