Skip to content

Commit

Permalink
Add mc_shell_init() and mc_shell_deinit() functions.
Browse files Browse the repository at this point in the history
Signed-off-by: Slava Zanko <[email protected]>
  • Loading branch information
slavaz authored and aborodin committed Jan 1, 2016
1 parent 0e79be1 commit 7f383fb
Show file tree
Hide file tree
Showing 5 changed files with 297 additions and 173 deletions.
2 changes: 1 addition & 1 deletion lib/Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ libmc_la_SOURCES = \
keybind.c keybind.h \
lock.c lock.h \
serialize.c serialize.h \
shell.h \
shell.c shell.h \
timefmt.c timefmt.h \
timer.c timer.h
Expand Down
251 changes: 251 additions & 0 deletions lib/shell.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,251 @@
/*
Provides a functions for working with shell.
Copyright (C) 2006-2015
Free Software Foundation, Inc.
Written by:
Slava Zanko <[email protected]>, 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 changes: 11 additions & 8 deletions lib/shell.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,15 +11,16 @@

typedef enum
{
BASH,
ASH_BUSYBOX, /* BusyBox default shell (ash) */
DASH, /* Debian variant of ash */
TCSH,
ZSH,
FISH
SHELL_NONE,
SHELL_SH,
SHELL_BASH,
SHELL_ASH_BUSYBOX, /* BusyBox default shell (ash) */
SHELL_DASH, /* Debian variant of ash */
SHELL_TCSH,
SHELL_ZSH,
SHELL_FISH
} shell_type_t;


/*** structures declarations (and typedefs of structures)*****************************************/

typedef struct
Expand All @@ -30,11 +31,13 @@ typedef struct
char *real_path;
} mc_shell_t;


/*** global variables defined in .c file *********************************************************/

/*** declarations of public functions ************************************************************/

void mc_shell_init (void);
void mc_shell_deinit (void);

/*** inline functions **************************************************/

#endif /* MC_SHELL_H */
Loading

0 comments on commit 7f383fb

Please sign in to comment.