Switch to unified view

a/src/execmd.cpp b/src/execmd.cpp
...
...
29
#include <signal.h>
29
#include <signal.h>
30
#include <time.h>
30
#include <time.h>
31
31
32
#include <vector>
32
#include <vector>
33
#include <string>
33
#include <string>
34
#include <sstream>
34
#include <memory>
35
#include <iostream>
36
35
37
#include "execmd.h"
36
#include "execmd.h"
38
37
39
#include "netcon.h"
38
#include "netcon.h"
40
#include "closefrom.h"
39
#include "closefrom.h"
41
42
using namespace std;
43
40
44
extern char **environ;
41
extern char **environ;
45
42
46
bool ExecCmd::o_useVfork = false;
43
bool ExecCmd::o_useVfork = false;
47
44
...
...
64
61
65
#ifndef MIN
62
#ifndef MIN
66
#define MIN(A,B) ((A) < (B) ? (A) : (B))
63
#define MIN(A,B) ((A) < (B) ? (A) : (B))
67
#endif
64
#endif
68
65
66
static void stringToTokens(const std::string &s, 
67
                           std::vector<std::string> &tokens, 
68
                           const std::string &delims = " \t", 
69
                           bool skipinit=true);
70
69
static void stringToTokens(const string &s, vector<string> &tokens, 
71
static void stringToTokens(const std::string& str, 
72
                           std::vector<std::string>& tokens,
70
                    const string &delims = " \t", bool skipinit=true);
73
                           const std::string& delims, bool skipinit)
71
72
static void stringToTokens(const string& str, vector<string>& tokens,
73
          const string& delims, bool skipinit)
74
{
74
{
75
    string::size_type startPos = 0, pos;
75
    std::string::size_type startPos = 0, pos;
76
76
77
    // Skip initial delims, return empty if this eats all.
77
    // Skip initial delims, return empty if this eats all.
78
    if (skipinit && 
78
    if (skipinit && 
79
    (startPos = str.find_first_not_of(delims, 0)) == string::npos) {
79
    (startPos = str.find_first_not_of(delims, 0)) == std::string::npos) {
80
    return;
80
    return;
81
    }
81
    }
82
    while (startPos < str.size()) { 
82
    while (startPos < str.size()) { 
83
        // Find next delimiter or end of string (end of token)
83
        // Find next delimiter or end of string (end of token)
84
        pos = str.find_first_of(delims, startPos);
84
        pos = str.find_first_of(delims, startPos);
85
85
86
        // Add token to the vector and adjust start
86
        // Add token to the vector and adjust start
87
    if (pos == string::npos) {
87
    if (pos == std::string::npos) {
88
        tokens.push_back(str.substr(startPos));
88
        tokens.push_back(str.substr(startPos));
89
        break;
89
        break;
90
    } else if (pos == startPos) {
90
    } else if (pos == startPos) {
91
        // Dont' push empty tokens after first
91
        // Dont' push empty tokens after first
92
        if (tokens.empty())
92
        if (tokens.empty())
93
        tokens.push_back(string());
93
        tokens.push_back(std::string());
94
        startPos = ++pos;
94
        startPos = ++pos;
95
    } else {
95
    } else {
96
        tokens.push_back(str.substr(startPos, pos - startPos));
96
        tokens.push_back(str.substr(startPos, pos - startPos));
97
        startPos = ++pos;
97
        startPos = ++pos;
98
    }
98
    }
...
...
114
    return true;
114
    return true;
115
    }
115
    }
116
    return false;
116
    return false;
117
}
117
}
118
118
119
bool ExecCmd::which(const string& cmd, string& exepath, const char* path)
119
bool ExecCmd::which(const std::string& cmd, std::string& exepath, 
120
                    const char* path)
