GH-3507: Fix Tail producer for proper command
Fixes https://github.com/spring-projects/spring-integration/issues/3507 The `OSDelegatingFileTailingMessageProducer` passing command string to `Runtime.getRuntime().exec()` may cause problems if spaces (and other special characters) are used in the filename. * Use an array for command and its options to let the target `Runtime` to parse and execute it properly **Cherry-pick to 5.4.x, 5.3.x & 5.2.x**
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2020 the original author or authors.
|
||||
* Copyright 2002-2021 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -34,6 +34,7 @@ import org.springframework.util.Assert;
|
||||
* @author Gavin Gray
|
||||
* @author Ali Shahbour
|
||||
* @author Artem Bilan
|
||||
* @author Trung Pham
|
||||
*
|
||||
* @since 3.0
|
||||
*
|
||||
@@ -47,6 +48,8 @@ public class OSDelegatingFileTailingMessageProducer extends FileTailingMessagePr
|
||||
|
||||
private volatile String command = "ADAPTER_NOT_INITIALIZED";
|
||||
|
||||
private volatile String[] tailCommand;
|
||||
|
||||
private volatile Process nativeTailProcess;
|
||||
|
||||
private volatile BufferedReader stdOutReader;
|
||||
@@ -89,7 +92,12 @@ public class OSDelegatingFileTailingMessageProducer extends FileTailingMessagePr
|
||||
protected void doStart() {
|
||||
super.doStart();
|
||||
destroyProcess();
|
||||
this.command = "tail " + this.options + " " + getFile().getAbsolutePath();
|
||||
String[] tailOptions = this.options.split("\\s+");
|
||||
this.tailCommand = new String[tailOptions.length + 2];
|
||||
this.tailCommand[0] = "tail";
|
||||
this.tailCommand[this.tailCommand.length - 1] = getFile().getAbsolutePath();
|
||||
System.arraycopy(tailOptions, 0, this.tailCommand, 1, tailOptions.length);
|
||||
this.command = String.join(" ", this.tailCommand);
|
||||
getTaskExecutor().execute(this::runExec);
|
||||
}
|
||||
|
||||
@@ -111,20 +119,18 @@ public class OSDelegatingFileTailingMessageProducer extends FileTailingMessagePr
|
||||
* Exec the native tail process.
|
||||
*/
|
||||
private void runExec() {
|
||||
this.destroyProcess();
|
||||
if (logger.isInfoEnabled()) {
|
||||
logger.info("Starting tail process");
|
||||
}
|
||||
destroyProcess();
|
||||
logger.info("Starting tail process");
|
||||
try {
|
||||
Process process = Runtime.getRuntime().exec(this.command);
|
||||
Process process = Runtime.getRuntime().exec(this.tailCommand);
|
||||
BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
|
||||
this.nativeTailProcess = process;
|
||||
this.startProcessMonitor();
|
||||
startProcessMonitor();
|
||||
if (this.enableStatusReader) {
|
||||
startStatusReader();
|
||||
}
|
||||
this.stdOutReader = reader;
|
||||
this.getTaskExecutor().execute(this);
|
||||
getTaskExecutor().execute(this);
|
||||
}
|
||||
catch (IOException e) {
|
||||
throw new MessagingException("Failed to exec tail command: '" + this.command + "'", e);
|
||||
@@ -136,33 +142,34 @@ public class OSDelegatingFileTailingMessageProducer extends FileTailingMessagePr
|
||||
* Runs a thread that waits for the Process result.
|
||||
*/
|
||||
private void startProcessMonitor() {
|
||||
this.getTaskExecutor().execute(() -> {
|
||||
Process process = OSDelegatingFileTailingMessageProducer.this.nativeTailProcess;
|
||||
if (process == null) {
|
||||
logger.debug("Process destroyed before starting process monitor");
|
||||
return;
|
||||
}
|
||||
getTaskExecutor()
|
||||
.execute(() -> {
|
||||
Process process = OSDelegatingFileTailingMessageProducer.this.nativeTailProcess;
|
||||
if (process == null) {
|
||||
logger.debug("Process destroyed before starting process monitor");
|
||||
return;
|
||||
}
|
||||
|
||||
int result;
|
||||
try {
|
||||
logger.debug(() -> "Monitoring process " + process);
|
||||
result = process.waitFor();
|
||||
logger.info(() -> "tail process terminated with value " + result);
|
||||
}
|
||||
catch (InterruptedException ex) {
|
||||
Thread.currentThread().interrupt();
|
||||
logger.error(ex, "Interrupted - stopping adapter");
|
||||
stop();
|
||||
}
|
||||
finally {
|
||||
destroyProcess();
|
||||
}
|
||||
if (isRunning()) {
|
||||
logger.info(() -> "Restarting tail process in " + getMissingFileDelay() + " milliseconds");
|
||||
getTaskScheduler()
|
||||
.schedule(this::runExec, new Date(System.currentTimeMillis() + getMissingFileDelay()));
|
||||
}
|
||||
});
|
||||
int result;
|
||||
try {
|
||||
logger.debug(() -> "Monitoring process " + process);
|
||||
result = process.waitFor();
|
||||
logger.info(() -> "tail process terminated with value " + result);
|
||||
}
|
||||
catch (InterruptedException ex) {
|
||||
Thread.currentThread().interrupt();
|
||||
logger.error(ex, "Interrupted - stopping adapter");
|
||||
stop();
|
||||
}
|
||||
finally {
|
||||
destroyProcess();
|
||||
}
|
||||
if (isRunning()) {
|
||||
logger.info(() -> "Restarting tail process in " + getMissingFileDelay() + " milliseconds");
|
||||
getTaskScheduler()
|
||||
.schedule(this::runExec, new Date(System.currentTimeMillis() + getMissingFileDelay()));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user