views:

630

answers:

2

Hello,

Hope I can find some help here cause I'm starting to give up. Heads up as this is an homework assignment, hence why it might be stupid.

Context: Have to program something which will be shell executed as such:
logn [--tick n] cmd [args] [, cmd [args]]...

Basically, it's a program that multiple programs simultanously.

Constraints: Each output line has to start with it's command number in front in format printf "%d: %s" ie: 0: first line of first command.
0: second line of first command.
1: first line of second command.
0: third line of first command.
1: second line of second command.

If the tick has been specified, system will print a period if no output has been sent for n seconds.
Must use Select()
If the last output was a period, system does not print another period.

Now here is my issue! I was able to make it work with a single command. The moment I try to make it multiple command, I seem to fail. I believe it may be my approach. Maybe some of you would be able to help me.

Here is what I attempted for Multiple Cmd. It may possbile that I am totally wrong, hence why I need help:

#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/time.h> 
#include "readline.h"

// Reference: http://www.gnu.org/s/libc/manual/html_node/Waiting-for-I_002fO.html
int input_timeout (int filedes, unsigned int seconds)
{
    fd_set set;
    struct timeval timeout;

    /* Initialize the file descriptor set. */
    FD_ZERO (&set);
    FD_SET (filedes, &set);

    /* Initialize the timeout data structure. */
    timeout.tv_sec = seconds;
    timeout.tv_usec = 0;

    /* select returns 0 if timeout, 1 if input available, -1 if error. */
    return (select (FD_SETSIZE,&set, NULL, NULL, &timeout));
}

/* Fetches the number of commands in parameters. Number of Commas + 1 */
int getNbCmd(char ** argv)
{
    int nbCmd = 1;
    int i;    
    while(argv[i] != '\0')
    {        
        if(strcmp(argv[i], ",") == 0)
            nbCmd++;
        i++;
    }

    return nbCmd;
}


/* Fills the Command Array */
void getCommandes(char *** tbCmd, int argc, char ** argv)
{    
    int indexArgv = 1;
    int indexCmd = 0;
    int indexTbCmd = 0;        

    char ** cmd = (char **)malloc(argc*sizeof(char *));

    if(strcmp(argv[indexArgv], "--tick") == 0)
        indexArgv = 3;

    while (indexArgv < argc)
    {

        if(strcmp(argv[indexArgv], ",") == 0)
        {    
            cmd[indexCmd] = (char *) 0;
            tbCmd[indexTbCmd] = cmd;
            free(cmd);
            cmd = (char **)malloc(argc*sizeof(char *));

            indexTbCmd++;
            indexCmd = 0;
        }
        else
        {
            char * arg;
            arg = argv[indexArgv];
            cmd[indexCmd] = arg;        

            indexCmd++;
        }
        indexArgv++;
    }

    cmd[indexCmd] = (char *) 0;
    tbCmd[indexTbCmd] = cmd;
    free(cmd);        
}


int main (int argc, char ** argv)
{
    int nbCmds = getNbCmd(argv);    
    int tick = -1;    

    char *** tbCmd = (char ***) malloc (nbCmds*sizeof(char **));

    if(strcmp(argv[1], "--tick") == 0)
        tick = atoi(argv[2]);

    getCommandes(tbCmd, argc, argv);

    int i;

    pid_t pidM[nbCmds];    
    int p[nbCmds][2];

    for (i = 0;i < nbCmds;i++)
    {            
        if ( pipe( p[i] ) != 0 ){ perror( "pipe()" ); exit(1); }

        // fork() to get child process        
        pidM[i] = fork();    

        if ( pidM[i] < 0 ){ perror( "fork()" ); exit(1); }
        else if (pidM[i] == 0)
        {
            close(p[i][0]);
            dup2(p[i][1], STDOUT_FILENO);    

            int ret;
            ret = execvp(tbCmd[i][0], tbCmd[i]);            
        }
        else
        {
            close(p[i][1]);

            char * buffer;
            int retval = 1;
            int pntAfficher = 0;  //Boolean for Period Printing
            /* select returns 0 if timeout, 1 if input available, -1 if error. */
            if(tick >= 0)
                retval = input_timeout(p[i][0], tick);
            if (retval == 0 && pntAfficher == 0)
            {
                printf(".\n");
                pntAfficher = 1;
            }

            buffer = readline(p[i][0]);
            while(buffer[0] != '\0')
            {                
                printf("%d: %s",i, buffer);
                free(buffer);

                /* select returns 0 if timeout, 1 if input available, -1 if error. */
                if(tick >= 0)
                    retval = input_timeout(p[i][0], tick);
                if (retval == 0 && pntAfficher == 0)
                {
                    printf(".\n");
                    pntAfficher = 1;
                }
                buffer = readline(p[i][0]);
                pntAfficher = 0;

            free(buffer);
            }
        }
    }
free(tbCmd);

}
+2  A: 

You need to fork all the children in a loop, then in a second loop, read all the data out from all the children.

You're wanting to listen to the output of all the children in parallel (which is what the select is doing for you), but all the children need to be running for that to work. Your current for loop spawns a child, then goes to the select... which isn't the right place for it.

retracile
+1  A: 

Not quite sure what you mean when you say "seem to fail" but it looks like you need to modify your code in order to listen to ALL your children. select can be used to do so, just look at the man of select and try to add multiple FDs using FD_SET

nico