Java calls linux pipeline command & whitelist configuration

1 Execute a single pipeline command

  Applicable to the scenario of a single pipeline command, such as checking process, killing process, calling global commands, etc.;

	/**
	 * 单条管道命令
	 * @param command 单条管道命令
	 */
	public static void executeCMD(String command) {
		String safeCommand = getSafeCommand(command, "/bin/sh -c ");
		Process pr = null;
		try {
			pr = Runtime.getRuntime().exec(safeCommand, null, new File(Constants.PATH_SLASH));

			// 读取输出,脚本运行结束后获取返回值 
			// 防阻塞,起独立线程获取输出流及错误流
			getInputStreamResponse(pr.getInputStream(), "InputStream");
			getInputStreamResponse(pr.getErrorStream(), "ErrorStream");

			// 等待进程执行结束并销毁
			pr.waitFor();
		} catch (IOException | InterruptedException e) {
			throw new RuntimeException("executeCMD process error", e);
		} finally {
			pr.destroy();
		}
	}

	private static void getInputStreamResponse(InputStream is, String streamType) {
		new Thread(() -> {
			try {
				BufferedReader stdInput = new BufferedReader(new InputStreamReader(is));
				StringBuffer strBuf = new StringBuffer();
				String line;
				while ((line = stdInput.readLine()) != null) {
					log.info(line);
				}
			} catch (Exception e) {
				log.error(e);
			} finally {
				try {
					is.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}).start();
	}

Defects in the above code:

1. The pipeline commands are independent of each other. The above method does not support the execution of continuous pipeline commands, eg: 1. cd directory 2. ./test.sh. In this scenario, consider using the following batch pipeline command execution method;

2. Remaining issues: In the above method, because Thread is used to print stream logs, the main method executeCMD() may be called to pr.destroy(); when the stream log output in the independent thread has not yet finished, the getInputStreamResponse() method will report a stream closed exception. Since I don’t pay attention to the output results in my business, this problem has not been fixed yet, and small partners in need can solve it by themselves;

 

Two batch pipeline commands

    Applicable to the execution of commands that are dependent on each other, such as entering a certain directory first, and then executing commands in this directory;

	/**
	 * 批量执行管道命令
	 * @param commands 批量管道命令
	 */
	public static void executeBatchCMD(String[] commands) {
		Runtime run = Runtime.getRuntime();
		File wd = new File("/bin");
		Process proc = null;
		try {
			proc = run.exec("/bin/bash", null, wd);
		} catch (IOException e) {
			e.printStackTrace();
		}
		if (proc != null) {
			BufferedReader in = new BufferedReader(new InputStreamReader(proc.getInputStream()));
			PrintWriter out = new PrintWriter(new BufferedWriter(new OutputStreamWriter(proc.getOutputStream())), true);
			for (String command : commands) {
				out.println(getSafeCommand(command, ""));
			}
			out.println(getSafeCommand("exit", ""));

			try {
				String line;
				while ((line = in.readLine()) != null) {
					log.info(line);
				}
				proc.waitFor();
			} catch (Exception e) {
				e.printStackTrace();
			} finally {
				try {
					in.close();
				} catch (IOException e) {}

				out.close();
				proc.destroy();
			}
		}
	}

Three pipeline command whitelist configuration

    Mainly to prevent command injection, so add a whitelist configuration

	/**
	 * 管道命令白名单
	 * @param command 管道命令
	 * @param suffix
	 * @return
	 */
	public static String getSafeCommand(String command, String suffix) {
		//command = "/bin/sh -c "+command;
		command = suffix + command;
		StringBuffer safeCommand = new StringBuffer();
		String whiteList = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890-=[]\\',./";
		char[] safeCommandChars = command.toCharArray();

		for (int i = 0, length = safeCommandChars.length; i < length; i++) {
			int whiteListIndex = whiteList.indexOf(safeCommandChars[i]);
			if (-1 == whiteListIndex) {
				return safeCommand.toString();
			}
			safeCommand.append(whiteList.charAt(whiteListIndex));
		}
		return safeCommand.toString();
	}

 

Guess you like

Origin blog.csdn.net/sxg0205/article/details/106928799