120
{
121
{
121
    if (cmd.empty()) 
122
    if (cmd.empty()) 
122
    return false;
123
    return false;
123
    if (cmd[0] == '/') {
124
    if (cmd[0] == '/') {
124
    if (exec_is_there(cmd.c_str())) {
125
    if (exec_is_there(cmd.c_str())) {
...
...
136
    pp = getenv("PATH");
137
    pp = getenv("PATH");
137
    }
138
    }
138
    if (pp == 0)
139
    if (pp == 0)
139
    return false;
140
    return false;
140
141
141
    vector<string> pels;
142
    std::vector<std::string> pels;
142
    stringToTokens(pp, pels, ":");
143
    stringToTokens(pp, pels, ":");
143
    for (vector<string>::iterator it = pels.begin(); it != pels.end(); it++) {
144
    for (std::vector<std::string>::iterator it = pels.begin(); 
145
         it != pels.end(); it++) {
144
    if (it->empty())
146
    if (it->empty())
145
        *it = ".";
147
        *it = ".";
146
    string candidate = (it->empty() ? string(".") : *it) + "/" + cmd;
148
    std::string candidate = (it->empty() ? std::string(".") : *it) + 
149
            "/" + cmd;
147
    if (exec_is_there(candidate.c_str())) {
150
    if (exec_is_there(candidate.c_str())) {
148
        exepath = candidate;
151
        exepath = candidate;
149
        return true;
152
        return true;
150
    }
153
    }
151
    }
154
    }
152
    return false;
155
    return false;
153
}
156
}
154
157
155
void  ExecCmd::putenv(const string &ea)
158
void  ExecCmd::putenv(const std::string &ea)
156
{
159
{
157
    m_env.push_back(ea);
160
    m_env.push_back(ea);
158
}
161
}
159
162
160
void  ExecCmd::putenv(const string &name, const string& value)
163
void  ExecCmd::putenv(const std::string &name, const std::string& value)
161
{
164
{
162
    string ea = name + "=" + value;
165
    std::string ea = name + "=" + value;
163
    putenv(ea);
166
    putenv(ea);
164
}
167
}
165
168
166
static void msleep(int millis)
169
static void msleep(int millis)
167
{
170
{
...
...
217
        } else {
220
        } else {
218
                LOGERR(("ExecCmd: error killing process group %d: %d\n",
221
                LOGERR(("ExecCmd: error killing process group %d: %d\n",
219
                        grp, errno));
222
                        grp, errno));
220
            }
223
            }
221
    }
224
    }
222
    m_parent->m_tocmd = shared_ptr<Netcon>(0);
225
    m_parent->m_tocmd = std::shared_ptr<Netcon>(0);
223
    m_parent->m_fromcmd = shared_ptr<Netcon>(0);
226
    m_parent->m_fromcmd = std::shared_ptr<Netcon>(0);
224
    pthread_sigmask(SIG_UNBLOCK, &m_parent->m_blkcld, 0);
227
    pthread_sigmask(SIG_UNBLOCK, &m_parent->m_blkcld, 0);
225
    m_parent->reset();
228
    m_parent->reset();
226
    }
229
    }
227
private:
230
private:
228
    ExecCmd *m_parent;
231
    ExecCmd *m_parent;
...
...
245
// father process, so that only absolutely exceptional conditions, 
248
// father process, so that only absolutely exceptional conditions, 
246
// should be logged, for debugging and post-mortem purposes
249
// should be logged, for debugging and post-mortem purposes
247
// If one of the calls block, the problem manifests itself by 20mn
250
// If one of the calls block, the problem manifests itself by 20mn
248
// (filter timeout) of looping on "ExecCmd::doexec: selectloop
251
// (filter timeout) of looping on "ExecCmd::doexec: selectloop
249
// returned 1', because the father is waiting on the read descriptor
252
// returned 1', because the father is waiting on the read descriptor
250
inline void ExecCmd::dochild(const string &cmd, const char **argv,
253
inline void ExecCmd::dochild(const std::string &cmd, const char **argv,
251
                 const char **envv,
254
                 const char **envv,
252
                 bool has_input, bool has_output)
255
                 bool has_input, bool has_output)
