Overview

Why?

Question: Why reuse a system facility at the user level in this way?

The user plugs or unplugs a peripheral device.

A process changes state.

A file gets created.

A file is deleted.

A D-Bus signal is emitted.

et cetera.

is

Question: Yes but isn't having Upstart manage users sessions overkill?

init-checkconf(8)

update-notifier

update-manager

Enabling

Upstart User Sessions for the default desktop will be enabled by default for the "S" cycle.

Enabling Upstart User Sessions for the default Ubuntu Raring desktop is extremely easy!

ubuntu

/etc/upstart-xsessions

sudo sed -i 's/^#ubuntu/ubuntu/' /etc/upstart-xsessions

ubuntu

sudo sed -i 's/^ubuntu/#ubuntu/' /etc/upstart-xsessions

Show me my Session

When you've enabled sessions and re-logged in, everything will look the same but you'll be running within an Upstart environment. You can see the session you're running in by looking at the value of the $UPSTART_SESSION environment variable:





$ echo $UPSTART_SESSION unix:abstract=/com/ubuntu/upstart-session/1000/3066

$ initctl list-sessions 3066 unix:abstract=/com/ubuntu/upstart-session/1000/3066

list-sessions

$pid $UPSTART_SESSION





$ ps -fp 3066 UID PID PPID C STIME TTY TIME CMD james 3066 2884 0 07:58 ? 00:00:00 init --user

Have I got any jobs running?

$ initctl list xsession-init stop/waiting dbus start/running, process 3304 firefox stop/waiting procenv stop/waiting term start/running, process 3289 gnome-session start/running, process 3343 logrotate stop/waiting thunderbird start/running, process 3339 mumble stop/waiting gnome-settings-daemon start/running, process 3309 emacs start/running, process 4324 re-exec stop/waiting upstart-event-bridge start/running, process 3305

/usr/share/upstart/sessions/

thunderbird

emacs

term

procenv

mumble

initctl list

$ sudo initctl list $ initctl --system list

Writing your first user job

xclock

$XDG_CONFIG_HOME/upstart/

$HOME/.config/upstart/

$ conf_dir=${XDG_CONFIG_HOME:-$HOME/.config}/upstart $ mkdir -p $conf_dir

$conf_dir

$conf_dir/xclock.conf

start on desktop-start stop on desktop-end

exec xclock -update 1

$ init-checkconf $conf_dir/xclock.conf File /home/james/.config/upstart/xclock.conf: syntax ok

init-checkconf(8)

$ start xclock

xclock

$ stop xclock

xclock.conf

Delete xclock.conf - the job is then gone.

- the job is then gone. Add " manual " anywhere after the start on line in xclock.conf such that the job will not be auto-started.

" anywhere the line in such that the job will not be auto-started. Create a new file called xclock.override in the same directory that simply contains " manual ". Again, this will stop the file from being auto-started but allows you to leave the existing .conf file as-is.

in the same directory that simply contains " ". Again, this will stop the file from being auto-started but allows you to leave the existing file as-is. Delete (or simply comment out) the start on condition.





Let's create another job to start firefox which we shall call somewhat unimaginatively firefox.conf :





start on desktop-start stop on desktop-end

exec firefox

start on

stop on

xclock.conf

start on started firefox stop on stopping firefox

exec xclock -update 1

initctl list " output) are called starting , started , stopping and stopped but there are The job events (events that are emitted by jobs in your "" output) are calledandbut there are many more interesting ones

Application Output

$HOME/.xsession-errors

$XDG_CACHE_HOME/upstart/$job.log

$HOME/.cache/upstart/$job.log

gnome-session

$HOME/.xsession-errors

logrotate

$ start logrotate

logrotate

/usr/share/upstart/sessions/logrotate.conf

upstart-monitor

$ sudo apt-get install upstart-monitor $ upstart-monitor

Auto-start an application on plugging a USB device

$HOME/.config/upstart/mumble.conf

