123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264 |
- /*
- Provides a functions for working with shell.
- Copyright (C) 2006-2024
- 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 ****************************************************************/
- /*** forward declarations (file scope functions) *************************************************/
- /*** file scope variables ************************************************************************/
- static char rp_shell[PATH_MAX];
- /* --------------------------------------------------------------------------------------------- */
- /*** file scope functions ************************************************************************/
- /* --------------------------------------------------------------------------------------------- */
- /**
- * Get a system shell.
- *
- * @return newly allocated mc_shell_t object 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");
- else if (access ("/bin/csh", X_OK) == 0)
- mc_shell->path = g_strdup ("/bin/csh");
- /* 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;
- }
- /* --------------------------------------------------------------------------------------------- */
- static void
- mc_shell_recognize_real_path (mc_shell_t *mc_shell)
- {
- 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, "/csh") != NULL
- || strstr (mc_shell->real_path, "/csh") != NULL)
- {
- mc_shell->type = SHELL_TCSH;
- mc_shell->name = "csh";
- }
- 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
- mc_shell->type = SHELL_NONE;
- }
- /* --------------------------------------------------------------------------------------------- */
- static void
- mc_shell_recognize_path (mc_shell_t *mc_shell)
- {
- /* If shell is not symlinked to busybox, it is safe to assume it is a real shell */
- if (strstr (mc_shell->path, "/bash") != NULL || getenv ("BASH") != NULL)
- {
- mc_shell->type = SHELL_BASH;
- mc_shell->name = "bash";
- }
- else if (strstr (mc_shell->path, "/sh") != NULL || getenv ("SH") != NULL)
- {
- mc_shell->type = SHELL_SH;
- mc_shell->name = "sh";
- }
- else if (strstr (mc_shell->path, "/ash") != NULL || getenv ("ASH") != NULL)
- {
- mc_shell->type = SHELL_ASH_BUSYBOX;
- mc_shell->name = "ash";
- }
- else
- mc_shell->type = SHELL_NONE;
- }
- /* --------------------------------------------------------------------------------------------- */
- /*** 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);
- /* 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 (mc_shell->real_path != NULL)
- mc_shell_recognize_real_path (mc_shell);
- if (mc_shell->type == SHELL_NONE)
- mc_shell_recognize_path (mc_shell);
- if (mc_shell->type == SHELL_NONE)
- 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);
- }
- }
- /* --------------------------------------------------------------------------------------------- */
|