func installService(name, desc string) error { exepath, err := exePath() if err != nil { return err } m, err := mgr.Connect() if err != nil { return err } defer m.Disconnect() s, err := m.OpenService(name) if err == nil { s.Close() return fmt.Errorf("service %s already exists", name) } s, err = m.CreateService(name, exepath, mgr.Config{DisplayName: desc}) if err != nil { return err } defer s.Close() err = eventlog.InstallAsEventCreate(name, eventlog.Error|eventlog.Warning|eventlog.Info) if err != nil { s.Delete() return fmt.Errorf("SetupEventLogSource() failed: %s", err) } return nil }
func controlService(name string, c svc.Cmd, to svc.State) error { m, err := mgr.Connect() if err != nil { return err } defer m.Disconnect() s, err := m.OpenService(name) if err != nil { return fmt.Errorf("could not access service: %v", err) } defer s.Close() status, err := s.Control(c) if err != nil { return fmt.Errorf("could not send control=%d: %v", c, err) } timeout := time.Now().Add(10 * time.Second) for status.State != to { if timeout.Before(time.Now()) { return fmt.Errorf("timeout waiting for service to go to state=%d", to) } time.Sleep(300 * time.Millisecond) status, err = s.Query() if err != nil { return fmt.Errorf("could not retrieve service status: %v", err) } } return nil }
// installService attempts to install the btcd service. Typically this should // be done by the msi installer, but it is provided here since it can be useful // for development. func installService() error { // Get the path of the current executable. This is needed because // os.Args[0] can vary depending on how the application was launched. // For example, under cmd.exe it will only be the name of the app // without the path or extension, but under mingw it will be the full // path including the extension. exePath, err := filepath.Abs(os.Args[0]) if err != nil { return err } if filepath.Ext(exePath) == "" { exePath += ".exe" } // Connect to the windows service manager. serviceManager, err := mgr.Connect() if err != nil { return err } defer serviceManager.Disconnect() // Ensure the service doesn't already exist. service, err := serviceManager.OpenService(svcName) if err == nil { service.Close() return fmt.Errorf("service %s already exists", svcName) } // Install the service. service, err = serviceManager.CreateService(svcName, exePath, mgr.Config{ DisplayName: svcDisplayName, Description: svcDesc, }) if err != nil { return err } defer service.Close() // Support events to the event log using the standard "standard" Windows // EventCreate.exe message file. This allows easy logging of custom // messges instead of needing to create our own message catalog. eventlog.Remove(svcName) eventsSupported := uint32(eventlog.Error | eventlog.Warning | eventlog.Info) err = eventlog.InstallAsEventCreate(svcName, eventsSupported) if err != nil { return err } return nil }
func TestOpenLanManServer(t *testing.T) { m, err := mgr.Connect() if err != nil { t.Fatalf("SCM connection failed: %s", err) } defer m.Disconnect() s, err := m.OpenService("lanmanserver") if err != nil { t.Fatalf("OpenService(lanmanserver) failed: %s", err) } _, err = s.Config() if err != nil { t.Fatalf("Config failed: %s", err) } defer s.Close() }
func startService(name string) error { m, err := mgr.Connect() if err != nil { return err } defer m.Disconnect() s, err := m.OpenService(name) if err != nil { return fmt.Errorf("could not access service: %v", err) } defer s.Close() err = s.Start([]string{"p1", "p2", "p3"}) if err != nil { return fmt.Errorf("could not start service: %v", err) } return nil }
func TestMyService(t *testing.T) { const name = "myservice" m, err := mgr.Connect() if err != nil { t.Fatalf("SCM connection failed: %s", err) } defer m.Disconnect() c := mgr.Config{ StartType: mgr.StartDisabled, DisplayName: "my service", Description: "my service is just a test", } exename := os.Args[0] exepath, err := filepath.Abs(exename) if err != nil { t.Fatalf("filepath.Abs(%s) failed: %s", exename, err) } install(t, m, name, exepath, c) s, err := m.OpenService(name) if err != nil { t.Fatalf("service %s is not installed", name) } defer s.Close() c.BinaryPathName = exepath c = testConfig(t, s, c) c.StartType = mgr.StartManual err = s.UpdateConfig(c) if err != nil { t.Fatalf("UpdateConfig failed: %v", err) } testConfig(t, s, c) remove(t, s) }
func removeService(name string) error { m, err := mgr.Connect() if err != nil { return err } defer m.Disconnect() s, err := m.OpenService(name) if err != nil { return fmt.Errorf("service %s is not installed", name) } defer s.Close() err = s.Delete() if err != nil { return err } err = eventlog.Remove(name) if err != nil { return fmt.Errorf("RemoveEventLogSource() failed: %s", err) } return nil }
// startService attempts to start the btcd service. func startService() error { // Connect to the windows service manager. serviceManager, err := mgr.Connect() if err != nil { return err } defer serviceManager.Disconnect() service, err := serviceManager.OpenService(svcName) if err != nil { return fmt.Errorf("could not access service: %v", err) } defer service.Close() err = service.Start(os.Args) if err != nil { return fmt.Errorf("could not start service: %v", err) } return nil }
// removeService attempts to uninstall the btcd service. Typically this should // be done by the msi uninstaller, but it is provided here since it can be // useful for development. Not the eventlog entry is intentionally not removed // since it would invalidate any existing event log messages. func removeService() error { // Connect to the windows service manager. serviceManager, err := mgr.Connect() if err != nil { return err } defer serviceManager.Disconnect() // Ensure the service exists. service, err := serviceManager.OpenService(svcName) if err != nil { return fmt.Errorf("service %s is not installed", svcName) } defer service.Close() // Remove the service. err = service.Delete() if err != nil { return err } return nil }
// controlService allows commands which change the status of the service. It // also waits for up to 10 seconds for the service to change to the passed // state. func controlService(c svc.Cmd, to svc.State) error { // Connect to the windows service manager. serviceManager, err := mgr.Connect() if err != nil { return err } defer serviceManager.Disconnect() service, err := serviceManager.OpenService(svcName) if err != nil { return fmt.Errorf("could not access service: %v", err) } defer service.Close() status, err := service.Control(c) if err != nil { return fmt.Errorf("could not send control=%d: %v", c, err) } // Send the control message. timeout := time.Now().Add(10 * time.Second) for status.State != to { if timeout.Before(time.Now()) { return fmt.Errorf("timeout waiting for service to go "+ "to state=%d", to) } time.Sleep(300 * time.Millisecond) status, err = service.Query() if err != nil { return fmt.Errorf("could not retrieve service "+ "status: %v", err) } } return nil }
func TestExample(t *testing.T) { const name = "myservice" m, err := mgr.Connect() if err != nil { t.Fatalf("SCM connection failed: %s", err) } defer m.Disconnect() dir, err := ioutil.TempDir("", "svc") if err != nil { t.Fatalf("failed to create temp directory: %v", err) } defer os.RemoveAll(dir) exepath := filepath.Join(dir, "a.exe") o, err := exec.Command("go", "build", "-o", exepath, "github.com/conseweb/winsvc/example").CombinedOutput() if err != nil { t.Fatalf("failed to build service program: %v\n%v", err, string(o)) } s, err := m.OpenService(name) if err == nil { err = s.Delete() if err != nil { s.Close() t.Fatalf("Delete failed: %s", err) } s.Close() } s, err = m.CreateService(name, exepath, mgr.Config{DisplayName: "my service"}) if err != nil { t.Fatalf("CreateService(%s) failed: %v", name, err) } defer s.Close() testState(t, s, svc.Stopped) err = s.Start(nil) if err != nil { t.Fatalf("Start(%s) failed: %s", s.Name, err) } waitState(t, s, svc.Running) time.Sleep(1 * time.Second) // testing deadlock from https://code.google.com/p/winsvc/issues/detail?id=4 _, err = s.Control(svc.Interrogate) if err != nil { t.Fatalf("Control(%s) failed: %s", s.Name, err) } _, err = s.Control(svc.Interrogate) if err != nil { t.Fatalf("Control(%s) failed: %s", s.Name, err) } time.Sleep(1 * time.Second) _, err = s.Control(svc.Stop) if err != nil { t.Fatalf("Control(%s) failed: %s", s.Name, err) } waitState(t, s, svc.Stopped) err = s.Delete() if err != nil { t.Fatalf("Delete failed: %s", err) } }