| 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. |