"Fossies" - the Fresh Open Source Software Archive

Member "which-2.21/bash.c" (19 Mar 2015, 13140 Bytes) of package /linux/privat/which-2.21.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "bash.c" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 2.20_vs_2.21.

    1 /*
    2  * Copyright (C) 1987 - 2002 Free Software Foundation, Inc.
    3  *
    4  * This file is based on stuff from GNU Bash 1.14.7, the Bourne Again SHell.
    5  * Everything that was changed is marked with the word `CHANGED'.
    6  *
    7  * This program is free software; you can redistribute it and/or
    8  * modify it under the terms of the GNU General Public License
    9  * as published by the Free Software Foundation; either version 2
   10  * of the License, or (at your option) any later version.
   11  *
   12  * This program is distributed in the hope that it will be useful,
   13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
   14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   15  * GNU General Public License for more details.
   16  *
   17  * You should have received a copy of the GNU General Public License
   18  * along with this program; if not, write to the Free Software
   19  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02110-1301, USA.
   20  */
   21 
   22 #include "sys.h"
   23 #include "posixstat.h"
   24 #include <pwd.h>
   25 #include <unistd.h>
   26 #include "bash.h"
   27 
   28 /* Use the type that was determined by configure. */
   29 #define GID_T GETGROUPS_T
   30 
   31 /*
   32  * CHANGED:
   33  * Perhaps these need new configure.in entries.
   34  * The following macro's are used in bash, and below:
   35  */
   36 #undef SHELL
   37 #undef AFS
   38 #undef NOGROUP
   39 
   40 /*
   41  * CHANGED:
   42  * - Added prototypes,
   43  * - used ANSI function arguments,
   44  * - made all functions static and
   45  * - changed all occurences of 'char *' into 'char const*' where possible.
   46  * - changed all occurences of 'gid_t' into 'GID_T'.
   47  * - exported functions needed in which.c
   48  */
   49 static char* extract_colon_unit (char const* string, int* p_index);
   50 
   51 /*===========================================================================
   52  *
   53  * Everything below is from bash-4.3.
   54  *
   55  */
   56 
   57 /* From bash-4.3 / shell.h / line 113 */
   58 /* Information about the current user. */
   59 struct user_info {
   60   uid_t uid, euid;
   61   GID_T gid, egid;
   62   char *user_name;
   63   char *shell;          /* shell from the password file */
   64   char *home_dir;
   65 };
   66 
   67 /* From bash-4.3 / shell.c / line 116 */
   68 /* Information about the current user. */
   69 struct user_info current_user =
   70 {
   71   (uid_t)-1, (uid_t)-1, (GID_T)-1, (GID_T)-1,
   72   (char *)NULL, (char *)NULL, (char *)NULL
   73 };
   74 
   75 /* From bash-4.3 / general.h / line 153 */
   76 #define FREE(s)  do { if (s) free (s); } while (0)
   77 
   78 /* From bash-4.3 / shell.c / line 1201 */
   79 /* Fetch the current set of uids and gids and return 1 if we're running
   80    setuid or setgid. */
   81 int
   82 uidget ()
   83 {
   84   uid_t u;
   85 
   86   u = getuid ();
   87   if (current_user.uid != u)
   88     {
   89       FREE (current_user.user_name);
   90       FREE (current_user.shell);
   91       FREE (current_user.home_dir);
   92       current_user.user_name = current_user.shell = current_user.home_dir = (char *)NULL;
   93     }
   94   current_user.uid = u;
   95   current_user.gid = getgid ();
   96   current_user.euid = geteuid ();
   97   current_user.egid = getegid ();
   98 
   99   /* See whether or not we are running setuid or setgid. */
  100   return (current_user.uid != current_user.euid) ||
  101            (current_user.gid != current_user.egid);
  102 }
  103 
  104 /* From bash-4.3 / general.c / line 1018 */
  105 static int ngroups, maxgroups;
  106 
  107 /* From bash-4.3 / general.c / line 1020 */
  108 /* The set of groups that this user is a member of. */
  109 static GETGROUPS_T *group_array = (GETGROUPS_T *)NULL;
  110 
  111 /* From bash-4.3 / general.c / line 1023 */
  112 #if !defined (NOGROUP)
  113 #  define NOGROUP (GID_T) -1
  114 #endif
  115 
  116 /* From bash-4.3 / lib/sh/oslib.c / line 250 */
  117 #define DEFAULT_MAXGROUPS 64
  118 
  119 /* From bash-4.3 / lib/sh/oslib.c / line 252 */
  120 int
  121 getmaxgroups ()
  122 {
  123   static int maxgroups = -1;
  124 
  125   if (maxgroups > 0)
  126     return maxgroups;
  127 
  128 #if defined (HAVE_SYSCONF) && defined (_SC_NGROUPS_MAX)
  129   maxgroups = sysconf (_SC_NGROUPS_MAX);
  130 #else
  131 #  if defined (NGROUPS_MAX)
  132   maxgroups = NGROUPS_MAX;
  133 #  else /* !NGROUPS_MAX */
  134 #    if defined (NGROUPS)
  135   maxgroups = NGROUPS;
  136 #    else /* !NGROUPS */
  137   maxgroups = DEFAULT_MAXGROUPS;
  138 #    endif /* !NGROUPS */
  139 #  endif /* !NGROUPS_MAX */
  140 #endif /* !HAVE_SYSCONF || !SC_NGROUPS_MAX */
  141 
  142   if (maxgroups <= 0)
  143     maxgroups = DEFAULT_MAXGROUPS;
  144 
  145   return maxgroups;
  146 }
  147 
  148 /* From bash-4.3 / general.c / line 1027 */
  149 static void
  150 initialize_group_array ()
  151 {
  152   register int i;
  153 
  154   if (maxgroups == 0)
  155     maxgroups = getmaxgroups ();
  156 
  157   ngroups = 0;
  158   group_array = (GETGROUPS_T *)xrealloc (group_array, maxgroups * sizeof (GETGROUPS_T));
  159 
  160 #if defined (HAVE_GETGROUPS)
  161   ngroups = getgroups (maxgroups, group_array);
  162 #endif
  163 
  164   /* If getgroups returns nothing, or the OS does not support getgroups(),
  165      make sure the groups array includes at least the current gid. */
  166   if (ngroups == 0)
  167     {
  168       group_array[0] = current_user.gid;
  169       ngroups = 1;
  170     }
  171 
  172   /* If the primary group is not in the groups array, add it as group_array[0]
  173      and shuffle everything else up 1, if there's room. */
  174   for (i = 0; i < ngroups; i++)
  175     if (current_user.gid == (GID_T)group_array[i])
  176       break;
  177   if (i == ngroups && ngroups < maxgroups)
  178     {
  179       for (i = ngroups; i > 0; i--)
  180         group_array[i] = group_array[i - 1];
  181       group_array[0] = current_user.gid;
  182       ngroups++;
  183     }
  184 
  185   /* If the primary group is not group_array[0], swap group_array[0] and
  186      whatever the current group is.  The vast majority of systems should
  187      not need this; a notable exception is Linux. */
  188   if (group_array[0] != current_user.gid)
  189     {
  190       for (i = 0; i < ngroups; i++)
  191         if (group_array[i] == current_user.gid)
  192           break;
  193       if (i < ngroups)
  194         {
  195           group_array[i] = group_array[0];
  196           group_array[0] = current_user.gid;
  197         }
  198     }
  199 }
  200 
  201 /* From bash-4.3 / general.c / line 1079 */
  202 /* Return non-zero if GID is one that we have in our groups list. */
  203 int
  204 #if defined (__STDC__) || defined ( _MINIX)
  205 group_member (GID_T gid)
  206 #else
  207 group_member (gid)
  208      GID_T gid;
  209 #endif /* !__STDC__ && !_MINIX */
  210 {
  211 #if defined (HAVE_GETGROUPS)
  212   register int i;
  213 #endif
  214 
  215   /* Short-circuit if possible, maybe saving a call to getgroups(). */
  216   if (gid == current_user.gid || gid == current_user.egid)
  217     return (1);
  218 
  219 #if defined (HAVE_GETGROUPS)
  220   if (ngroups == 0)
  221     initialize_group_array ();
  222 
  223   /* In case of error, the user loses. */
  224   if (ngroups <= 0)
  225     return (0);
  226 
  227   /* Search through the list looking for GID. */
  228   for (i = 0; i < ngroups; i++)
  229     if (gid == (GID_T)group_array[i])
  230       return (1);
  231 #endif
  232 
  233   return (0);
  234 }
  235 
  236 /* From bash-4.3 / findcmd.c / line 80 */
  237 /* Return some flags based on information about this file.
  238    The EXISTS bit is non-zero if the file is found.
  239    The EXECABLE bit is non-zero the file is executble.
  240    Zero is returned if the file is not found. */
  241 int
  242 file_status (char const* name)
  243 {
  244   struct stat finfo;
  245   int r;
  246 
  247   /* Determine whether this file exists or not. */
  248   if (stat (name, &finfo) < 0)
  249     return (0);
  250 
  251   /* If the file is a directory, then it is not "executable" in the
  252      sense of the shell. */
  253   if (S_ISDIR (finfo.st_mode))
  254     return (FS_EXISTS|FS_DIRECTORY);
  255 
  256   r = FS_EXISTS;
  257 
  258 #if defined (HAVE_EACCESS)
  259   /* Use eaccess(2) if we have it to take things like ACLs and other
  260      file access mechanisms into account.  eaccess uses the effective
  261      user and group IDs, not the real ones.  We could use sh_eaccess,
  262      but we don't want any special treatment for /dev/fd. */
  263   if (eaccess (name, X_OK) == 0)
  264     r |= FS_EXECABLE;
  265   if (eaccess (name, R_OK) == 0)
  266     r |= FS_READABLE;
  267 
  268   return r;
  269 #elif defined (AFS)
  270   /* We have to use access(2) to determine access because AFS does not
  271      support Unix file system semantics.  This may produce wrong
  272      answers for non-AFS files when ruid != euid.  I hate AFS. */
  273   if (access (name, X_OK) == 0)
  274     r |= FS_EXECABLE;
  275   if (access (name, R_OK) == 0)
  276     r |= FS_READABLE;
  277 
  278   return r;
  279 #else /* !AFS */
  280 
  281   /* Find out if the file is actually executable.  By definition, the
  282      only other criteria is that the file has an execute bit set that
  283      we can use.  The same with whether or not a file is readable. */
  284 
  285   /* Root only requires execute permission for any of owner, group or
  286      others to be able to exec a file, and can read any file. */
  287   if (current_user.euid == (uid_t)0)
  288     {
  289       r |= FS_READABLE;
  290       if (finfo.st_mode & S_IXUGO)
  291     r |= FS_EXECABLE;
  292       return r;
  293     }
  294 
  295   /* If we are the owner of the file, the owner bits apply. */
  296   if (current_user.euid == finfo.st_uid)
  297     {
  298       if (finfo.st_mode & S_IXUSR)
  299     r |= FS_EXECABLE;
  300       if (finfo.st_mode & S_IRUSR)
  301     r |= FS_READABLE;
  302     }
  303 
  304   /* If we are in the owning group, the group permissions apply. */
  305   else if (group_member (finfo.st_gid))
  306     {
  307       if (finfo.st_mode & S_IXGRP)
  308     r |= FS_EXECABLE;
  309       if (finfo.st_mode & S_IRGRP)
  310     r |= FS_READABLE;
  311     }
  312 
  313   /* Else we check whether `others' have permission to execute the file */
  314   else
  315     {
  316       if (finfo.st_mode & S_IXOTH)
  317     r |= FS_EXECABLE;
  318       if (finfo.st_mode & S_IROTH)
  319     r |= FS_READABLE;
  320     }
  321 
  322   return r;
  323 #endif /* !AFS */
  324 }
  325 
  326 /* From bash-4.3 / general.c / line 604 ; Changes: Using 'strchr' instead of 'mbschr'. */
  327 /* Return 1 if STRING is an absolute program name; it is absolute if it
  328    contains any slashes.  This is used to decide whether or not to look
  329    up through $PATH. */
  330 int
  331 absolute_program (char const* string)
  332 {
  333   return ((char *)strchr (string, '/') != (char *)NULL);
  334 }
  335 
  336 /* From bash-4.3 / stringlib.c / line 124 */
  337 /* Cons a new string from STRING starting at START and ending at END,
  338    not including END. */
  339 char *
  340 substring (char const* string, int start, int end)
  341 {
  342   register int len;
  343   register char *result;
  344 
  345   len = end - start;
  346   result = (char *)xmalloc (len + 1);
  347   memcpy (result, string + start, len);
  348   result[len] = '\0';
  349   return (result);
  350 }
  351 
  352 /* From bash-4.3 / general.c / line 780 ; changes: Return NULL instead of 'string' when string == 0. */
  353 /* Given a string containing units of information separated by colons,
  354    return the next one pointed to by (P_INDEX), or NULL if there are no more.
  355    Advance (P_INDEX) to the character after the colon. */
  356 char*
  357 extract_colon_unit (char const* string, int* p_index)
  358 {
  359   int i, start, len;
  360   char *value;
  361 
  362   if (string == 0)
  363     return NULL;
  364 
  365   len = strlen (string);
  366   if (*p_index >= len)
  367     return ((char *)NULL);
  368 
  369   i = *p_index;
  370 
  371   /* Each call to this routine leaves the index pointing at a colon if
  372      there is more to the path.  If I is > 0, then increment past the
  373      `:'.  If I is 0, then the path has a leading colon.  Trailing colons
  374      are handled OK by the `else' part of the if statement; an empty
  375      string is returned in that case. */
  376   if (i && string[i] == ':')
  377     i++;
  378 
  379   for (start = i; string[i] && string[i] != ':'; i++)
  380     ;
  381 
  382   *p_index = i;
  383 
  384   if (i == start)
  385     {
  386       if (string[i])
  387         (*p_index)++;
  388       /* Return "" in the case of a trailing `:'. */
  389       value = (char *)xmalloc (1);
  390       value[0] = '\0';
  391     }
  392   else
  393     value = substring (string, start, i);
  394 
  395   return (value);
  396 }
  397 
  398 /* From bash-4.3 / findcmd.c / line 273 */
  399 /* Return the next element from PATH_LIST, a colon separated list of
  400    paths.  PATH_INDEX_POINTER is the address of an index into PATH_LIST;
  401    the index is modified by this function.
  402    Return the next element of PATH_LIST or NULL if there are no more. */
  403 char*
  404 get_next_path_element (char const* path_list, int* path_index_pointer)
  405 {
  406   char* path;
  407 
  408   path = extract_colon_unit (path_list, path_index_pointer);
  409 
  410   if (path == 0)
  411     return (path);
  412 
  413   if (*path == '\0')
  414     {
  415       free (path);
  416       path = savestring (".");
  417     }
  418 
  419   return (path);
  420 }
  421 
  422 /* From bash-1.14.7 */
  423 /* Turn PATH, a directory, and NAME, a filename, into a full pathname.
  424    This allocates new memory and returns it. */
  425 char *
  426 make_full_pathname (const char *path, const char *name, int name_len)
  427 {
  428   char *full_path;
  429   int path_len;
  430 
  431   path_len = strlen (path);
  432   full_path = (char *) xmalloc (2 + path_len + name_len);
  433   strcpy (full_path, path);
  434   full_path[path_len] = '/';
  435   strcpy (full_path + path_len + 1, name);
  436   return (full_path);
  437 }
  438 
  439 /* From bash-4.3 / shell.c / line 1659 */
  440 void
  441 get_current_user_info ()
  442 {
  443   struct passwd *entry;
  444 
  445   /* Don't fetch this more than once. */
  446   if (current_user.user_name == 0)
  447     {
  448 #if defined (__TANDEM)
  449       entry = getpwnam (getlogin ());
  450 #else
  451       entry = getpwuid (current_user.uid);
  452 #endif
  453       if (entry)
  454         {
  455           current_user.user_name = savestring (entry->pw_name);
  456           current_user.shell = (entry->pw_shell && entry->pw_shell[0])
  457                                 ? savestring (entry->pw_shell)
  458                                 : savestring ("/bin/sh");
  459           current_user.home_dir = savestring (entry->pw_dir);
  460         }
  461       else
  462         {
  463           current_user.user_name = "I have no name!";
  464           current_user.user_name = savestring (current_user.user_name);
  465           current_user.shell = savestring ("/bin/sh");
  466           current_user.home_dir = savestring ("/");
  467         }
  468       endpwent ();
  469     }
  470 }
  471 
  472 /* This is present for use by the tilde library. */
  473 char* sh_get_env_value (const char* v)
  474 {
  475   return getenv(v);
  476 }
  477 
  478 char* sh_get_home_dir(void)
  479 {
  480   if (current_user.home_dir == NULL)
  481     get_current_user_info();
  482   return current_user.home_dir;
  483 }
  484