executable JARs, Solaris execev() and java version

J

James Lee

For test I have made a trivial Java program that prints the java version
and directory from the System properties:

public class JavaTest
{
public static void main(String[] argv)
{
System.out.println(System.getProperty("java.home"));
System.out.println(System.getProperty("java.version");
}
}

I compile it with a low version of javac to ensure compatibility with many
JVMs:
$ PATH=/usr/java1.1/bin:$PATH javac JavaTest.java

Make the executable jar:
$ echo 'Main-Class: JavaTest' > manifest
$ jar cmf manifest JavaTest JavaTest.class
$ chmod +x JavaTest

When I execute it using the java command it uses the JVM of the first
java on the PATH - exactly as expected:
$ java JavaTest
/opt/jdk1.5.0/jre
1.5.0

The JVM is also confirmed by:
$ java -version
java version "1.5.0"
Java(TM) 2 Runtime Environment, Standard Edition (build 1.5.0-b64) Java
HotSpot(TM) Client VM (build 1.5.0-b64, mixed mode, sharing)

When I execute the jar I get what I expect:
$ ./JavaTest
/opt/jdk1.5.0/jre
1.5.0


If I change the PATH so another JVM is first I get unexpected results:

$ PATH=/usr/java1.2/bin:$PATH java -version
java version "1.2.2"
Solaris VM (build Solaris_JDK_1.2.2_10, native threads, sunwjit)

$ PATH=/usr/java1.2/bin:$PATH java JavaTest
/usr/java1.2/jre
1.2.2

$ PATH=/usr/java1.1/bin:$PATH java -version
java version "1.1.8"

$ PATH=/usr/java1.2/bin:$PATH ./JavaTest
/opt/jdk1.5.0/jre
1.5.0

$ PATH=/usr/java1.1/bin:$PATH ./JavaTest
/opt/jdk1.5.0/jre
1.5.0


With another machine:
$ java -version
java version "1.4.1_01"
Java(TM) 2 Runtime Environment, Standard Edition (build 1.4.1_01-b01) Java
HotSpot(TM) Client VM (build 1.4.1_01-b01, mixed mode)

$ ./JavaTest
/usr/java1.2/jre
1.2.2

If I compile with java v1.5 it still execs an old version which duly fails.

"truss -ef ./JavaTest" shows that it is execve(2) executing the jar file,
it also shows the PATH active for execve, but in choosing a JVM execve is
not using the PATH.

Finally the question: How does execve decide which JVM to use when
executing a jar file?
 
J

James Lee

Pardon me, I'll try the same again, hopefully with out the @#$% wrap "feature"
of the newsreader...


For test I have made a trivial Java program that prints the java version
and directory from the System properties:

public class JavaTest
{
public static void main(String[] argv) {
System.out.println(System.getProperty("java.home"));
System.out.println(System.getProperty("java.version");
}
}

I compile it with a low version of javac to ensure compatibility with
many JVMs:
$ PATH=/usr/java1.1/bin:$PATH javac JavaTest.java

Make the executable jar:
$ echo 'Main-Class: JavaTest' manifest
$ jar cmf manifest JavaTest JavaTest.class
$ chmod +x JavaTest

When I execute it using the java command it uses the JVM of the first java
on the PATH - exactly as expected:
$ java JavaTest
/opt/jdk1.5.0/jre
1.5.0

The JVM is also confirmed by:
$ java -version
java version "1.5.0"
Java(TM) 2 Runtime Environment, Standard Edition (build 1.5.0-b64) Java
HotSpot(TM) Client VM (build 1.5.0-b64, mixed mode, sharing)


When I execute the jar I get what I expect:
$ ./JavaTest
/opt/jdk1.5.0/jre
1.5.0


If I change the PATH so another JVM is first I get unexpected results:

$ PATH=/usr/java1.2/bin:$PATH java -version java
version "1.2.2"
Solaris VM (build Solaris_JDK_1.2.2_10, native threads, sunwjit)

$ PATH=/usr/java1.2/bin:$PATH java JavaTest
/usr/java1.2/jre
1.2.2

$ PATH=/usr/java1.1/bin:$PATH java -version
java version "1.1.8"

$ PATH=/usr/java1.2/bin:$PATH ./JavaTest
/opt/jdk1.5.0/jre
1.5.0

$ PATH=/usr/java1.1/bin:$PATH ./JavaTest
/opt/jdk1.5.0/jre
1.5.0


With another machine:
$ java -version
java version "1.4.1_01"
Java(TM) 2 Runtime Environment, Standard Edition (build 1.4.1_01-b01) Java
HotSpot(TM) Client VM (build 1.4.1_01-b01, mixed mode)

$ ./JavaTest
/usr/java1.2/jre
1.2.2

If I compile with java v1.5 it still execs an old version which duly
fails.

"truss -ef ./JavaTest" shows that it is execve(2) executing the jar file,
it also shows the PATH active for execve, but in choosing a JVM execve is
not using the PATH.

Finally the question: How does execve decide which JVM to use when
executing a jar file?
 
D

Drazen Kacar

James said:
Finally the question: How does execve decide which JVM to use when
executing a jar file?

I think it just executes /usr/java/bin/java and ignores PATH completely.
So JVM selection is controlled with /usr/java symlink.
 
J

James Lee

I think it just executes /usr/java/bin/java and ignores PATH completely.
So JVM selection is controlled with /usr/java symlink.

Simple test, rename the link and:
$ ./JavaTest
../JavaTest: syntax error at line 1: `(' unexpected

Thank you.

So it seems to do that; that's weak! I would have hoped it invokes
something like isexec which found a suitable java from the PATH and the
version info. I can set the link for myself but means I can't use
executable JARs for other people in places unknown. I must add use
wrapper script and it all gets messy as it's delivered in more parts.
 
M

Markus Gyger

Drazen said:
I think it just executes /usr/java/bin/java and ignores PATH completely.
So JVM selection is controlled with /usr/java symlink.

Currently, strings /usr/kernel/exec/javaexec shows you which binary
is called by the kernel. This binary in turn execs the real java
interpreter higher up in its tree (e.g. /usr/java/jre/lib/i386/jexec
execs /usr/java/jre/bin/java). You can either change the symlink
as mentioned above or put the following in /etc/system and reboot:

set javaexec:jexec = "/usr/java/bin/java"

/usr/java/bin/java would be replaced with your java interpreter,
e.g. /usr/j2se/jre/bin/java or /usr/j2se/bin/java, etc., which
is then called with -jar and your JAR file as arguments (you can
change -jar by setting javaexec:jexec_arg).


Markus
 
S

Scott Howard

In comp.unix.solaris James Lee said:
Finally the question: How does execve decide which JVM to use when
executing a jar file?

It uses /usr/java/jre/lib/sparc/jexec (Replace "sparc" with "i386" where
relevant) with a default option of -jar. This in turn calls /bin/java
which is actually /usr/bin/java, which is a symlink to /usr/java/bin/java

The only way to change this is to put the following in /etc/system and
reboot :
set javaexec:jexec = "/path/to/my/jexec"
set javaexec:jexec_arg = "-other -options"

There should be little from stopping you writing your own jexec which is
PATH-aware, just be aware that it might break other things on the system
if you're not careful.

Scott.
 
R

Richard L. Hamilton

Currently, strings /usr/kernel/exec/javaexec shows you which binary
is called by the kernel. This binary in turn execs the real java
interpreter higher up in its tree (e.g. /usr/java/jre/lib/i386/jexec
execs /usr/java/jre/bin/java). You can either change the symlink
as mentioned above or put the following in /etc/system and reboot:

set javaexec:jexec = "/usr/java/bin/java"

/usr/java/bin/java would be replaced with your java interpreter,
e.g. /usr/j2se/jre/bin/java or /usr/j2se/bin/java, etc., which
is then called with -jar and your JAR file as arguments (you can
change -jar by setting javaexec:jexec_arg).

To get more flexibility, could one create an executable wrapper that
attempted to locate "java" via PATH, and if it couldn't, fell back to the
original hardcoded value (typically /usr/java/jre/lib/{i386|sparc}/jexec),
and passed all its args to it; then set javaexec:jexec in /etc/system to
point to that? Seems that would let people have it locate the java
interpreter via PATH if possible, else fall back to the default one.

As of Solaris 8 FCS, setuid java executables weren't supported, so one
wouldn't have to reset PATH on there to a safe default value (like
/usr/bin for non-root or /usr/sbin:/usr/bin for root) if effective uid !=
real uid (or effective gid != real gid or one of the gid list members),
although it would probably be very wise to do that extra work anyway, in
case javaexec at some later version does support setuid java executables.

So, think that would work???
 
M

Markus Gyger

Richard said:
To get more flexibility, could one create an executable wrapper that
attempted to locate "java" via PATH, and if it couldn't, fell back to the
original hardcoded value (typically /usr/java/jre/lib/{i386|sparc}/jexec),
and passed all its args to it; then set javaexec:jexec in /etc/system to
point to that? Seems that would let people have it locate the java
interpreter via PATH if possible, else fall back to the default one.

Maybe a JAR could even include some options for how to start the
interpreter. Currently, a JAR file's first entry has a zero-length
0xcafe subfield added (in Java this is added using something like
ZipEntry.setExtra(new byte[] { -2, -54, 0, 0 })), which could carry
additional content that could be passed to the interpreter (like
initial memory size) or be used to select a certain JVM version...


Markus
 
R

Roland Mainz

Scott said:
It uses /usr/java/jre/lib/sparc/jexec (Replace "sparc" with "i386" where
relevant) with a default option of -jar. This in turn calls /bin/java
which is actually /usr/bin/java, which is a symlink to /usr/java/bin/java

The only way to change this is to put the following in /etc/system and
reboot :
set javaexec:jexec = "/path/to/my/jexec"
set javaexec:jexec_arg = "-other -options"

There should be little from stopping you writing your own jexec which is
PATH-aware, just be aware that it might break other things on the system
if you're not careful.

Will the javaexec:jexec property be changeable on-the-fly in Solaris 10
?

----

Bye,
Roland

--
__ . . __
(o.\ \/ /.o) (e-mail address removed)
\__\/\/__/ MPEG specialist, C&&JAVA&&Sun&&Unix programmer
/O /==\ O\ TEL +49 641 7950090
(;O/ \/ \O;)
 
J

James Lee

Maybe a JAR could even include some options for how to start the
interpreter. Currently, a JAR file's first entry has a zero-length
0xcafe subfield added (in Java this is added using something like
ZipEntry.setExtra(new byte[] { -2, -54, 0, 0 })), which could carry
additional content that could be passed to the interpreter (like initial
memory size) or be used to select a certain JVM version...

I like the idea of additional args in the JAR but the META-INF/MANIFEST.MF
can be used, like "Main-Class" is specified, or even just an additional
file in the JAR.

My original question was how Solaris selected a JVM but of course I would
like to be sure this worked in a wider OS context. Java is supposed to be
platform independent but its invocation isn't. Improved executable JARs
could do it.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,769
Messages
2,569,582
Members
45,066
Latest member
VytoKetoReviews

Latest Threads

Top