253
{
256
{
254
    // Start our own process group
257
    // Start our own process group
255
    if (setpgid(0, getpid())) {
258
    if (setpgid(0, getpid())) {
...
...
315
    LOGERR(("ExecCmd::DOCHILD: execve(%s) failed. errno %d\n", cmd.c_str(),
318
    LOGERR(("ExecCmd::DOCHILD: execve(%s) failed. errno %d\n", cmd.c_str(),
316
        errno));
319
        errno));
317
    _exit(127);
320
    _exit(127);
318
}
321
}
319
322
320
int ExecCmd::startExec(const string &cmd, const vector<string>& args,
323
int ExecCmd::startExec(const std::string &cmd, 
324
                       const std::vector<std::string>& args,
321
               bool has_input, bool has_output)
325
               bool has_input, bool has_output)
322
{
326
{
323
    { // Debug and logging
327
    { // Debug and logging
324
    string command = cmd + " ";
328
    std::string command = cmd + " ";
325
    for (vector<string>::const_iterator it = args.begin();it != args.end();
329
    for (std::vector<std::string>::const_iterator it = args.begin();
326
       it++) {
330
             it != args.end(); it++) {
327
        command += "{" + *it + "} ";
331
        command += "{" + *it + "} ";
328
    }
332
    }
329
    LOGDEB(("ExecCmd::startExec: (%d|%d) %s\n", 
333
    LOGDEB(("ExecCmd::startExec: (%d|%d) %s\n", 
330
        has_input, has_output, command.c_str()));
334
        has_input, has_output, command.c_str()));
331
    }
335
    }
...
...
358
        return -1;
362
        return -1;
359
    }
363
    }
360
    // Fill up argv
364
    // Fill up argv
361
    argv[0] = cmd.c_str();
365
    argv[0] = cmd.c_str();
362
    int i = 1;
366
    int i = 1;
363
    vector<string>::const_iterator it;
367
    std::vector<std::string>::const_iterator it;
364
    for (it = args.begin(); it != args.end(); it++) {
368
    for (it = args.begin(); it != args.end(); it++) {
365
    argv[i++] = it->c_str();
369
    argv[i++] = it->c_str();
366
    }
370
    }
367
    argv[i] = 0;
371
    argv[i] = 0;
368
372
...
...
378
        return -1;
382
        return -1;
379
    }
383
    }
380
    int eidx;
384
    int eidx;
381
    for (eidx = 0; eidx < envsize; eidx++)
385
    for (eidx = 0; eidx < envsize; eidx++)
382
    envv[eidx] = environ[eidx];
386
    envv[eidx] = environ[eidx];
383
    for (vector<string>::const_iterator it = m_env.begin(); 
387
    for (std::vector<std::string>::const_iterator it = m_env.begin(); 
384
     it != m_env.end(); it++) {
388
     it != m_env.end(); it++) {
385
    envv[eidx++] = it->c_str();
389
    envv[eidx++] = it->c_str();
386
    }
390
    }
387
    envv[eidx] = 0;
391
    envv[eidx] = 0;
388
392
389
    // As we are going to use execve, not execvp, do the PATH thing.
393
    // As we are going to use execve, not execvp, do the PATH thing.
390
    string exe;
394
    std::string exe;
391
    if (!which(cmd, exe)) {
395
    if (!which(cmd, exe)) {
392
        LOGERR(("ExecCmd::startExec: %s not found\n", cmd.c_str()));
396
        LOGERR(("ExecCmd::startExec: %s not found\n", cmd.c_str()));
393
        free(argv);
397
        free(argv);
394
        free(envv);
398
        free(envv);
395
        return -1;
399
        return -1;
...
...
457
}
461
}
458
462
459
// Netcon callback. Send data to the command's input
463
// Netcon callback. Send data to the command's input
460
class ExecWriter : public NetconWorker {
464
class ExecWriter : public NetconWorker {
461
public:
465
public:
462
    ExecWriter(const string *input, ExecCmdProvide *provide) 
466
    ExecWriter(const std::string *input, ExecCmdProvide *provide) 
463
    : m_input(input), m_cnt(0), m_provide(provide)
467
    : m_input(input), m_cnt(0), m_provide(provide)
464
    {}                  
468
    {}                  
465
    virtual int data(NetconData *con, Netcon::Event reason)
469
    virtual int data(NetconData *con, Netcon::Event reason)
466
    {
470
    {
467
    if (!m_input) return -1;
471
    if (!m_input) return -1;
...
...
491
    }
495
    }
492
    m_cnt += ret;
496
    m_cnt += ret;
493
    return ret;
497
    return ret;
494
    }
498
    }
