<?xml version="1.0"?>
<!--
 Licensed to the Apache Software Foundation (ASF) under one or more
 contributor license agreements.  See the NOTICE file distributed with
 this work for additional information regarding copyright ownership.
 The ASF licenses this file to You under the Apache License, Version 2.0
 (the "License"); you may not use this file except in compliance with
 the License.  You may obtain a copy of the License at

      https://www.apache.org/licenses/LICENSE-2.0

 Unless required by applicable law or agreed to in writing, software
 distributed under the License is distributed on an "AS IS" BASIS,
 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 See the License for the specific language governing permissions and
 limitations under the License.
-->
<document xmlns="http://maven.apache.org/XDOC/2.0"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/XDOC/2.0 https://maven.apache.org/xsd/xdoc-2.0.xsd">
 <properties>
  <title>Daemon : Java Service</title>
  <author email="jfrederic.clere@fujitsu-siemens.con">Jean-Frederic Clere</author>
 </properties>

<body>
<section name="Introduction">
<p>
      Jsvc is a set of libraries and applications for making Java
      applications run on UNIX more easily.
      <br/>
      Jsvc allows the application (e.g. Tomcat) to perform some privileged operations as root
      (e.g. bind to a port &lt; 1024), and then switch identity to a non-privileged user.
      <br/>
      It can run on Win32 via the Cygwin emulation layer (see
      <a href="https://www.cygwin.com/"> Cygwin</a> for more information),
      however Win32 users may prefer to use <a href="procrun.html"> procrun</a>
      instead, which allows the application to run as a Windows Service.
</p>
<p>
      The sources are located in the src/native/unix subdirectory.
</p>
<p>
      In the future <a href="https://apr.apache.org/"> APR </a> may be used
      to provide more portable platform support.
</p>
</section>

<section name="Building from source">
<p>
To build under a UNIX operating system you will need:
</p>
<ul>
  <li>GNU AutoConf (at least version 2.53)</li>
  <li>An ANSI-C compliant compiler (GCC is good)</li>
  <li>GNU Make</li>
  <li>A Java Platform 2 compliant SDK</li>
</ul>
<p>
You need to build the "configure" program with:
</p>
<source>
sh support/buildconf.sh
</source>
<p>
(Note it is possible to replace sh by any compatible shell like bash, ksh).

The result should be something like:
<source>
support/buildconf.sh
support/buildconf.sh: configure script generated successfully
</source>
Once the configure script is generated, follow the next section.
</p>
</section>

<section name="Building from a release tarball">
<p>
To build the binary under a UNIX operating system you will need:
</p>
<ul>
  <li>An ANSI-C compliant compiler (GCC is good)</li>
  <li>GNU Make</li>
  <li>A Java Platform 2 compliant SDK</li>
</ul>
<p>
You have to specify the <code>JAVA_HOME</code> of the SDK
either with the <code>--with-java=&lt;dir&gt;</code> parameter or set the <code>JAVA_HOME</code> environment
to point to your SDK installation. For example:
<source>
./configure --with-java=/usr/java
</source>
or
<source>
export JAVA_HOME
./configure
</source>

If your operating system is supported, configure will go through cleanly,
otherwise it will report an error (please send us the details of your
OS/JDK, or a patch against the sources). To build the binaries and
libraries simply do:
<source>
make
</source>
This will generate the executable file <code>jsvc</code>.
</p>
</section>

<section name="Starting jsvc">
<p>
To check the allowed parameters for the jsvc binary simply do:
<source>
./jsvc -help
Usage: jsvc [-options] class [args...]

Where options include:

    -help | --help | -?
        show this help page (implies -nodetach)
    -jvm &lt;JVM name&gt;
        use a specific Java Virtual Machine. Available JVMs:
            'client' 'server'
    -client
        use a client Java Virtual Machine.
    -server
        use a server Java Virtual Machine.
    -cp / -classpath &lt;directories and zip/jar files&gt;
        set search path for service classes and resouces
    -home &lt;directory&gt;
        set the path of your JDK or JRE installation (or set
        the JAVA_HOME environment variable)
    -version
        show the current Java environment version (to check
        correctness of -home and -jvm. Implies -nodetach)
    -showversion
        show the current Java environment version (to check
        correctness of -home and -jvm) and continue execution.
    -nodetach
        don't detach from parent process and become a daemon
    -debug
        verbosely print debugging information
    -check
        only check service (implies -nodetach)
    -user &lt;user&gt;
        user used to run the daemon (defaults to current user)
    -verbose[:class|gc|jni]
        enable verbose output
    -cwd &lt;/full/path&gt;
        set working directory to given location (defaults to /)
    -outfile &lt;/full/path/to/file&gt;
        Location for output from stdout (defaults to /dev/null)
        Use the value '&amp;2' to simulate '1&gt;&amp;2'
    -errfile &lt;/full/path/to/file&gt;
        Location for output from stderr (defaults to /dev/null)
        Use the value '&amp;1' to simulate '2&gt;&amp;1'
    -pidfile &lt;/full/path/to/file&gt;
        Location for output from the file containing the pid of jsvc
        (defaults to /var/run/jsvc.pid)
    -D&lt;name&gt;=&lt;value&gt;
        set a Java system property
    -X&lt;option&gt;
        set Virtual Machine specific option
    -ea[:&lt;packagename&gt;...|:&lt;classname&gt;]
    -enableassertions[:&lt;packagename&gt;...|:&lt;classname&gt;]
        enable assertions
    -da[:&lt;packagename&gt;...|:&lt;classname&gt;]
    -disableassertions[:&lt;packagename&gt;...|:&lt;classname&gt;]
        disable assertions
    -esa | -enablesystemassertions
        enable system assertions
    -dsa | -disablesystemassertions
        disable system assertions
    -agentlib:&lt;libname&gt;[=&lt;options&gt;]
        load native agent library &lt;libname&gt;, e.g. -agentlib:hprof
    -agentpath:&lt;pathname&gt;[=&lt;options&gt;]
        load native agent library by full pathname
    -javaagent:&lt;jarpath&gt;[=&lt;options&gt;]
        load Java programming language agent, see java.lang.instrument
    -procname &lt;procname&gt;
        use the specified process name (works only for Linux and FreeBSD)
    -wait &lt;waittime&gt;
        wait waittime seconds for the service to start
        waittime should multiple of 10 (min=10)
    -restarts &lt;maxrestarts&gt;
        maximum automatic restarts (integer)
        -1=infinite (default), 0=none, 1..(INT_MAX-1)=fixed restart count
    -stop
        stop the service using the file given in the -pidfile option
    -keepstdin
        does not redirect stdin to /dev/null
    --add-modules=&lt;module name&gt;
        Java 9 --add-modules option. Passed as it is to JVM
    --module-path=&lt;module path&gt;
        Java 9 --module-path option. Passed as it is to JVM
    --upgrade-module-path=&lt;module path&gt;
        Java 9 --upgrade-module-path option. Passed as it is to JVM
    --add-reads=&lt;module name&gt;
        Java 9 --add-reads option. Passed as it is to JVM
    --add-exports=&lt;module name&gt;
        Java 9 --add-exports option. Passed as it is to JVM
    --add-opens=&lt;module name&gt;
        Java 9 --add-opens option. Passed as it is to JVM
    --limit-modules=&lt;module name&gt;
        Java 9 --limit-modules option. Passed as it is to JVM
    --patch-module=&lt;module name&gt;
        Java 9 --patch-module option. Passed as it is to JVM
    --illegal-access=&lt;value&gt;
        Java 9 --illegal-access option. Passed as it is to JVM. Refer java help for possible values.
    --enable-preview
        Java 11 --enable-preview option. Passed as it is to JVM
    --enable-native-access=&lt;module name&gt;
        Java 21 --enable-native-access option. Passed as it is to JVM