# start VoIP client of choice exec mumble

start mumble

stop mumble

mumble

upstart-monitor

sound-device-changed

:sys:sound-device-changed KERNEL='card2' DEVPATH='/devices/pci0000:00/0000:00:1d.0/usb2/2-1/2-1.2/2-1.2:1.0/sound/card2' SUBSYSTEM='sound' ACTION='change' ID_BUS='usb' ID_FOR_SEAT='sound-pci-0000_00_1d_0-usb-0_1_2_1_0' ID_ID='usb-Logitech_Logitech_USB_Headset-00-Headset' ID_MODEL='Logitech_USB_Headset' ID_MODEL_ENC='Logitech\x20USB\x20Headset' ID_MODEL_FROM_DATABASE='ClearChat Pro USB' ID_MODEL_ID='0a0b' ID_PATH='pci-0000:00:1d.0-usb-0:1.2:1.0' ID_PATH_TAG='pci-0000_00_1d_0-usb-0_1_2_1_0' ID_REVISION='1013' ID_SERIAL='Logitech_Logitech_USB_Headset' ID_TYPE='audio' ID_USB_DRIVER='snd-usb-audio' ID_USB_INTERFACES=':010100:010200:030000:' ID_USB_INTERFACE_NUM='00' ID_VENDOR='Logitech' ID_VENDOR_ENC='Logitech' ID_VENDOR_FROM_DATABASE='Logitech, Inc.' ID_VENDOR_ID='046d' SEQNUM='2803' SOUND_FORM_FACTOR='headset' SOUND_INITIALIZED='1' TAGS=':seat:' UDEV_LOG='3' USEC_INITIALIZED='795038608'

sound-device-changed

:sys:sound-device-changed KERNEL='card2' DEVPATH='/devices/pci0000:00/0000:00:1d.0/usb2/2-1/2-1.2/2-1.2:1.0/sound/card2' SUBSYSTEM='sound' ACTION='change' ID_BUS='usb' ID_FOR_SEAT='sound-pci-0000_00_1d_0-usb-0_1_2_1_0' ID_ID='usb-Logitech_Logitech_USB_Headset-00-Headset' ID_MODEL='Logitech_USB_Headset' ID_MODEL_ENC='Logitech\x20USB\x20Headset' ID_MODEL_FROM_DATABASE='ClearChat Pro USB' ID_MODEL_ID='0a0b' ID_PATH='pci-0000:00:1d.0-usb-0:1.2:1.0' ID_PATH_TAG='pci-0000_00_1d_0-usb-0_1_2_1_0' ID_REVISION='1013' ID_SERIAL='Logitech_Logitech_USB_Headset' ID_TYPE='audio' ID_USB_DRIVER='snd-usb-audio' ID_USB_INTERFACES=':010100:010200:030000:' ID_USB_INTERFACE_NUM='00' ID_VENDOR='Logitech' ID_VENDOR_ENC='Logitech' ID_VENDOR_FROM_DATABASE='Logitech, Inc.' ID_VENDOR_ID='046d' SEQNUM='2803' SOUND_FORM_FACTOR='headset' SOUND_INITIALIZED='1' TAGS=':seat:' UDEV_LOG='3' USEC_INITIALIZED='795038608'

