Switch to unified view

a/src/utils/execmd.cpp b/src/utils/execmd.cpp
1
#ifndef lint
1
#ifndef lint
2
static char rcsid[] = "@(#$Id: execmd.cpp,v 1.13 2006-01-24 12:22:20 dockes Exp $ (C) 2004 J.F.Dockes";
2
static char rcsid[] = "@(#$Id: execmd.cpp,v 1.14 2006-01-26 17:44:51 dockes Exp $ (C) 2004 J.F.Dockes";
3
#endif
3
#endif
4
/*
4
/*
5
 *   This program is free software; you can redistribute it and/or modify
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
6
 *   it under the terms of the GNU General Public License as published by
7
 *   the Free Software Foundation; either version 2 of the License, or
7
 *   the Free Software Foundation; either version 2 of the License, or
...
...
47
void  ExecCmd::putenv(const string &ea)
47
void  ExecCmd::putenv(const string &ea)
48
{
48
{
49
    m_env.push_back(ea);
49
    m_env.push_back(ea);
50
}
50
}
51
51
52
/** A resource manager to ensure that execcmd cleans up if an exception is 
53
 * raised in the callback */
54
class ExecCmdRsrc {
55
public:
56
    int pipein[2];
57
    int pipeout[2];
58
    pid_t pid;
59
    ExecCmdRsrc() {
60
  reset();
61
    }
62
    void reset() {
63
  pipein[0] = pipein[1] = pipeout[0] = pipeout[1] = -1;
64
  pid = -1;
65
    }
66
    ~ExecCmdRsrc() {
67
  int status;
68
  if (pid > 0) {
69
      LOGDEB(("ExecCmd: killing cmd\n"));
70
      if (kill(pid, SIGTERM) == 0) {
71
      for (int i = 0; i < 3; i++) {
72
          (void)waitpid(pid, &status, WNOHANG);
73
          if (kill(pid, 0) != 0)
74
          break;
75
          sleep(1);
76
          if (i == 2) {
77
          LOGDEB(("ExecCmd: killing (KILL) cmd\n"));
78
          kill(pid, SIGKILL);
79
          }
80
      }
81
      }
82
  }
83
  if (pipein[0] >= 0)
84
      close(pipein[0]);
85
  if (pipein[1] >= 0)
86
      close(pipein[1]);
87
  if (pipeout[0] >= 0)
88
      close(pipeout[0]);
89
  if (pipeout[1] >= 0)
90
      close(pipeout[1]);
91
    }
92
};
93
94
  
52
int ExecCmd::doexec(const string &cmd, const list<string>& args,
95
int ExecCmd::doexec(const string &cmd, const list<string>& args,
53
        const string *inputstring, string *output)
96
        const string *inputstring, string *output)
