mirror of
https://github.com/MidnightCommander/mc
synced 2024-12-22 12:32:40 +03:00
Add mc_shell_init() and mc_shell_deinit() functions.
Signed-off-by: Slava Zanko <slavazanko@gmail.com>
This commit is contained in:
parent
0e79be1b7a
commit
7f383fbd6b
@ -40,7 +40,7 @@ libmc_la_SOURCES = \
|
|||||||
keybind.c keybind.h \
|
keybind.c keybind.h \
|
||||||
lock.c lock.h \
|
lock.c lock.h \
|
||||||
serialize.c serialize.h \
|
serialize.c serialize.h \
|
||||||
shell.h \
|
shell.c shell.h \
|
||||||
timefmt.c timefmt.h \
|
timefmt.c timefmt.h \
|
||||||
timer.c timer.h
|
timer.c timer.h
|
||||||
|
|
||||||
|
251
lib/shell.c
Normal file
251
lib/shell.c
Normal file
@ -0,0 +1,251 @@
|
|||||||
|
/*
|
||||||
|
Provides a functions for working with shell.
|
||||||
|
|
||||||
|
Copyright (C) 2006-2015
|
||||||
|
Free Software Foundation, Inc.
|
||||||
|
|
||||||
|
Written by:
|
||||||
|
Slava Zanko <slavazanko@gmail.com>, 2015.
|
||||||
|
|
||||||
|
This file is part of the Midnight Commander.
|
||||||
|
|
||||||
|
The Midnight Commander is free software: you can redistribute it
|
||||||
|
and/or modify it under the terms of the GNU General Public License as
|
||||||
|
published by the Free Software Foundation, either version 3 of the License,
|
||||||
|
or (at your option) any later version.
|
||||||
|
|
||||||
|
The Midnight Commander is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** \file shell.c
|
||||||
|
* \brief Source: provides a functions for working with shell.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <config.h>
|
||||||
|
|
||||||
|
#include <pwd.h> /* for username in xterm title */
|
||||||
|
#include <stdarg.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#include "global.h"
|
||||||
|
#include "util.h"
|
||||||
|
|
||||||
|
|
||||||
|
/*** global variables ****************************************************************************/
|
||||||
|
|
||||||
|
/*** file scope macro definitions ****************************************************************/
|
||||||
|
|
||||||
|
/*** file scope type declarations ****************************************************************/
|
||||||
|
|
||||||
|
/*** file scope variables ************************************************************************/
|
||||||
|
|
||||||
|
static char rp_shell[PATH_MAX];
|
||||||
|
|
||||||
|
/*** file scope functions ************************************************************************/
|
||||||
|
/* --------------------------------------------------------------------------------------------- */
|
||||||
|
/**
|
||||||
|
* Get a system shell.
|
||||||
|
*
|
||||||
|
* @return newly allocated string with shell name
|
||||||
|
*/
|
||||||
|
|
||||||
|
static mc_shell_t *
|
||||||
|
mc_shell_get_installed_in_system (void)
|
||||||
|
{
|
||||||
|
mc_shell_t *mc_shell;
|
||||||
|
|
||||||
|
mc_shell = g_new0 (mc_shell_t, 1);
|
||||||
|
|
||||||
|
/* 3rd choice: look for existing shells supported as MC subshells. */
|
||||||
|
if (access ("/bin/bash", X_OK) == 0)
|
||||||
|
mc_shell->path = g_strdup ("/bin/bash");
|
||||||
|
else if (access ("/bin/ash", X_OK) == 0)
|
||||||
|
mc_shell->path = g_strdup ("/bin/ash");
|
||||||
|
else if (access ("/bin/dash", X_OK) == 0)
|
||||||
|
mc_shell->path = g_strdup ("/bin/dash");
|
||||||
|
else if (access ("/bin/busybox", X_OK) == 0)
|
||||||
|
mc_shell->path = g_strdup ("/bin/busybox");
|
||||||
|
else if (access ("/bin/zsh", X_OK) == 0)
|
||||||
|
mc_shell->path = g_strdup ("/bin/zsh");
|
||||||
|
else if (access ("/bin/tcsh", X_OK) == 0)
|
||||||
|
mc_shell->path = g_strdup ("/bin/tcsh");
|
||||||
|
/* No fish as fallback because it is so much different from other shells and
|
||||||
|
* in a way exotic (even though user-friendly by name) that we should not
|
||||||
|
* present it as a subshell without the user's explicit intention. We rather
|
||||||
|
* will not use a subshell but just a command line.
|
||||||
|
* else if (access("/bin/fish", X_OK) == 0)
|
||||||
|
* mc_global.tty.shell = g_strdup ("/bin/fish");
|
||||||
|
*/
|
||||||
|
else
|
||||||
|
/* Fallback and last resort: system default shell */
|
||||||
|
mc_shell->path = g_strdup ("/bin/sh");
|
||||||
|
|
||||||
|
return mc_shell;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* --------------------------------------------------------------------------------------------- */
|
||||||
|
|
||||||
|
static char *
|
||||||
|
mc_shell_get_name_env (void)
|
||||||
|
{
|
||||||
|
const char *shell_env;
|
||||||
|
char *shell_name = NULL;
|
||||||
|
|
||||||
|
shell_env = g_getenv ("SHELL");
|
||||||
|
if ((shell_env == NULL) || (shell_env[0] == '\0'))
|
||||||
|
{
|
||||||
|
/* 2nd choice: user login shell */
|
||||||
|
struct passwd *pwd;
|
||||||
|
|
||||||
|
pwd = getpwuid (geteuid ());
|
||||||
|
if (pwd != NULL)
|
||||||
|
shell_name = g_strdup (pwd->pw_shell);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
/* 1st choice: SHELL environment variable */
|
||||||
|
shell_name = g_strdup (shell_env);
|
||||||
|
|
||||||
|
return shell_name;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* --------------------------------------------------------------------------------------------- */
|
||||||
|
|
||||||
|
static mc_shell_t *
|
||||||
|
mc_shell_get_from_env (void)
|
||||||
|
{
|
||||||
|
mc_shell_t *mc_shell = NULL;
|
||||||
|
|
||||||
|
char *shell_name;
|
||||||
|
|
||||||
|
shell_name = mc_shell_get_name_env ();
|
||||||
|
|
||||||
|
if (shell_name != NULL)
|
||||||
|
{
|
||||||
|
mc_shell = g_new0 (mc_shell_t, 1);
|
||||||
|
mc_shell->path = shell_name;
|
||||||
|
}
|
||||||
|
|
||||||
|
return mc_shell;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* --------------------------------------------------------------------------------------------- */
|
||||||
|
/**
|
||||||
|
* Get a shell type and store in mc_shell->type variable
|
||||||
|
*/
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
mc_shell_recognize_and_fill_type (mc_shell_t * mc_shell)
|
||||||
|
{
|
||||||
|
gboolean result = TRUE;
|
||||||
|
|
||||||
|
/* Find out what type of shell we have. Also consider real paths (resolved symlinks)
|
||||||
|
* because e.g. csh might point to tcsh, ash to dash or busybox, sh to anything. */
|
||||||
|
|
||||||
|
if (strstr (mc_shell->path, "/zsh") != NULL || strstr (mc_shell->real_path, "/zsh") != NULL
|
||||||
|
|| getenv ("ZSH_VERSION") != NULL)
|
||||||
|
{
|
||||||
|
/* Also detects ksh symlinked to zsh */
|
||||||
|
mc_shell->type = SHELL_ZSH;
|
||||||
|
mc_shell->name = "zsh";
|
||||||
|
}
|
||||||
|
else if (strstr (mc_shell->path, "/tcsh") != NULL
|
||||||
|
|| strstr (mc_shell->real_path, "/tcsh") != NULL)
|
||||||
|
{
|
||||||
|
/* Also detects csh symlinked to tcsh */
|
||||||
|
mc_shell->type = SHELL_TCSH;
|
||||||
|
mc_shell->name = "tcsh";
|
||||||
|
}
|
||||||
|
else if (strstr (mc_shell->path, "/fish") != NULL
|
||||||
|
|| strstr (mc_shell->real_path, "/fish") != NULL)
|
||||||
|
{
|
||||||
|
mc_shell->type = SHELL_FISH;
|
||||||
|
mc_shell->name = "fish";
|
||||||
|
}
|
||||||
|
else if (strstr (mc_shell->path, "/dash") != NULL
|
||||||
|
|| strstr (mc_shell->real_path, "/dash") != NULL)
|
||||||
|
{
|
||||||
|
/* Debian ash (also found if symlinked to by ash/sh) */
|
||||||
|
mc_shell->type = SHELL_DASH;
|
||||||
|
mc_shell->name = "dash";
|
||||||
|
}
|
||||||
|
else if (strstr (mc_shell->real_path, "/busybox") != NULL)
|
||||||
|
{
|
||||||
|
/* If shell is symlinked to busybox, assume it is an ash, even though theoretically
|
||||||
|
* it could also be a hush (a mini shell for non-MMU systems deactivated by default).
|
||||||
|
* For simplicity's sake we assume that busybox always contains an ash, not a hush.
|
||||||
|
* On embedded platforms or on server systems, /bin/sh often points to busybox.
|
||||||
|
* Sometimes even bash is symlinked to busybox (CONFIG_FEATURE_BASH_IS_ASH option),
|
||||||
|
* so we need to check busybox symlinks *before* checking for the name "bash"
|
||||||
|
* in order to avoid that case. */
|
||||||
|
mc_shell->type = SHELL_ASH_BUSYBOX;
|
||||||
|
mc_shell->name = mc_shell->path;
|
||||||
|
}
|
||||||
|
else if (strstr (mc_shell->path, "/bash") != NULL || getenv ("BASH") != NULL)
|
||||||
|
{
|
||||||
|
/* If bash is not symlinked to busybox, it is safe to assume it is a real bash */
|
||||||
|
mc_shell->type = SHELL_BASH;
|
||||||
|
mc_shell->name = "bash";
|
||||||
|
}
|
||||||
|
else if (strstr (mc_shell->path, "/sh") != NULL || getenv ("SH") != NULL)
|
||||||
|
{
|
||||||
|
/* If bash is not symlinked to busybox, it is safe to assume it is a real bash */
|
||||||
|
mc_shell->type = SHELL_SH;
|
||||||
|
mc_shell->name = "sh";
|
||||||
|
}
|
||||||
|
else if (strstr (mc_shell->path, "/ash") != NULL || getenv ("ASH") != NULL)
|
||||||
|
{
|
||||||
|
/* If bash is not symlinked to busybox, it is safe to assume it is a real bash */
|
||||||
|
mc_shell->type = SHELL_ASH_BUSYBOX;
|
||||||
|
mc_shell->name = "ash";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
mc_shell->type = SHELL_NONE;
|
||||||
|
mc_global.tty.use_subshell = FALSE;
|
||||||
|
result = FALSE;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* --------------------------------------------------------------------------------------------- */
|
||||||
|
/*** public functions ****************************************************************************/
|
||||||
|
/* --------------------------------------------------------------------------------------------- */
|
||||||
|
|
||||||
|
void
|
||||||
|
mc_shell_init (void)
|
||||||
|
{
|
||||||
|
mc_shell_t *mc_shell;
|
||||||
|
|
||||||
|
mc_shell = mc_shell_get_from_env ();
|
||||||
|
|
||||||
|
if (mc_shell == NULL)
|
||||||
|
mc_shell = mc_shell_get_installed_in_system ();
|
||||||
|
|
||||||
|
mc_shell->real_path = mc_realpath (mc_shell->path, rp_shell);
|
||||||
|
|
||||||
|
if (!mc_shell_recognize_and_fill_type (mc_shell))
|
||||||
|
mc_global.tty.use_subshell = FALSE;
|
||||||
|
|
||||||
|
mc_global.shell = mc_shell;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* --------------------------------------------------------------------------------------------- */
|
||||||
|
|
||||||
|
void
|
||||||
|
mc_shell_deinit (void)
|
||||||
|
{
|
||||||
|
if (mc_global.shell != NULL)
|
||||||
|
{
|
||||||
|
g_free (mc_global.shell->path);
|
||||||
|
MC_PTR_FREE (mc_global.shell);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* --------------------------------------------------------------------------------------------- */
|
19
lib/shell.h
19
lib/shell.h
@ -11,15 +11,16 @@
|
|||||||
|
|
||||||
typedef enum
|
typedef enum
|
||||||
{
|
{
|
||||||
BASH,
|
SHELL_NONE,
|
||||||
ASH_BUSYBOX, /* BusyBox default shell (ash) */
|
SHELL_SH,
|
||||||
DASH, /* Debian variant of ash */
|
SHELL_BASH,
|
||||||
TCSH,
|
SHELL_ASH_BUSYBOX, /* BusyBox default shell (ash) */
|
||||||
ZSH,
|
SHELL_DASH, /* Debian variant of ash */
|
||||||
FISH
|
SHELL_TCSH,
|
||||||
|
SHELL_ZSH,
|
||||||
|
SHELL_FISH
|
||||||
} shell_type_t;
|
} shell_type_t;
|
||||||
|
|
||||||
|
|
||||||
/*** structures declarations (and typedefs of structures)*****************************************/
|
/*** structures declarations (and typedefs of structures)*****************************************/
|
||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
@ -30,11 +31,13 @@ typedef struct
|
|||||||
char *real_path;
|
char *real_path;
|
||||||
} mc_shell_t;
|
} mc_shell_t;
|
||||||
|
|
||||||
|
|
||||||
/*** global variables defined in .c file *********************************************************/
|
/*** global variables defined in .c file *********************************************************/
|
||||||
|
|
||||||
/*** declarations of public functions ************************************************************/
|
/*** declarations of public functions ************************************************************/
|
||||||
|
|
||||||
|
void mc_shell_init (void);
|
||||||
|
void mc_shell_deinit (void);
|
||||||
|
|
||||||
/*** inline functions **************************************************/
|
/*** inline functions **************************************************/
|
||||||
|
|
||||||
#endif /* MC_SHELL_H */
|
#endif /* MC_SHELL_H */
|
||||||
|
75
src/main.c
75
src/main.c
@ -87,9 +87,6 @@
|
|||||||
/*** file scope variables ************************************************************************/
|
/*** file scope variables ************************************************************************/
|
||||||
|
|
||||||
/*** file scope functions ************************************************************************/
|
/*** file scope functions ************************************************************************/
|
||||||
|
|
||||||
static char rp_shell[PATH_MAX];
|
|
||||||
|
|
||||||
/* --------------------------------------------------------------------------------------------- */
|
/* --------------------------------------------------------------------------------------------- */
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@ -121,75 +118,14 @@ check_codeset (void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* --------------------------------------------------------------------------------------------- */
|
/* --------------------------------------------------------------------------------------------- */
|
||||||
/**
|
|
||||||
* Get a system shell.
|
|
||||||
*
|
|
||||||
* @return newly allocated string with shell name
|
|
||||||
*/
|
|
||||||
|
|
||||||
static char *
|
|
||||||
mc_get_system_shell (void)
|
|
||||||
{
|
|
||||||
char *sh_str;
|
|
||||||
/* 3rd choice: look for existing shells supported as MC subshells. */
|
|
||||||
if (access ("/bin/bash", X_OK) == 0)
|
|
||||||
sh_str = g_strdup ("/bin/bash");
|
|
||||||
else if (access ("/bin/ash", X_OK) == 0)
|
|
||||||
sh_str = g_strdup ("/bin/ash");
|
|
||||||
else if (access ("/bin/dash", X_OK) == 0)
|
|
||||||
sh_str = g_strdup ("/bin/dash");
|
|
||||||
else if (access ("/bin/busybox", X_OK) == 0)
|
|
||||||
sh_str = g_strdup ("/bin/busybox");
|
|
||||||
else if (access ("/bin/zsh", X_OK) == 0)
|
|
||||||
sh_str = g_strdup ("/bin/zsh");
|
|
||||||
else if (access ("/bin/tcsh", X_OK) == 0)
|
|
||||||
sh_str = g_strdup ("/bin/tcsh");
|
|
||||||
/* No fish as fallback because it is so much different from other shells and
|
|
||||||
* in a way exotic (even though user-friendly by name) that we should not
|
|
||||||
* present it as a subshell without the user's explicit intention. We rather
|
|
||||||
* will not use a subshell but just a command line.
|
|
||||||
* else if (access("/bin/fish", X_OK) == 0)
|
|
||||||
* mc_global.tty.shell = g_strdup ("/bin/fish");
|
|
||||||
*/
|
|
||||||
else
|
|
||||||
/* Fallback and last resort: system default shell */
|
|
||||||
sh_str = g_strdup ("/bin/sh");
|
|
||||||
|
|
||||||
return sh_str;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* --------------------------------------------------------------------------------------------- */
|
|
||||||
|
|
||||||
/** POSIX version. The only version we support. */
|
/** POSIX version. The only version we support. */
|
||||||
|
|
||||||
static void
|
static void
|
||||||
OS_Setup (void)
|
OS_Setup (void)
|
||||||
{
|
{
|
||||||
const char *shell_env;
|
|
||||||
const char *datadir_env;
|
const char *datadir_env;
|
||||||
|
|
||||||
|
mc_shell_init ();
|
||||||
mc_global.shell = g_new0 (mc_shell_t, 1);
|
|
||||||
|
|
||||||
shell_env = getenv ("SHELL");
|
|
||||||
if ((shell_env == NULL) || (shell_env[0] == '\0'))
|
|
||||||
{
|
|
||||||
/* 2nd choice: user login shell */
|
|
||||||
struct passwd *pwd;
|
|
||||||
|
|
||||||
pwd = getpwuid (geteuid ());
|
|
||||||
if (pwd != NULL)
|
|
||||||
mc_global.shell->path = g_strdup (pwd->pw_shell);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
/* 1st choice: SHELL environment variable */
|
|
||||||
mc_global.shell->path = g_strdup (shell_env);
|
|
||||||
|
|
||||||
if ((mc_global.shell->path == NULL) || (mc_global.shell->path[0] == '\0'))
|
|
||||||
{
|
|
||||||
g_free (mc_global.shell->path);
|
|
||||||
mc_global.shell->path = mc_get_system_shell ();
|
|
||||||
}
|
|
||||||
mc_global.shell->real_path = mc_realpath (mc_global.shell->path, rp_shell);
|
|
||||||
|
|
||||||
/* This is the directory, where MC was installed, on Unix this is DATADIR */
|
/* This is the directory, where MC was installed, on Unix this is DATADIR */
|
||||||
/* and can be overriden by the MC_DATADIR environment variable */
|
/* and can be overriden by the MC_DATADIR environment variable */
|
||||||
@ -303,10 +239,8 @@ main (int argc, char *argv[])
|
|||||||
startup_exit_falure:
|
startup_exit_falure:
|
||||||
fprintf (stderr, _("Failed to run:\n%s\n"), mcerror->message);
|
fprintf (stderr, _("Failed to run:\n%s\n"), mcerror->message);
|
||||||
g_error_free (mcerror);
|
g_error_free (mcerror);
|
||||||
|
|
||||||
g_free (mc_global.shell->path);
|
|
||||||
g_free (mc_global.shell);
|
|
||||||
startup_exit_ok:
|
startup_exit_ok:
|
||||||
|
mc_shell_deinit ();
|
||||||
str_uninit_strings ();
|
str_uninit_strings ();
|
||||||
mc_timer_destroy (mc_global.timer);
|
mc_timer_destroy (mc_global.timer);
|
||||||
return exit_code;
|
return exit_code;
|
||||||
@ -512,8 +446,7 @@ main (int argc, char *argv[])
|
|||||||
}
|
}
|
||||||
g_free (last_wd_string);
|
g_free (last_wd_string);
|
||||||
|
|
||||||
g_free (mc_global.shell->path);
|
mc_shell_deinit ();
|
||||||
g_free (mc_global.shell);
|
|
||||||
|
|
||||||
done_key ();
|
done_key ();
|
||||||
|
|
||||||
|
@ -131,17 +131,6 @@ enum
|
|||||||
WRITE = 1
|
WRITE = 1
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Subshell type (gleaned from the SHELL environment variable, if available) */
|
|
||||||
//static enum
|
|
||||||
//{
|
|
||||||
// BASH,
|
|
||||||
// ASH_BUSYBOX, /* BusyBox default shell (ash) */
|
|
||||||
// DASH, /* Debian variant of ash */
|
|
||||||
// TCSH,
|
|
||||||
// ZSH,
|
|
||||||
// FISH
|
|
||||||
//} subshell_type;
|
|
||||||
|
|
||||||
/*** file scope variables ************************************************************************/
|
/*** file scope variables ************************************************************************/
|
||||||
|
|
||||||
/* tcsh closes all non-standard file descriptors, so we have to use a pipe */
|
/* tcsh closes all non-standard file descriptors, so we have to use a pipe */
|
||||||
@ -282,7 +271,7 @@ init_subshell_child (const char *pty_name)
|
|||||||
|
|
||||||
switch (mc_global.shell->type)
|
switch (mc_global.shell->type)
|
||||||
{
|
{
|
||||||
case BASH:
|
case SHELL_BASH:
|
||||||
/* Do we have a custom init file ~/.local/share/mc/bashrc? */
|
/* Do we have a custom init file ~/.local/share/mc/bashrc? */
|
||||||
init_file = mc_config_get_full_path ("bashrc");
|
init_file = mc_config_get_full_path ("bashrc");
|
||||||
|
|
||||||
@ -312,8 +301,8 @@ init_subshell_child (const char *pty_name)
|
|||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case ASH_BUSYBOX:
|
case SHELL_ASH_BUSYBOX:
|
||||||
case DASH:
|
case SHELL_DASH:
|
||||||
/* Do we have a custom init file ~/.local/share/mc/ashrc? */
|
/* Do we have a custom init file ~/.local/share/mc/ashrc? */
|
||||||
init_file = mc_config_get_full_path ("ashrc");
|
init_file = mc_config_get_full_path ("ashrc");
|
||||||
|
|
||||||
@ -332,9 +321,9 @@ init_subshell_child (const char *pty_name)
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
/* TODO: Find a way to pass initfile to TCSH, ZSH and FISH */
|
/* TODO: Find a way to pass initfile to TCSH, ZSH and FISH */
|
||||||
case TCSH:
|
case SHELL_TCSH:
|
||||||
case ZSH:
|
case SHELL_ZSH:
|
||||||
case FISH:
|
case SHELL_FISH:
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
@ -365,21 +354,21 @@ init_subshell_child (const char *pty_name)
|
|||||||
|
|
||||||
switch (mc_global.shell->type)
|
switch (mc_global.shell->type)
|
||||||
{
|
{
|
||||||
case BASH:
|
case SHELL_BASH:
|
||||||
execl (mc_global.shell->path, "bash", "-rcfile", init_file, (char *) NULL);
|
execl (mc_global.shell->path, "bash", "-rcfile", init_file, (char *) NULL);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case ZSH:
|
case SHELL_ZSH:
|
||||||
/* Use -g to exclude cmds beginning with space from history
|
/* Use -g to exclude cmds beginning with space from history
|
||||||
* and -Z to use the line editor on non-interactive term */
|
* and -Z to use the line editor on non-interactive term */
|
||||||
execl (mc_global.shell->path, "zsh", "-Z", "-g", (char *) NULL);
|
execl (mc_global.shell->path, "zsh", "-Z", "-g", (char *) NULL);
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case ASH_BUSYBOX:
|
case SHELL_ASH_BUSYBOX:
|
||||||
case DASH:
|
case SHELL_DASH:
|
||||||
case TCSH:
|
case SHELL_TCSH:
|
||||||
case FISH:
|
case SHELL_FISH:
|
||||||
execl (mc_global.shell->path, mc_global.shell->path, (char *) NULL);
|
execl (mc_global.shell->path, mc_global.shell->path, (char *) NULL);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@ -790,58 +779,6 @@ pty_open_slave (const char *pty_name)
|
|||||||
#endif /* !HAVE_GRANTPT */
|
#endif /* !HAVE_GRANTPT */
|
||||||
|
|
||||||
|
|
||||||
/* --------------------------------------------------------------------------------------------- */
|
|
||||||
/**
|
|
||||||
* Get a subshell type and store in subshell_type variable
|
|
||||||
*
|
|
||||||
* @return TRUE if subtype was gotten, FALSE otherwise
|
|
||||||
*/
|
|
||||||
|
|
||||||
static gboolean
|
|
||||||
init_subshell_type (void)
|
|
||||||
{
|
|
||||||
gboolean result = TRUE;
|
|
||||||
|
|
||||||
/* Find out what type of shell we have. Also consider real paths (resolved symlinks)
|
|
||||||
* because e.g. csh might point to tcsh, ash to dash or busybox, sh to anything. */
|
|
||||||
|
|
||||||
if (strstr (mc_global.shell->path, "/zsh") != NULL
|
|
||||||
|| strstr (mc_global.shell->real_path, "/zsh") != NULL || getenv ("ZSH_VERSION") != NULL)
|
|
||||||
/* Also detects ksh symlinked to zsh */
|
|
||||||
mc_global.shell->type = ZSH;
|
|
||||||
else if (strstr (mc_global.shell->path, "/tcsh") != NULL
|
|
||||||
|| strstr (mc_global.shell->real_path, "/tcsh") != NULL)
|
|
||||||
/* Also detects csh symlinked to tcsh */
|
|
||||||
mc_global.shell->type = TCSH;
|
|
||||||
else if (strstr (mc_global.shell->path, "/fish") != NULL
|
|
||||||
|| strstr (mc_global.shell->real_path, "/fish") != NULL)
|
|
||||||
mc_global.shell->type = FISH;
|
|
||||||
else if (strstr (mc_global.shell->path, "/dash") != NULL
|
|
||||||
|| strstr (mc_global.shell->real_path, "/dash") != NULL)
|
|
||||||
/* Debian ash (also found if symlinked to by ash/sh) */
|
|
||||||
mc_global.shell->type = DASH;
|
|
||||||
else if (strstr (mc_global.shell->real_path, "/busybox") != NULL)
|
|
||||||
{
|
|
||||||
/* If shell is symlinked to busybox, assume it is an ash, even though theoretically
|
|
||||||
* it could also be a hush (a mini shell for non-MMU systems deactivated by default).
|
|
||||||
* For simplicity's sake we assume that busybox always contains an ash, not a hush.
|
|
||||||
* On embedded platforms or on server systems, /bin/sh often points to busybox.
|
|
||||||
* Sometimes even bash is symlinked to busybox (CONFIG_FEATURE_BASH_IS_ASH option),
|
|
||||||
* so we need to check busybox symlinks *before* checking for the name "bash"
|
|
||||||
* in order to avoid that case. */
|
|
||||||
mc_global.shell->type = ASH_BUSYBOX;
|
|
||||||
}
|
|
||||||
else if (strstr (mc_global.shell->path, "/bash") != NULL || getenv ("BASH") != NULL)
|
|
||||||
/* If bash is not symlinked to busybox, it is safe to assume it is a real bash */
|
|
||||||
mc_global.shell->type = BASH;
|
|
||||||
else
|
|
||||||
{
|
|
||||||
mc_global.tty.use_subshell = FALSE;
|
|
||||||
result = FALSE;
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* --------------------------------------------------------------------------------------------- */
|
/* --------------------------------------------------------------------------------------------- */
|
||||||
/**
|
/**
|
||||||
* Set up `precmd' or equivalent for reading the subshell's CWD.
|
* Set up `precmd' or equivalent for reading the subshell's CWD.
|
||||||
@ -858,12 +795,12 @@ init_subshell_precmd (char *precmd, size_t buff_size)
|
|||||||
{
|
{
|
||||||
switch (mc_global.shell->type)
|
switch (mc_global.shell->type)
|
||||||
{
|
{
|
||||||
case BASH:
|
case SHELL_BASH:
|
||||||
g_snprintf (precmd, buff_size,
|
g_snprintf (precmd, buff_size,
|
||||||
" PROMPT_COMMAND='pwd>&%d; kill -STOP $$';\n", subshell_pipe[WRITE]);
|
" PROMPT_COMMAND='pwd>&%d; kill -STOP $$';\n", subshell_pipe[WRITE]);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case ASH_BUSYBOX:
|
case SHELL_ASH_BUSYBOX:
|
||||||
/* BusyBox ash needs a somewhat complicated precmd emulation via PS1, and it is vital
|
/* BusyBox ash needs a somewhat complicated precmd emulation via PS1, and it is vital
|
||||||
* that BB be built with active CONFIG_ASH_EXPAND_PRMT, but this is the default anyway.
|
* that BB be built with active CONFIG_ASH_EXPAND_PRMT, but this is the default anyway.
|
||||||
*
|
*
|
||||||
@ -884,7 +821,7 @@ init_subshell_precmd (char *precmd, size_t buff_size)
|
|||||||
* "PRECMD=precmd; "
|
* "PRECMD=precmd; "
|
||||||
* "PS1='$(eval $PRECMD)\\u@\\h:\\w\\$ '\n",
|
* "PS1='$(eval $PRECMD)\\u@\\h:\\w\\$ '\n",
|
||||||
*/
|
*/
|
||||||
case DASH:
|
case SHELL_DASH:
|
||||||
/* Debian ash needs a precmd emulation via PS1, similar to BusyBox ash,
|
/* Debian ash needs a precmd emulation via PS1, similar to BusyBox ash,
|
||||||
* but does not support escape sequences for user, host and cwd in prompt.
|
* but does not support escape sequences for user, host and cwd in prompt.
|
||||||
* Attention! Make sure that the buffer for precmd is big enough.
|
* Attention! Make sure that the buffer for precmd is big enough.
|
||||||
@ -917,20 +854,20 @@ init_subshell_precmd (char *precmd, size_t buff_size)
|
|||||||
"}; " "PRECMD=precmd; " "PS1='$($PRECMD)$ '\n", subshell_pipe[WRITE]);
|
"}; " "PRECMD=precmd; " "PS1='$($PRECMD)$ '\n", subshell_pipe[WRITE]);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case ZSH:
|
case SHELL_ZSH:
|
||||||
g_snprintf (precmd, buff_size,
|
g_snprintf (precmd, buff_size,
|
||||||
" precmd() { pwd>&%d; kill -STOP $$; }; "
|
" precmd() { pwd>&%d; kill -STOP $$; }; "
|
||||||
"PS1='%%n@%%m:%%~%%# '\n", subshell_pipe[WRITE]);
|
"PS1='%%n@%%m:%%~%%# '\n", subshell_pipe[WRITE]);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case TCSH:
|
case SHELL_TCSH:
|
||||||
g_snprintf (precmd, buff_size,
|
g_snprintf (precmd, buff_size,
|
||||||
"set echo_style=both; "
|
"set echo_style=both; "
|
||||||
"set prompt='%%n@%%m:%%~%%# '; "
|
"set prompt='%%n@%%m:%%~%%# '; "
|
||||||
"alias precmd 'echo $cwd:q >>%s; kill -STOP $$'\n", tcsh_fifo);
|
"alias precmd 'echo $cwd:q >>%s; kill -STOP $$'\n", tcsh_fifo);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case FISH:
|
case SHELL_FISH:
|
||||||
/* We also want a fancy user@host:cwd prompt here, but fish makes it very easy to also
|
/* We also want a fancy user@host:cwd prompt here, but fish makes it very easy to also
|
||||||
* use colours, which is what we will do. But first here is a simpler, uncoloured version:
|
* use colours, which is what we will do. But first here is a simpler, uncoloured version:
|
||||||
* "function fish_prompt; "
|
* "function fish_prompt; "
|
||||||
@ -978,7 +915,7 @@ subshell_name_quote (const char *s)
|
|||||||
const char *su, *n;
|
const char *su, *n;
|
||||||
const char *quote_cmd_start, *quote_cmd_end;
|
const char *quote_cmd_start, *quote_cmd_end;
|
||||||
|
|
||||||
if (mc_global.shell->type == FISH)
|
if (mc_global.shell->type == SHELL_FISH)
|
||||||
{
|
{
|
||||||
quote_cmd_start = "(printf \"%b\" '";
|
quote_cmd_start = "(printf \"%b\" '";
|
||||||
quote_cmd_end = "')";
|
quote_cmd_end = "')";
|
||||||
@ -1071,7 +1008,7 @@ init_subshell (void)
|
|||||||
|
|
||||||
if (mc_global.tty.subshell_pty == 0)
|
if (mc_global.tty.subshell_pty == 0)
|
||||||
{ /* First time through */
|
{ /* First time through */
|
||||||
if (!init_subshell_type ())
|
if (mc_global.shell->type == SHELL_NONE)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
/* Open a pty for talking to the subshell */
|
/* Open a pty for talking to the subshell */
|
||||||
@ -1096,7 +1033,7 @@ init_subshell (void)
|
|||||||
|
|
||||||
/* Create a pipe for receiving the subshell's CWD */
|
/* Create a pipe for receiving the subshell's CWD */
|
||||||
|
|
||||||
if (mc_global.shell->type == TCSH)
|
if (mc_global.shell->type == SHELL_TCSH)
|
||||||
{
|
{
|
||||||
g_snprintf (tcsh_fifo, sizeof (tcsh_fifo), "%s/mc.pipe.%d",
|
g_snprintf (tcsh_fifo, sizeof (tcsh_fifo), "%s/mc.pipe.%d",
|
||||||
mc_tmpdir (), (int) getpid ());
|
mc_tmpdir (), (int) getpid ());
|
||||||
@ -1157,13 +1094,13 @@ init_subshell (void)
|
|||||||
|
|
||||||
switch (mc_global.shell->type)
|
switch (mc_global.shell->type)
|
||||||
{
|
{
|
||||||
case BASH:
|
case SHELL_BASH:
|
||||||
g_snprintf (precmd, sizeof (precmd),
|
g_snprintf (precmd, sizeof (precmd),
|
||||||
" PROMPT_COMMAND=${PROMPT_COMMAND:+$PROMPT_COMMAND\n}'pwd>&%d;kill -STOP $$'\n"
|
" PROMPT_COMMAND=${PROMPT_COMMAND:+$PROMPT_COMMAND\n}'pwd>&%d;kill -STOP $$'\n"
|
||||||
"PS1='\\u@\\h:\\w\\$ '\n", subshell_pipe[WRITE]);
|
"PS1='\\u@\\h:\\w\\$ '\n", subshell_pipe[WRITE]);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case ASH_BUSYBOX:
|
case SHELL_ASH_BUSYBOX:
|
||||||
/* BusyBox ash needs a somewhat complicated precmd emulation via PS1, and it is vital
|
/* BusyBox ash needs a somewhat complicated precmd emulation via PS1, and it is vital
|
||||||
* that BB be built with active CONFIG_ASH_EXPAND_PRMT, but this is the default anyway.
|
* that BB be built with active CONFIG_ASH_EXPAND_PRMT, but this is the default anyway.
|
||||||
*
|
*
|
||||||
@ -1184,7 +1121,7 @@ init_subshell (void)
|
|||||||
* "PRECMD=precmd; "
|
* "PRECMD=precmd; "
|
||||||
* "PS1='$(eval $PRECMD)\\u@\\h:\\w\\$ '\n",
|
* "PS1='$(eval $PRECMD)\\u@\\h:\\w\\$ '\n",
|
||||||
*/
|
*/
|
||||||
case DASH:
|
case SHELL_DASH:
|
||||||
/* Debian ash needs a precmd emulation via PS1, similar to BusyBox ash,
|
/* Debian ash needs a precmd emulation via PS1, similar to BusyBox ash,
|
||||||
* but does not support escape sequences for user, host and cwd in prompt.
|
* but does not support escape sequences for user, host and cwd in prompt.
|
||||||
* Attention! Make sure that the buffer for precmd is big enough.
|
* Attention! Make sure that the buffer for precmd is big enough.
|
||||||
@ -1217,20 +1154,20 @@ init_subshell (void)
|
|||||||
"}; " "PRECMD=precmd; " "PS1='$($PRECMD)$ '\n", subshell_pipe[WRITE]);
|
"}; " "PRECMD=precmd; " "PS1='$($PRECMD)$ '\n", subshell_pipe[WRITE]);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case ZSH:
|
case SHELL_ZSH:
|
||||||
g_snprintf (precmd, sizeof (precmd),
|
g_snprintf (precmd, sizeof (precmd),
|
||||||
" _mc_precmd(){ pwd>&%d;kill -STOP $$ }; precmd_functions+=(_mc_precmd)\n"
|
" _mc_precmd(){ pwd>&%d;kill -STOP $$ }; precmd_functions+=(_mc_precmd)\n"
|
||||||
"PS1='%%n@%%m:%%~%%# '\n", subshell_pipe[WRITE]);
|
"PS1='%%n@%%m:%%~%%# '\n", subshell_pipe[WRITE]);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case TCSH:
|
case SHELL_TCSH:
|
||||||
g_snprintf (precmd, sizeof (precmd),
|
g_snprintf (precmd, sizeof (precmd),
|
||||||
"set echo_style=both; "
|
"set echo_style=both; "
|
||||||
"set prompt='%%n@%%m:%%~%%# '; "
|
"set prompt='%%n@%%m:%%~%%# '; "
|
||||||
"alias precmd 'echo $cwd:q >>%s; kill -STOP $$'\n", tcsh_fifo);
|
"alias precmd 'echo $cwd:q >>%s; kill -STOP $$'\n", tcsh_fifo);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case FISH:
|
case SHELL_FISH:
|
||||||
/* Use fish_prompt_mc function for prompt, if not present then copy fish_prompt to it. */
|
/* Use fish_prompt_mc function for prompt, if not present then copy fish_prompt to it. */
|
||||||
/* We also want a fancy user@host:cwd prompt here, but fish makes it very easy to also
|
/* We also want a fancy user@host:cwd prompt here, but fish makes it very easy to also
|
||||||
* use colours, which is what we will do. But first here is a simpler, uncoloured version:
|
* use colours, which is what we will do. But first here is a simpler, uncoloured version:
|
||||||
@ -1414,7 +1351,7 @@ exit_subshell (void)
|
|||||||
|
|
||||||
if (subshell_quit)
|
if (subshell_quit)
|
||||||
{
|
{
|
||||||
if (mc_global.shell->type == TCSH)
|
if (mc_global.shell->type == SHELL_TCSH)
|
||||||
{
|
{
|
||||||
if (unlink (tcsh_fifo) == -1)
|
if (unlink (tcsh_fifo) == -1)
|
||||||
fprintf (stderr, "Cannot remove named pipe %s: %s\r\n",
|
fprintf (stderr, "Cannot remove named pipe %s: %s\r\n",
|
||||||
@ -1488,7 +1425,7 @@ do_subshell_chdir (const vfs_path_t * vpath, gboolean update_prompt)
|
|||||||
|
|
||||||
bPathNotEq = strcmp (subshell_cwd, pcwd) != 0;
|
bPathNotEq = strcmp (subshell_cwd, pcwd) != 0;
|
||||||
|
|
||||||
if (bPathNotEq && mc_global.shell->type == TCSH)
|
if (bPathNotEq && mc_global.shell->type == SHELL_TCSH)
|
||||||
{
|
{
|
||||||
char rp_subshell_cwd[PATH_MAX];
|
char rp_subshell_cwd[PATH_MAX];
|
||||||
char rp_current_panel_cwd[PATH_MAX];
|
char rp_current_panel_cwd[PATH_MAX];
|
||||||
@ -1517,7 +1454,7 @@ do_subshell_chdir (const vfs_path_t * vpath, gboolean update_prompt)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Really escape Zsh history */
|
/* Really escape Zsh history */
|
||||||
if (mc_global.shell->type == ZSH)
|
if (mc_global.shell->type == SHELL_ZSH)
|
||||||
{
|
{
|
||||||
/* Per Zsh documentation last command prefixed with space lingers in the internal history
|
/* Per Zsh documentation last command prefixed with space lingers in the internal history
|
||||||
* until the next command is entered before it vanishes. To make it vanish right away,
|
* until the next command is entered before it vanishes. To make it vanish right away,
|
||||||
|
Loading…
Reference in New Issue
Block a user