:sys:sound-device-changed KERNEL='card2' DEVPATH='/devices/pci0000:00/0000:00:1d.0/usb2/2-1/2-1.2/2-1.2:1.0/sound/card2' SUBSYSTEM='sound' ACTION='change' ID_BUS='usb' ID_FOR_SEAT='sound-pci-0000_00_1d_0-usb-0_1_2_1_0' ID_ID='usb-Logitech_Logitech_USB_Headset-00-Headset' ID_MODEL='Logitech_USB_Headset' ID_MODEL_ENC='Logitech\x20USB\x20Headset' ID_MODEL_FROM_DATABASE='ClearChat Pro USB' ID_MODEL_ID='0a0b' ID_PATH='pci-0000:00:1d.0-usb-0:1.2:1.0' ID_PATH_TAG='pci-0000_00_1d_0-usb-0_1_2_1_0' ID_REVISION='1013' ID_SERIAL='Logitech_Logitech_USB_Headset' ID_TYPE='audio' ID_USB_DRIVER='snd-usb-audio' ID_USB_INTERFACES=':010100:010200:030000:' ID_USB_INTERFACE_NUM='00' ID_VENDOR='Logitech' ID_VENDOR_ENC='Logitech' ID_VENDOR_FROM_DATABASE='Logitech, Inc.' ID_VENDOR_ID='046d' SEQNUM='2803' SOUND_FORM_FACTOR='headset'

SOUND_INITIALIZED='1'

TAGS=':seat:' UDEV_LOG='3' USEC_INITIALIZED='795038608'

KERNEL and DEVPATH : these refer to the physical location of the device so don't select these as that location will differ depending on which USB port you plug your device into.

and : these refer to the physical location of the device so don't select these as that location will differ depending on which USB port you plug your device into. DEVNAME and DEVNUM are incremented every time a new device is plugged in (even if it's the same device you plugged in before).

