Skip to content

Conversation

@gnodet
Copy link
Contributor

@gnodet gnodet commented Nov 24, 2025

Description

This PR fixes #11485 by replacing the non-POSIX-compliant xargs -0 option with a pure shell solution that works on all POSIX-compliant systems including AIX, FreeBSD, and others.

Problem

The xargs -0 option was introduced in commit aeff353 to handle special characters (pipes, quotes, spaces) in .mvn/jvm.config files. However, this option is not part of the POSIX standard and is not available on AIX, FreeBSD, and other systems, causing the Maven wrapper to fail on these platforms.

Solution

The fix replaces xargs -0 with a pure shell solution that:

  • Uses the read builtin with -d '' option to read NUL-terminated strings
  • Builds the result string incrementally in a while loop
  • Maintains the same functionality of handling special characters correctly
  • Works on all POSIX-compliant systems

Changes

  • Modified concat_lines() function in apache-maven/src/assembly/maven/bin/mvn
  • Replaced the pipeline using xargs -n 1 -0 with a while loop using read -r -d ''
  • Preserved all existing functionality for handling special characters

Testing

  • All existing tests pass, including the integration test for pipes in MAVEN_OPTS (MavenITgh10937QuotedPipesInMavenOptsTest)
  • Manually tested the concat_lines function with special characters
  • Full build completed successfully with mvn clean install

Compatibility

This change maintains backward compatibility while extending support to more platforms. The behavior for handling special characters in .mvn/jvm.config remains unchanged.


Pull Request opened by Augment Code with guidance from the PR author

@gnodet gnodet added bug Something isn't working backport-to-4.0.x labels Nov 24, 2025
@gnodet gnodet added this to the 4.1.0 milestone Nov 24, 2025
@gnodet gnodet changed the title [gh-11485] Replace xargs -0 with POSIX-compliant alternative Replace xargs -0 with POSIX-compliant alternative (fixes #11485) Nov 24, 2025
@bmarwell
Copy link
Contributor

bmarwell commented Nov 24, 2025

Hi @gnodet, I just checked.
Only AIX (as far as I know) is missing out the -0 parameter. I have not checked Haiko or OpenIndiana, etc. FreeBSD does have -0.

For AIX: we could work around that by requiring AIX users of Maven to use the "Open Source Toolbox". I tested that successfully.

However, the assumption is correct that -0 is not a POSIX standard: https://pubs.opengroup.org/onlinepubs/9699919799/utilities/xargs.html

Given we can work around this OR just require it anyway, I am open to either solution.

@gnodet gnodet force-pushed the gh-11485-xargs-posix-fix branch from 18ab53a to fbdb26b Compare November 24, 2025 16:29
The xargs -0 option is not POSIX-compliant and is not available on AIX,
FreeBSD, and other systems. This commit replaces the use of xargs -0 in
the concat_lines function with a pure shell solution that reads
NUL-terminated strings using the read builtin with -d '' option.

The new implementation:
- Maintains the same functionality of handling special characters like
  pipes, quotes, and spaces correctly
- Avoids the non-portable xargs -0 option
- Uses a while loop with read -r -d '' to process NUL-terminated strings
- Builds the result string incrementally instead of using tr to convert
  newlines to spaces

This fix ensures that the mvn script works correctly on all POSIX-compliant
systems while preserving the behavior introduced in commit aeff353
to handle quoted pipes and other special characters in .mvn/jvm.config.

Fixes apache#11485
@gnodet gnodet force-pushed the gh-11485-xargs-posix-fix branch from fbdb26b to 3f5f5d4 Compare November 25, 2025 07:22
Comment on lines 171 to 201
result=""
# Read the file line by line
while IFS= read -r line || [ -n "$line" ]; do
# Convert CR to LF
line=$(echo "$line" | tr '\r' '\n')
# Remove comments
line=$(echo "$line" | sed 's/#.*$//')
# Skip empty lines
[ -z "$(echo "$line" | tr -d ' \t')" ] && continue

# Process each argument in the line using eval to handle quotes
eval "set -- $line"
for arg in "$@"; do
# Replace variables
arg=$(echo "$arg" | sed \
-e "s@\${MAVEN_PROJECTBASEDIR}@$MAVEN_PROJECTBASEDIR@g" \
-e "s@\$MAVEN_PROJECTBASEDIR@$MAVEN_PROJECTBASEDIR@g")

# Quote the argument if it contains spaces or special shell characters
case "$arg" in
*[\ \|\&\;\<\>\(\)\$\`\\\"\'\~\*\?\[\]\#\~\=]*)
arg="\"$arg\""
;;
esac

if [ -n "$result" ]; then
result="$result $arg"
else
result="$arg"
fi
done
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  1. imho this should be an extra function
  2. we might want to document why we do not use xargs -0 here and that we agreed to use posix-only arguments (did we agree on that?)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure what you mean by extra function. The concat_lines function is the code above (but for an if which verifies the argument is actually a file...

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I just thought we might want to extract a method/function here, because we get a lot of indentation and the method gets longer and longer.

Did we agree on "we must be POSIX compliant"? If not, we could leave xargs in here and just concentrate on the sed part.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  1. I think 30 lines is still manageable.

  2. Yes, unless there's a strong reason, I think keeping POSIX compliant script is better. maven-wrapper has an additional job to validate posix compliance, we may want to do the same: https://github.com/apache/maven-wrapper/blob/master/.github/workflows/shellcheck-posix.yml

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great, I fully agree!

Copy link
Contributor

@bmarwell bmarwell left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

AIX is gloriously stubborn — ancient userland tools (no GNU xargs -0) and a nonstandard /bin/sh make portability a landmine, so avoiding non‑POSIX flags is absolutely the right goal.

[ -z "$(echo "$line" | tr -d ' \t')" ] && continue

# Process each argument in the line using eval to handle quotes
eval "set -- $line"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This allows command substitution/globbing -> unsafe and can execute backticks/$() from .mvn/jvm.config. Is this wanted? Seems dangerous, we might want to at least document this.

# Do not use `xargs -0` as this is not POSIX-compliant
while IFS= read -r line || [ -n "$line" ]; do
# Convert CR to LF
line=$(echo "$line" | tr '\r' '\n')
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this can produce embedded newlines that confuse splitting if \r is in the middle of a line. But I think that is problematic anyway.


# Quote the argument if it contains spaces or special shell characters
case "$arg" in
*[\ \|\&\;\<\>\(\)\$\`\\\"\'\~\*\?\[\]\#\~\=]*)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks fragile. Does work correctly on backticks and double quotes? If backticks or double quotes are inside, should we not use `arg="'$arg'" instead?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

xargs -0 not available on AIX, FreeBSD, etc.

2 participants