which.c

Go to the documentation of this file.
00001 /*                         W H I C H . C
00002  * BRL-CAD
00003  *
00004  * Copyright (c) 2005-2006 United States Government as represented by
00005  * the U.S. Army Research Laboratory.
00006  *
00007  * This library is free software; you can redistribute it and/or
00008  * modify it under the terms of the GNU Lesser General Public License
00009  * as published by the Free Software Foundation; either version 2 of
00010  * the License, or (at your option) any later version.
00011  *
00012  * This library is distributed in the hope that it will be useful, but
00013  * WITHOUT ANY WARRANTY; without even the implied warranty of
00014  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00015  * Library General Public License for more details.
00016  *
00017  * You should have received a copy of the GNU Lesser General Public
00018  * License along with this file; see the file named COPYING for more
00019  * information.
00020  */
00021 /** @addtogroup bu_log */
00022 /*@{*/
00023 /** @file which.c
00024  *
00025  * Routine to provide BSD "which" functionality, locating binaries of
00026  * specified programs from the user's PATH (i.e.  not necessarily the
00027  * system path).  This is useful to locate system binaries and
00028  * resources at run-time such as where the current binary is being
00029  * executed from.
00030  *
00031  *  Author -
00032  *      Christopher Sean Morrison
00033  *
00034  *  Source -
00035  *      The U. S. Army Research Laboratory
00036  *      Aberdeen Proving Ground, Maryland  21005-5068  USA
00037  */
00038 #include "common.h"
00039 
00040 #include <stdlib.h>
00041 #include <stdio.h>
00042 #include <string.h>
00043 #ifdef HAVE_SYS_TYPES_H
00044 #  include <sys/types.h>
00045 #endif
00046 #ifdef HAVE_SYS_SYSCTL_H
00047 #  ifdef HAVE_SYS_PARAM_H
00048 #    include <sys/param.h>
00049 #  endif
00050 #  include <sys/sysctl.h>
00051 #endif
00052 
00053 #include "machine.h"
00054 #include "bu.h"
00055 
00056 
00057 /** b u _ w h i c h
00058  *
00059  * Sets argv array of path matches to the given executable cmd name
00060  * returning up to lim number of occurances found.  the user path is
00061  * obtained getenv(PATH) or in its absense, via the sysctl
00062  * ``user.cs_path'' string.
00063  *
00064  * It is the callers responsibility to allocate sufficient memory to
00065  * the argv array itself (lim elements), memory for the array contents
00066  * will be automatically allocated as needed.  It is the callers
00067  * responsibility to free the array contents with bu_free_array() as
00068  * well as the argv array itself.
00069  */
00070 int bu_which(char *argv[], int lim, const char *cmd)
00071 {
00072   char *PATH = {0};
00073   int free_path = 0;
00074   char *curr_path;
00075   int max_length;
00076 
00077   char *directory;
00078   char *fullname = {0};
00079 
00080   int found_it;
00081   int found_count = 0;
00082 
00083   int i;
00084 
00085   if (!cmd) {
00086     return 0;
00087   }
00088 
00089   if (lim <= 0) {
00090     return 0;
00091   }
00092 
00093   if (!argv) {
00094     bu_bomb("bu_which was given a null array?\n");
00095   }
00096 
00097   if (bu_file_exists(cmd)) {
00098     /* add the finding */
00099     argv[found_count] = bu_malloc(strlen(cmd) * sizeof(char) + 1, "bu_which argv entry");
00100     strncpy(argv[found_count], cmd, strlen(cmd) + 1);
00101     found_count++;
00102   }
00103 
00104   /* use getenv() if it is available to get the PATH */
00105 #ifdef HAVE_GETENV
00106 #  define bu_which_found_path 1
00107   PATH = getenv("PATH");
00108   goto found_path;
00109 #endif  /* HAVE_GETENV */
00110 
00111   /* otherwise use sysctl() to get the PATH */
00112 #if defined(HAVE_SYSCTL) && defined(CTL_USER) && defined(USER_CS_PATH)
00113 #  define bu_which_found_path 1
00114  {
00115    int mib[2];
00116    size_t len;
00117    mib[0] = CTL_USER;
00118    mib[1] = USER_CS_PATH;
00119 
00120    if (sysctl(mib, 2, NULL, &len, NULL, 0) != 0) {
00121      perror("sysctl unable to read user.cs_path");
00122      return 0;
00123    }
00124    if (len > 0) {
00125      PATH = bu_calloc(len, sizeof(char), "bu_which PATH");
00126      free_path = 1;
00127    }
00128    if (sysctl(mib, 2, PATH, &len, NULL, 0) != 0) {
00129      perror("sysctl unable to get user.cs_path");
00130      return 0;
00131    }
00132    goto found_path;
00133  }
00134 #endif  /* HAVE_SYSCTL */
00135 
00136  /* sanity check, make sure we have _some_ means to get a PATH */
00137 #ifndef bu_which_found_path
00138 #  error "Do not know how to read the PATH environment variable on this system"
00139 #endif
00140 
00141  found_path:
00142 
00143   if (!PATH) {
00144     /* no path, no match */
00145     bu_log("Unable to read the environment PATH\n");
00146     return 0;
00147   }
00148 
00149   /* something big enough to hold any path */
00150   max_length = strlen(PATH) + strlen(cmd) + 1;
00151   fullname = (char *)bu_calloc(max_length+1, sizeof(char), "bu_which fullname");
00152 
00153   /* search the PATH for the executable */
00154   for (curr_path = PATH; ; *curr_path++ = BU_PATH_SEPARATOR) {
00155     directory = curr_path;
00156 
00157     if ((curr_path = strchr(curr_path, BU_PATH_SEPARATOR)) != NULL) {
00158       *curr_path = '\0';
00159 
00160       /* equal means empty, so use current directory */
00161       if (directory == curr_path) {
00162         directory = ".";
00163       }
00164     } else {
00165       /* did not find a path separator, so this is the last element in the list */
00166       if (strlen(directory) == 0) {
00167         directory = ".";
00168       }
00169     }
00170 
00171     (void)snprintf(fullname, max_length, "%s/%s", directory, cmd);
00172 
00173     if (bu_file_exists(fullname)) {
00174       found_it = 0;
00175 
00176       /* make sure it is a new unique path */
00177       for (i = 0; i < found_count; i++) {
00178         if (strncmp(argv[i], fullname, max_length) == 0) {
00179           found_it = 1;
00180           break;
00181         }
00182       }
00183 
00184       /* add the finding if not previously added result */
00185       if (!found_it) {
00186         argv[found_count] = bu_malloc(max_length, "bu_which argv entry");
00187         strncpy(argv[found_count], fullname, max_length);
00188         found_count++;
00189       }
00190     }
00191 
00192     if (!curr_path) {
00193       break;
00194     }
00195     if (found_count >= lim) {
00196       break;
00197     }
00198   } /* end loop over PATH directories */
00199 
00200   bu_free(fullname, "bu_which fullname");
00201   fullname = NULL;
00202 
00203   /* free up the temporary resources */
00204 #ifdef HAVE_SYSCTL
00205   if (free_path && PATH) {
00206     bu_free(PATH, "bu_which PATH");
00207     PATH = NULL;
00208   }
00209 #endif
00210 
00211   return found_count;
00212 }
00213 /*@}*/
00214 /*
00215  * Local Variables:
00216  * mode: C
00217  * tab-width: 8
00218  * c-basic-offset: 4
00219  * indent-tabs-mode: t
00220  * End:
00221  * ex: shiftwidth=4 tabstop=8
00222  */

Generated on Mon Sep 18 01:24:48 2006 for BRL-CAD by  doxygen 1.4.6