and are incremented every time a new device is plugged in (even if it's the same device you plugged in before). UDEV_LOG , USEC_INITIALIZED , SEQNUM .

Describe your device clearly.

Will always have the same value whenever and wherever you plug the device.

ID_MODEL

$HOME/.config/upstart/mumble.conf

start on

start on :sys:sound-device-changed ID_MODEL="Logitech_USB_Headset" SOUND_INITIALIZED="1" stop on desktop-end # start VoIP client of choice exec mumble

mumble

The kernel detects the device and generates a uevent.

The upstart-udev-bridge , running at the system level , is monitoring the kernels netlink socket via libudev and therefore sees the event and emits a corresponding Upstart system event .

, running at the , is monitoring the kernels netlink socket via libudev and therefore sees the event and emits a corresponding Upstart . The users upstart-event-bridge sees the system event and proxies it down to the users Upstart session by emitting an Upstart user event tagged with a " :sys: " prefix.

sees the system event and proxies it down to the users Upstart session by emitting an Upstart tagged with a " " prefix. The users Session Init compares the start on condition in mumble.conf with the Upstart event emitted by the upstart-event-bridge , finds that it matches and so starts the mumble job.

upstart-events(7)

Restrictions

upstart-udev-bridge

upstart-event-bridge

The File Bridge

xclock

start on file FILE=~/.xsession-errors EVENT=modify exec xclock

start on file FILE=~/var/mydir/ exec xclock

$HOME/var/mydir/.

start on file FILE=~/.cache/myapp/*.crash exec handle-my-buggy-app

handle-my-buggy-app

.crash

Understanding how jobs interact

initctl2dot which generates



Upstart provides a tool calledwhich generates graphviz visualisations of jobs. Let's run it:

$ initctl2dot -o - | dot -Tpng -o upstart.png



The rectangular nodes represent jobs.

The diamonds denote events.

Blue lines represent start on conditions.

conditions. Red lines represent stop on conditions.

conditions. Green lines show the events that jobs may emit. There's quite a lot happening in that diagram partly as we've added some useful "well-known" events that you can use for your jobs. In particular, note the desktop-start and desktop-end events. These are not the first events emitted, but if your job specifies the following, it is guaranteed to run in a fully-functional desktop environment:



start on desktop-start stop on desktop-end





start on startup stop on session-end

Note: The desktop-start and desktop-end events are emitted by the job that actually starts the users graphical desktop. Currently, only the default Ubuntu desktop is emitting these events, but all desktop environments that support for Session Inits need to emit these events.

The Future There are already a lot of





Suspend/Resume events

Improved sound device events (for example, start a job when headphones plugged)

network events (for example, start/stop jobs when you connect to an open wifi network)

D-Bus signals ( upstart-dbus-bridge )

) dconf/gsettings changes ( upstart-dconf-bridge )

) cron-like temporal events ( upstart-time-bridge ) If you want your job to start as early as possible and end as late as possible, but don't care about whether the desktop is usable when the job starts, you can specify:Note: Theandevents are emitted by the job that actually starts the users graphical desktop. Currently, only the default Ubuntu desktop is emitting these events, but all desktop environments that support for Session Inits need to emit these events.There are already a lot of "well-known" events your jobs can make use of, but we plan to introduce even more to enrich the available palette next cycle. Ideas for event sources include:

Further Information

The Upstart Cookbook

#upstart on freenode

The upstart-devel mailing list.

The all-important man pages:

init(5)



init(8)



upstart-monitor(8)



upstart-events(7)

Ubuntu Raring now includes Upstart 1.8 Upstart 1.7 and 1.8 combined mark a major milestone since they bring the proven power of Upstart to the user as never before: not only is Upstart now managing the system, but it is also capable of managing the default Ubuntu user's desktop sessions too.The modern Linux desktop environment is a very dynamic one: users start and stop applications, switch workspaces, search the dash, adjust personal settings in the panel, connect to different networks, hot-plug USB devices and so on. All of these activities can be represented by "events".Stepping back a second, recall that Upstart was writtento take advantage of the dynamic nature of a modern Linux system . Long gone are the days when a system booted serially. A modern Linux system abounds with "events" from all sorts of different sources:In recognition of this, Upstarts core conceptthat of an event . At its heart, Upstart is an event-based process supervisor. So what better than to use a proven facility such as Upstart at the session level too? Upstarts design fits perfectly with the requirements for an init daemon butfits the requirements for a session supervisor!Not really - Upstart is not a big application: it was written to be small, fast, safe and reliable, all of which are highly desirable attributes for controlling sessions.Aside: Upstart has in fact been able to run as a non-privileged user for a couple of years now (since version 1.3) although the facility was added initially for testing and then later for theutility.This cycle, the Ubuntu developers have gone to great lengths to squash down the default image making the overall system smaller, leaner and faster. By allowing Upstart to manage user sessions, even greater gains can be achieved going forwards since although we've now added a small number of extra (albeit small) user processes, these allow us to convert some of the historically "long-running" user applications to "on-demand" ones. Like the corresponding Upstart system jobs, by default these won't run at all: Upstart will start themInitial targets are apps likeand. However, for the "S" cycle we'll be looking even more closely at what is running by default to see if we can start more of those processes on demand.Some of the changes recently introduced to Upstart also mean that additionalservices can also benefit further from on-demand startup. For example, the plan is for the whoopsie daemon to only start on-demand.This will be an ongoing project, but the foundations have been laid and the concept proved.The default Ubuntu Desktopin Raring is now fully capable of being managed by Upstart. However, since all the changes landed relatively late in the cycle, the decision was taken not to enable this feature by default.- we'd like to offer this facility to all the others desktop environments so please contact us if you wish to get involved in making the remaining Xsession scripts Upstart-aware.However, the good news is two-fold:If you wish to try out User Sessions (and I'd like to encourage as many folks as possible to) and you use the default Ubuntu desktop, you just need to change a single file, then logout and back in again:To enable, simply uncomment "" in filelike this:To disable, simply comment-out "" again by running the following:To list all running sessions for your user:The format of theoutput in case you haven't guessed it is:Proof that we are running Upstart:Yes!What's interesting is that some of those jobs are "built-ins" fromwhilst some are jobs I've created myself (and).Note that if you're already familiar with Upstart, there is a subtle behavioural change here - since you are running within an Upstart session, "" shows jobs. To see, you can run either of the following:Let's create a job that pops upwhen it's started. Upstart 1.7 can read configuration files from multiple locations, but the main location for user jobs should be. For most folk, this equates to(Note that ifdid not exist initially, you will need to logout and back in for jobs in that directory to take effect - a one-off task)Now, create filecontaining:That's it. But to be sure we have specified the syntax correctly, let's check that Upstart is happy with it first:I'd recommend always usingto sanity-check your jobs. So, Upstart is happy with this job. Let's start it:And you should now see the wonderfully retrorunning. To stop the job simply run:Note that since we specified a " start on " and " stop on " stanza in thejob configuration file, this job will now run every time you login and stop just before you logout. If you don't want that to happen, you have a few choices:Now, that is more useful - firefox will now start when we login and stop just before we logout!But what if we want xclock to startfirefox starts and stop just before firefox stops? Simple, just change theandstanzas inError output from applications started from within a session (that is applications started from the Unity dash or launcher) still gets redirected to the usualfile. However,output from Upstart sessionis redirected automatically to,which equates toby default.Sinceis now running as an Upstart job, it too gets it own log file. By each job having its own log file, you can now identify where messages are coming from (not always obvious when perusing).We have included ajob that automatically keeps the Upstart logs conveniently compressed and rotated. In fact, if you discover whilst testing a job that it is starting to use too much space, or if you simply want to shrink the amount of space your logs are taking, you can run this job whenever you wish like this:Thejob () is rather interesting in that it changes its behavior based on whether it was started by the Session Init, or was invoked manually by a user. Study of this job could be instructive for those wishing to explore some of the possibilities provided by having Upstart manage your session.To use the GUI , you'll first need to install it (as it is not part of the core upstart package):If you have already enabled User Sessions, it will connect to your session. Otherwise, the default is to connect to the system Upstart (running as PID 1).This is my favourite example of the power of user jobs. Let's create a job that auto-starts a VoIP client when you plug in your USB headset.The skeleton of the job is simple. So, I'll createcontaining:It's a start, but it's not terribly impressive is it? However, we can now "" and "" and Upstart will DTRT.But what about the ' start on ' condition? We need a way to tell Upstart when to start. The simplest way to ascertain this for your particular USB headset is to fire up the, plug in your headset and see what happens:As you can see, I get quite a few (15!) events for my USB headset, partly because it is providing multiple sound devices (headphones and a microphone). But which event do I need? Luckily, the answer is simple for sounds devices: theevent. So, let's copy it...... and paste it here:As you can see, that's a lot of information! The most important part of this event and the reason we chose theevent in the first place is highlighted below:The event containingdenotes that the "overall" headset device comprising multiple sound devices is "ready to use". So we have the correct type of event and we know that that event is only emitted when the device really is ready but we still need to identify the device uniquely. That might sound like an arduous task, but it really isn't so panic not! Since this is my workstation and since I know I've only got a single USB headset, all I have to do is select some unique value (or combination of values) from the variables in the above data.There are some variables you dowant to select on:What you are looking for ideally is one more more variables that are:Your mileage may vary (for example if you have multiple different USB headsets). However, for me,is sufficient and conveniently human-readable ;-)Back to oursession job. I can now specify thecondition:I've added a stop on condition too such that Upstart will stopjust before the desktop session ends (in case I forget to stop it myself). And that's it. To try it out, simply plug in your USB headset!An approximation of what is happening when the USB device is plugged in is:This example should give you a taste of the power you now have at your fingertips to harness system-level events in your own jobs :-)A summary of well-known user-level and system-level upstart jobs is available in themanual page.The above will not work if the device isat boot time. The problem is that although thewill emit the correct set of events for your device at boot time, your session won't have started at that point in time so there will be noto listen for them. So by the time your session starts, those events will have gone.Wouldn't it be great if you could create a job that would only start when a particular file got created? Well, now you can....Highly contrived, but let's startwhen the X session errors file gets modified:How about watching a directory for any activity?Now, xclock will get started when files get created, modified or deleted in the directoryOr maybe a file glob might be useful to you?Here, the "" application will be started to do something useful when your app creates "" files.Here's the result on my system: