diff --git a/changelog.html b/changelog.html
index 67fcc38739c5049cb772c3eba064de1df04fc4bf..b64e62fa9def0663fbff65956b403540a218e802 100644
--- a/changelog.html
+++ b/changelog.html
@@ -61,6 +61,9 @@ Upcoming changes
Optimizations in fingerprint recording.
(issue 16301)
+
+ Using JNR-POSIX rather than JNA-POSIX for better platform support.
+ (issue 14351)
Errors searching build records when builds were misordered.
(issue 15652)
diff --git a/core/pom.xml b/core/pom.xml
index 439073496b8a4b17e690fdaf00a2b702069e38c9..aee9a887c0d02b07378e29378b865983d8b3ca0e 100644
--- a/core/pom.xml
+++ b/core/pom.xml
@@ -112,11 +112,16 @@ THE SOFTWARE.
-
+
org.jruby.ext.posix
jna-posix
1.0.3
+
+ com.github.jnr
+ jnr-posix
+ 3.0.0
+
org.kohsuke
trilead-putty-extension
diff --git a/core/src/main/java/hudson/Util.java b/core/src/main/java/hudson/Util.java
index 696bfe5f64e1c2fc4a2353031739907ffc249468..d91b85fa75ea0f64f28e6dea72da5d1c320a1bb6 100644
--- a/core/src/main/java/hudson/Util.java
+++ b/core/src/main/java/hudson/Util.java
@@ -40,8 +40,8 @@ import org.apache.tools.ant.Project;
import org.apache.tools.ant.taskdefs.Chmod;
import org.apache.tools.ant.taskdefs.Copy;
import org.apache.tools.ant.types.FileSet;
-import org.jruby.ext.posix.FileStat;
-import org.jruby.ext.posix.POSIX;
+import jnr.posix.FileStat;
+import jnr.posix.POSIX;
import org.codehaus.mojo.animal_sniffer.IgnoreJRERequirement;
import javax.crypto.SecretKey;
@@ -281,7 +281,7 @@ public class Util {
}
try {// try libc chmod
- POSIX posix = PosixAPI.get();
+ POSIX posix = PosixAPI.jnr();
String path = f.getAbsolutePath();
FileStat stat = posix.stat(path);
posix.chmod(path, stat.mode()|0200); // u+w
@@ -1073,13 +1073,16 @@ public class Util {
} catch (LinkageError e) {
// if JNA is unavailable, fall back.
// we still prefer to try JNA first as PosixAPI supports even smaller platforms.
- if (PosixAPI.supportsNative()) {
- r = PosixAPI.get().symlink(targetPath,symlinkFile.getAbsolutePath());
+ POSIX posix = PosixAPI.jnr();
+ if (posix.isNative()) {
+ // XXX should we rethrow PosixException as IOException here?
+ r = posix.symlink(targetPath,symlinkFile.getAbsolutePath());
}
}
}
if (r==null) {
// if all else fail, fall back to the most expensive approach of forking a process
+ // XXX is this really necessary? JavaPOSIX should do this automatically
r = new LocalProc(new String[]{
"ln","-s", targetPath, symlinkPath},
new String[0],listener.getLogger(), baseDir).join();
@@ -1221,7 +1224,7 @@ public class Util {
} catch (LinkageError e) {
// if JNA is unavailable, fall back.
// we still prefer to try JNA first as PosixAPI supports even smaller platforms.
- return PosixAPI.get().readlink(filename);
+ return PosixAPI.jnr().readlink(filename);
}
}
diff --git a/core/src/main/java/hudson/cli/ClientAuthenticationCache.java b/core/src/main/java/hudson/cli/ClientAuthenticationCache.java
index 25bc040d8b3bd97b294752daad100f14e0d917ed..3525599178a9372b5971a629df23f51a1202466e 100644
--- a/core/src/main/java/hudson/cli/ClientAuthenticationCache.java
+++ b/core/src/main/java/hudson/cli/ClientAuthenticationCache.java
@@ -118,7 +118,7 @@ public class ClientAuthenticationCache implements Serializable {
}
// try to protect this file from other users, if we can.
- PosixAPI.get().chmod(f.getAbsolutePath(),0600);
+ PosixAPI.jnr().chmod(f.getAbsolutePath(),0600);
return null;
}
});
diff --git a/core/src/main/java/hudson/os/PosixAPI.java b/core/src/main/java/hudson/os/PosixAPI.java
index 1e893c1b903201f1a710072e1799efc69a55a798..2e69069c1c2e4a94e7dfbb782be4e12d9112cbc4 100644
--- a/core/src/main/java/hudson/os/PosixAPI.java
+++ b/core/src/main/java/hudson/os/PosixAPI.java
@@ -1,45 +1,74 @@
package hudson.os;
-import org.jruby.ext.posix.JavaPOSIX;
-import org.jruby.ext.posix.POSIX;
-import org.jruby.ext.posix.POSIXFactory;
-import org.jruby.ext.posix.POSIXHandler;
-import org.jruby.ext.posix.POSIX.ERRORS;
-
import java.io.File;
import java.io.InputStream;
import java.io.PrintStream;
import java.util.Map;
import java.util.logging.Logger;
+import jnr.constants.platform.Errno;
+import jnr.posix.POSIX;
+import jnr.posix.POSIXFactory;
+import jnr.posix.util.DefaultPOSIXHandler;
/**
* POSIX API wrapper.
- *
+ * Formerly used the jna-posix library, but this has been superseded by jnr-posix.
* @author Kohsuke Kawaguchi
*/
public class PosixAPI {
- public static POSIX get() {
+
+ private static POSIX posix;
+
+ /**
+ * Load the JNR implementation of the POSIX APIs for the current platform.
+ * Runtime exceptions will be of type {@link PosixException}.
+ * @return some implementation (even on Windows or unsupported Unix)
+ * @since 1.518
+ */
+ public static synchronized POSIX jnr() {
+ if (posix == null) {
+ posix = POSIXFactory.getPOSIX(new DefaultPOSIXHandler() {
+ @Override public void error(Errno error, String extraData) {
+ throw new PosixException("native error " + error.description() + " " + extraData, convert(error));
+ }
+ @Override public void error(Errno error, String methodName, String extraData) {
+ throw new PosixException("native error calling " + methodName + ": " + error.description() + " " + extraData, convert(error));
+ }
+ private org.jruby.ext.posix.POSIX.ERRORS convert(Errno error) {
+ try {
+ return org.jruby.ext.posix.POSIX.ERRORS.valueOf(error.name());
+ } catch (IllegalArgumentException x) {
+ return org.jruby.ext.posix.POSIX.ERRORS.EIO; // PosixException.message has real error anyway
+ }
+ }
+ }, true);
+ }
return posix;
}
/**
- * @deprecated as of 1.448
- * Use {@link #supportsNative()}.
+ * @deprecated use {@link #jnr} and {@link POSIX#isNative}
*/
+ @Deprecated
public boolean isNative() {
return supportsNative();
}
/**
- * Determine if the jna-posix library could not provide native support, and
- * used a fallback java implementation which does not support many operations.
+ * @deprecated use {@link #jnr} and {@link POSIX#isNative}
*/
+ @Deprecated
public static boolean supportsNative() {
- return !(posix instanceof JavaPOSIX);
+ return !(jnaPosix instanceof org.jruby.ext.posix.JavaPOSIX);
}
-
- private static final POSIX posix = POSIXFactory.getPOSIX(new POSIXHandler() {
- public void error(ERRORS errors, String s) {
+
+ private static org.jruby.ext.posix.POSIX jnaPosix;
+ /** @deprecated Use {@link #jnr} instead. */
+ @Deprecated
+ public static synchronized org.jruby.ext.posix.POSIX get() {
+ if (jnaPosix == null) {
+ jnaPosix = org.jruby.ext.posix.POSIXFactory.getPOSIX(new org.jruby.ext.posix.POSIXHandler() {
+ public void error(org.jruby.ext.posix.POSIX.ERRORS errors, String s) {
throw new PosixException(s,errors);
}
@@ -87,6 +116,9 @@ public class PosixAPI {
return System.err;
}
}, true);
+ }
+ return jnaPosix;
+ }
private static final Logger LOGGER = Logger.getLogger(PosixAPI.class.getName());
}
diff --git a/core/src/main/java/hudson/os/PosixException.java b/core/src/main/java/hudson/os/PosixException.java
index 93e96ef5d0d1aec7a7ad23968ca62068741a9cec..03cdd50e38b8c176b7ecc5571d1c10c8a855f96d 100644
--- a/core/src/main/java/hudson/os/PosixException.java
+++ b/core/src/main/java/hudson/os/PosixException.java
@@ -4,7 +4,7 @@ import org.jruby.ext.posix.POSIX.ERRORS;
/**
* Indicates an error during POSIX API call.
- *
+ * @see PosixAPI
* @author Kohsuke Kawaguchi
*/
public class PosixException extends RuntimeException {
@@ -15,6 +15,8 @@ public class PosixException extends RuntimeException {
this.errors = errors;
}
+ /** @deprecated Leaks reference to deprecated jna-posix API. */
+ @Deprecated
public ERRORS getErrorCode() {
return errors;
}
diff --git a/core/src/main/java/hudson/tools/ZipExtractionInstaller.java b/core/src/main/java/hudson/tools/ZipExtractionInstaller.java
index 1fa7adb8bd0fdcecc07a6be852359f98b7e9bd7f..48ef62b97cf053693b355bf239ce9b9cc7a09201 100644
--- a/core/src/main/java/hudson/tools/ZipExtractionInstaller.java
+++ b/core/src/main/java/hudson/tools/ZipExtractionInstaller.java
@@ -137,7 +137,7 @@ public class ZipExtractionInstaller extends ToolInstaller {
} catch (LinkageError e) {
// if JNA is unavailable, fall back.
// we still prefer to try JNA first as PosixAPI supports even smaller platforms.
- PosixAPI.get().chmod(f.getAbsolutePath(),0755);
+ PosixAPI.jnr().chmod(f.getAbsolutePath(),0755);
}
}
} else {
diff --git a/core/src/main/java/hudson/util/IOUtils.java b/core/src/main/java/hudson/util/IOUtils.java
index 4d046b7541294c0dd3b6db3fc026a50dffe5443b..60faaaf032726d0029604c9f67c80af2c65a0419 100644
--- a/core/src/main/java/hudson/util/IOUtils.java
+++ b/core/src/main/java/hudson/util/IOUtils.java
@@ -122,7 +122,7 @@ public class IOUtils extends org.apache.commons.io.IOUtils {
*/
public static int mode(File f) throws PosixException {
if(Functions.isWindows()) return -1;
- return PosixAPI.get().stat(f.getPath()).mode();
+ return PosixAPI.jnr().stat(f.getPath()).mode();
}
/**
diff --git a/core/src/main/java/hudson/util/jna/GNUCLibrary.java b/core/src/main/java/hudson/util/jna/GNUCLibrary.java
index aa397b5b371e1a73406b6440a4ef778d439be7bb..8659089f52ab72ff25fd75d8d58c3ab67f7a996c 100644
--- a/core/src/main/java/hudson/util/jna/GNUCLibrary.java
+++ b/core/src/main/java/hudson/util/jna/GNUCLibrary.java
@@ -30,6 +30,8 @@ import com.sun.jna.Native;
import com.sun.jna.Memory;
import com.sun.jna.NativeLong;
import com.sun.jna.ptr.IntByReference;
+import hudson.os.PosixAPI;
+import jnr.posix.POSIX;
import org.jvnet.libpam.impl.CLibrary.passwd;
/**
@@ -38,7 +40,7 @@ import org.jvnet.libpam.impl.CLibrary.passwd;
*
* Not available on all platforms (such as Linux/PPC, IBM mainframe, etc.), so the caller should recover gracefully
* in case of {@link LinkageError}. See HUDSON-4820.
- *
+ *
Consider deprecating all methods present also in {@link POSIX} (as obtained by {@link PosixAPI#jnr}).
* @author Kohsuke Kawaguchi
*/
public interface GNUCLibrary extends Library {