495
private:
499
private:
496
    const string   *m_input;
500
    const std::string   *m_input;
497
    unsigned int    m_cnt; // Current offset inside m_input
501
    unsigned int    m_cnt; // Current offset inside m_input
498
    ExecCmdProvide *m_provide;
502
    ExecCmdProvide *m_provide;
499
};
503
};
500
504
501
// Netcon callback. Get data from the command output.
505
// Netcon callback. Get data from the command output.
502
class ExecReader : public NetconWorker {
506
class ExecReader : public NetconWorker {
503
public:
507
public:
504
    ExecReader(string *output, ExecCmdAdvise *advise) 
508
    ExecReader(std::string *output, ExecCmdAdvise *advise) 
505
    : m_output(output), m_advise(advise)
509
    : m_output(output), m_advise(advise)
506
    {}                  
510
    {}                  
507
    virtual int data(NetconData *con, Netcon::Event reason)
511
    virtual int data(NetconData *con, Netcon::Event reason)
508
    {
512
    {
509
    char buf[8192];
513
    char buf[8192];
...
...
517
        m_advise->newData(n);
521
        m_advise->newData(n);
518
    } // else n == 0, just return
522
    } // else n == 0, just return
519
    return n;
523
    return n;
520
    }
524
    }
521
private:
525
private:
522
    string        *m_output;
526
    std::string        *m_output;
523
    ExecCmdAdvise *m_advise;
527
    ExecCmdAdvise *m_advise;
524
};
528
};
525
529
526
530
527
int ExecCmd::doexec(const string &cmd, const vector<string>& args,
531
int ExecCmd::doexec(const std::string &cmd, 
532
                    const std::vector<std::string>& args,
528
            const string *input, string *output)
533
            const std::string *input, std::string *output)
529
{
534
{
530
535
531
    if (startExec(cmd, args, input != 0, output != 0) < 0) {
536
    if (startExec(cmd, args, input != 0, output != 0) < 0) {
532
    return -1;
537
    return -1;
533
    }
538
    }
...
...
542
        NetconCli *oclicon = dynamic_cast<NetconCli *>(m_fromcmd.get());
547
        NetconCli *oclicon = dynamic_cast<NetconCli *>(m_fromcmd.get());
543
        if (!oclicon) {
548
        if (!oclicon) {
544
        LOGERR(("ExecCmd::doexec: no connection from command\n"));
549
        LOGERR(("ExecCmd::doexec: no connection from command\n"));
545
        return -1;
550
        return -1;
546
        }
551
        }
547
        oclicon->setcallback(make_shared<ExecReader>
552
        oclicon->setcallback(std::make_shared<ExecReader>
548
                 (ExecReader(output, m_advise)));
553
                 (ExecReader(output, m_advise)));
549
        myloop.addselcon(m_fromcmd, Netcon::NETCONPOLL_READ);
554
        myloop.addselcon(m_fromcmd, Netcon::NETCONPOLL_READ);
550
        // Give up ownership 
555
        // Give up ownership 
551
        m_fromcmd = shared_ptr<Netcon>(0);
556
        m_fromcmd = std::shared_ptr<Netcon>(0);
552
    } 
557
    } 
553
        // Setup input
558
        // Setup input
