X

News, tips, partners, and perspectives for the Oracle Solaris operating system

An Introduction to Creating SMF Services

Guest Author
A while back I wrote an entry on how to access Windows shares. One limitation I ran into was the inability to mount the windows share at boot. A comment to my recent post on Startup Programs got me thinking about alternative solutions.













I presume I'm unable to mount the windows share at boot via the /etc/vfstab file because the smb client SMF service that is required hasn't started yet. Well then, why not create my own SMF service, that's dependent on the smb client, to handle the mount for me?

Well, the first problem is that I've never written an SMF service. This Service Developer Introduction, although not quite complete, did get me pointed in the right direction. After some trial and error, I now have my own service that mounts my Windows share at boot. Right or wrong, what follows are the steps I took to get there, and should roughly apply for any type of service you may be interested in creating.

Decide on a Name and Location for the Service Manifest

The service manifest is an XML file that describes your service. Before we begin writing it we need to decide where to put it and what to call it (and optionally what to create it with).

Pick a Location

The service manifest file resides somewhere under /var/svc/manifest. The existing smb client service manifest which my service depends on can be found at /var/svc/manifest/network/smb/client.xml, so this seems like a logical location to put my new service manifest.

Pick a Name

I'm going to call my service integrity, named after the Windows machine to which I'm connecting. So my service manifest will be /var/svc/manifest/network/smb/integrity.xml

Get a Good XML Editor

OK, this is optional, but I hate XML. One thing that makes working with it bearable is a good XML editor that will parse the DTD and provide code completion, syntax checking and validation. I will be using NetBeans. Since we'll be editing a privilged directory, start it from the terminal using "pfexec netbeans".

Write the Service Manifest 

The Service Manifest file has several required sections, which I'll introduce piece by piece. As I build up the file from scratch, each new piece that I introduce will be shown in bold type.

Define the DOCTYPE

Add the following two lines to the beginning of the XML file. If you've decided to use an XML editor, it will parse the DTD to provide code completion, etc.

<?xml version="1.0"?>
<!DOCTYPE service_bundle SYSTEM "/usr/share/lib/xml/dtd/service_bundle.dtd.1">

Define the Service Bundle

The service bundle has two attributes, type and name.  Since we're creating a service manifest, our type will be 'manifest'. The name is arbitrary - I'm using 'integrity':

<?xml version="1.0"?>
<!DOCTYPE service_bundle SYSTEM "/usr/share/lib/xml/dtd/service_bundle.dtd.1">
<service_bundle type="manifest" name="integrity">
</service_bundle>


Define the Service

Here we'll simply give our service a name, version and type:

<?xml version="1.0"?>
<!DOCTYPE service_bundle SYSTEM "/usr/share/lib/xml/dtd/service_bundle.dtd.1">
<service_bundle type="manifest" name="integrity">
    <service
        name="network/smb/integrity"
        type="service"
version="1" >
</service>
</service_bundle>

Identify if the Service may have Multiple Instances 

If I had multiple Windows shares to mount, this may be true. For now, to keep things simple, I'm going with a single instance:

<?xml version="1.0"?>
<!DOCTYPE service_bundle SYSTEM "/usr/share/lib/xml/dtd/service_bundle.dtd.1">
<service_bundle type="manifest" name="integrity">
<service
name="integrity"
type="service"
version="1" >
<single_instance/>
</service>
</service_bundle>

Define the Dependencies (if any) 

In my case, there's no point in trying to connect to the Windows share if the SMB client isn't running:

<?xml version="1.0"?>
<!DOCTYPE service_bundle SYSTEM "/usr/share/lib/xml/dtd/service_bundle.dtd.1">
<service_bundle type="manifest" name="integrity">
<service
name="integrity"
type="service"
version="1" >
<single_instance/>
<!--

Dependencies. The SMB client must be enabled before shares can be

mounted.

-->
<dependency
name="client"
type="service"
grouping="reqiure_all"
restart_on="none">
<service_fmri value="svc:/network/smb/client"/>
</dependency>

</service>
</service_bundle>

Note, I've configured this service to never restart. I could possibly look into making the service more robust in the future, but this will serve my needs for now.

Define the Instance Name

My service has a single default instance. The guidelines recommend that all services be delivered as disabled,
unless they are critical to system boot. I'm not really "delivering"
this service to anyone but myself, but I've followed that
convention:

<?xml version="1.0"?>
<!DOCTYPE service_bundle SYSTEM "/usr/share/lib/xml/dtd/service_bundle.dtd.1">
<service_bundle type="manifest" name="integrity">
<service
name="integrity"
type="service"
version="1" >
<single_instance/>
<!--

Dependencies. The SMB client must be enabled before shares can be

mounted.

-->
<dependency
name="client"
type="service"
grouping="reqiure_all"
restart_on="none">
<service_fmri value="svc:/network/smb/client"/>
</dependency>
<instance name="default" enabled="false">
</instance>

</service>
</service_bundle>

Define the Start and Stop Methods

This is the meat of the service, the job we're asking it to do. The service could call a script, but in my case I simply want to run mount and umount commands:

<?xml version="1.0"?>
<!DOCTYPE service_bundle SYSTEM "/usr/share/lib/xml/dtd/service_bundle.dtd.1">
<service_bundle type="manifest" name="integrity">
<service
name="integrity"
type="service"
version="1" >
<single_instance/>
<!--

Dependencies. The SMB client must be enabled before shares can be

mounted.

