What is a .i file?

A .i file is a file that lets you start a service or program easily by using the ngc or ng-update commands.

Where are they located?

The .i files are located in the /etc/initng directory or subdirectories such as /etc/initng/system or /etc/initng/daemon.

Why would I want to edit or make one of these files?

Well the reason is simple what if you would like to have a program start on startup but currently there is no script for it. Or a program won't start yet there is a script so soon you will have the skills to edit and fix these files.

Notice: the file must end in .i or initng will not see it!

Basic Syntax:
# start SaTaN0rX

there are different things: daemons and services.

a service is something that is only run once and then terminates. examples
are: mount something, set the hostname, bring the network up, ...

in contrary, a daemon is a programm thats being started and runs all the time.
for example apache, cups, ...

the first thing you need to do is to figure out what you want to write:
an .i file for a service or a daemon?

SERVICES:

a service might look like this:

service system/foo {
   need = system/initial system/mountfs;
   use = system/alsasound;
   exec start = /sbin/foo;
   exec_args start = bar baz;
}

i'll explain these lines.
the first line says that this service requires system/initial and
system/mountfs to be run before it can be started.

the second line says that it should also wait for system/alsasound is also in
the current runlevel, then it should also wait for system/alsasound. but if
system/alsasound is NOT in the current runlevel,  this line would be ignored.
in contrary, if it would have said need = system/alsasound, then
system/alsasound would also have been started even if it is not in the current
runlevel.

the third line gives the program to start, in this case /sbin/foo

and the forth line, you may have guessed it, gives additional parameters that
should be passed to /sbin/foo.

ok, now can also have a service that does something on start and on shutdown.
it would look like this:

service system/foo {
   need = system/initial system/mountfs;
   use = system/alsasound;
   exec start = /sbin/foo;
   exec_args start = bar baz;
   exec stop = /sbin/foo;
   exec_args stop = qux quux;
}

here, the stop and stop_args lines have been added. pretty easy.
but there are situations in which you can not use some simple program, but u
need a shell script. one solution would be to write that shell script to a
file, and have a line like "exec start = /path/to/my/script.sh". while i would
suggest you to do that for really large scripts (>100 lines), it would be kind
an overkill to do so for a script with 5 lines of code. so initng provides a
possibility to include these scripts .i files. example:

service system/foo {
   need = system/initial system/mountfs;
   use = system/alsasound;
   script start = {
      [ -f /etc/conf.d/foo.conf ] && source /etc/conf.d/foo.conf
      [ -z "$FOO" ] & FOO="bar baz"
      /sbin/foo $FOO
   };
}

note that you could also have stop script-block that is executed on shutdown.
this block would be named, you guessed it, script stop { }.

DAEMONS:

a basic daemon .i file might look like this:
daemon daemon/vixie-cron {
        need = system/initial system/clock system/mountfs system/bootmisc;
        exec daemon = /usr/sbin/cron;
        exec_args daemon = -n;
}

it starts with "daemon daemon/blah {", and has a "exec daemon =" line in it.
the "exec daemon =" specifies the daemon executable. 

a daemon doesn't have "exec start", "exec_args start", "exec stop" or "exec_args stop" directives, but has a 
"exec daemon" and "exec_args daemon" directive. all other directives are the
same as with services.

initng will by default track what the daemons are doing, ie it will monitor if
a daemon crashes, etc. unfotunately, some daemons have a bad habit: forking.

when a daemon forks, it spawns a copy of itself with a new pid. then the
father process, with the old pid, dies. 

this has some advantages: if you start cron from your console, then you
instantly will see the bash prompt again. thats why most daemons fork.

unfortunately, initng has up to now no possibility to know if a daemon spawns
a child or not. initng will only notice that the father process dies, and
thinks that the daemon died.

fortunately most daemons have a commandline switch which makes them not
forking. in the case of vixie-cron it is -n. consult your daemons manpage.

in some cases, the daemon can't be prevented from forking, but it will write
the pid of the child process in a file, called the pid-file. initng can also use 
the pid file to track the daemon. an example:

daemon daemon/ntpd {
        need = system/initial system/mountfs system/mountfs net/lo;
        require_network;
        use = daemon/ntpdate;
        exec daemon = /usr/sbin/ntpd;
        exec_args daemon = -p /var/run/ntpd.pid;
        pid_file = /var/run/ntpd.pid;
}


this daemon WILL fork, but it will write the pid of the doughter process in
/var/run/ntpd.pid. initng can also track this daemon.

another thing you can see is the require_network directive. this will delay
the starting of this daemon until a network device is set up.

In a very bad case, a deamon might provide neither a switch to disable
forking, nor will it write the pid of the forked process to a pidfile.
for this case, initng has the possibility to look for a process by its name,
as shown in this example:

daemon daemon/portmap {
        need = system/mountroot;
        require_network;
        pid_of = portmap;
        exec daemon = /sbin/portmap;
}

portmap will fork, and write no pidfile. when the father porcess dies, 
initng will look for an process named portmap, and if one exists, it will use
it's pid.

While this sounds pretty easy, this should be used as LAST option. always use
this order: 
1) try to prevent the daemon from forking at all
2) if 1) is not possible, try to use pid_file
3) only if 1) and 2) are not possible, use pid_of

ok, what's the buzz when you need some shell script to bring up the daemon?
have a look at this example:

