Ce nouveau mécanisme utilise la notion de job et d'événement. Les actions à réaliser sont définies au sein d'un job, par un script shell. Le job contient une liste d'actions sur ce qu'il doit faire lorsqu'un événement donné se produit.
Les jobs sont placés dans le répertoire /etc/event.d, dont voici une liste typique :
logd                    rc0           rc0-poweroff   rc2  rc4  rc6  rcS-sulogin  tty1  tty3  tty5
control-alt-delete rc-default rc0-halt rc1 rc3 rc5 rcS sulogin tty2 tty4
La commande initctl list fournit la liste des jobs lancés, actifs ou en attente :
control-alt-delete (stop) waiting
logd (start) running, process 1821 active
rc-default (stop) waiting
rc0 (stop) waiting
rc0-halt (stop) waiting
rc0-poweroff (stop) waiting
rc1 (stop) waiting
rc2 (stop) waiting
rc3 (stop) waiting
rc4 (stop) waiting
rc5 (stop) waiting
rc6 (stop) waiting
rcS (stop) waiting
rcS-sulogin (stop) waiting
sulogin (stop) waiting
tty1 (start) running, process 3356 active
tty2 (start) running, process 3357 active
tty3 (start) running, process 3358 active
tty4 (start) running, process 3359 active
tty5 (start) running, process 3360 active
tty6 (start) running, process 3361 active
Et le contenu typique d'un fichier job est :
# tty1 - getty
#
# This service maintains a getty on tty1 from the point the system is
# started until it is shut down again.

start on runlevel-2
start on runlevel-3
start on runlevel-4
start on runlevel-5

stop on shutdown

respawn /sbin/getty 38400 tty1
On y trouve tout simplement les actions à mener lorsqu'un événement (runlevel-2, runlevel-3, ... ou shutdown) se produit, et les instructions à exécuter lorsque le job est lancé.

Un exemple un peu plus complexe ?

# rc2 - runlevel 2 compatibility
#
# This task runs the old sysv-rc runlevel 2 ("multi-user") scripts. It
# is usually started by the telinit compatibility wrapper.

start on runlevel-2

stop on shutdown
stop on runlevel-3
stop on runlevel-4
stop on runlevel-5

script
set $(runlevel --set 2 || true)
if [ "$1" != "unknown" ]; then
PREVLEVEL=$1
RUNLEVEL=$2
export PREVLEVEL RUNLEVEL
fi

exec /etc/init.d/rc 2
end script
On retrouve un fonctionnement habituel, qui lance les scripts dans rc2.d lorsqu'on entre dans le niveau 2, et arrête le job lorsqu'on entre dans d'autres niveaux. On remarque que le script exécuté par le job est un peu plus complexe, et on voit l'un des intérêts de ce nouveau mécanisme, à savoir éviter d'écrire un script uniquement pour le placer dans une ligne de /etc/inittab.

A l'issue de ce petit tour, vous vous demandez peut être quel est l'intérêt de ce changement ?
Pour ma part, j'en vois un majeur, qu'on ne peut pas réaliser avec le init classique sans aller modifier le fichier inittab. Il est possible d'arrêter ou de lancer temporairement et interactivement un job, c'est à dire d'être dans un niveau de fonctionnement donné sans que ce job ne continue à tourner, à l'aide des commandes start et stop.
Par exemple stop tty1 arrête le processus de login lancé sur le port virtuel tty1.
Essayez donc de faire la même chose de façon interactive avec un init classique : voues êtes obligés de modifier /etc/inittab, et de faire un telinit q. Et si vous oubliez ensuite d'annuler votre modification dans /etc/inittab, votre système reste configuré de travers, ce qui ne sera pas le cas avec upstart puisque vous n'avez rien modifié aux fichiers de configuration.

Oh j'allais oublier de donner la réponse à la question. Sous Ubuntu, le niveau par défaut est le 2, et on peut le voir en lisant le contenu du job rc-default !