54
{
97
{
55
    { // Debug and logging
98
    { // Debug and logging
56
    string command = cmd + " ";
99
    string command = cmd + " ";
...
...
61
    LOGDEB(("ExecCmd::doexec: %s\n", command.c_str()));
104
    LOGDEB(("ExecCmd::doexec: %s\n", command.c_str()));
62
    }
105
    }
63
    const char *input = inputstring ? inputstring->data() : 0;
106
    const char *input = inputstring ? inputstring->data() : 0;
64
    unsigned int inputlen = inputstring ? inputstring->length() : 0;
107
    unsigned int inputlen = inputstring ? inputstring->length() : 0;
65
108
66
    int pipein[2]; // subproc input
109
    ExecCmdRsrc e;
67
    int pipeout[2]; // subproc output
68
    pipein[0] = pipein[1] = pipeout[0] = pipeout[1] = -1;
69
110
70
    if (input && pipe(pipein) < 0) {
111
    if (input && pipe(e.pipein) < 0) {
71
    LOGERR(("ExecCmd::doexec: pipe(2) failed. errno %d\n", errno));
112
    LOGERR(("ExecCmd::doexec: pipe(2) failed. errno %d\n", errno));
72
    return -1;
113
    return -1;
73
    }
114
    }
74
    if (output && pipe(pipeout) < 0) {
115
    if (output && pipe(e.pipeout) < 0) {
75
    LOGERR(("ExecCmd::doexec: pipe(2) failed. errno %d\n", errno));
116
    LOGERR(("ExecCmd::doexec: pipe(2) failed. errno %d\n", errno));
76
  if (pipein[0] >= 0) close(pipein[0]);
77
  if (pipein[1] >= 0) close(pipein[1]);
78
    return -1;
117
    return -1;
79
    }
118
    }
80
119
81
    pid_t pid = fork();
120
    e.pid = fork();
82
    if (pid < 0) {
121
    if (e.pid < 0) {
83
    LOGERR(("ExecCmd::doexec: fork(2) failed. errno %d\n", errno));
122
    LOGERR(("ExecCmd::doexec: fork(2) failed. errno %d\n", errno));
84
    return -1;
123
    return -1;
85
    }
124
    }
86
125
87
    if (pid) {
126
    if (e.pid) {
88
    if (input) {
127
    if (input) {
89
        close(pipein[0]);
128
        close(e.pipein[0]);
90
        pipein[0] = -1;
129
        e.pipein[0] = -1;
91
    }
130
    }
92
    if (output) {
131
    if (output) {
93
        close(pipeout[1]);
132
        close(e.pipeout[1]);
94
        pipeout[1] = -1;
133
        e.pipeout[1] = -1;
95
    }
134
    }
96
    fd_set readfds, writefds;
135
    fd_set readfds, writefds;
97
    struct timeval tv;
136
    struct timeval tv;
98
    tv.tv_sec = 1;
137
    tv.tv_sec = 1;
99
    tv.tv_usec = 0;
138
    tv.tv_usec = 0;
100
139
101
    if (input || output) {
140
    if (input || output) {
102
        if (input)
141
        if (input)
103
        fcntl(pipein[1], F_SETFL, O_NONBLOCK);
142
        fcntl(e.pipein[1], F_SETFL, O_NONBLOCK);
104
        if (output) 
143
        if (output) 
105
        fcntl(pipeout[0], F_SETFL, O_NONBLOCK);
144
        fcntl(e.pipeout[0], F_SETFL, O_NONBLOCK);
106
        unsigned int nwritten = 0;
145
        unsigned int nwritten = 0;
107
        int nfds = MAX(pipein[1], pipeout[0]) + 1;
146
        int nfds = MAX(e.pipein[1], e.pipeout[0]) + 1;
108
        for(; nfds > 0;) {
147
        for(; nfds > 0;) {
109
        if (m_cancelRequest)
148
        if (m_cancelRequest)
110
            break;
149
            break;
111
150
112
        FD_ZERO(&writefds);
151
        FD_ZERO(&writefds);
113
        FD_ZERO(&readfds);
152
        FD_ZERO(&readfds);
114
        if (pipein[1] >= 0)
153
        if (e.pipein[1] >= 0)
115
            FD_SET(pipein[1], &writefds);
154
            FD_SET(e.pipein[1], &writefds);
116
        if (pipeout[0] >= 0)
155
        if (e.pipeout[0] >= 0)
117
            FD_SET(pipeout[0], &readfds);
156
            FD_SET(e.pipeout[0], &readfds);
118
        nfds = MAX(pipein[1], pipeout[0]) + 1;
157
        nfds = MAX(e.pipein[1], e.pipeout[0]) + 1;
119
        //struct timeval to; to.tv_sec = 1;to.tv_usec=0;
158
        //struct timeval to; to.tv_sec = 1;to.tv_usec=0;
120
        //cerr << "pipein[1] "<< pipein[1] << " pipeout[0] " << 
159
        //cerr << "e.pipein[1] "<< e.pipein[1] << " e.pipeout[0] " << 
121
        //pipeout[0] << " nfds " << nfds << endl;
160
        //e.pipeout[0] << " nfds " << nfds << endl;
122
        int ss;
161
        int ss;
123
        if ((ss = select(nfds, &readfds, &writefds, 0, &tv)) <= 0) {
162
        if ((ss = select(nfds, &readfds, &writefds, 0, &tv)) <= 0) {
124
            if (ss == 0) {
163
            if (ss == 0) {
125
            // Timeout, is ok.
164
            // Timeout, is ok.
126
            continue;
165
            continue;
127
            }
166
            }
128
            LOGERR(("ExecCmd::doexec: select(2) failed. errno %d\n", 
167
            LOGERR(("ExecCmd::doexec: select(2) failed. errno %d\n", 
129
                errno));
168
                errno));
130
            break;
169
            break;
131
        }
170
        }
132
        if (pipein[1] >= 0 && FD_ISSET(pipein[1], &writefds)) {
171
        if (e.pipein[1] >= 0 && FD_ISSET(e.pipein[1], &writefds)) {
133
            int n = write(pipein[1], input + nwritten, 
172
            int n = write(e.pipein[1], input + nwritten, 
134
                  inputlen - nwritten);
173
                  inputlen - nwritten);
135
            if (n < 0) {
174
            if (n < 0) {
136
            LOGERR(("ExecCmd::doexec: write(2) failed. errno %d\n",
175
            LOGERR(("ExecCmd::doexec: write(2) failed. errno %d\n",
137
                errno));
176
                errno));
138
            goto out;
177
            goto out;
139
            }
178
            }
140
            nwritten += n;
179
            nwritten += n;
141
            if (nwritten == inputlen) {
180
            if (nwritten == inputlen) {
142
            // cerr << "Closing output" << endl;
181
            // cerr << "Closing output" << endl;
143
            close(pipein[1]);
182
            close(e.pipein[1]);
144
            pipein[1] = -1;
183
            e.pipein[1] = -1;
145
            }
184
            }
146
        }
185
        }
147
        if (pipeout[0] > 0 && FD_ISSET(pipeout[0], &readfds)) {
186
        if (e.pipeout[0] > 0 && FD_ISSET(e.pipeout[0], &readfds)) {
148
            char buf[8192];
187
            char buf[8192];
149
            int n = read(pipeout[0], buf, 8192);
188
            int n = read(e.pipeout[0], buf, 8192);
150
            if (n == 0) {
189
            if (n == 0) {
151
            goto out;
190
            goto out;
152
            } else if (n < 0) {
191
            } else if (n < 0) {
153
            LOGERR(("ExecCmd::doexec: read(2) failed. errno %d\n",
192
            LOGERR(("ExecCmd::doexec: read(2) failed. errno %d\n",
154
                errno));
193
                errno));
...
...
163
        }
202
        }
164
    }
203
    }
165
204
166
    out:
205
    out:
167
    int status = -1;
206
    int status = -1;
168
169
    if (m_cancelRequest) {
207
    if (!m_cancelRequest) {
170
      // If we were canceled, need to cleanup
208
      LOGDEB(("Execmd: canceled\n"));
171
      LOGDEB1(("Killing cmd\n"));
172
      kill(pid, SIGTERM);
173
      for (int i = 0; i < 3; i++) {
174
      if (kill(pid, 0) != 0)
175
          break;
176
      sleep(1);
177
      if (i == 2) {
178
          LOGDEB1(("Killing (KILL) cmd\n"));
179
          kill(pid, SIGKILL);
180
      }
181
      }
182
  }
183
    (void)waitpid(pid, &status, 0);
209
        (void)waitpid(e.pid, &status, 0);
184
  if (pipein[0] >= 0)
210
      e.pid = -1;
185
      close(pipein[0]);
211
  }
186
  if (pipein[1] >= 0)
187
      close(pipein[1]);
188
  if (pipeout[0] >= 0)
189
      close(pipeout[0]);
190
  if (pipeout[1] >= 0)
191
      close(pipeout[1]);
192
    LOGDEB1(("ExecCmd::doexec: father got status 0x%x\n", status));
212
    LOGDEB1(("ExecCmd::doexec: father got status 0x%x\n", status));
193
    return status;
213
    return status;
194
214
195
    } else {
215
    } else {
196
    // In child process. Set up pipes, environment, and exec command
216
    // In child process. Set up pipes, environment, and exec command
197
217
198
    if (input) {
218
    if (input) {
199
        close(pipein[1]);
219
        close(e.pipein[1]);
200
        pipein[1] = -1;
220
        e.pipein[1] = -1;
201
        if (pipein[0] != 0) {
221
        if (e.pipein[0] != 0) {
202
        dup2(pipein[0], 0);
222
        dup2(e.pipein[0], 0);
203
        close(pipein[0]);
223
        close(e.pipein[0]);
204
        pipein[0] = -1;
224
        e.pipein[0] = -1;
205
        }
225
        }
206
    }
226
    }
207
    if (output) {
227
    if (output) {
208
        close(pipeout[0]);
228
        close(e.pipeout[0]);
209
        pipeout[0] = -1;
229
        e.pipeout[0] = -1;
210
        if (pipeout[1] != 1) {
230
        if (e.pipeout[1] != 1) {
211
        if (dup2(pipeout[1], 1) < 0) {
231
        if (dup2(e.pipeout[1], 1) < 0) {
212
            LOGERR(("ExecCmd::doexec: dup2(2) failed. errno %d\n",
232
            LOGERR(("ExecCmd::doexec: dup2(2) failed. errno %d\n",
213
                errno));
233
                errno));
214
        }
234
        }
215
        if (close(pipeout[1]) < 0) {
235
        if (close(e.pipeout[1]) < 0) {
216
            LOGERR(("ExecCmd::doexec: close(2) failed. errno %d\n",
236
            LOGERR(("ExecCmd::doexec: close(2) failed. errno %d\n",
217
                errno));
237
                errno));
218
        }
238
        }
219
        pipeout[1] = -1;
239
        e.pipeout[1] = -1;
220
        }
240
        }
221
    }
241
    }
222
242
223
  // Count args
243
  e.reset();
224
  list<string>::const_iterator it;
244
225
  int i = 0;
226
  for (it = args.begin(); it != args.end(); it++) i++;
227
    // Allocate arg vector (2 more for arg0 + final 0)
245
    // Allocate arg vector (2 more for arg0 + final 0)
228
    typedef const char *Ccharp;
246
    typedef const char *Ccharp;
229
    Ccharp *argv;
247
    Ccharp *argv;
230
    argv = (Ccharp *)malloc((i+2) * sizeof(char *));
248
    argv = (Ccharp *)malloc((args.size()+2) * sizeof(char *));
231
    if (argv == 0) {
249
    if (argv == 0) {
232
        LOGERR(("ExecCmd::doexec: malloc() failed. errno %d\n",
250
        LOGERR(("ExecCmd::doexec: malloc() failed. errno %d\n",
233
            errno));
251
            errno));
234
        exit(1);
252
        exit(1);
235
    }
253
    }
236
    
254
    
237
    // Fill up argv
255
    // Fill up argv
238
    argv[0] = path_getsimple(cmd).c_str();
256
    argv[0] = path_getsimple(cmd).c_str();
239
    i = 1;
257
    int i = 1;
258
  list<string>::const_iterator it;
240
    for (it = args.begin(); it != args.end(); it++) {
259
    for (it = args.begin(); it != args.end(); it++) {
241
        argv[i++] = it->c_str();
260
        argv[i++] = it->c_str();
242
    }
261
    }
243
    argv[i] = 0;
262
    argv[i] = 0;
244
263
...
...
252
        ::putenv(strdup(it->c_str()));
271
        ::putenv(strdup(it->c_str()));
253
#else
272
#else
254
        ::putenv(it->c_str());
273
        ::putenv(it->c_str());
255
#endif
274
#endif
256
    }
275
    }
257
  
258
    execvp(cmd.c_str(), (char *const*)argv);
276
    execvp(cmd.c_str(), (char *const*)argv);
259
    // Hu ho
277
    // Hu ho
260
    LOGERR(("ExecCmd::doexec: execvp(%s) failed. errno %d\n", cmd.c_str(),
278
    LOGERR(("ExecCmd::doexec: execvp(%s) failed. errno %d\n", cmd.c_str(),
261
        errno));
279
        errno));
262
    _exit(128);
280
    _exit(128);
...
...
267
#include <stdio.h>
285
#include <stdio.h>
268
#include <string>
286
#include <string>
269
#include <iostream>
287
#include <iostream>
270
#include <list>
288
#include <list>
271
#include "debuglog.h"
289
#include "debuglog.h"
290
#include "cancelcheck.h"
291
272
using namespace std;
292
using namespace std;
273
293
274
#include "execmd.h"
294
#include "execmd.h"
275
295
276
const char *data = "Une ligne de donnees\n";
296
const char *data = "Une ligne de donnees\n";
277
class MEAdv : public ExecCmdAdvise {
297
class MEAdv : public ExecCmdAdvise {
278
public:
298
public:
279
    ExecCmd *cmd;
299
    ExecCmd *cmd;
280
    void newData() {cerr << "New Data!" << endl;cmd->setCancel();}
300
    void newData() {
301
  cerr << "New Data!" << endl;
302
  CancelCheck::instance().setCancel();
303
  CancelCheck::instance().checkCancel();
304
  //  cmd->setCancel();
305
    }
281
};
306
};
307
282
int main(int argc, const char **argv)
308
int main(int argc, const char **argv)
283
{
309
{
284
    DebugLog::getdbl()->setloglevel(DEBDEB1);
310
    DebugLog::getdbl()->setloglevel(DEBDEB1);
285
    DebugLog::setfilename("stderr");
311
    DebugLog::setfilename("stderr");
286
    if (argc < 2) {
312
    if (argc < 2) {
...
...
302
    //ip = &input;
328
    //ip = &input;
303
    mexec.putenv("TESTVARIABLE1=TESTVALUE1");
329
    mexec.putenv("TESTVARIABLE1=TESTVALUE1");
304
    mexec.putenv("TESTVARIABLE2=TESTVALUE2");
330
    mexec.putenv("TESTVARIABLE2=TESTVALUE2");
305
    mexec.putenv("TESTVARIABLE3=TESTVALUE3");
331
    mexec.putenv("TESTVARIABLE3=TESTVALUE3");
306
332
333
    int status = -1;
334
    try {
307
    int status = mexec.doexec(cmd, l, ip, &output);
335
  status = mexec.doexec(cmd, l, ip, &output);
336
    } catch (CancelExcept) {
337
  cerr << "CANCELED" << endl;
338
    }
308
339
309
    fprintf(stderr, "Status: 0x%x\n", status);
340
    fprintf(stderr, "Status: 0x%x\n", status);
310
    cout << "Output:" << output << endl;
341
    cout << "Output:" << output << endl;
311
    exit (status >> 8);
342
    exit (status >> 8);
312
}
343
}