Initial revision
[kopensolaris-gnu/glibc.git] / posix / execvp.c
1 /* Copyright (C) 1991 Free Software Foundation, Inc.
2 This file is part of the GNU C Library.
3
4 The GNU C Library is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Library General Public License as
6 published by the Free Software Foundation; either version 2 of the
7 License, or (at your option) any later version.
8
9 The GNU C Library is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12 Library General Public License for more details.
13
14 You should have received a copy of the GNU Library General Public
15 License along with the GNU C Library; see the file COPYING.LIB.  If
16 not, write to the Free Software Foundation, Inc., 675 Mass Ave,
17 Cambridge, MA 02139, USA.  */
18
19 #include <ansidecl.h>
20 #include <unistd.h>
21 #include <stdarg.h>
22 #include <stdlib.h>
23 #include <string.h>
24 #include <sys/stat.h>
25 #include <limits.h>
26 #include <sys/types.h>
27
28 /* Execute FILE, searching in the `PATH' environment variable if it contains
29    no slashes, with arguments ARGV and environment from `environ'.  */
30 int
31 DEFUN(execvp, (file, argv), CONST char *file AND char *CONST argv[])
32 {
33   char name[PATH_MAX];
34
35   if (strchr(file, '/') == NULL)
36     {
37       char *path, *p;
38       struct stat st;
39       size_t len;
40       uid_t uid;
41       gid_t gid;
42       int ngroups;
43       gid_t groups[NGROUPS_MAX];
44
45       path = getenv("PATH");
46       if (path == NULL)
47         {
48           /* There is no `PATH' in the environment.
49              The default search path is the current directory
50              followed by the path `confstr' returns for `_CS_PATH'.  */
51           len = confstr(_CS_PATH, (char *) NULL, 0);
52           path = (char *) __alloca(1 + len);
53           path[0] = ':';
54           (void) confstr(_CS_PATH, path + 1, len);
55         }
56
57       len = strlen(file) + 1;
58       uid = geteuid();
59       gid = getegid();
60       ngroups = getgroups(sizeof(groups) / sizeof(groups[0]), groups);
61       p = path;
62       do
63         {
64           path = p;
65           p = strchr(path, ':');
66           if (p == NULL)
67             p = strchr(path, '\0');
68
69           if (p == path)
70             /* Two adjacent colons, or a colon at the beginning or the end
71                of `PATH' means to search the current directory.  */
72             (void) memcpy(name, file, len);
73           else
74             {
75               /* Construct the pathname to try.  */
76               (void) memcpy(name, path, p - path);
77               name[p - path] = '/';
78               (void) memcpy(&name[(p - path) + 1], file, len);
79             }
80           if (stat(name, &st) == 0 && S_ISREG(st.st_mode))
81             {
82               int bit = S_IXOTH;
83               if (st.st_uid == uid)
84                 bit = S_IXUSR;
85               else if (st.st_gid == gid)
86                 bit = S_IXGRP;
87               else
88                 {
89                   register int i;
90                   for (i = 0; i < ngroups; ++i)
91                     if (st.st_gid == groups[i])
92                       {
93                         bit = S_IXGRP;
94                         break;
95                       }
96                 }
97               if (st.st_mode & bit)
98                 {
99                   file = name;
100                   break;
101                 }
102             }
103         } while (*p++ != '\0');
104     }
105
106   return __execve(file, argv, __environ);
107 }