-->
<dependency
name="client"
type="service"
grouping="reqiure_all"
restart_on="none">
<service_fmri value="svc:/network/smb/client"/>
</dependency>
<instance name="default" enabled="false">
<!-- Start method: mounts the share -->
<exec_method
type="method"
name="start"
exec="mount //integrity.local/MyDocuments"
timeout_seconds="30"/>
<!-- Stop method: umounts the share -->
<exec_method
type="method"
name="stop"
exec="umount //integrity.local/MyDocuments"
timeout_seconds="30" />

</instance>
</service>
</service_bundle

Define the Property Group

Since this is a configuration service (no processes are started), we have to specify its type in the manifest as transient. If we were writing a service for a process, this entry could be left out:

<⁞?xml version="1.0"?>
<!DOCTYPE service_bundle SYSTEM "/usr/share/lib/xml/dtd/service_bundle.dtd.1">
<service_bundle type="manifest" name="integrity">
<service
name="integrity"
type="service"
version="1" >
<single_instance/>
<!--

Dependencies. The SMB client must be enabled before shares can be

mounted.

-->
<dependency
name="client"
type="service"
grouping="require_all"
restart_on="none">
<service_fmri value="svc:/network/smb/client"/>
</dependency>
<instance name="default" enabled="false">
<!-- Start method: mounts the share -->
<exec_method
type="method"
name="start"
exec="mount //integrity.local/MyDocuments"
timeout_seconds="30"/>
<!-- Stop method: umounts the share -->
<exec_method
type="method"
name="stop"
exec="umount //integrity.local/MyDocuments"
timeout_seconds="30" />
<property_group name="startd" type="framework">
<propval name="duration" type="astring" value="transient"/>
</property_group>

</instance>
</service>
</service_bundle>

Describe the Service

Finally we describe the service. This is the information that will appear when we query the service using the svcs command:

<?xml version="1.0"?>
<!DOCTYPE service_bundle SYSTEM "/usr/share/lib/xml/dtd/service_bundle.dtd.1">
<service_bundle type="manifest" name="integrity">
<service
name="integrity"
type="service"
version="1" >
<single_instance/>
<!--

Dependencies. The SMB client must be enabled before shares can be

mounted.

-->
<dependency
name="client"
type="service"
grouping="reqiure_all"
restart_on="none">
<service_fmri value="svc:/network/smb/client"/>
</dependency>
<instance name="default" enabled="false">
<!-- Start method: mounts the share -->
<exec_method
type="method"
name="start"
exec="mount //integrity.local/MyDocuments"
timeout_seconds="30"/>
<!-- Stop method: umounts the share -->
<exec_method
type="method"
name="stop"
exec="umount //integrity.local/MyDocuments"
timeout_seconds="30" />
<property_group name="startd" type="framework">
<propval name="duration" type="astring" value="transient"/>
</property_group>
</instance>
<template>
<common_name>
<loctext xml:lang="C">
integrity.local smb share configuration
</loctext>
</common_name>
</template>

</service>
</service_bundle>

Check and Validate Your XML

If you are using an XML editor such as NetBeans, verify your XML parses correctly and validates against the DTD.

Install the Service

Once the service is defined, it needs to be installed. This can be done with the svccfg command as follows:

svccfg import /var/svc/manifest/network/smb/integrity.xml

Manage Your Service

You can then manage your service like any other.

Query

bleonard@opensolaris:~$ svcs integrity
STATE STIME FMRI
disabled 12:43:40 svc:/integrity:default

Start

svcadm enable integrity

Verbose Query

bleonard@opensolaris:~$ svcs -l integrity
fmri svc:/integrity:default
name integrity.local smb share configuration
enabled true
state online
next_state none
state_time Thu Nov 20 12:43:40 2008
logfile /var/svc/log/integrity:default.log
restarter svc:/system/svc/restarter:default
dependency require_all/none svc:/network/smb/client (online)

Notice your service even has its own log file...

bleonard@opensolaris:~$ cat /var/svc/log/integrity:default.log
[ Nov 20 12:45:57 Enabled. ]
[ Nov 20 12:45:57 Executing start method ("mount //integrity.local/MyDocuments"). ]
[ Nov 20 12:45:57 Method "start" exited with status 0. ] 

And Most Importantly...

It accomplishes it's task, in this case mounting my Windows share at boot:

bleonard@opensolaris:~/IntegrityDocs$ ls
Calphalon.odt My Faxes My Videos Our Money.mny Software My Music
My eBooks My Pictures

Join the discussion

Comments ( 7 )
  • goddard Thursday, November 20, 2008

    that's cool :) i actually wanted to read and then write something about smf in czech ;)


  • rob Friday, November 21, 2008

    Thanx been looking for a good example of making a SMF service for a while.


  • bithin Thursday, November 27, 2008

    How can we integrate VISUAL PANAL with SMF


  • William Leonard Wednesday, December 3, 2008

    bithin, can you elaborate on your question? As far as I understand Visual Panels, they only work with SMF services today.


  • Joseph Sniderman Thursday, December 25, 2008

    Beautiful!

    You explain so clearly how to create an SMF service, which is something I have wanted to learn how to do for a long time.

    Of all the great features Solaris has, SMF is the one that keeps me loyal. I love it!


  • Ransford Friday, October 16, 2009

    Can I do this in my exec-method "java -jar lightsky.jar"

    so it starts the application?, I tried but it didnt work


  • Deepak Wednesday, August 25, 2010

    Nice article, was helpful.


Please enter your name.Please provide a valid email address.Please enter a comment.CAPTCHA challenge response provided was incorrect. Please try again.