Skip to content

Commit 57e9ac6

Browse files
committed
Remove a commented and outdated busybox code
This piece of code was never live in mc. It would work around a BusyBox bug that was fixed in 2012. Signed-off-by: Egmont Koblinger <egmont@gmail.com>
1 parent 4960287 commit 57e9ac6

File tree

1 file changed

+141
-45
lines changed

1 file changed

+141
-45
lines changed

src/subshell/common.c

Lines changed: 141 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,10 @@ gboolean should_read_new_subshell_prompt;
152152
/* Length of the buffer for all I/O with the subshell */
153153
#define PTY_BUFFER_SIZE BUF_MEDIUM // Arbitrary; but keep it >= 80
154154

155+
/* Assume that the kernel's cooked mode buffer size might not be larger than this.
156+
* On Solaris it's 256 bytes, see ticket #4480. Shave off a few bytes, just in case. */
157+
#define COOKED_MODE_BUFFER_SIZE 250
158+
155159
/*** file scope type declarations ****************************************************************/
156160

157161
/* For pipes */
@@ -1310,75 +1314,163 @@ init_subshell_precmd (void)
13101314

13111315
/* --------------------------------------------------------------------------------------------- */
13121316
/**
1313-
* Carefully quote directory name to allow entering any directory safely,
1314-
* no matter what weird characters it may contain in its name.
1315-
* NOTE: Treat directory name an untrusted data, don't allow it to cause
1316-
* executing any commands in the shell. Escape all control characters.
1317-
* Use following technique:
1318-
*
1319-
* printf(1) with format string containing a single conversion specifier,
1320-
* "b", and an argument which contains a copy of the string passed to
1321-
* subshell_name_quote() with all characters, except digits and letters,
1322-
* replaced by the backslash-escape sequence \0nnn, where "nnn" is the
1323-
* numeric value of the character converted to octal number.
1317+
* Carefully construct a 'cd' command that allows entering any directory safely. Two things to
1318+
* watch out for:
13241319
*
1325-
* cd "`printf '%b' 'ABC\0nnnDEF\0nnnXYZ'`"
1320+
* Enter any directory safely, no matter what special bytes its name contains (special shell
1321+
* characters, control characters, non-printable characters, invalid UTF-8 etc.).
1322+
* NOTE: Treat directory name as untrusted data, don't allow it to cause executing any commands in
1323+
* the shell!
13261324
*
1327-
* N.B.: Use single quotes for conversion specifier to work around
1328-
* tcsh 6.20+ parser breakage, see ticket #3852 for the details.
1325+
* Keep physical lines under COOKED_MODE_BUFFER_SIZE bytes, as in some kernels the buffer for the
1326+
* tty line's cooked mode is quite small. If the directory name is longer, we have to somehow
1327+
* construct a multiline cd command.
13291328
*/
13301329

