fgetws implementation.
[kopensolaris-gnu/glibc.git] / posix / execvp.c
1 /* Copyright (C) 1991, 92, 95, 96, 97, 98, 99 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 not,
16    write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17    Boston, MA 02111-1307, USA.  */
18
19 #include <unistd.h>
20 #include <stdarg.h>
21 #include <stdlib.h>
22 #include <string.h>
23 #include <errno.h>
24 #include <paths.h>
25
26
27 /* The file is accessible but it is not an executable file.  Invoke
28    the shell to interpret it as a script.  */
29 static void
30 internal_function
31 script_execute (const char *file, char *const argv[])
32 {
33   /* Count the arguments.  */
34   int argc = 0;
35   while (argv[argc++])
36     ;
37
38   /* Construct an argument list for the shell.  */
39   {
40     char *new_argv[argc + 1];
41     new_argv[0] = (char *) _PATH_BSHELL;
42     new_argv[1] = (char *) file;
43     while (argc > 1)
44       {
45         new_argv[argc] = argv[argc - 1];
46         --argc;
47       }
48
49     /* Execute the shell.  */
50     execv (new_argv[0], new_argv);
51   }
52 }
53
54
55 /* Execute FILE, searching in the `PATH' environment variable if it contains
56    no slashes, with arguments ARGV and environment from `environ'.  */
57 int
58 execvp (file, argv)
59      const char *file;
60      char *const argv[];
61 {
62   if (*file == '\0')
63     {
64       /* We check the simple case first. */
65       __set_errno (ENOENT);
66       return -1;
67     }
68
69   if (strchr (file, '/') != NULL)
70     {
71       /* Don't search when it contains a slash.  */
72       execv (file, argv);
73
74       if (errno == ENOEXEC)
75         script_execute (file, argv);
76     }
77   else
78     {
79       int got_eacces = 0;
80       char *path, *p, *name;
81       size_t len;
82
83       path = getenv ("PATH");
84       if (path == NULL)
85         {
86           /* There is no `PATH' in the environment.
87              The default search path is the current directory
88              followed by the path `confstr' returns for `_CS_PATH'.  */
89           len = confstr (_CS_PATH, (char *) NULL, 0);
90           path = (char *) __alloca (1 + len);
91           path[0] = ':';
92           (void) confstr (_CS_PATH, path + 1, len);
93         }
94
95       len = strlen (file) + 1;
96       name = __alloca (strlen (path) + len);
97       p = path;
98       do
99         {
100           path = p;
101           p = __strchrnul (path, ':');
102
103           if (p == path)
104             /* Two adjacent colons, or a colon at the beginning or the end
105                of `PATH' means to search the current directory.  */
106             (void) memcpy (name, file, len);
107           else
108             {
109               /* Construct the pathname to try.  */
110               char *tmp = __mempcpy (name, path, p - path);
111               *tmp++ = '/';
112               memcpy (tmp, file, len);
113             }
114
115           /* Try to execute this name.  If it works, execv will not return.  */
116           execv (name, argv);
117
118           if (errno == ENOEXEC)
119             script_execute (name, argv);
120
121           switch (errno)
122             {
123             case EACCES:
124               /* Record the we got a `Permission denied' error.  If we end
125                  up finding no executable we can use, we want to diagnose
126                  that we did find one but were denied access.  */
127               got_eacces = 1;
128             case ENOENT:
129             case ESTALE:
130             case ENOTDIR:
131               /* Those errors indicate the file is missing or not executable
132                  by us, in which case we want to just try the next path
133                  directory.  */
134               break;
135
136             default:
137               /* Some other error means we found an executable file, but
138                  something went wrong executing it; return the error to our
139                  caller.  */
140               return -1;
141             }
142         }
143       while (*p++ != '\0');
144
145       /* We tried every element and none of them worked.  */
146       if (got_eacces)
147         /* At least one failure was due to permissions, so report that
148            error.  */
149         __set_errno (EACCES);
150     }
151
152   /* Return the error from the last attempt (probably ENOENT).  */
153   return -1;
154 }