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