13311330
static GString *
1332-
subshell_name_quote (const char *s)
1331+
create_cd_command (const char *s)
13331332
{
13341333
GString *ret;
13351334
const char *n;
1336-
const char *quote_cmd_start, *quote_cmd_end;
1335+
const char *quote_cmd_start, *before_wrap, *after_wrap, *quote_cmd_end;
1336+
const char *escape_fmt;
1337+
int line_length;
1338+
char buf[BUF_TINY];
13371339

1338-
if (mc_global.shell->type == SHELL_FISH)
1340+
if (mc_global.shell->type == SHELL_BASH || mc_global.shell->type == SHELL_ZSH)
1341+
{
1342+
/*
1343+
* bash and zsh: Use $'...\ooo...' notation (ooo is three octal digits).
1344+
*
1345+
* Use octal because hex mode likes to go multibyte.
1346+
*
1347+
* Line wrapping (if necessary) with a trailing backslash outside of quotes.
1348+
*/
1349+
quote_cmd_start = " cd $'";
1350+
before_wrap = "'\\";
1351+
after_wrap = "$'";
1352+
quote_cmd_end = "'";
1353+
escape_fmt = "\\%03o";
1354+
}
1355+
else if (mc_global.shell->type == SHELL_FISH)
13391356
{
1340-
quote_cmd_start = "(printf '%b' '";
1341-
quote_cmd_end = "')";
1357+
/*
1358+
* fish: Use ...\xHH... notation (HH is two hex digits).
1359+
*
1360+
* Its syntax requires that escapes go outside of quotes, and the rest is also safe there.
1361+
* Use hex because it only supports octal for low (up to octal 177 / decimal 127) bytes.
1362+
*
1363+
* Line wrapping (if necessary) with a trailing backslash.
1364+
*/
1365+
quote_cmd_start = " cd ";
1366+
before_wrap = "\\";
1367+
after_wrap = "";
1368+
quote_cmd_end = "";
1369+
escape_fmt = "\\x%02X";
1370+
}
1371+
else if (mc_global.shell->type == SHELL_TCSH)
1372+
{
1373+
/*
1374+
* tcsh: Use $'...\ooo...' notation (ooo is three octal digits).
1375+
*
1376+
* It doesn't support string contants spanning across multipline lines (a trailing
1377+
* backslash introduces a space), therefore construct the string in a tmp variable.
1378+
* Nevertheless emit a trailing backslash so it's just one line in its history.
1379+
*
1380+
* The :q modifier is needed to preserve newlines and other special chars.
1381+
*
1382+
* Note that tcsh's variables aren't binary clean, in its UTF-8 mode they are enforced
1383+
* to be valid UTF-8. So unfortunately we cannot enter every weird directory.
1384+
*/
1385+
quote_cmd_start = " set _mc_newdir=$'";
1386+
before_wrap = "'; \\";
1387+
after_wrap = " set _mc_newdir=${_mc_newdir:q}$'";
1388+
quote_cmd_end = "'; cd ${_mc_newdir:q}";
1389+
escape_fmt = "\\%03o";
13421390
}
1343-
/* TODO: When BusyBox printf is fixed, get rid of this "else if", see
1344-
https://lists.busybox.net/pipermail/busybox/2012-March/077460.html */
1345-
/* else if (subshell_type == ASH_BUSYBOX)
1346-
{
1347-
quote_cmd_start = "\"`echo -en '";
1348-
quote_cmd_end = "'`\"";
1349-
} */
13501391
else
13511392
{
1352-
quote_cmd_start = "\"`printf '%b' '";
1353-
quote_cmd_end = "'`\"";
1393+
/*
1394+
* Fallback / POSIX sh: Construct a command like this:
1395+
*
1396+
* _mc_newdir_=`printf '%b_' 'ABC\0oooDEF\0oooXYZ'` # ooo are three octal digits
1397+
* cd "${_mc_newdir_%_}"
1398+
*
1399+
* Command substitution removes final '\n's, hence the added and later removed '_' (#2325).
1400+
*
1401+
* Wrapping to new line with a trailing backslash outside of the innermost single quotes.
1402+
*/
1403+
quote_cmd_start = " _mc_newdir_=`printf '%b_' '";
1404+
before_wrap = "'\\";
1405+
after_wrap = "'";
1406+
quote_cmd_end = "'`; cd \"${_mc_newdir_%_}\"";
1407+
escape_fmt = "\\0%03o";
13541408
}
13551409

1410+
const int quote_cmd_start_len = strlen (quote_cmd_start);
1411+
const int before_wrap_len = strlen (before_wrap);
1412+
const int after_wrap_len = strlen (after_wrap);
1413+
const int quote_cmd_end_len = strlen (quote_cmd_end);
1414+
1415+
/* Measure the length of an escaped byte. In the unlikely case that it won't be uniform in some
1416+
* future shell, have an upper estimate by measuring the largest byte. */
1417+
const int escaped_char_len = sprintf (buf, escape_fmt, 0xFF);
1418+
13561419
ret = g_string_sized_new (64);
13571420

1421+
// Copy the beginning of the command to the buffer
1422+
g_string_append_len (ret, quote_cmd_start, quote_cmd_start_len);
1423+
13581424
// Prevent interpreting leading '-' as a switch for 'cd'
13591425
if (s[0] == '-')
13601426
g_string_append (ret, "./");
13611427

1362-
// Copy the beginning of the command to the buffer
1363-
g_string_append (ret, quote_cmd_start);
1428+
/* Sending physical lines over a certain small limit causes problems on some platforms,
1429+
* see ticket #4480. Make sure to wrap in time. See how large we can grow so that an
1430+
* additional line wrapping or closing string still fits. */
1431+
const int max_length = COOKED_MODE_BUFFER_SIZE - MAX (before_wrap_len, quote_cmd_end_len);
1432+
g_assert (max_length >= 64); // Make sure we have enough room to breathe.
13641433

1365-
/*
1366-
* Print every character except digits and letters as a backslash-escape
1367-
* sequence of the form \0nnn, where "nnn" is the numeric value of the
1368-
* character converted to octal number.
1369-
*/
1434+
line_length = ret->len;
1435+
1436+
/* Print (possibly multibyte) alphanumeric characters and '/' verbatim.
1437+
* Print everything else escaping each byte individually. */
13701438
for (const char *su = s; su[0] != '\0'; su = n)
13711439
{
13721440
n = str_cget_next_char_safe (su);
13731441

1374-
if (str_isalnum (su))
1442+
if (su[0] == '/' || str_isalnum (su))
1443+
{
1444+
if (line_length + (n - su) > max_length)
1445+
{
1446+
// wrap to next physical line
1447+
g_string_append_len (ret, before_wrap, before_wrap_len);
1448+
g_string_append_c (ret, '\n');
1449+
g_string_append_len (ret, after_wrap, after_wrap_len);
1450+
line_length = after_wrap_len;
1451+
}
1452+
// append character
13751453
g_string_append_len (ret, su, (size_t) (n - su));
1454+
line_length += (n - su);
1455+
}
13761456
else
13771457
for (size_t c = 0; c < (size_t) (n - su); c++)
1378-
g_string_append_printf (ret, "\\0%03o", (unsigned char) su[c]);
1458+
{
1459+
if (line_length + escaped_char_len > max_length)
1460+
{
1461+
// wrap to next physical line
1462+
g_string_append_len (ret, before_wrap, before_wrap_len);
1463+
g_string_append_c (ret, '\n');
1464+
g_string_append_len (ret, after_wrap, after_wrap_len);
1465+
line_length = after_wrap_len;
1466+
}
1467+
// append escaped byte
1468+
g_string_append_printf (ret, escape_fmt, (unsigned char) su[c]);
1469+
line_length += escaped_char_len;
1470+
}
13791471
}
13801472

1381-
g_string_append (ret, quote_cmd_end);
1473+
g_string_append_len (ret, quote_cmd_end, quote_cmd_end_len);
13821474

13831475
return ret;
13841476
}
@@ -1459,23 +1551,27 @@ do_subshell_chdir (const vfs_path_t *vpath, gboolean update_prompt)
14591551
feed_subshell (QUIETLY, TRUE);
14601552
}
14611553

