root/lib/shell.c

/* [previous][next][first][last][top][bottom][index][help]  */

DEFINITIONS

This source file includes following definitions.
  1. mc_shell_get_installed_in_system
  2. mc_shell_get_name_env
  3. mc_shell_get_from_env
  4. mc_shell_recognize_real_path
  5. mc_shell_recognize_path
  6. mc_shell_init
  7. mc_shell_deinit

   1 /*
   2    Provides a functions for working with shell.
   3 
   4    Copyright (C) 2006-2019
   5    Free Software Foundation, Inc.
   6 
   7    Written by:
   8    Slava Zanko <slavazanko@gmail.com>, 2015.
   9 
  10    This file is part of the Midnight Commander.
  11 
  12    The Midnight Commander is free software: you can redistribute it
  13    and/or modify it under the terms of the GNU General Public License as
  14    published by the Free Software Foundation, either version 3 of the License,
  15    or (at your option) any later version.
  16 
  17    The Midnight Commander is distributed in the hope that it will be useful,
  18    but WITHOUT ANY WARRANTY; without even the implied warranty of
  19    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  20    GNU General Public License for more details.
  21 
  22    You should have received a copy of the GNU General Public License
  23    along with this program.  If not, see <http://www.gnu.org/licenses/>.
  24  */
  25 
  26 /** \file shell.c
  27  *  \brief Source: provides a functions for working with shell.
  28  */
  29 
  30 #include <config.h>
  31 
  32 #include <pwd.h>                /* for username in xterm title */
  33 #include <stdarg.h>
  34 #include <stdio.h>
  35 #include <stdlib.h>
  36 
  37 #include "global.h"
  38 #include "util.h"
  39 
  40 
  41 /*** global variables ****************************************************************************/
  42 
  43 /*** file scope macro definitions ****************************************************************/
  44 
  45 /*** file scope type declarations ****************************************************************/
  46 
  47 /*** file scope variables ************************************************************************/
  48 
  49 static char rp_shell[PATH_MAX];
  50 
  51 /*** file scope functions ************************************************************************/
  52 /* --------------------------------------------------------------------------------------------- */
  53 /**
  54  * Get a system shell.
  55  *
  56  * @return newly allocated mc_shell_t object with shell name
  57  */
  58 
  59 static mc_shell_t *
  60 mc_shell_get_installed_in_system (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
  61 {
  62     mc_shell_t *mc_shell;
  63 
  64     mc_shell = g_new0 (mc_shell_t, 1);
  65 
  66     /* 3rd choice: look for existing shells supported as MC subshells.  */
  67     if (access ("/bin/bash", X_OK) == 0)
  68         mc_shell->path = g_strdup ("/bin/bash");
  69     else if (access ("/bin/ash", X_OK) == 0)
  70         mc_shell->path = g_strdup ("/bin/ash");
  71     else if (access ("/bin/dash", X_OK) == 0)
  72         mc_shell->path = g_strdup ("/bin/dash");
  73     else if (access ("/bin/busybox", X_OK) == 0)
  74         mc_shell->path = g_strdup ("/bin/busybox");
  75     else if (access ("/bin/zsh", X_OK) == 0)
  76         mc_shell->path = g_strdup ("/bin/zsh");
  77     else if (access ("/bin/tcsh", X_OK) == 0)
  78         mc_shell->path = g_strdup ("/bin/tcsh");
  79     else if (access ("/bin/csh", X_OK) == 0)
  80         mc_shell->path = g_strdup ("/bin/csh");
  81     /* No fish as fallback because it is so much different from other shells and
  82      * in a way exotic (even though user-friendly by name) that we should not
  83      * present it as a subshell without the user's explicit intention. We rather
  84      * will not use a subshell but just a command line.
  85      * else if (access("/bin/fish", X_OK) == 0)
  86      *     mc_global.tty.shell = g_strdup ("/bin/fish");
  87      */
  88     else
  89         /* Fallback and last resort: system default shell */
  90         mc_shell->path = g_strdup ("/bin/sh");
  91 
  92     return mc_shell;
  93 }
  94 
  95 /* --------------------------------------------------------------------------------------------- */
  96 
  97 static char *
  98 mc_shell_get_name_env (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
  99 {
 100     const char *shell_env;
 101     char *shell_name = NULL;
 102 
 103     shell_env = g_getenv ("SHELL");
 104     if ((shell_env == NULL) || (shell_env[0] == '\0'))
 105     {
 106         /* 2nd choice: user login shell */
 107         struct passwd *pwd;
 108 
 109         pwd = getpwuid (geteuid ());
 110         if (pwd != NULL)
 111             shell_name = g_strdup (pwd->pw_shell);
 112     }
 113     else
 114         /* 1st choice: SHELL environment variable */
 115         shell_name = g_strdup (shell_env);
 116 
 117     return shell_name;
 118 }
 119 
 120 /* --------------------------------------------------------------------------------------------- */
 121 
 122 static mc_shell_t *
 123 mc_shell_get_from_env (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
 124 {
 125     mc_shell_t *mc_shell = NULL;
 126 
 127     char *shell_name;
 128 
 129     shell_name = mc_shell_get_name_env ();
 130 
 131     if (shell_name != NULL)
 132     {
 133         mc_shell = g_new0 (mc_shell_t, 1);
 134         mc_shell->path = shell_name;
 135     }
 136 
 137     return mc_shell;
 138 }
 139 
 140 /* --------------------------------------------------------------------------------------------- */
 141 
 142 static void
 143 mc_shell_recognize_real_path (mc_shell_t * mc_shell)
     /* [previous][next][first][last][top][bottom][index][help]  */
 144 {
 145     if (strstr (mc_shell->path, "/zsh") != NULL || strstr (mc_shell->real_path, "/zsh") != NULL
 146         || getenv ("ZSH_VERSION") != NULL)
 147     {
 148         /* Also detects ksh symlinked to zsh */
 149         mc_shell->type = SHELL_ZSH;
 150         mc_shell->name = "zsh";
 151     }
 152     else if (strstr (mc_shell->path, "/tcsh") != NULL
 153              || strstr (mc_shell->real_path, "/tcsh") != NULL)
 154     {
 155         /* Also detects csh symlinked to tcsh */
 156         mc_shell->type = SHELL_TCSH;
 157         mc_shell->name = "tcsh";
 158     }
 159     else if (strstr (mc_shell->path, "/csh") != NULL
 160              || strstr (mc_shell->real_path, "/csh") != NULL)
 161     {
 162         mc_shell->type = SHELL_TCSH;
 163         mc_shell->name = "csh";
 164     }
 165     else if (strstr (mc_shell->path, "/fish") != NULL
 166              || strstr (mc_shell->real_path, "/fish") != NULL)
 167     {
 168         mc_shell->type = SHELL_FISH;
 169         mc_shell->name = "fish";
 170     }
 171     else if (strstr (mc_shell->path, "/dash") != NULL
 172              || strstr (mc_shell->real_path, "/dash") != NULL)
 173     {
 174         /* Debian ash (also found if symlinked to by ash/sh) */
 175         mc_shell->type = SHELL_DASH;
 176         mc_shell->name = "dash";
 177     }
 178     else if (strstr (mc_shell->real_path, "/busybox") != NULL)
 179     {
 180         /* If shell is symlinked to busybox, assume it is an ash, even though theoretically
 181          * it could also be a hush (a mini shell for non-MMU systems deactivated by default).
 182          * For simplicity's sake we assume that busybox always contains an ash, not a hush.
 183          * On embedded platforms or on server systems, /bin/sh often points to busybox.
 184          * Sometimes even bash is symlinked to busybox (CONFIG_FEATURE_BASH_IS_ASH option),
 185          * so we need to check busybox symlinks *before* checking for the name "bash"
 186          * in order to avoid that case. */
 187         mc_shell->type = SHELL_ASH_BUSYBOX;
 188         mc_shell->name = mc_shell->path;
 189     }
 190     else
 191         mc_shell->type = SHELL_NONE;
 192 }
 193 
 194 /* --------------------------------------------------------------------------------------------- */
 195 
 196 static void
 197 mc_shell_recognize_path (mc_shell_t * mc_shell)
     /* [previous][next][first][last][top][bottom][index][help]  */
 198 {
 199     /* If shell is not symlinked to busybox, it is safe to assume it is a real shell */
 200     if (strstr (mc_shell->path, "/bash") != NULL || getenv ("BASH") != NULL)
 201     {
 202         mc_shell->type = SHELL_BASH;
 203         mc_shell->name = "bash";
 204     }
 205     else if (strstr (mc_shell->path, "/sh") != NULL || getenv ("SH") != NULL)
 206     {
 207         mc_shell->type = SHELL_SH;
 208         mc_shell->name = "sh";
 209     }
 210     else if (strstr (mc_shell->path, "/ash") != NULL || getenv ("ASH") != NULL)
 211     {
 212         mc_shell->type = SHELL_ASH_BUSYBOX;
 213         mc_shell->name = "ash";
 214     }
 215     else
 216         mc_shell->type = SHELL_NONE;
 217 }
 218 
 219 /* --------------------------------------------------------------------------------------------- */
 220 /*** public functions ****************************************************************************/
 221 /* --------------------------------------------------------------------------------------------- */
 222 
 223 void
 224 mc_shell_init (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
 225 {
 226     mc_shell_t *mc_shell;
 227 
 228     mc_shell = mc_shell_get_from_env ();
 229 
 230     if (mc_shell == NULL)
 231         mc_shell = mc_shell_get_installed_in_system ();
 232 
 233     mc_shell->real_path = mc_realpath (mc_shell->path, rp_shell);
 234 
 235     /* Find out what type of shell we have. Also consider real paths (resolved symlinks)
 236      * because e.g. csh might point to tcsh, ash to dash or busybox, sh to anything. */
 237 
 238     if (mc_shell->real_path != NULL)
 239         mc_shell_recognize_real_path (mc_shell);
 240 
 241     if (mc_shell->type == SHELL_NONE)
 242         mc_shell_recognize_path (mc_shell);
 243 
 244     if (mc_shell->type == SHELL_NONE)
 245         mc_global.tty.use_subshell = FALSE;
 246 
 247     mc_global.shell = mc_shell;
 248 }
 249 
 250 /* --------------------------------------------------------------------------------------------- */
 251 
 252 void
 253 mc_shell_deinit (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
 254 {
 255     if (mc_global.shell != NULL)
 256     {
 257         g_free (mc_global.shell->path);
 258         MC_PTR_FREE (mc_global.shell);
 259     }
 260 }
 261 
 262 /* --------------------------------------------------------------------------------------------- */

/* [previous][next][first][last][top][bottom][index][help]  */