executable JARs, Solaris execev() and java version

executable JARs, Solaris execev() and java version

Post by James Le » Thu, 25 Nov 2004 20:14:48



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");
        }

Quote:}

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?

 
 
 

executable JARs, Solaris execev() and java version

Post by James Le » Thu, 25 Nov 2004 20:26:18



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");
        }

Quote:}

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?

 
 
 

executable JARs, Solaris execev() and java version

Post by James Le » Thu, 25 Nov 2004 20:29:33




> "feature" of the newsreader...

...I give up!
 
 
 

executable JARs, Solaris execev() and java version

Post by Drazen Kaca » Thu, 25 Nov 2004 20:31:42



>  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.

--
 .-.   .-.    Yes, I am an agent of Satan, but my duties are largely
(_  \ /  _)   ceremonial.
     |

 
 
 

executable JARs, Solaris execev() and java version

Post by James Le » Thu, 25 Nov 2004 20:55:44



>>  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.

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.

 
 
 

executable JARs, Solaris execev() and java version

Post by Markus Gyg » Thu, 25 Nov 2004 21:29:42


Drazen Kacar writes:

> > 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.

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

 
 
 

executable JARs, Solaris execev() and java version

Post by Scott Howar » Thu, 25 Nov 2004 22:05:31



Quote:> 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.

 
 
 

executable JARs, Solaris execev() and java version

Post by Richard L. Hamilt » Thu, 25 Nov 2004 22:36:28




> Drazen Kacar writes:

>> > 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.

> 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???

--

Lasik/PRK theme music:
    "In the Hall of the Mountain King", from "Peer Gynt"

 
 
 

executable JARs, Solaris execev() and java version

Post by Markus Gyg » Fri, 26 Nov 2004 00:59:39


Quote:Richard L. Hamilton writes:
> 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

 
 
 

executable JARs, Solaris execev() and java version

Post by Roland Main » Fri, 26 Nov 2004 01:52:27




> > 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.

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

----

Bye,
Roland

--
  __ .  . __

  \__\/\/__/  MPEG specialist, C&&JAVA&&Sun&&Unix programmer
  /O /==\ O\  TEL +49 641 7950090
 (;O/ \/ \O;)

 
 
 

executable JARs, Solaris execev() and java version

Post by James Le » Fri, 26 Nov 2004 19:15:22



> 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.