Imported Upstream version 1.1.11
[platform/upstream/cdrkit.git] / librols / fexec.c
1 /*
2  * This file has been modified for the cdrkit suite.
3  *
4  * The behaviour and appearence of the program code below can differ to a major
5  * extent from the version distributed by the original author(s).
6  *
7  * For details, see Changelog file distributed with the cdrkit package. If you
8  * received this file from another source then ask the distributing person for
9  * a log of modifications.
10  *
11  */
12
13 /* @(#)fexec.c  1.24 04/06/06 Copyright 1985, 1995-2004 J. Schilling */
14 /*
15  *      Execute a program with stdio redirection
16  *
17  *      Copyright (c) 1985, 1995-2004 J. Schilling
18  */
19 /*
20  * This program is free software; you can redistribute it and/or modify
21  * it under the terms of the GNU General Public License version 2
22  * as published by the Free Software Foundation.
23  *
24  * This program is distributed in the hope that it will be useful,
25  * but WITHOUT ANY WARRANTY; without even the implied warranty of
26  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
27  * GNU General Public License for more details.
28  *
29  * You should have received a copy of the GNU General Public License along with
30  * this program; see the file COPYING.  If not, write to the Free Software
31  * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
32  */
33
34 #include <mconfig.h>
35 #include <stdio.h>
36 #include <standard.h>
37 #define rols_fexecl     __nothing_1_    /* prototype in schily.h is wrong */
38 #define rols_fexecle    __nothing_2_    /* prototype in schily.h is wrong */
39 #include <schily.h>
40 #undef  rols_fexecl
41 #undef  rols_fexecle
42         int rols_fexecl  __PR((const char *, FILE *, FILE *, FILE *, ...));
43         int rols_fexecle __PR((const char *, FILE *, FILE *, FILE *, ...));
44 #include <unixstd.h>
45 #include <stdxlib.h>
46 #include <strdefs.h>
47 #include <vadefs.h>
48
49 #ifdef JOS
50 #       include <error.h>
51 #else
52 #       include <errno.h>
53 #endif
54 #include <fctldefs.h>
55 #include <dirdefs.h>
56 #include <maxpath.h>
57
58 #define MAX_F_ARGS      16
59
60 extern  char **environ;
61
62 LOCAL void       fdcopy __PR((int, int));
63 LOCAL void       fdmove __PR((int, int));
64 LOCAL const char *chkname __PR((const char *, const char *));
65 LOCAL const char *getpath __PR((char * const *));
66
67 #ifdef  PROTOTYPES
68 EXPORT int
69 rols_fexecl(const char *name, FILE *in, FILE *out, FILE *err, ...)
70 #else
71 EXPORT int
72 rols_fexecl(name, in, out, err, va_alist)
73         char    *name;
74         FILE    *in;
75         FILE    *out;
76         FILE    *err;
77         va_dcl
78 #endif
79 {
80         va_list args;
81         int     ac = 0;
82         char    *xav[MAX_F_ARGS];
83         char    **av;
84         char    **pav;
85         char    *p;
86         int     ret;
87
88 #ifdef  PROTOTYPES
89         va_start(args, err);
90 #else
91         va_start(args);
92 #endif
93         while (va_arg(args, char *) != NULL)
94                 ac++;
95         va_end(args);
96
97         if (ac < MAX_F_ARGS) {
98                 pav = av = xav;
99         } else {
100                 pav = av = (char **)malloc((ac+1)*sizeof (char *));
101                 if (av == 0)
102                         return (-1);
103         }
104
105 #ifdef  PROTOTYPES
106         va_start(args, err);
107 #else
108         va_start(args);
109 #endif
110         do {
111                 p = va_arg(args, char *);
112                 *pav++ = p;
113         } while (p != NULL);
114         va_end(args);
115
116         ret = rols_fexecv(name, in, out, err, ac, av);
117         if (av != xav)
118                 free(av);
119         return (ret);
120 }
121
122 #ifdef  PROTOTYPES
123 EXPORT int
124 rols_fexecle(const char *name, FILE *in, FILE *out, FILE *err, ...)
125 #else
126 EXPORT int
127 rols_fexecle(name, in, out, err, va_alist)
128         char    *name;
129         FILE    *in;
130         FILE    *out;
131         FILE    *err;
132         va_dcl
133 #endif
134 {
135         va_list args;
136         int     ac = 0;
137         char    *xav[MAX_F_ARGS];
138         char    **av;
139         char    **pav;
140         char    *p;
141         char    **env;
142         int     ret;
143
144 #ifdef  PROTOTYPES
145         va_start(args, err);
146 #else
147         va_start(args);
148 #endif
149         while (va_arg(args, char *) != NULL)
150                 ac++;
151         env = va_arg(args, char **);
152         va_end(args);
153
154         if (ac < MAX_F_ARGS) {
155                 pav = av = xav;
156         } else {
157                 pav = av = (char **)malloc((ac+1)*sizeof (char *));
158                 if (av == 0)
159                         return (-1);
160         }
161
162 #ifdef  PROTOTYPES
163         va_start(args, err);
164 #else
165         va_start(args);
166 #endif
167         do {
168                 p = va_arg(args, char *);
169                 *pav++ = p;
170         } while (p != NULL);
171         va_end(args);
172
173         ret = rols_fexecve(name, in, out, err, av, env);
174         if (av != xav)
175                 free(av);
176         return (ret);
177 }
178
179 EXPORT int
180 rols_fexecv(name, in, out, err, ac, av)
181         const char *name;
182         FILE *in, *out, *err;
183         int ac;
184         char *av[];
185 {
186         av[ac] = NULL;                  /*  force list to be null terminated */
187         return (rols_fexecve(name, in, out, err, av, environ));
188 }
189
190 EXPORT int
191 rols_fexecve(name, in, out, err, av, env)
192         const char *name;
193         FILE *in, *out, *err;
194         char * const av[], * const env[];
195 {
196         char    nbuf[MAXPATHNAME+1];
197         char    *np;
198         const char *path;
199         int     ret;
200         int     fin;
201         int     fout;
202         int     ferr;
203 #ifndef JOS
204         int     o[3];
205         int     f[3];
206         int     errsav;
207
208         o[0] = o[1] = o[2] = f[0] = f[1] = f[2] = 0;
209 #endif
210
211         fflush(out);
212         fflush(err);
213         fin  = fdown(in);
214         fout = fdown(out);
215         ferr = fdown(err);
216 #ifdef JOS
217
218         /*
219          * If name contains a pathdelimiter ('/' on unix)
220          * or name is too long ...
221          * try exec without path search.
222          */
223         if (find('/', name) || strlen(name) > MAXFILENAME) {
224                 ret = exec_env(name, fin, fout, ferr, av, env);
225
226         } else if ((path = getpath(env)) == NULL) {
227                 ret = exec_env(name, fin, fout, ferr, av, env);
228                 if ((ret == ENOFILE) && strlen(name) <= (sizeof (nbuf) - 6)) {
229                         strcatl(nbuf, "/bin/", name, (char *)NULL);
230                         ret = exec_env(nbuf, fin, fout, ferr, av, env);
231                         if (ret == EMISSDIR)
232                                 ret = ENOFILE;
233                 }
234         } else {
235                 int     nlen = strlen(name);
236
237                 for (;;) {
238                         np = nbuf;
239                         /*
240                          * JOS always uses ':' as PATH Environ separator
241                          */
242                         while (*path != ':' && *path != '\0' &&
243                                 np < &nbuf[MAXPATHNAME-nlen-2]) {
244
245                                 *np++ = *path++;
246                         }
247                         *np = '\0';
248                         if (*nbuf == '\0')
249                                 strcatl(nbuf, name, (char *)NULL);
250                         else
251                                 strcatl(nbuf, nbuf, "/", name, (char *)NULL);
252                         ret = exec_env(nbuf, fin, fout, ferr, av, env);
253                         if (ret == EMISSDIR)
254                                 ret = ENOFILE;
255                         if (ret != ENOFILE || *path == '\0')
256                                 break;
257                         path++;
258                 }
259         }
260         return (ret);
261
262 #else   /* JOS */
263
264         if (fin != 0) {
265                 f[0] = fcntl(0, F_GETFD, 0);
266                 o[0] = dup(0);
267                 fcntl(o[0], F_SETFD, 1);
268                 fdcopy(fin, 0);
269         }
270         if (fout != 1) {
271                 f[1] = fcntl(1, F_GETFD, 0);
272                 o[1] = dup(1);
273                 fcntl(o[1], F_SETFD, 1);
274                 fdcopy(fout, 1);
275         }
276         if (ferr != 2) {
277                 f[2] = fcntl(2, F_GETFD, 0);
278                 o[2] = dup(2);
279                 fcntl(o[2], F_SETFD, 1);
280                 fdcopy(ferr, 2);
281         }
282         if (fin != 0)
283                 close(fin);
284         if (fout != 1)
285                 close(fout);
286         if (ferr != 2)
287                 close(ferr);
288
289         /*
290          * If name contains a pathdelimiter ('/' on unix)
291          * or name is too long ...
292          * try exec without path search.
293          */
294 #ifdef  FOUND_MAXFILENAME
295         if (strchr(name, '/') || strlen(name) > (unsigned)MAXFILENAME) {
296 #else
297         if (strchr(name, '/')) {
298 #endif
299                 ret = execve(name, av, env);
300
301         } else if ((path = getpath(env)) == NULL) {
302                 ret = execve(name, av, env);
303                 if ((geterrno() == ENOENT) && strlen(name) <= (sizeof (nbuf) - 6)) {
304                         strcatl(nbuf, "/bin/", name, (char *)NULL);
305                         ret = execve(nbuf, av, env);
306                 }
307         } else {
308                 int     nlen = strlen(name);
309
310                 for (;;) {
311                         np = nbuf;
312                         while (*path != PATH_ENV_DELIM && *path != '\0' &&
313                                 np < &nbuf[MAXPATHNAME-nlen-2]) {
314
315                                 *np++ = *path++;
316                         }
317                         *np = '\0';
318                         if (*nbuf == '\0')
319                                 strcatl(nbuf, name, (char *)NULL);
320                         else
321                                 strcatl(nbuf, nbuf, "/", name, (char *)NULL);
322                         ret = execve(nbuf, av, env);
323                         if (geterrno() != ENOENT || *path == '\0')
324                                 break;
325                         path++;
326                 }
327         }
328         errsav = geterrno();
329                         /* reestablish old files */
330         if (ferr != 2) {
331                 fdmove(2, ferr);
332                 fdmove(o[2], 2);
333                 if (f[2] == 0)
334                         fcntl(2, F_SETFD, 0);
335         }
336         if (fout != 1) {
337                 fdmove(1, fout);
338                 fdmove(o[1], 1);
339                 if (f[1] == 0)
340                         fcntl(1, F_SETFD, 0);
341         }
342         if (fin != 0) {
343                 fdmove(0, fin);
344                 fdmove(o[0], 0);
345                 if (f[0] == 0)
346                         fcntl(0, F_SETFD, 0);
347         }
348         seterrno(errsav);
349         return (ret);
350
351 #endif  /* JOS */
352 }
353
354 #ifndef JOS
355
356 LOCAL void
357 fdcopy(fd1, fd2)
358         int     fd1;
359         int     fd2;
360 {
361         close(fd2);
362         fcntl(fd1, F_DUPFD, fd2);
363 }
364
365 LOCAL void
366 fdmove(fd1, fd2)
367         int     fd1;
368         int     fd2;
369 {
370         fdcopy(fd1, fd2);
371         close(fd1);
372 }
373
374 #endif
375
376 /*----------------------------------------------------------------------------
377 |
378 |       get PATH from env
379 |
380 +----------------------------------------------------------------------------*/
381
382 LOCAL const char *
383 getpath(env)
384         char    * const *env;
385 {
386         char * const *p = env;
387         const char *p2;
388
389         if (p != NULL) {
390                 while (*p != NULL) {
391                         if ((p2 = chkname("PATH", *p)) != NULL)
392                                 return (p2);
393                         p++;
394                 }
395         }
396         return (NULL);
397 }
398
399
400 /*----------------------------------------------------------------------------
401 |
402 | Check if name is in environment.
403 | Return pointer to value name is found.
404 |
405 +----------------------------------------------------------------------------*/
406
407 LOCAL const char *
408 chkname(name, ev)
409         const char      *name;
410         const char      *ev;
411 {
412         for (;;) {
413                 if (*name != *ev) {
414                         if (*ev == '=' && *name == '\0')
415                                 return (++ev);
416                         return (NULL);
417                 }
418                 name++;
419                 ev++;
420         }
421 }