daemon daemon/acpid {
        need = system/mountfs system/modules;
        use = system/discover system/coldplug;
        script daemon = {


                # As the name says. If the kernel supports modules, it'll try to load
                # the ones listed in "MODULES".
                
		.....
                # Check for ACPI support on kernel side
                [ -d /proc/acpi ] || exit 0

                # Include acpid defaults if available
                OPTIONS=""
                if [ -f /etc/default/acpid ] ; then
                        . /etc/default/acpid
                fi

                [ -f /proc/modules ] && load_modules


                #for x in ac battery button fan ibm_acpi processor thermal video ; do
                #       modprobe ${x} &> /dev/null
                #done

                exec /usr/sbin/acpid -f -c /etc/acpi/events
        };
}

i've shortened this a little bit :P

as you can see you can also embedd an "script daemon = { script };" bash script in an .i
file. but notice the "exec blah" statement. when you write "exec blah" in an
bash script, the blah process will REPLACE the bash process, inheriting it's
pid. this is necessary, so that initng can track your service. if you use
pid_file, it is not absolutely necessary, but i'd suggest to do so.

DIRECTIVES:
this should give an incomplete list of the other directives not explained
above.

you can get a list of most available options with a short description if you type "ngc -O"

require_network: the start service or daemon is delayed until a network device
			other then lo is configured.

last: the start service or daemon is delayed until all services and daemons,
			which are not last, are started.

respawn: if the daemon dies, it will be restarted.


NAMING THE .i FILE:
when you name the .i file:
initng will look for the service "daemon/something" in
"/etc/initng/daemon/smoething.i". so the exaple above has to go into
"/etc/initng/daemon/acpid.i".

ADVANCED TOPICS:

have a look at daemon/agetty.i:

daemon daemon/agetty/tty1 {
        need = system/mountfs;
        exec daemon = /sbin/agetty;
        exec_args daemon = 38400 ${NAME};
        respawn;
        last;
}

daemon daemon/agetty/* {
        need = system/mountfs;
        exec daemon = /sbin/agetty;
        exec_args daemon = 38400 ${NAME};
        respawn;
}

virtual daemon/agetty {
    need = daemon/agetty/tty1 daemon/agetty/tty2 daemon/agetty/tty3 daemon/agetty/tty4 daemon/agetty/tty5 daemon/agetty/tty6;
    use = system/mountfs system/netmount;
}

#end of daemon/agetty.i

the first block will define a daemon "daemon/agetty/tty1"

the second block defines "daemon/agetty/*". now what is this? this Block
contains a wildchar. when you tell initng to start daemon/agetty/foo, this
block will match it, so initng will use this block.

You might notice the shell-style ${NAME} keyword. this keyword will be
replaced by initng with the actual name of the service. 

NOTE: ${NAME} won't be "deamon/agetty/tty1" or the like, but it WILL be "tty1"

This is usefull fr things like getty's, AND for things like network daemons
that bind to individual interfaces. see daemon/<your favourite dhcp-client>
for an example.

the third block is an virtual. As you can see, there is neither a script, nor
a exec statement in this block. So the virtual's don't do very much, the only
thing they do is to depend on something, in this case in /daemon/agetty/tty1
to tty6. This way, the user only needs to add daemon/agetty to his runlevel,
and he gets all those agettys. after all agettys were started, daemon/agetty
gets the status DONE. 

The order of the three blocks is of importance (it shuld not be important, but
due to some bugs, it is).

the first block should be in the file before the second one. When initng trys
to find daemon/agetty/tty1 it will first find the first block, which matches,
and executes this block.

OTOH if the order of the block 1 and 2 was reversed, initng would first find the
"daemon/agetty/*" block, which ALSO matches "deamon/agetty/tty1", and execute
this block - this is not the desired behaviour.

note that this is not the desired behaviour of initng, but rather a bug in
initng, that was recently fixed, but, as devellopment goes on, it might
re-appear ;).

the third block shold be the last block for one reason: if the user adds
daemon/agetty to his/her default runlevel, initng will look for this specific
.i file, and parse it until it found daemon/agetty. it will stop after it has
parsed the daemon/agetty{} block. any other block in the .i file up to this
block will ALSO be parsed and added to initng's internal database. So, the
other two blocks will already be parsed when they are needed. 

In this case, there should be no problem if the last block was the first one,
BUT it might become a problem if the daemons are named differently.

So in theory, the order would NOT matter, but in practice, the order might
matter, due to some bugs. (this bugs should be fixed in 0.4.5, thou)

TESTING YOUR .i FILE
after you have written your .i file, it may still contain syntax errors and
the like. so it's better not to shoot directly with "ngc -u daemon/mydaemon",
but to do some test it first.

The first step is to check for syntax errors. You can use the ./test_parser
inside the devtool directory of the initng source distribution.

after you have installed your .i file in the correct location ( usually
/etc/initng/system/ or /etc/initng/daemon/ ), just run "./test_parser
daemon/mydaemon". unfortunately, it's output is not very informative, so you
have to check the exit status: "echo $?". if the exit staus is 2, an error has
occured. otherwise, it is 0.

The next thing you might try is to see if your .i file works pretty.
i'd suggest you doing so by using initng in fake mode:

a) launch initng (as root). this will bring up another initng instance in the
so called fake mode.

b) comment all "need=" "require=" lines in your .i file

c) do "ngdc -u daemon/mydaemon", and see what happens. if something doesn't
work, and you need to change something in the .i file, just kill initng (the
fake instance, of course!), edit your file and start with a)

d) if you are satisfied with your work, kill the fake instance, uncomment the 
"need=" and "require=" statements, and do "ngc -u daemon/mydaemon"

e) if possible share your .i file with us! either send it to the ML, post it
in bugzilla, or talk to one of us in the irc!



To be continued ...
