HADOOP-13434. Add bash quoting to Shell class. (Owen O'Malley)

This commit is contained in:
Arpit Agarwal 2016-08-02 13:40:33 -07:00
parent 288f9ccde2
commit 745ba1160b
2 changed files with 73 additions and 44 deletions

View File

@ -118,6 +118,21 @@ public abstract class Shell {
} }
} }
/**
* Quote the given arg so that bash will interpret it as a single value.
* Note that this quotes it for one level of bash, if you are passing it
* into a badly written shell script, you need to fix your shell script.
* @param arg the argument to quote
* @return the quoted string
*/
static String bashQuote(String arg) {
StringBuilder buffer = new StringBuilder(arg.length() + 2);
buffer.append('\'');
buffer.append(arg.replace("'", "'\\''"));
buffer.append('\'');
return buffer.toString();
}
/** a Unix command to get the current user's name: {@value}. */ /** a Unix command to get the current user's name: {@value}. */
public static final String USER_NAME_COMMAND = "whoami"; public static final String USER_NAME_COMMAND = "whoami";
@ -173,7 +188,7 @@ public abstract class Shell {
/** a Unix command to get the current user's groups list. */ /** a Unix command to get the current user's groups list. */
public static String[] getGroupsCommand() { public static String[] getGroupsCommand() {
return (WINDOWS)? new String[]{"cmd", "/c", "groups"} return (WINDOWS)? new String[]{"cmd", "/c", "groups"}
: new String[]{"bash", "-c", "groups"}; : new String[]{"groups"};
} }
/** /**
@ -184,10 +199,14 @@ public abstract class Shell {
*/ */
public static String[] getGroupsForUserCommand(final String user) { public static String[] getGroupsForUserCommand(final String user) {
//'groups username' command return is inconsistent across different unixes //'groups username' command return is inconsistent across different unixes
return WINDOWS ? if (WINDOWS) {
new String[] return new String[]
{getWinUtilsPath(), "groups", "-F", "\"" + user + "\""} {getWinUtilsPath(), "groups", "-F", "\"" + user + "\""};
: new String[] {"bash", "-c", "id -gn " + user + "; id -Gn " + user}; } else {
String quotedUser = bashQuote(user);
return new String[] {"bash", "-c", "id -gn " + quotedUser +
"; id -Gn " + quotedUser};
}
} }
/** /**
@ -199,17 +218,20 @@ public abstract class Shell {
*/ */
public static String[] getGroupsIDForUserCommand(final String user) { public static String[] getGroupsIDForUserCommand(final String user) {
//'groups username' command return is inconsistent across different unixes //'groups username' command return is inconsistent across different unixes
return WINDOWS ? if (WINDOWS) {
new String[] return new String[]{getWinUtilsPath(), "groups", "-F", "\"" + user +
{getWinUtilsPath(), "groups", "-F", "\"" + user + "\""} "\""};
: new String[] {"bash", "-c", "id -g " + user + "; id -G " + user}; } else {
String quotedUser = bashQuote(user);
return new String[] {"bash", "-c", "id -g " + quotedUser + "; id -G " +
quotedUser};
}
} }
/** A command to get a given netgroup's user list. */ /** A command to get a given netgroup's user list. */
public static String[] getUsersForNetgroupCommand(final String netgroup) { public static String[] getUsersForNetgroupCommand(final String netgroup) {
//'groups username' command return is non-consistent across different unixes //'groups username' command return is non-consistent across different unixes
return WINDOWS ? new String [] {"cmd", "/c", "getent netgroup " + netgroup} return new String[] {"getent", "netgroup", netgroup};
: new String [] {"bash", "-c", "getent netgroup " + netgroup};
} }
/** Return a command to get permission information. */ /** Return a command to get permission information. */
@ -240,7 +262,8 @@ public abstract class Shell {
* @return String[] containing command and arguments * @return String[] containing command and arguments
*/ */
public static String[] getSetPermissionCommand(String perm, public static String[] getSetPermissionCommand(String perm,
boolean recursive, String file) { boolean recursive,
String file) {
String[] baseCmd = getSetPermissionCommand(perm, recursive); String[] baseCmd = getSetPermissionCommand(perm, recursive);
String[] cmdWithFile = Arrays.copyOf(baseCmd, baseCmd.length + 1); String[] cmdWithFile = Arrays.copyOf(baseCmd, baseCmd.length + 1);
cmdWithFile[cmdWithFile.length - 1] = file; cmdWithFile[cmdWithFile.length - 1] = file;
@ -290,9 +313,9 @@ public abstract class Shell {
if (isSetsidAvailable) { if (isSetsidAvailable) {
// Use the shell-builtin as it support "--" in all Hadoop supported OSes // Use the shell-builtin as it support "--" in all Hadoop supported OSes
return new String[] { "bash", "-c", "kill -" + code + " -- -" + pid }; return new String[] {"kill", "-" + code, "--", "-" + pid};
} else { } else {
return new String[] { "bash", "-c", "kill -" + code + " " + pid }; return new String[] {"kill", "-" + code, pid };
} }
} }
@ -342,8 +365,8 @@ public abstract class Shell {
public static String[] getRunScriptCommand(File script) { public static String[] getRunScriptCommand(File script) {
String absolutePath = script.getAbsolutePath(); String absolutePath = script.getAbsolutePath();
return WINDOWS ? return WINDOWS ?
new String[] { "cmd", "/c", absolutePath } new String[] {"cmd", "/c", absolutePath }
: new String[] { "/bin/bash", absolutePath }; : new String[] {"/bin/bash", bashQuote(absolutePath) };
} }
/** a Unix command to set permission: {@value}. */ /** a Unix command to set permission: {@value}. */

View File

@ -238,9 +238,9 @@ public class TestShell extends Assert {
expectedCommand = expectedCommand =
new String[]{getWinUtilsPath(), "task", "isAlive", anyPid }; new String[]{getWinUtilsPath(), "task", "isAlive", anyPid };
} else if (Shell.isSetsidAvailable) { } else if (Shell.isSetsidAvailable) {
expectedCommand = new String[] { "bash", "-c", "kill -0 -- -" + anyPid }; expectedCommand = new String[] {"kill", "-0", "--", "-" + anyPid };
} else { } else {
expectedCommand = new String[]{ "bash", "-c", "kill -0 " + anyPid }; expectedCommand = new String[] {"kill", "-0", anyPid };
} }
Assert.assertArrayEquals(expectedCommand, checkProcessAliveCommand); Assert.assertArrayEquals(expectedCommand, checkProcessAliveCommand);
} }
@ -258,9 +258,9 @@ public class TestShell extends Assert {
expectedCommand = expectedCommand =
new String[]{getWinUtilsPath(), "task", "kill", anyPid }; new String[]{getWinUtilsPath(), "task", "kill", anyPid };
} else if (Shell.isSetsidAvailable) { } else if (Shell.isSetsidAvailable) {
expectedCommand = new String[] { "bash", "-c", "kill -9 -- -" + anyPid }; expectedCommand = new String[] {"kill", "-9", "--", "-" + anyPid };
} else { } else {
expectedCommand = new String[]{ "bash", "-c", "kill -9 " + anyPid }; expectedCommand = new String[] {"kill", "-9", anyPid };
} }
Assert.assertArrayEquals(expectedCommand, checkProcessAliveCommand); Assert.assertArrayEquals(expectedCommand, checkProcessAliveCommand);
} }
@ -464,4 +464,10 @@ public class TestShell extends Assert {
} }
} }
@Test
public void testBashQuote() {
assertEquals("'foobar'", Shell.bashQuote("foobar"));
assertEquals("'foo'\\''bar'", Shell.bashQuote("foo'bar"));
assertEquals("''\\''foo'\\''bar'\\'''", Shell.bashQuote("'foo'bar'"));
}
} }