Example #1
0
int
invoke_subshell (const char *command, int how, vfs_path_t ** new_dir_vpath)
{
    char *pcwd;

    /* Make the MC terminal transparent */
    tcsetattr (STDOUT_FILENO, TCSANOW, &raw_mode);

    /* Make the subshell change to MC's working directory */
    if (new_dir_vpath != NULL)
        do_subshell_chdir (current_panel->cwd_vpath, TRUE, TRUE);

    if (command == NULL)        /* The user has done "C-o" from MC */
    {
        if (subshell_state == INACTIVE)
        {
            subshell_state = ACTIVE;
            /* FIXME: possibly take out this hack; the user can
               re-play it by hitting C-hyphen a few times! */
            if (subshell_ready)
                write_all (mc_global.tty.subshell_pty, " \b", 2);       /* Hack to make prompt reappear */
        }
    }
    else                        /* MC has passed us a user command */
    {
        if (how == QUIETLY)
            write_all (mc_global.tty.subshell_pty, " ", 1);
        /* FIXME: if command is long (>8KB ?) we go comma */
        write_all (mc_global.tty.subshell_pty, command, strlen (command));
        write_all (mc_global.tty.subshell_pty, "\n", 1);
        subshell_state = RUNNING_COMMAND;
        subshell_ready = FALSE;
    }

    feed_subshell (how, FALSE);

    {
        char *cwd_str;

        cwd_str = vfs_path_to_str (current_panel->cwd_vpath);
        pcwd = vfs_translate_path_n (cwd_str);
        g_free (cwd_str);
    }

    if (new_dir_vpath != NULL && subshell_alive && strcmp (subshell_cwd, pcwd))
        *new_dir_vpath = vfs_path_from_str (subshell_cwd);      /* Make MC change to the subshell's CWD */
    g_free (pcwd);

    /* Restart the subshell if it has died by SIGHUP, SIGQUIT, etc. */
    while (!subshell_alive && quit == 0 && mc_global.tty.use_subshell)
        init_subshell ();

    prompt_pos = 0;

    return quit;
}
Example #2
0
void
init_subshell (void)
{
    /* This must be remembered across calls to init_subshell() */
    static char pty_name[BUF_SMALL];
    char precmd[BUF_SMALL];

    switch (check_sid ())
    {
    case 1:
        mc_global.tty.use_subshell = FALSE;
        return;
    case 2:
        mc_global.tty.use_subshell = FALSE;
        mc_global.midnight_shutdown = TRUE;
        return;
    }

    /* Take the current (hopefully pristine) tty mode and make */
    /* a raw mode based on it now, before we do anything else with it */
    init_raw_mode ();

    if (mc_global.tty.subshell_pty == 0)
    {   /* First time through */
        /* Find out what type of shell we have */

        if (strstr (mc_global.tty.shell, "/zsh") || getenv ("ZSH_VERSION"))
            subshell_type = ZSH;
        else if (strstr (mc_global.tty.shell, "/tcsh"))
            subshell_type = TCSH;
        else if (strstr (mc_global.tty.shell, "/csh"))
            subshell_type = TCSH;
        else if (strstr (mc_global.tty.shell, "/bash") || getenv ("BASH"))
            subshell_type = BASH;
        else if (strstr (mc_global.tty.shell, "/fish"))
            subshell_type = FISH;
        else
        {
            mc_global.tty.use_subshell = FALSE;
            return;
        }

        /* Open a pty for talking to the subshell */

        /* FIXME: We may need to open a fresh pty each time on SVR4 */

        mc_global.tty.subshell_pty = pty_open_master (pty_name);
        if (mc_global.tty.subshell_pty == -1)
        {
            fprintf (stderr, "Cannot open master side of pty: %s\r\n", unix_error_string (errno));
            mc_global.tty.use_subshell = FALSE;
            return;
        }
        subshell_pty_slave = pty_open_slave (pty_name);
        if (subshell_pty_slave == -1)
        {
            fprintf (stderr, "Cannot open slave side of pty %s: %s\r\n",
                     pty_name, unix_error_string (errno));
            mc_global.tty.use_subshell = FALSE;
            return;
        }

        /* Create a pipe for receiving the subshell's CWD */

        if (subshell_type == TCSH)
        {
            g_snprintf (tcsh_fifo, sizeof (tcsh_fifo), "%s/mc.pipe.%d",
                        mc_tmpdir (), (int) getpid ());
            if (mkfifo (tcsh_fifo, 0600) == -1)
            {
                fprintf (stderr, "mkfifo(%s) failed: %s\r\n", tcsh_fifo, unix_error_string (errno));
                mc_global.tty.use_subshell = FALSE;
                return;
            }

            /* Opening the FIFO as O_RDONLY or O_WRONLY causes deadlock */

            if ((subshell_pipe[READ] = open (tcsh_fifo, O_RDWR)) == -1
                    || (subshell_pipe[WRITE] = open (tcsh_fifo, O_RDWR)) == -1)
            {
                fprintf (stderr, _("Cannot open named pipe %s\n"), tcsh_fifo);
                perror (__FILE__ ": open");
                mc_global.tty.use_subshell = FALSE;
                return;
            }
        }
        else /* subshell_type is BASH or ZSH */ if (pipe (subshell_pipe))
        {
            perror (__FILE__ ": couldn't create pipe");
            mc_global.tty.use_subshell = FALSE;
            return;
        }
    }

    /* Fork the subshell */

    subshell_alive = TRUE;
    subshell_stopped = FALSE;
    subshell_pid = fork ();

    if (subshell_pid == -1)
    {
        fprintf (stderr, "Cannot spawn the subshell process: %s\r\n", unix_error_string (errno));
        /* We exit here because, if the process table is full, the */
        /* other method of running user commands won't work either */
        exit (EXIT_FAILURE);
    }

    if (subshell_pid == 0)
    {
        /* We are in the child process */
        init_subshell_child (pty_name);
    }

    /* Set up 'precmd' or equivalent for reading the subshell's CWD */

    switch (subshell_type)
    {
    case BASH:
        g_snprintf (precmd, sizeof (precmd),
                    " PROMPT_COMMAND='pwd>&%d;kill -STOP $$'\n", subshell_pipe[WRITE]);
        break;

    case ZSH:
        g_snprintf (precmd, sizeof (precmd),
                    " precmd(){ pwd>&%d;kill -STOP $$ }\n", subshell_pipe[WRITE]);
        break;

    case TCSH:
        g_snprintf (precmd, sizeof (precmd),
                    "set echo_style=both;"
                    "alias precmd 'echo $cwd:q >>%s;kill -STOP $$'\n", tcsh_fifo);
        break;
    case FISH:
        g_snprintf (precmd, sizeof (precmd),
                    "function fish_prompt ; pwd>&%d;kill -STOP %%self; end\n",
                    subshell_pipe[WRITE]);
        break;

    }
    write_all (mc_global.tty.subshell_pty, precmd, strlen (precmd));

    /* Wait until the subshell has started up and processed the command */

    subshell_state = RUNNING_COMMAND;
    tty_enable_interrupt_key ();
    if (!feed_subshell (QUIETLY, TRUE))
    {
        mc_global.tty.use_subshell = FALSE;
    }
    tty_disable_interrupt_key ();
    if (!subshell_alive)
        mc_global.tty.use_subshell = FALSE;     /* Subshell died instantly, so don't use it */
}
Example #3
0
/** If it actually changed the directory it returns true */
void
do_subshell_chdir (const vfs_path_t * vpath, gboolean update_prompt)
{
    char *pcwd;

    pcwd = vfs_path_to_str_flags (current_panel->cwd_vpath, 0, VPF_RECODE);

    if (!(subshell_state == INACTIVE && strcmp (subshell_cwd, pcwd) != 0))
    {
        /* We have to repaint the subshell prompt if we read it from
         * the main program.  Please note that in the code after this
         * if, the cd command that is sent will make the subshell
         * repaint the prompt, so we don't have to paint it. */
        if (update_prompt)
            do_update_prompt ();
        g_free (pcwd);
        return;
    }

    /* The initial space keeps this out of the command history (in bash
       because we set "HISTCONTROL=ignorespace") */
    write_all (mc_global.tty.subshell_pty, " cd ", 4);

    if (vpath != NULL)
    {
        char *translate;

        translate = vfs_translate_path_n (vfs_path_as_str (vpath));
        if (translate != NULL)
        {
            GString *temp;

            temp = subshell_name_quote (translate);
            write_all (mc_global.tty.subshell_pty, temp->str, temp->len);
            g_string_free (temp, TRUE);

            g_free (translate);
        }
        else
        {
            write_all (mc_global.tty.subshell_pty, ".", 1);
        }
    }
    else
    {
        write_all (mc_global.tty.subshell_pty, "/", 1);
    }
    write_all (mc_global.tty.subshell_pty, "\n", 1);

    subshell_state = RUNNING_COMMAND;
    feed_subshell (QUIETLY, FALSE);

    if (subshell_alive)
    {
        int bPathNotEq = strcmp (subshell_cwd, pcwd);

        if (bPathNotEq && subshell_type == TCSH)
        {
            char rp_subshell_cwd[PATH_MAX];
            char rp_current_panel_cwd[PATH_MAX];

            char *p_subshell_cwd = mc_realpath (subshell_cwd, rp_subshell_cwd);
            char *p_current_panel_cwd = mc_realpath (pcwd, rp_current_panel_cwd);

            if (p_subshell_cwd == NULL)
                p_subshell_cwd = subshell_cwd;
            if (p_current_panel_cwd == NULL)
                p_current_panel_cwd = pcwd;
            bPathNotEq = strcmp (p_subshell_cwd, p_current_panel_cwd);
        }

        if (bPathNotEq && !DIR_IS_DOT (pcwd))
        {
            char *cwd;

            cwd = vfs_path_to_str_flags (current_panel->cwd_vpath, 0, VPF_STRIP_PASSWORD);
            vfs_print_message (_("Warning: Cannot change to %s.\n"), cwd);
            g_free (cwd);
        }
    }

    update_subshell_prompt = FALSE;

    g_free (pcwd);
    /* Make sure that MC never stores the CWD in a silly format */
    /* like /usr////lib/../bin, or the strcmp() above will fail */
}
Example #4
0
void
init_subshell (void)
{
    /* This must be remembered across calls to init_subshell() */
    static char pty_name[BUF_SMALL];
    /* Must be considerably longer than BUF_SMALL (128) to support fancy shell prompts */
    char precmd[BUF_MEDIUM];

    switch (check_sid ())
    {
    case 1:
        mc_global.tty.use_subshell = FALSE;
        return;
    case 2:
        mc_global.tty.use_subshell = FALSE;
        mc_global.midnight_shutdown = TRUE;
        return;
    default:
        break;
    }

    /* Take the current (hopefully pristine) tty mode and make */
    /* a raw mode based on it now, before we do anything else with it */
    init_raw_mode ();

    if (mc_global.tty.subshell_pty == 0)
    {                           /* First time through */
        if (mc_global.shell->type == SHELL_NONE)
            return;

        /* Open a pty for talking to the subshell */

        /* FIXME: We may need to open a fresh pty each time on SVR4 */

        mc_global.tty.subshell_pty = pty_open_master (pty_name);
        if (mc_global.tty.subshell_pty == -1)
        {
            fprintf (stderr, "Cannot open master side of pty: %s\r\n", unix_error_string (errno));
            mc_global.tty.use_subshell = FALSE;
            return;
        }
        subshell_pty_slave = pty_open_slave (pty_name);
        if (subshell_pty_slave == -1)
        {
            fprintf (stderr, "Cannot open slave side of pty %s: %s\r\n",
                     pty_name, unix_error_string (errno));
            mc_global.tty.use_subshell = FALSE;
            return;
        }

        /* Create a pipe for receiving the subshell's CWD */

        if (mc_global.shell->type == SHELL_TCSH)
        {
            g_snprintf (tcsh_fifo, sizeof (tcsh_fifo), "%s/mc.pipe.%d",
                        mc_tmpdir (), (int) getpid ());
            if (mkfifo (tcsh_fifo, 0600) == -1)
            {
                fprintf (stderr, "mkfifo(%s) failed: %s\r\n", tcsh_fifo, unix_error_string (errno));
                mc_global.tty.use_subshell = FALSE;
                return;
            }

            /* Opening the FIFO as O_RDONLY or O_WRONLY causes deadlock */

            if ((subshell_pipe[READ] = open (tcsh_fifo, O_RDWR)) == -1
                || (subshell_pipe[WRITE] = open (tcsh_fifo, O_RDWR)) == -1)
            {
                fprintf (stderr, _("Cannot open named pipe %s\n"), tcsh_fifo);
                perror (__FILE__ ": open");
                mc_global.tty.use_subshell = FALSE;
                return;
            }
        }
        else if (pipe (subshell_pipe))  /* subshell_type is BASH, ASH_BUSYBOX, DASH or ZSH */
        {
            perror (__FILE__ ": couldn't create pipe");
            mc_global.tty.use_subshell = FALSE;
            return;
        }
    }

    /* Fork the subshell */

    subshell_alive = TRUE;
    subshell_stopped = FALSE;
    subshell_pid = fork ();

    if (subshell_pid == -1)
    {
        fprintf (stderr, "Cannot spawn the subshell process: %s\r\n", unix_error_string (errno));
        /* We exit here because, if the process table is full, the */
        /* other method of running user commands won't work either */
        exit (EXIT_FAILURE);
    }

    if (subshell_pid == 0)
    {
        /* We are in the child process */
        init_subshell_child (pty_name);
    }

    init_subshell_precmd (precmd, BUF_MEDIUM);

    write_all (mc_global.tty.subshell_pty, precmd, strlen (precmd));

    /* Wait until the subshell has started up and processed the command */

    subshell_state = RUNNING_COMMAND;
    tty_enable_interrupt_key ();
    if (!feed_subshell (QUIETLY, TRUE))
    {
        mc_global.tty.use_subshell = FALSE;
    }
    tty_disable_interrupt_key ();
    if (!subshell_alive)
        mc_global.tty.use_subshell = FALSE;     /* Subshell died instantly, so don't use it */
}
Example #5
0
/** If it actually changed the directory it returns true */
void
do_subshell_chdir (const char *directory, gboolean update_prompt, gboolean reset_prompt)
{
    char *pcwd;
    char *temp;
    char *translate;

    pcwd = vfs_translate_path_n (current_panel->cwd);

    if (!(subshell_state == INACTIVE && strcmp (subshell_cwd, pcwd) != 0))
    {
        /* We have to repaint the subshell prompt if we read it from
         * the main program.  Please note that in the code after this
         * if, the cd command that is sent will make the subshell
         * repaint the prompt, so we don't have to paint it. */
        if (update_prompt)
            do_update_prompt ();
        g_free (pcwd);
        return;
    }

    /* The initial space keeps this out of the command history (in bash
       because we set "HISTCONTROL=ignorespace") */
    write_all (mc_global.tty.subshell_pty, " cd ", 4);
    if (*directory)
    {
        translate = vfs_translate_path_n (directory);
        if (translate)
        {
            temp = subshell_name_quote (translate);
            if (temp)
            {
                write_all (mc_global.tty.subshell_pty, temp, strlen (temp));
                g_free (temp);
            }
            else
            {
                /* Should not happen unless the directory name is so long
                   that we don't have memory to quote it.  */
                write_all (mc_global.tty.subshell_pty, ".", 1);
            }
            g_free (translate);
        }
        else
        {
            write_all (mc_global.tty.subshell_pty, ".", 1);
        }
    }
    else
    {
        write_all (mc_global.tty.subshell_pty, "/", 1);
    }
    write_all (mc_global.tty.subshell_pty, "\n", 1);

    subshell_state = RUNNING_COMMAND;
    feed_subshell (QUIETLY, FALSE);

    if (subshell_alive)
    {
        int bPathNotEq = strcmp (subshell_cwd, pcwd);

        if (bPathNotEq && subshell_type == TCSH)
        {
            char rp_subshell_cwd[PATH_MAX];
            char rp_current_panel_cwd[PATH_MAX];

            char *p_subshell_cwd = mc_realpath (subshell_cwd, rp_subshell_cwd);
            char *p_current_panel_cwd = mc_realpath (pcwd, rp_current_panel_cwd);

            if (p_subshell_cwd == NULL)
                p_subshell_cwd = subshell_cwd;
            if (p_current_panel_cwd == NULL)
                p_current_panel_cwd = pcwd;
            bPathNotEq = strcmp (p_subshell_cwd, p_current_panel_cwd);
        }

        if (bPathNotEq && strcmp (pcwd, "."))
        {
            char *cwd = strip_password (g_strdup (pcwd), 1);
            fprintf (stderr, _("Warning: Cannot change to %s.\n"), cwd);
            g_free (cwd);
        }
    }

    if (reset_prompt)
        prompt_pos = 0;
    update_subshell_prompt = FALSE;

    g_free (pcwd);
    /* Make sure that MC never stores the CWD in a silly format */
    /* like /usr////lib/../bin, or the strcmp() above will fail */
}