</source>
</p>
<subsection name="Mac OS X universal binaries">
<p>
If jsvc was build with universal binary support the proper way of
starting <code>jsvc</code> is by using Mac OS X <code>arch</code> command:
</p>
<source>
    arch -arch i386 ./jsvc -jvm server &lt;original jsvc parameters&gt;

    for running 64-bit JVM use the:
    arch -arch x86_64 ./jsvc -jvm server &lt;original jsvc parameters&gt;

</source>
<p>
Use <code>-jvm server</code> because default <code>client</code> JVM is
not present for all architectures.
</p>
</subsection>
</section>
<section name="Using jsvc">
<p>
There two ways to use jsvc: via a Class that implements the Daemon interface or
via calling a Class that has the required methods.
For example Tomcat-4.1.x uses the Daemon interface
whereas Tomcat-5.0.x provides a Class whose methods are called by jsvc directly.
</p>
<subsection name="Via Daemon interface">
<p>
Do the following:
</p>
<ul>
  <li>Write a Class that implements the Daemon interface (MyClass).</li>
  <li>Put it in a jarfile (my.jar).</li>
  <li>Call jsvc like:
  <source>
./jsvc -cp commons-daemon.jar:my.jar MyClass
  </source>
  </li>
</ul>
</subsection>
<subsection name="Directly">
<p>
Write a Class (MyClass) that implements the following methods:
</p>
<ul>
  <li>void init(String[] arguments): Here open configuration files, create a trace file, create
      ServerSockets, Threads</li>
  <li>void start(): Start the Thread, accept incoming connections</li>
  <li>void stop(): Inform the Thread to terminate the run(), close the ServerSockets</li>
  <li><code>void destroy()</code>: Destroy any object created in init()</li>
</ul>
<p>
Store it in a jarfile and use as above:
<source>
./jsvc -cp my.jar MyClass
</source>
</p>
</subsection>
</section>
<section name="How jsvc works">
<p>
Jsvc uses 3 processes: a launcher process, a controller process and a controlled process.
The controlled process is also the main java thread, if the JVM crashes
the controller will restart it in the next minute.
Jsvc is a daemon process so it should be started as root and the <code>-user</code> parameter
allows to downgrade to an unprivilegded user.
When the <code>-wait</code> parameter is used, the launcher process waits until the controller says
"I am ready", otherwise it returns after creating the controller process.
</p>

<subsection name="Forks in commons-daemon">
<p>
Launcher process:
<source>
main()
{
  fork()
  parent: wait_child(), wait until JAVA service started when the child says "I am ready".
  child: controller process.
}
</source>

Controller process:
<source>
  while (fork()) {
    parent: wait_for_child.
      if exited and restart needed continue
      else exit.
    child: exit(child()). controlled process.
  }
</source>

Controlled process:
<source>
In child(): controlled process.
  init_JVM().
  load_service().
  start_service().
  say "I am ready"
  wait for signal or poll for stop
  stop_service().
  destroy_service().
  destroy_JVM().
  exit (with different codes so that parent knows if it has to restart us).
</source>
Note: The controller process uses signals to stop the controlled process.
</p>
</subsection>

<subsection name="Downgrading user">
<p>
On Linux <code>setuid()</code>/<code>setgid()</code> + capabilities are used. On other Unix <code>setgid</code>/<code>initgroups</code> are used.

We have something like:
<source>
/* as root */
init_JVM().
load_service. /*  java_load() calls the load method */
downgrade user (set_caps() or set_user_group())
/* as the user $USER (from -user $USER parameter) */
umask()
start_service. /* java_start() calls the start method */
</source>
</p>
</subsection>
</section>

</body>
</document>
