Hi. I'm trying to get my program to work using job control. I want to be able to use the parent process to spawn child programs on-demand, or by user input.

The problem I've been trying to solve, is that when I run my code, it launches a child process on its own (by design) without any issues. The child process displays a selection window.

When I make a selection, though, the 2nd child process begins and displays, but my input is disabled. I can see the 2nd child process in 'ps', and it's in the foreground, but when I debug my code, I see that it fails on tcsetpgrp(STDIN_FILENO, child_pid) (It fails with EINVAL; in GDB, I see that the correct process ID is being passed to the function).

Why is my input working the first time the child is run, but not when I spawn another?

Relevant code:

This is what I use to launch a new job:

Code:
int launch_job(char *title)
  {
    extern int shell_terminal;
    char *fifo_file = new_fifo_name("../tmp");
    job *cur_job = 0, *new_job = 0;
    pid_t pid = 0, pgid = 0;
    int stat;

    tab_append(title);/*make the new tab entry - parent*/
    new_job = job_append(0, title);

    pid = fork();

    pid_t test_pid;

    switch(pid)
      {
        case 0:/*child*/
          init_child(getpid()); 

          if(!strcmp("Main Menu", title)) { execl("../menu/menu", "../menu/menu", "-f", fifo_file, NULL); }
          else if(!strcmp("Program Listing", title)) { execl("../display_tk/display_tk", "../display_tk/display_tk", "-f", fifo_file, NULL); }
          else if(!strcmp("Editor", title)) { execl("../editor_tk/editor_tk", "../editor_tk/editor_tk", "-f", fifo_file, NULL); }

          _exit(1);

          break;

        case -1:/*error*/
          perror("fork");
          break;

        default:/*parent*/
          pgid = pid;

          /*process group*/
          stat = setpgid(pid, pid);
          if( stat < 0 ) { perror("setpgid:launch_job()"); sleep(2); }
          /*terminal group*/
          stat = tcsetpgrp(STDIN_FILENO, getpgid(pgid));
          if(stat != 0) { perror("tcsetpgrp:stdin:launch_job()"); sleep(2); }

          //stat = tcsetpgrp(STDOUT_FILENO, pgid);
          //if(stat != 0) { perror("tcsetpgrp:stdout:launch_job()"); sleep(2); }

          //stat = tcsetpgrp(STDERR_FILENO, pgid);
          //if(stat != 0) { perror("tcsetpgrp:stderr:launch_job()"); sleep(2); }

          new_job->pgid = pid;

          cur_job = get_current_job();

          cur_job->fifo_file = concat_string(fifo_file, 0);

          break;
      }

    fifo_file = xfree(fifo_file);

    return 0;
  }
Here's the code that I run to initialize the child process (init_child()):

Code:
void init_child(pid_t pgid)
  {
    int stat;
    extern int shell_terminal;
    extern int shell_is_interactive;
    pid_t pid;

    if (shell_is_interactive)
      {   
        /* Put the process into the process group and give the process group
        the terminal, if appropriate.
        This has to be done both by the shell and in the individual
        child processes because of potential race conditions.  */
    
        pid = getpid();

        if(!pgid) { pgid = pid; }
  
        stat = setpgid(0, 0);/*process group*/
        if(stat != 0) { perror("setpgid:init_child()"); sleep(4); }

        tcsetpgrp(shell_terminal, pgid);

        /* Set the handling for job control signals back to the default.  */
        signal (SIGINT, SIG_DFL);
        signal (SIGQUIT, SIG_DFL);
        signal (SIGTSTP, SIG_DFL);
        signal (SIGTTIN, SIG_DFL);
        signal (SIGTTOU, SIG_DFL);
        signal (SIGCHLD, SIG_DFL);
      }
  }
Am I not fully understanding job control and foreground/background processing? Thank you to whomever helps, in advance.