1462-
/* The initial space keeps this out of the command history (in bash
1463-
because we set "HISTCONTROL=ignorespace") */
1464-
write_all (mc_global.tty.subshell_pty, " cd ", 4);
1465-
14661554
if (vpath == NULL)
1467-
write_all (mc_global.tty.subshell_pty, "/", 1);
1555+
{
1556+
/* The initial space keeps this out of the command history (in bash
1557+
because we set "HISTCONTROL=ignorespace") */
1558+
const char *cmd = " cd /";
1559+
write_all (mc_global.tty.subshell_pty, cmd, sizeof (cmd) - 1);
1560+
}
14681561
else
14691562
{
14701563
const char *translate = vfs_translate_path (vfs_path_as_str (vpath));
14711564

14721565
if (translate == NULL)
1473-
write_all (mc_global.tty.subshell_pty, ".", 1);
1566+
{
1567+
const char *cmd = " cd .";
1568+
write_all (mc_global.tty.subshell_pty, cmd, sizeof (cmd) - 1);
1569+
}
14741570
else
14751571
{
14761572
GString *temp;
14771573

1478-
temp = subshell_name_quote (translate);
1574+
temp = create_cd_command (translate);
14791575
write_all (mc_global.tty.subshell_pty, temp->str, temp->len);
14801576
g_string_free (temp, TRUE);
14811577
}

0 commit comments

Comments
 (0)