From b4613ba616bae5901edc1c8bd3cf2c714fd00e2b Mon Sep 17 00:00:00 2001 From: ckullabosch <137039388+ckullabosch@users.noreply.github.com> Date: Fri, 2 Feb 2024 07:46:59 +0100 Subject: [PATCH 1/2] [JENKINS-70784] Fix 'Text file busy' issue --- .../plugins/durabletask/BourneShellScript.java | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/src/main/java/org/jenkinsci/plugins/durabletask/BourneShellScript.java b/src/main/java/org/jenkinsci/plugins/durabletask/BourneShellScript.java index 1eb947c7..c80f952b 100644 --- a/src/main/java/org/jenkinsci/plugins/durabletask/BourneShellScript.java +++ b/src/main/java/org/jenkinsci/plugins/durabletask/BourneShellScript.java @@ -141,6 +141,7 @@ public String getScript() { ShellController c = new ShellController(ws,(os == OsType.ZOS), cookieValue, jenkinsResultTxtEncoding); FilePath shf = c.getScriptFile(ws); + // here we need to keep the file open for a longer time to make the race to happen more likely shf.write(script, scriptEncodingCharset); String shell = null; @@ -229,27 +230,32 @@ private List scriptLauncherCmd(ShellController c, FilePath ws, @CheckFor if (os == OsType.WINDOWS) { // JENKINS-40255 scriptPath = scriptPath.replace("\\", "/"); // cygwin sh understands mixed path (ie : "c:/jenkins/workspace/script.sh" ) } + String scriptPathCopy = scriptPath + ".copy"; // copy file to protect against "Text file busy", see JENKINS-70874 if (capturingOutput) { - cmdString = String.format("{ while [ -d '%s' -a \\! -f '%s' ]; do touch '%s'; sleep 3; done } & jsc=%s; %s=$jsc %s '%s' > '%s' 2> '%s'; echo $? > '%s.tmp'; mv '%s.tmp' '%s'; wait", + cmdString = String.format("cp '%s' '%s'; { while [ -d '%s' -a \\! -f '%s' ]; do touch '%s'; sleep 3; done } & jsc=%s; %s=$jsc %s '%s' > '%s' 2> '%s'; echo $? > '%s.tmp'; mv '%s.tmp' '%s'; wait", + scriptPath, + scriptPathCopy, controlDir, resultFile, logFile, cookieValue, cookieVariable, interpreter, - scriptPath, + scriptPathCopy, c.getOutputFile(ws), logFile, resultFile, resultFile, resultFile); } else { - cmdString = String.format("{ while [ -d '%s' -a \\! -f '%s' ]; do touch '%s'; sleep 3; done } & jsc=%s; %s=$jsc %s '%s' > '%s' 2>&1; echo $? > '%s.tmp'; mv '%s.tmp' '%s'; wait", + cmdString = String.format("cp '%s' '%s'; { while [ -d '%s' -a \\! -f '%s' ]; do touch '%s'; sleep 3; done } & jsc=%s; %s=$jsc %s '%s' > '%s' 2>&1; echo $? > '%s.tmp'; mv '%s.tmp' '%s'; wait", + scriptPath, + scriptPathCopy, controlDir, resultFile, logFile, cookieValue, cookieVariable, interpreter, - scriptPath, + scriptPathCopy, logFile, resultFile, resultFile, resultFile); } From b70d63eab3f001d764e6a2fa039f3ffe569feeb4 Mon Sep 17 00:00:00 2001 From: ckullabosch <137039388+ckullabosch@users.noreply.github.com> Date: Fri, 2 Feb 2024 08:07:00 +0100 Subject: [PATCH 2/2] Update comment --- .../org/jenkinsci/plugins/durabletask/BourneShellScript.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/jenkinsci/plugins/durabletask/BourneShellScript.java b/src/main/java/org/jenkinsci/plugins/durabletask/BourneShellScript.java index c80f952b..2ece052b 100644 --- a/src/main/java/org/jenkinsci/plugins/durabletask/BourneShellScript.java +++ b/src/main/java/org/jenkinsci/plugins/durabletask/BourneShellScript.java @@ -141,7 +141,8 @@ public String getScript() { ShellController c = new ShellController(ws,(os == OsType.ZOS), cookieValue, jenkinsResultTxtEncoding); FilePath shf = c.getScriptFile(ws); - // here we need to keep the file open for a longer time to make the race to happen more likely + // JENKINS-70874: if a new process is forked during this call, the writeable file handle will be copied and leading to the "Text file busy" issue + // when executing the script. shf.write(script, scriptEncodingCharset); String shell = null;