Stop FileMaker server from script

Posted by Simon Brown Tue, 20 Apr 2010 20:01:00 GMT

If you have a FileMaker system and you need to script the processing of adding or removing files on the server, the first problem you are going to come across is: how do I stop the server from a script?

You may already be familiar with the fmsadmin command. This is present on both Mac OS and Windows installs of FileMaker server. You can simply run the following command in Terminal to stop the server:

fmsadmin stop server

The difficulty is that this command normally expects a live user to key in some information to complete the command. In particular, a password must be supplied.

How do we stop the server from a script then?

fmsadmin -uYourAccount -pYourPassword -y -t300 stop server

Here we have supplied the user name and password, plus the -y option to answer that yes, we really want to stop the server, and -t to allow users up to 5 minutes to log off the database files.

Somewhat incongruously, to restart the server when done you simply use:

fmsadmin start server

No user or password is required.

Other Methods

On the Mac OS, if your script is running as root, you could’ve also used launchctl to stop the server:

launchctl stop com.filemaker.fms

The main downside to this is that you can’t specify a grace period to disconnect users. Also, if your script isn’t currently running as root, you’d have to use the sudo command to make command execute as root, and the expect command to supply a password to sudo.

For Windows, you do something similar to launchctl on OSX to stop the FileMaker database service:

net stop "FileMaker Server 8"

Kill Command

On OSX, you will almost never want to use the kill or killall command on the fmserverd process. If you do, the launchd daemon will almost immediately restart the server process. If for some you do need to use this command, perhaps because a server is not responding normally, perform in this order for best results:

sudo launchctl stop com.filemaker.fms
sudo killall fmserver_helperd
sudo killall fmserverd

Even more dangerous is to use kill -9, which is likely to cause any open files to be corrupted. If you must force quite the server, first disable or disconnect the network connection on the server, wait at least a minute, and only then force quite the fmserverd process. This should reduce the chances of your database being corrupted.

Trackbacks

Use the following link to trackback from your own site:
http://buzz.beezwax.net/trackbacks?article_id=37

Comments

Leave a comment

  1. Wim Decorte 1 day later:

    The article fails to mention that the best practice is to first - disconnect all clients - then close all files before attempting to stop filemaker server (database engine). Almost never should you try to stop FMS from hosting by stopping the underlying OS service or daemon.

    Disconnecting clients and closing files can also be done from the command line using the “fmsadmin” command. Below is a VBscript that does just that:

    ’ Author: Wim Decorte ’ Version: 2.0 ’ Description: Uses the FileMaker Server 10 command line to disconnect ’ all users And close all hosted files ’ ’ This is a basic example. This script is not meant as a finished product, ’ its only purpose is as a learning & demo tool. ’ ’ This script does not have full Error handling. ’ For instance, it will break if there are spaces in the FM file names. ’ The script also does not handle infinite loops in disconnecting clients ’ or closing files. ’ ’ This script is provided as is, without any implied warranty or support.

    Const WshFinished = 1 q = Chr(34) ’ the ” character, needed to wrap around paths with spaces

    ‘——————————————————————————————– ’ Change these variables to match your setup

    theAdminUser = “” theAdminPW = “” pathToSAtool = “C:\Program Files\FileMaker\FileMaker Server\Database Server\fmsadmin.exe”

    ‘——————————————————————————————–

    SAT = “cmd /c ” & q & pathToSAtool & q & ” ” ’ watch the trailing space

    callFMS = SAT If Len(theAdminUser) > 0 Then

    callFMS = callFMS & " -u " & theAdminUser
    

    End If If Len(theAdminPW) > 0 Then

    callFMS = callFMS & " -p " & theAdminPW
    

    End If

    listClients = callFMS & ” list clients” disconnectClients = callFMS & ” disconnect client -y” listfiles = callFMS & ” list files -s” closeFiles = callFMS & ” close file ” stopServer = callFMS & ” stop server -y -t 15”

    ’ hook into the Windows shell Set sh = WScript.CreateObject(“wscript.shell”)

    ’ get a list of all clients and force kick them off clientIDs = getCurrentClients() clientCount = UBound(clientIDs)

    ’ loop through the clients and kick them off If clientCount > 0 Then

        fullCommand = disconnectClients
        Set oExec = sh.Exec(fullCommand)
        ' give FMS some time and then requery the list of clients
        Do Until oExec.Status = WshFinished
            WScript.Sleep 50
        Loop
        Do Until clientCount = 0
            WScript.Sleep 1000
            Debug.WriteLine "Waiting for clients to disconnect..."
            clientIDs = getCurrentClients()
            clientCount = UBound(clientIDs)
        Loop
    

    End If

    ’ get list of files and close them fileIDs = getCurrentFiles() fileCount = UBound(fileIDs)

    ’ loop through the files and close them If fileCount > 0 Then

    Do Until fileCount = 0
        fullCommand = closeFiles & fileIDs(0) & " -y"
        Set oExec = sh.Exec(fullCommand)
        ' give FMS some time and then requery the list of files
        Do Until oExec.Status = WshFinished
            WScript.Sleep 50
        Loop
        fileIDs = getCurrentFiles()
        fileCount = UBound(fileIDs)
    
    Loop
    

    End If

    ’ all clients and files stopped ’ shut down the database sever (does not stop the FMS service!) fullCommand = stopServer Set oExec = sh.Exec(fullCommand) Do Until oExec.Status = WshFinished

    WScript.Sleep 50
    

    Loop

    ’ done, exit the script Set sh = Nothing WScript.Quit ’ ——————————————————————————

    Function getCurrentClients()

    tempCount = 0
    Dim tempArray()
    Set oExec = sh.Exec(listClients)
    
    ' in case there are no clients...
    If oexec.StdOut.AtEndOfStream Then Redim temparray(0)
    
    ' read the output of the command
    Do While Not oExec.StdOut.AtEndOfStream
        strText = oExec.StdOut.ReadLine()
        strText = Replace(strtext, vbTab, "")
        Do Until InStr(strtext, "  ") = 0
            strText = Replace (strtext, "  ", " ")
        Loop
        If InStr(strText, "Client ID User Name Computer Name Ext Privilege") > 0 OR _
            InStr(strText, "ommiORB") > 0 OR _
            InStr(strText, "IP Address Is invalid Or inaccessible") > 0 Then
            ' do nothing
            Redim temparray(0)
        Else
            tempClient = Split(strtext, " ")
            tempCount = tempCount + 1
            Redim Preserve tempArray(tempCount)
            tempArray(tempCount-1) = tempClient(0)
        End If
    Loop
    
    getCurrentClients = tempArray
    

    End Function

    Function getCurrentFiles()

    tempCount = 0
    Dim tempArray()
    Set oExec = sh.Exec(listfiles)
    
    ' in case there are no files...
    If oexec.StdOut.AtEndOfStream Then Redim temparray(0)
    
    ' read the output of the command
    Do While Not oExec.StdOut.AtEndOfStream
        strText = oExec.StdOut.ReadLine()
        strText = Replace(strtext, vbTab, "")
        Do Until InStr(strtext, "  ") = 0
            strText = Replace (strtext, "  ", " ")
        Loop
        If InStr(strText, "ID File Clients Size Status Enabled Extended Privileges") > 0 OR _
            InStr(strText, "ommiORB") > 0 OR _
            InStr(strText, "IP Address Is invalid Or inaccessible") > 0 OR _
            Left(strtext, 2) = "ID" Then
            ' do nothing
            Redim temparray(0)
        Else
            tempFile = Split(strtext, " ")
            status = LCase(tempFile(4))
            If status = "normal" Then
                tempCount = tempCount + 1
                Redim Preserve tempArray(tempCount)
                tempArray(tempCount - 1) = tempFile(1) & ".fp7"
            End If
        End If
    Loop
    
    getCurrentFiles = tempArray
    

    End Function

Comments