Search code examples
cforkexecncurses

How to properly fork+exec in ncurses?


I've looked around, but there doesn't seem to be anything on using fork+exec with ncurses. Here's my attempt at a simple program:

#include <ncurses.h>
#include <unistd.h>
#include <sys/wait.h>

extern char **environ;

int
main(void){
  initscr(); cbreak(); noecho();
  pid_t child;

  mvprintw(0, 0, "press to continue"), refresh();
  getch();

  if (!(child = fork())) {
    def_prog_mode(), endwin();
    if (execve("/bin/ksh", (char*[]){"ksh", NULL}, environ) < 0) {
      perror("execve failed");
    }
  }
  else if (child > 0) {
    wait(&child);
    reset_prog_mode(), refresh();
    mvprintw(0, 0, "Done!"), refresh();
    getch();
    endwin();
  }
  else {
    endwin();
    perror("fork failed");
  }

  return 0;
}

It works fine, except output by the execve-ed process is all below the shell prompt that I get once the program is finished. Video to understand what I mean.

What is the proper way to fork+exec without mangled output?


Solution

  • Turns out if I move def_prog_mode(), refresh() out of the child process and into the parent process, everything works fine. Makes sense: two process controlling the same curses window doesn't seem like something that'd work.

    Here's the fixed code:

    #include <ncurses.h>
    #include <unistd.h>
    #include <sys/wait.h>
    
    extern char **environ;
    
    int
    main(void){
      initscr(); cbreak(); noecho();
      pid_t child;
    
      mvprintw(0, 0, "press to continue"), refresh();
      getch();
    
      def_prog_mode(), endwin();
      if (!(child = fork())) {
        if (execve("/bin/ksh", (char*[]){"ksh", NULL}, environ) < 0) {
          perror("execve failed");
        }
      }
      else if (child > 0) {
        wait(&child);
        reset_prog_mode(), erase();
        mvprintw(0, 0, "Done!"), refresh();
        getch();
        endwin();
      }
      else {
        endwin();
        perror("fork failed");
      }
    
      return 0;
    }