An Introduction to Creating SMF Services

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  
Comments:

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

Posted by goddard on November 20, 2008 at 10:42 PM GMT #

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

Posted by rob on November 21, 2008 at 03:41 AM GMT #

How can we integrate VISUAL PANAL with SMF

Posted by bithin on November 27, 2008 at 09:06 PM GMT #

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

Posted by William Leonard on December 03, 2008 at 01:41 PM GMT #

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!

Posted by Joseph Sniderman on December 25, 2008 at 10:03 AM GMT #

Can I do this in my exec-method "java -jar lightsky.jar"
so it starts the application?, I tried but it didnt work

Posted by Ransford on October 16, 2009 at 05:47 AM GMT #

Nice article, was helpful.

Posted by Deepak on August 25, 2010 at 02:21 PM GMT #

Post a Comment:
  • HTML Syntax: NOT allowed
About

The Observatory is a blog for users of Oracle Solaris. Tune in here for tips, tricks and more as we explore the Solaris operating system from Oracle.

Connect with Oracle Solaris:


Search

Archives
« July 2014
SunMonTueWedThuFriSat
  
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
  
       
Today