2 Provides a functions for working with shell.
4 Copyright (C) 2006-2016
5 Free Software Foundation, Inc.
8 Slava Zanko <slavazanko@gmail.com>, 2015.
10 This file is part of the Midnight Commander.
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.
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.
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/>.
27 * \brief Source: provides a functions for working with shell.
32 #include <pwd.h> /* for username in xterm title */
41 /*** global variables ****************************************************************************/
43 /*** file scope macro definitions ****************************************************************/
45 /*** file scope type declarations ****************************************************************/
47 /*** file scope variables ************************************************************************/
49 static char rp_shell
[PATH_MAX
];
51 /*** file scope functions ************************************************************************/
52 /* --------------------------------------------------------------------------------------------- */
56 * @return newly allocated mc_shell_t object with shell name
60 mc_shell_get_installed_in_system (void)
64 mc_shell
= g_new0 (mc_shell_t
, 1);
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");
89 /* Fallback and last resort: system default shell */
90 mc_shell
->path
= g_strdup ("/bin/sh");
95 /* --------------------------------------------------------------------------------------------- */
98 mc_shell_get_name_env (void)
100 const char *shell_env
;
101 char *shell_name
= NULL
;
103 shell_env
= g_getenv ("SHELL");
104 if ((shell_env
== NULL
) || (shell_env
[0] == '\0'))
106 /* 2nd choice: user login shell */
109 pwd
= getpwuid (geteuid ());
111 shell_name
= g_strdup (pwd
->pw_shell
);
114 /* 1st choice: SHELL environment variable */
115 shell_name
= g_strdup (shell_env
);
120 /* --------------------------------------------------------------------------------------------- */
123 mc_shell_get_from_env (void)
125 mc_shell_t
*mc_shell
= NULL
;
129 shell_name
= mc_shell_get_name_env ();
131 if (shell_name
!= NULL
)
133 mc_shell
= g_new0 (mc_shell_t
, 1);
134 mc_shell
->path
= shell_name
;
140 /* --------------------------------------------------------------------------------------------- */
143 mc_shell_recognize_real_path (mc_shell_t
* mc_shell
)
145 if (strstr (mc_shell
->path
, "/zsh") != NULL
|| strstr (mc_shell
->real_path
, "/zsh") != NULL
146 || getenv ("ZSH_VERSION") != NULL
)
148 /* Also detects ksh symlinked to zsh */
149 mc_shell
->type
= SHELL_ZSH
;
150 mc_shell
->name
= "zsh";
152 else if (strstr (mc_shell
->path
, "/tcsh") != NULL
153 || strstr (mc_shell
->real_path
, "/tcsh") != NULL
)
155 /* Also detects csh symlinked to tcsh */
156 mc_shell
->type
= SHELL_TCSH
;
157 mc_shell
->name
= "tcsh";
159 else if (strstr (mc_shell
->path
, "/csh") != NULL
160 || strstr (mc_shell
->real_path
, "/csh") != NULL
)
162 mc_shell
->type
= SHELL_TCSH
;
163 mc_shell
->name
= "csh";
165 else if (strstr (mc_shell
->path
, "/fish") != NULL
166 || strstr (mc_shell
->real_path
, "/fish") != NULL
)
168 mc_shell
->type
= SHELL_FISH
;
169 mc_shell
->name
= "fish";
171 else if (strstr (mc_shell
->path
, "/dash") != NULL
172 || strstr (mc_shell
->real_path
, "/dash") != NULL
)
174 /* Debian ash (also found if symlinked to by ash/sh) */
175 mc_shell
->type
= SHELL_DASH
;
176 mc_shell
->name
= "dash";
178 else if (strstr (mc_shell
->real_path
, "/busybox") != NULL
)
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
;
191 mc_shell
->type
= SHELL_NONE
;
194 /* --------------------------------------------------------------------------------------------- */
197 mc_shell_recognize_path (mc_shell_t
* mc_shell
)
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
)
202 mc_shell
->type
= SHELL_BASH
;
203 mc_shell
->name
= "bash";
205 else if (strstr (mc_shell
->path
, "/sh") != NULL
|| getenv ("SH") != NULL
)
207 mc_shell
->type
= SHELL_SH
;
208 mc_shell
->name
= "sh";
210 else if (strstr (mc_shell
->path
, "/ash") != NULL
|| getenv ("ASH") != NULL
)
212 mc_shell
->type
= SHELL_ASH_BUSYBOX
;
213 mc_shell
->name
= "ash";
216 mc_shell
->type
= SHELL_NONE
;
219 /* --------------------------------------------------------------------------------------------- */
220 /*** public functions ****************************************************************************/
221 /* --------------------------------------------------------------------------------------------- */
226 mc_shell_t
*mc_shell
;
228 mc_shell
= mc_shell_get_from_env ();
230 if (mc_shell
== NULL
)
231 mc_shell
= mc_shell_get_installed_in_system ();
233 mc_shell
->real_path
= mc_realpath (mc_shell
->path
, rp_shell
);
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. */
238 if (mc_shell
->real_path
!= NULL
)
239 mc_shell_recognize_real_path (mc_shell
);
241 if (mc_shell
->type
== SHELL_NONE
)
242 mc_shell_recognize_path (mc_shell
);
244 if (mc_shell
->type
== SHELL_NONE
)
245 mc_global
.tty
.use_subshell
= FALSE
;
247 mc_global
.shell
= mc_shell
;
250 /* --------------------------------------------------------------------------------------------- */
253 mc_shell_deinit (void)
255 if (mc_global
.shell
!= NULL
)
257 g_free (mc_global
.shell
->path
);
258 MC_PTR_FREE (mc_global
.shell
);
262 /* --------------------------------------------------------------------------------------------- */