rc

[fork] interactive rc shell
Log | Files | Refs | README | LICENSE

commit 623048776e55ae3232cd13e1a3c61344de7b85b4
parent 39edd860750a18dffd6767042b90a69648d10db6
Author: tim <tim>
Date:   Thu, 22 May 1997 10:12:03 +0000

Initial revision

Diffstat:
Awhich.c | 114+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 114 insertions(+), 0 deletions(-)

diff --git a/which.c b/which.c @@ -0,0 +1,114 @@ +/* which.c: check to see if a file is executable. + + This function was originally written with Maarten Litmaath's which.c as + a template, but was changed in order to accomodate the possibility of + rc's running setuid or the possibility of executing files not in the + primary group. Much of this file has been re-vamped by Paul Haahr. + I re-re-vamped the functions that Paul supplied to correct minor bugs + and to strip out unneeded functionality. +*/ + +#include <sys/types.h> +#include <sys/stat.h> +#include <sys/param.h> +#include <errno.h> +#include "rc.h" + +#define X_USR 0100 +#define X_GRP 0010 +#define X_OTH 0001 +#define X_ALL (X_USR|X_GRP|X_OTH) + +extern int stat(const char *, struct stat *); + +static bool initialized = FALSE; +static int uid, gid; + +#ifdef NGROUPS +static int ngroups, gidset[NGROUPS]; + +/* determine whether gid lies in gidset */ + +static int ingidset(int g) { + int i; + for (i = 0; i < ngroups; i++) + if (g == gidset[i]) + return 1; + return 0; +} +#endif + +/* + A home-grown access/stat. Does the right thing for group-executable files. + Returns a bool instead of this -1 nonsense. +*/ + +static bool rc_access(char *path, bool verbose) { + struct stat st; + int mask; + if (stat(path, &st) != 0) { + if (verbose) /* verbose flag only set for absolute pathname */ + uerror(path); + return FALSE; + } + if (uid == 0) + mask = X_ALL; + else if (uid == st.st_uid) + mask = X_USR; +#ifdef NGROUPS + else if (gid == st.st_gid || ingidset(st.st_gid)) +#else + else if (gid == st.st_gid) +#endif + mask = X_GRP; + else + mask = X_OTH; + if (((st.st_mode & S_IFMT) == S_IFREG) && (st.st_mode & mask)) + return TRUE; + errno = EACCES; + if (verbose) + uerror(path); + return FALSE; +} + +/* return a full pathname by searching $path, and by checking the status of the file */ + +extern char *which(char *name, bool verbose) { + static char *test = NULL; + static SIZE_T testlen = 0; + List *path; + int len; + if (name == NULL) /* no filename? can happen with "> foo" as a command */ + return NULL; + if (!initialized) { + initialized = TRUE; + uid = geteuid(); + gid = getegid(); +#ifdef NGROUPS + ngroups = getgroups(NGROUPS, gidset); +#endif + } + if (isabsolute(name)) /* absolute pathname? */ + return rc_access(name, verbose) ? name : NULL; + len = strlen(name); + for (path = varlookup("path"); path != NULL; path = path->n) { + SIZE_T need = strlen(path->w) + len + 2; /* one for null terminator, one for the '/' */ + if (testlen < need) { + efree(test); + test = ealloc(testlen = need); + } + if (*path->w == '\0') { + strcpy(test, name); + } else { + strcpy(test, path->w); + if (!streq(test, "/")) /* "//" is special to POSIX */ + strcat(test, "/"); + strcat(test, name); + } + if (rc_access(test, FALSE)) + return test; + } + if (verbose) + fprint(2, "%s not found\n", name); + return NULL; +}