merge with 0.30.213
[util-vserver.git] / lib_internal / command-exec.c
1 // $Id: command-exec.c 1957 2005-03-22 15:25:54Z ensc $    --*- c -*--
2
3 // Copyright (C) 2004 Enrico Scholz <enrico.scholz@informatik.tu-chemnitz.de>
4 //  
5 // This program is free software; you can redistribute it and/or modify
6 // it under the terms of the GNU General Public License as published by
7 // the Free Software Foundation; version 2 of the License.
8 //  
9 // This program 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
12 // GNU General Public License for more details.
13 //  
14 // You should have received a copy of the GNU General Public License
15 // along with this program; if not, write to the Free Software
16 // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
17
18
19 #ifdef HAVE_CONFIG_H
20 #  include <config.h>
21 #endif
22
23 #include "command.h"
24 #include "util.h"
25
26 #include <unistd.h>
27 #include <fcntl.h>
28 #include <errno.h>
29 #include <assert.h>
30
31 static inline bool
32 initPipes(int p[2])
33 {
34   return (pipe(p)!=-1 &&
35           fcntl(p[1], F_SETFD, FD_CLOEXEC)!=-1);
36 }
37
38 bool
39 Command_exec(struct Command *cmd, bool do_fork)
40 {
41   int           p[2];
42
43   if (cmd->params_style_==parVEC)
44     Vector_zeroEnd(&cmd->params.v);
45
46   if (!do_fork)
47     cmd->pid = 0;
48   else if (!initPipes(p) ||
49            (cmd->pid = fork())==-1) {
50     cmd->err = errno;
51     return false;
52   }
53   
54   if (cmd->pid==0) {
55     char const **       argv = { 0 };
56     
57     if (do_fork) close(p[0]);
58
59     switch (cmd->params_style_) {
60       case parVEC       :  argv = cmd->params.v.data; break;
61       case parDATA      :  argv = cmd->params.d;      break;
62       default           :  break;
63     }
64
65     execv(cmd->filename ? cmd->filename : argv[0],
66           reinterpret_cast(char **const)(argv));
67     cmd->err = errno;
68     assert(cmd->err != 0);
69
70     if (do_fork) {
71       TEMP_FAILURE_RETRY(write(p[1], &cmd->err, sizeof(cmd->err)));
72       _exit(1); // implicates 'close(p[1])'
73     }
74   }
75   else {
76     close(p[1]);
77     if (read(p[0], &cmd->err, sizeof(cmd->err))==0)
78       cmd->err = 0;
79     else        // cleanup zombies
80       while (wait4(cmd->pid, 0,0,0)==-1 &&
81              (errno==EINTR || errno==EAGAIN)) {};
82     close(p[0]);
83   }
84
85   return cmd->err==0;
86 }