popen closing prematurely

Aug 11, 2010 at 10:07pm
I have written an application that does a popen call to get results from a linux system command (string) that I pass on the command line.

Example:
./myapp ls -l /home/someuser

Results:
As expected I get the same output as if I ran the "ls -l /home/someuser" command right on the shell.

The code works well for all tests except one so far... If I try to pass a command string which is an init script restart as follows:

./myapp /sbin/service tomcat restart

The command is only half processed!
Tomcat stops and does not start.

The issue (I believe) is that the init script issues a stop and then a seperate start. The initial stop exits with and exit code as expected and this is caught by popen and interpreted as the command finishing when in fact the start part has still not run.

If I run it seperately:
./myapp /sbin/service tomcat stop
and then
./myapp /sbin/service tomcat start

All works fine, which is what makes me think it is the init script returning an exit code before all sides of the "restart" are done.


anyway here is a snippet of my code that is in the child fork:

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
    // Start processing the command
    string send_data = "", start_time = get_time_date();
    int MAXBUF = 256;
    size_t n = 0;
    FILE *stream;
    char cmd_buff[MAXBUF];
    // I want ALL output to come back to me in the output string!
    cmd.append(" 2>&1");
    time_t tm_start = Str2DateTime(start_time);
    stream = popen(cmd.c_str(), "r");
    pid_t proc_pid = getpid();
    if (!stream){
        exit(1);
    }
    string curr_time;
    double curr_dif = 0.00;
    memset(cmd_buff, 0, MAXBUF + 1);
    // in case you are wondering
    // I am using curr_diff as a means to "time out" the command if 10 seconds
    // or more has elapsed
    while ((fgets(cmd_buff, MAXBUF, stream) != NULL) && (curr_dif < 10.00)){
        curr_time = get_time_date();
        time_t tm_curr = Str2DateTime(curr_time);
        curr_dif = difftime (tm_curr,tm_start);
        n = write( cli_sock, cmd_buff, MAXBUF );
        if (n < 0) {
            string msg = "";
            msg.append(get_time_date());
            msg.append(" - ERROR writing to socket.");
            WriteLogFile(msg, logfile);
        }

    }
    pclose(stream);
    shutdown(cli_sock, 2);
    close(cli_sock);
    // Now kill the child process
    waitpid(proc_pid, NULL, 0);
    kill (proc_pid, 9);


Can anyone see why this might fail or at least give me some pointers on a better (more ellegant) solution?

If this all looks ok and I am correct that the init script is returning an exit code, is there a way to combat that issue?
Maybe make the popen wait for the true end of the system command and not the first half exiting?


EDIT:
Sorry I pasted code from an earlier revision before, this is the latest and does still have the issue above.
Last edited on Aug 11, 2010 at 10:54pm
Aug 23, 2010 at 4:16pm
Follow up note:


I have found part of the issue I believe... tomcat's init script (in the stop function) calls the shutdown.sh shell script that comes with tomcat. In that shutdown.sh script at the very last line it uses the shell builtin command 'exec' to complete its shutdown.

Example:
exec "$PRGDIR"/"$EXECUTABLE" stop "$@"


I believe that since 'exec' actually replaces the current shell with the command passed as the first argument (man bash then find exec)... popen exits. I have created a small popen app and tested this by calling my own shell script which does an 'exec ls -l' and then 2 date commands.


The results are that the date commands never get processed because the popen process continued on with the 'exec ls -l' shell. I get the results of ls -l but not date commands. If I remove the 'exec' before 'ls -l' I see the output of all commands.




So, now my question becomes:

How can I unsure that I can grab all commands to follow any shell exec lines?
Topic archived. No new replies allowed.