|  | Windows Service Support for svnserve | 
|  | ==================================== | 
|  |  | 
|  | svnserve can now be run as a native Windows service.  This means that the | 
|  | service can be started at system boot, or at any other time, without the | 
|  | need for any wrapper code to start the service.  The service can be managed | 
|  | like any other Windows service, using command-line tools ("net start", | 
|  | "net stop", or sc.exe) or GUI tools (the Services administrative tool). | 
|  |  | 
|  |  | 
|  | Installation | 
|  | ------------ | 
|  |  | 
|  | For now, no means is provided to install the service.  Most Windows | 
|  | OSes derived from Windows NT (such as Windows XP, Windows 2000, | 
|  | Windows 2003 Server) provide a command-line tool for installing | 
|  | services, called SC.EXE for "Service Control". To create a service for | 
|  | svnserve, use SC.EXE: | 
|  |  | 
|  | sc create <name> | 
|  | binpath= "c:\svn\bin\svnserve.exe --service <svn-args>" | 
|  | displayname= "Subversion Repository" | 
|  | depend= Tcpip | 
|  |  | 
|  | where <name> is any service name you want, e.g. "svnserve", and | 
|  | <svn-args> are the arguments to svnserve, such as --root, | 
|  | --listen-port, etc.  (All of this should be specified on a single | 
|  | line, of course.) | 
|  |  | 
|  | In order for svnserve to run as a Windows service, you MUST specify | 
|  | the --service argument, and you must NOT specify any other run mode | 
|  | argument, such as --daemon, --tunnel, --inetd, or any of their short | 
|  | forms.  There is no short form for --service. | 
|  |  | 
|  | If the path to svnserve.exe contains spaces or other characters that | 
|  | must be escaped, then you must enclose the path to svnserve.exe with | 
|  | double-quotes, which themselves must be quoted using a backslash. | 
|  | Fortunately the syntax is similar to that on Unix platforms: | 
|  |  | 
|  | sc create <name> | 
|  | binpath= "\"c:\program files\subversion\bin\svnserve.exe\" ..." | 
|  |  | 
|  | SC has many options; use "sc /?".  The most relevant are: | 
|  |  | 
|  | sc create <name>     create a new service | 
|  | sc qc <name>         query config for a service | 
|  | sc query <name>      query status | 
|  | sc delete <name>     delete any service -- BE CAREFUL! | 
|  | sc config <name> ... update service config; same args as sc create | 
|  | sc start <name>      start a service (does NOT wait for completion!) | 
|  | sc stop <name>       stop a service (does NOT wait for it to stop!) | 
|  |  | 
|  | Note that the command-line syntax for SC is rather odd.  Key/value | 
|  | pairs are specified as "key= value" (without the double-quotes).  The | 
|  | "key=" part must not have any spaces, and the "value" part MUST be | 
|  | separated from the "key=" by a space. | 
|  |  | 
|  | If you want to be able to see the command shell, add these arguments | 
|  | to the "sc create" command-line: | 
|  |  | 
|  | type= own type= interact | 
|  |  | 
|  | This sets the "interactive" bit on the service, which allows it to | 
|  | interact with the local console session. | 
|  |  | 
|  | You can create as many services as you need; there is no restriction | 
|  | on the number of services, or their names.  I use a prefix, like | 
|  | "svn.foo", "svn.bar", etc.  Each service runs in a separate process. | 
|  | As usual, it is your responsbility as an administrator to make sure | 
|  | that no two service instances use the same repository root path, or | 
|  | the same combination of --listen-port and --listen-host. | 
|  |  | 
|  |  | 
|  | Uninstalling | 
|  | ------------ | 
|  |  | 
|  | To uninstall a service, stop the service, then delete it, using "sc | 
|  | delete <name>".  Be very careful with this command, since you can | 
|  | delete any system service, including essential Windows services, | 
|  | accidentally. | 
|  |  | 
|  | Also, make sure that you stop the service before you delete it.  If | 
|  | you delete the service before stopping it, the Service Control Manager | 
|  | will mark the service "deleted", but will intentionally not stop the | 
|  | service.  The service will be deleted when the system reboots, or when | 
|  | the service finally exits.  After all, you only asked to delete the | 
|  | service, not to stop it. | 
|  |  | 
|  | That's all there is to it. | 
|  |  | 
|  |  | 
|  | Automatically Starting Service on System Boot | 
|  | --------------------------------------------- | 
|  |  | 
|  | By default, SC creates the service with the start mode set to "demand" | 
|  | (manual).  If you want the service to start automatically when the | 
|  | system boots, add "start= auto" to the command line.  You can change | 
|  | the start mode for an existing service using "sc config <name> start= | 
|  | auto", or also by using the Windows GUI interface for managing | 
|  | services.  (Start, All Programs, Administrative Tools, Services, or | 
|  | just run "services.msc" from Start/Run or from a command-line.) | 
|  |  | 
|  | Note: In order for svnserve to start correctly on system boot, you | 
|  | must properly declare its startup dependencies.  The Service Control | 
|  | Manager will start services as early as it can, and if you do not | 
|  | properly declare its startup dependencies, it can potentially start | 
|  | before the TCP/IP stack has been started.  This is why you must | 
|  | provide specify 'depend= Tcpip' to SC.EXE when creating the service. | 
|  |  | 
|  |  | 
|  | Starting and Stopping the Service | 
|  | --------------------------------- | 
|  |  | 
|  | You start and stop the service like any other Windows service.  You | 
|  | can use the command-line "net start <name>", use the GUI Services | 
|  | interface. | 
|  |  | 
|  |  | 
|  | Debugging | 
|  | --------- | 
|  |  | 
|  | Debugging a Windows service can be difficult, because the service runs | 
|  | in a very different context than a user who is logged in.  By default, | 
|  | services run in a "null" desktop environment.  They cannot interact | 
|  | with the user (desktop) in any way, and vice versa. | 
|  |  | 
|  | Also, by default, services run as a special user, called LocalSystem. | 
|  | LocalSystem is not a "user" in the normal sense; it is an NT security | 
|  | ID (SID) that is sort of like root, but different.  LocalSystem | 
|  | typically does NOT have access to any network shares, even if you use | 
|  | "net use" to connect to a remote file server.  Again, this is because | 
|  | services run in a different login session. | 
|  |  | 
|  | Depending on which OS you are running, you may have difficulty | 
|  | attaching a debugger to a running service process.  Also, if you are | 
|  | having trouble *starting* a service, then you can't attach to the | 
|  | process early enough to debug it. | 
|  |  | 
|  | So what's a developer to do?  Well, there are several ways you can | 
|  | debug services.  First, you'll want to enable "interactive" access for | 
|  | the service.  This allows the service to interact with the local | 
|  | desktop -- you'll be able to see the command shell that the service | 
|  | runs in, see console output, etc.  To do this, you can either use the | 
|  | standard Windows Services tool (services.msc), or you can do it using | 
|  | sc.exe. | 
|  |  | 
|  | * With the GUI tool, open the properties page for a service, and go | 
|  | to the "Log On" page.  Select "Local System account", and make | 
|  | sure the "Allow service to interact with desktop" box is checked. | 
|  |  | 
|  | * With SC.EXE, configure the service using the command: | 
|  |  | 
|  | sc <name> config type= own type= interact | 
|  |  | 
|  | Yes, you must specify type= twice, and with exactly the spacing | 
|  | shown. | 
|  |  | 
|  | In both cases, you'll need to restart the service.  When you do, if | 
|  | the service started successfully, you'll see the console window of the | 
|  | service.  By default, it doesn't print anything out. | 
|  |  | 
|  | Next, you'll want to attach a debugger, or configure the service to | 
|  | start under a debugger.  Attaching a debugger should be | 
|  | straightforward -- just find the process ID.  But if you need to debug | 
|  | something in the service startup path, you'll need to have a debugger | 
|  | attached from the very beginning.  There are two ways to do this. | 
|  |  | 
|  | In the first method, you alter the command-line of the service (called | 
|  | the "binary path").  To do this, use SC.EXE to set the binary path to | 
|  | whatever debugger you are going to use.  I use the most recent version | 
|  | of WinDbg, which is excellent, and is available at: | 
|  |  | 
|  | http://www.microsoft.com/whdc/devtools/debugging/installx86.mspx | 
|  |  | 
|  | For example, this command would configure the service to start under a | 
|  | debugger: | 
|  |  | 
|  | sc config <name> binpath= "d:\dbg\windbg.exe -g -G d:\svn\bin\svnserve.exe | 
|  | --root d:\path\root --listen-port 9000" | 
|  | depend= Tcpip | 
|  |  | 
|  | The entire command must be on a single line, of course, and the binary | 
|  | path must be in double-quotes.  Also, the spacing MUST be: binpath= "..." | 
|  |  | 
|  | Substitute whatever debugger you want, with whatever command-line you | 
|  | want, in place of windbg.exe.  Then start the service (sc start | 
|  | <name>), and the Service Control Manager should execute the | 
|  | command-line you provided as the binary path.  Then your debugger | 
|  | should start, and should launch the svnserve process. | 
|  |  | 
|  |  | 
|  | Known Issues | 
|  | ------------ | 
|  |  | 
|  | * No management tool (installer, etc.).  For the first version, this | 
|  | is intentional; we just want to get the service functionality tested | 
|  | and committed before dealing with installation. | 
|  |  | 
|  | * Right now, I don't know of a way to cleanly stop the svnserve | 
|  | process.  Instead, the implementation closes the listen socket, | 
|  | which causes the main loop to exit.  This isn't as bad as it sounds, | 
|  | and is a LOT better than other options (such as terminating a | 
|  | thread). | 
|  |  | 
|  |  | 
|  | To Do | 
|  | ----- | 
|  |  | 
|  | * The support for running svnserve as a Windows service is complete, | 
|  | but there is still more work to be done for installing and managing | 
|  | services. |