554
    if (input) {
559
    if (input) {
555
        NetconCli *iclicon = dynamic_cast<NetconCli *>(m_tocmd.get());
560
        NetconCli *iclicon = dynamic_cast<NetconCli *>(m_tocmd.get());
556
        if (!iclicon) {
561
        if (!iclicon) {
557
        LOGERR(("ExecCmd::doexec: no connection from command\n"));
562
        LOGERR(("ExecCmd::doexec: no connection from command\n"));
558
        return -1;
563
        return -1;
559
        }
564
        }
560
        iclicon->setcallback(make_shared<ExecWriter>
565
        iclicon->setcallback(std::make_shared<ExecWriter>
561
                 (ExecWriter(input, m_provide)));
566
                 (ExecWriter(input, m_provide)));
562
        myloop.addselcon(m_tocmd, Netcon::NETCONPOLL_WRITE);
567
        myloop.addselcon(m_tocmd, Netcon::NETCONPOLL_WRITE);
563
        // Give up ownership 
568
        // Give up ownership 
564
        m_tocmd = shared_ptr<Netcon>(0);
569
        m_tocmd = std::shared_ptr<Netcon>(0);
565
    }
570
    }
566
571
567
        // Do the actual reading/writing/waiting
572
        // Do the actual reading/writing/waiting
568
    myloop.setperiodichandler(0, 0, m_timeoutMs);
573
    myloop.setperiodichandler(0, 0, m_timeoutMs);
569
    while ((ret = myloop.doLoop()) > 0) {
574
    while ((ret = myloop.doLoop()) > 0) {
...
...
600
    if (ret)
605
    if (ret)
601
    return -1;
606
    return -1;
602
    return ret1;
607
    return ret1;
603
}
608
}
604
609
605
int ExecCmd::send(const string& data)
610
int ExecCmd::send(const std::string& data)
606
{
611
{
607
    NetconCli *con = dynamic_cast<NetconCli *>(m_tocmd.get());
612
    NetconCli *con = dynamic_cast<NetconCli *>(m_tocmd.get());
608
    if (con == 0) {
613
    if (con == 0) {
609
    LOGERR(("ExecCmd::send: outpipe is closed\n"));
614
    LOGERR(("ExecCmd::send: outpipe is closed\n"));
610
    return -1;
615
    return -1;
...
...
621
    nwritten += n;
626
    nwritten += n;
622
    }
627
    }
623
    return nwritten;
628
    return nwritten;
624
}
629
}
625
630
626
int ExecCmd::receive(string& data, int cnt)
631
int ExecCmd::receive(std::string& data, int cnt)
627
{
632
{
628
    NetconCli *con = dynamic_cast<NetconCli *>(m_fromcmd.get());
633
    NetconCli *con = dynamic_cast<NetconCli *>(m_fromcmd.get());
629
    if (con == 0) {
634
    if (con == 0) {
630
    LOGERR(("ExecCmd::receive: inpipe is closed\n"));
635
    LOGERR(("ExecCmd::receive: inpipe is closed\n"));
631
    return -1;
636
    return -1;
...
...
648
        }
653
        }
649
    } while (cnt > 0 && ntot < cnt);
654
    } while (cnt > 0 && ntot < cnt);
650
    return ntot;
655
    return ntot;
