File: EShellProcess.cc

package info (click to toggle)
miwm 1.1-6
  • links: PTS, VCS
  • area: main
  • in suites: bullseye, buster, sid, stretch
  • size: 1,296 kB
  • ctags: 910
  • sloc: cpp: 8,179; sh: 231; makefile: 148
file content (124 lines) | stat: -rw-r--r-- 4,362 bytes parent folder | download | duplicates (3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
#include <stdio.h> // popen()
#include <stdlib.h> // system()
#include <sys/types.h> // pid_t
#include <sys/wait.h> // pid_t
#include <unistd.h> // fork()

#include "EShellProcess.h"
#include "EStringList.h"
#include <signal.h> // signal(), sighandler_t
#include <setjmp.h> // longjmp()

using std::string;
using std::endl;

sigjmp_buf EShellProcess_ctrl_c_jmp_buffer;

void EShellProcess_SIGINT(int)
{
        std::cout << "^C" << std::endl; // this really shouldn't be here, but i find it useful.
        ::siglongjmp( EShellProcess_ctrl_c_jmp_buffer, 1 );
}

int
EShellProcess::system( const std::string &cmdline, std::ostream & os  )
{
        return ::system( cmdline.c_str() ) / 256; // i don't like this /256. it's against the docs, but the return values aren't what the docs say :/
}

int
EShellProcess::fork( const std::string &cmdline, std::ostream & os  )
{ // my very first fork()/exec()
        pid_t pid;
        EStringList tokens = EStringList::tokenize( cmdline );
                
        pid = ::fork();
        if( pid == -1 )
        {
                os << "EShellProcess::fork("<<cmdline<<"): error fork()ing." << endl;
                return 1;
        }
        if( pid > 0 ) return 0; // parent, go away.
        // child...

        // i hate to do this array stuff, but i see no other
        // way around it without finding a template class for
        // dynamic arrays, and i'm not up for that right now...
        static const int maxargs = 100;
        char * args[maxargs];
        int tcount = tokens.count();
        int i = 0;
        string tok;
        string filearg;
        for( ; i < tcount; i++ )
        {
                tok = tokens.shift();
                if( i == 0 ) filearg = tok;
                if( tok.empty() ) continue;
                //os << "adding token ["<<tok<<"]"<<endl;
                args[i] = const_cast<char *>( tok.c_str() );
                // this ^^^^^^^^^^^ const_cast is theoretically okay
                // because we're not gonna de-allocate the
                // array and this process will never pass
                // control back to anyone else, so tokens
                // shouldn't be unduly molested behind our
                // back. i won't swear that it's safe, though :/.
        }
        if( i == maxargs )
        {
                os << __FILE__<<":"<<__LINE__<<": EShellProcess::fork(): you've met or overstepped the\n"
                   << "hard-coded limit of "<< maxargs<<" arguments.\n"
                   <<"Please contact the maintainer of this code with an example of how you're using it (stephan@wanderinghorse.net), "
                   << "or fix this bug and send him your fix :)."
                   << endl;
        }
        for( ; i < maxargs; i++ )
        {
                args[i] = NULL;
        }
        execvp( filearg.c_str(), args );
        _exit(0);
        return 0;
}

int
EShellProcess::pipe( const std::string &cmdline, std::ostream & os )
{
        if( cmdline.empty() )
        {
                os << "EShellProcess::pipe(): cannot run an empty command :(";
                return 1;
        }
        FILE *fp = 0;
        fp = ::popen( cmdline.c_str(), "r" );
        if( ! fp )
        {
                os << "EShellProcess::pipe(): popen("<<cmdline<<") failed :(" << std::endl;
                return 1;
        }
        ::fwrite( cmdline.c_str(), sizeof( char ), cmdline.size(), fp );
#define RESTORE_SIGNALS ::signal( SIGINT, old_sighandler )
        typedef void (*signalfunc)(int);
        signalfunc old_sighandler = ::signal( SIGINT, EShellProcess_SIGINT );
        int getcchar;
        if( 0 == ::sigsetjmp( EShellProcess_ctrl_c_jmp_buffer, 1 ) )
        {
                while( ! ::feof( fp ) )
                {
                        getcchar = ::getc( fp );
                        if( getcchar == EOF ) break;
                        os <<(unsigned char) getcchar;
                        if( ! os && (os != std::cerr) )
                        {
                                RESTORE_SIGNALS;
                                std::cerr << "EShellProcess::pipe(): error in output stream!" << std::endl;
                                return 1;
                        }
                }
        }
        RESTORE_SIGNALS;
        int ret = ::pclose( fp );
        return (ret == 0) ? 0 : (ret / 256);
}