651
}
656
}
652
657
653
int ExecCmd::getline(string& data)
658
int ExecCmd::getline(std::string& data)
654
{
659
{
655
    NetconCli *con = dynamic_cast<NetconCli *>(m_fromcmd.get());
660
    NetconCli *con = dynamic_cast<NetconCli *>(m_fromcmd.get());
656
    if (con == 0) {
661
    if (con == 0) {
657
    LOGERR(("ExecCmd::receive: inpipe is closed\n"));
662
    LOGERR(("ExecCmd::receive: inpipe is closed\n"));
658
    return -1;
663
    return -1;
...
...
714
}
719
}
715
720
716
// Static
721
// Static
717
bool ExecCmd::backtick(const std::vector<std::string> cmd, std::string& out)
722
bool ExecCmd::backtick(const std::vector<std::string> cmd, std::string& out)
718
{
723
{
719
    vector<string>::const_iterator it = cmd.begin();
724
    std::vector<std::string>::const_iterator it = cmd.begin();
720
    it++;
725
    it++;
721
    vector<string> args(it, cmd.end());
726
    std::vector<std::string> args(it, cmd.end());
722
    ExecCmd mexec;
727
    ExecCmd mexec;
723
    int status = mexec.doexec(*cmd.begin(), args, 0, &out);
728
    int status = mexec.doexec(*cmd.begin(), args, 0, &out);
724
    return status == 0;
729
    return status == 0;
725
}
730
}
726
731
...
...
740
    if (cd) 
745
    if (cd) 
741
    m_curdir = cd;
746
    m_curdir = cd;
742
    free(cd);
747
    free(cd);
743
}
748
}
744
749
745
void ReExec::insertArgs(const vector<string>& args, int idx)
750
void ReExec::insertArgs(const std::vector<std::string>& args, int idx)
746
{
751
{
747
    vector<string>::iterator it, cit;
752
    std::vector<std::string>::iterator it, cit;
748
    unsigned int cmpoffset = (unsigned int)-1;
753
    unsigned int cmpoffset = (unsigned int)-1;
749
754
750
    if (idx == -1 || string::size_type(idx) >= m_argv.size()) {
755
    if (idx == -1 || std::string::size_type(idx) >= m_argv.size()) {
751
    it = m_argv.end();
756
    it = m_argv.end();
752
    if (m_argv.size() >= args.size()) {
757
    if (m_argv.size() >= args.size()) {
753
        cmpoffset = m_argv.size() - args.size();
758
        cmpoffset = m_argv.size() - args.size();
754
    }
759
    }
755
    } else {
760
    } else {
...
...
773
    }
778
    }
774
779
775
    m_argv.insert(it, args.begin(), args.end());
780
    m_argv.insert(it, args.begin(), args.end());
776
}
781
}
777
782
778
void ReExec::removeArg(const string& arg)
783
void ReExec::removeArg(const std::string& arg)
779
{
784
{
780
    for (vector<string>::iterator it = m_argv.begin(); 
785
    for (std::vector<std::string>::iterator it = m_argv.begin(); 
781
     it != m_argv.end(); it++) {
786
     it != m_argv.end(); it++) {
782
    if (*it == arg)
787
    if (*it == arg)
783
        it = m_argv.erase(it);
788
        it = m_argv.erase(it);
784
    }
789
    }
785
}
790
}
...
...
792
    char *cwd;
797
    char *cwd;
793
    cwd = getcwd(0,0);
798
    cwd = getcwd(0,0);
794
    FILE *fp = stdout; //fopen("/tmp/exectrace", "w");
799
    FILE *fp = stdout; //fopen("/tmp/exectrace", "w");
795
    if (fp) {
800
    if (fp) {
796
    fprintf(fp, "reexec: pwd: [%s] args: ", cwd?cwd:"getcwd failed");
801
    fprintf(fp, "reexec: pwd: [%s] args: ", cwd?cwd:"getcwd failed");
797
    for (vector<string>::const_iterator it = m_argv.begin();
802
    for (std::vector<std::string>::const_iterator it = m_argv.begin();
798
         it != m_argv.end(); it++) {
803
         it != m_argv.end(); it++) {
799
        fprintf(fp, "[%s] ", it->c_str());
804
        fprintf(fp, "[%s] ", it->c_str());
800
    }
805
    }
801
    fprintf(fp, "\n");
806
    fprintf(fp, "\n");
802
    }
807
    }
...
...
828
    return;
833
    return;
829
    }
834
    }
830
    
835
    
831
    // Fill up argv
836
    // Fill up argv
832
    int i = 0;
837
    int i = 0;
833
    vector<string>::const_iterator it;
838
    std::vector<std::string>::const_iterator it;
834
    for (it = m_argv.begin(); it != m_argv.end(); it++) {
839
    for (it = m_argv.begin(); it != m_argv.end(); it++) {
835
    argv[i++] = it->c_str();
840
    argv[i++] = it->c_str();
836
    }
841
    }
837
    argv[i] = 0;
842
    argv[i] = 0;
838
    execvp(m_argv[0].c_str(), (char *const*)argv);
843
    execvp(m_argv[0].c_str(), (char *const*)argv);