mirror of
				https://github.com/tailscale/tailscale.git
				synced 2025-10-31 08:11:32 +01:00 
			
		
		
		
	It has nothing to do with logtail and is confusing named like that. Updates #cleanup Updates #17323 Change-Id: Idd34587ba186a2416725f72ffc4c5778b0b9db4a Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
		
			
				
	
	
		
			137 lines
		
	
	
		
			3.4 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			137 lines
		
	
	
		
			3.4 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| // Copyright (c) Tailscale Inc & AUTHORS
 | |
| // SPDX-License-Identifier: BSD-3-Clause
 | |
| 
 | |
| //go:build go1.19
 | |
| 
 | |
| package main
 | |
| 
 | |
| import (
 | |
| 	"context"
 | |
| 	"errors"
 | |
| 	"fmt"
 | |
| 	"os"
 | |
| 	"time"
 | |
| 
 | |
| 	"golang.org/x/sys/windows"
 | |
| 	"golang.org/x/sys/windows/svc"
 | |
| 	"golang.org/x/sys/windows/svc/mgr"
 | |
| 	"tailscale.com/cmd/tailscaled/tailscaledhooks"
 | |
| 	"tailscale.com/types/logger"
 | |
| 	"tailscale.com/util/backoff"
 | |
| )
 | |
| 
 | |
| func init() {
 | |
| 	installSystemDaemon = installSystemDaemonWindows
 | |
| 	uninstallSystemDaemon = uninstallSystemDaemonWindows
 | |
| }
 | |
| 
 | |
| // serviceDependencies lists all system services that tailscaled depends on.
 | |
| // This list must be kept in sync with the TailscaledDependencies preprocessor
 | |
| // variable in the installer.
 | |
| var serviceDependencies = []string{
 | |
| 	"Dnscache",
 | |
| 	"iphlpsvc",
 | |
| 	"netprofm",
 | |
| 	"WinHttpAutoProxySvc",
 | |
| }
 | |
| 
 | |
| func installSystemDaemonWindows(args []string) (err error) {
 | |
| 	m, err := mgr.Connect()
 | |
| 	if err != nil {
 | |
| 		return fmt.Errorf("failed to connect to Windows service manager: %v", err)
 | |
| 	}
 | |
| 
 | |
| 	service, err := m.OpenService(serviceName)
 | |
| 	if err == nil {
 | |
| 		service.Close()
 | |
| 		return fmt.Errorf("service %q is already installed", serviceName)
 | |
| 	}
 | |
| 
 | |
| 	// no such service; proceed to install the service.
 | |
| 
 | |
| 	exe, err := os.Executable()
 | |
| 	if err != nil {
 | |
| 		return err
 | |
| 	}
 | |
| 
 | |
| 	c := mgr.Config{
 | |
| 		ServiceType:  windows.SERVICE_WIN32_OWN_PROCESS,
 | |
| 		StartType:    mgr.StartAutomatic,
 | |
| 		ErrorControl: mgr.ErrorNormal,
 | |
| 		Dependencies: serviceDependencies,
 | |
| 		DisplayName:  serviceName,
 | |
| 		Description:  "Connects this computer to others on the Tailscale network.",
 | |
| 	}
 | |
| 
 | |
| 	service, err = m.CreateService(serviceName, exe, c)
 | |
| 	if err != nil {
 | |
| 		return fmt.Errorf("failed to create %q service: %v", serviceName, err)
 | |
| 	}
 | |
| 	defer service.Close()
 | |
| 
 | |
| 	// Exponential backoff is often too aggressive, so use (mostly)
 | |
| 	// squares instead.
 | |
| 	ra := []mgr.RecoveryAction{
 | |
| 		{mgr.ServiceRestart, 1 * time.Second},
 | |
| 		{mgr.ServiceRestart, 2 * time.Second},
 | |
| 		{mgr.ServiceRestart, 4 * time.Second},
 | |
| 		{mgr.ServiceRestart, 9 * time.Second},
 | |
| 		{mgr.ServiceRestart, 16 * time.Second},
 | |
| 		{mgr.ServiceRestart, 25 * time.Second},
 | |
| 		{mgr.ServiceRestart, 36 * time.Second},
 | |
| 		{mgr.ServiceRestart, 49 * time.Second},
 | |
| 		{mgr.ServiceRestart, 64 * time.Second},
 | |
| 	}
 | |
| 	const resetPeriodSecs = 60
 | |
| 	err = service.SetRecoveryActions(ra, resetPeriodSecs)
 | |
| 	if err != nil {
 | |
| 		return fmt.Errorf("failed to set service recovery actions: %v", err)
 | |
| 	}
 | |
| 
 | |
| 	return nil
 | |
| }
 | |
| 
 | |
| func uninstallSystemDaemonWindows(args []string) (ret error) {
 | |
| 	for _, f := range tailscaledhooks.UninstallSystemDaemonWindows {
 | |
| 		f()
 | |
| 	}
 | |
| 
 | |
| 	m, err := mgr.Connect()
 | |
| 	if err != nil {
 | |
| 		return fmt.Errorf("failed to connect to Windows service manager: %v", err)
 | |
| 	}
 | |
| 	defer m.Disconnect()
 | |
| 
 | |
| 	service, err := m.OpenService(serviceName)
 | |
| 	if err != nil {
 | |
| 		return fmt.Errorf("failed to open %q service: %v", serviceName, err)
 | |
| 	}
 | |
| 
 | |
| 	st, err := service.Query()
 | |
| 	if err != nil {
 | |
| 		service.Close()
 | |
| 		return fmt.Errorf("failed to query service state: %v", err)
 | |
| 	}
 | |
| 	if st.State != svc.Stopped {
 | |
| 		service.Control(svc.Stop)
 | |
| 	}
 | |
| 	err = service.Delete()
 | |
| 	service.Close()
 | |
| 	if err != nil {
 | |
| 		return fmt.Errorf("failed to delete service: %v", err)
 | |
| 	}
 | |
| 
 | |
| 	bo := backoff.NewBackoff("uninstall", logger.Discard, 30*time.Second)
 | |
| 	end := time.Now().Add(15 * time.Second)
 | |
| 	for time.Until(end) > 0 {
 | |
| 		service, err = m.OpenService(serviceName)
 | |
| 		if err != nil {
 | |
| 			// service is no longer openable; success!
 | |
| 			break
 | |
| 		}
 | |
| 		service.Close()
 | |
| 		bo.BackOff(context.Background(), errors.New("service not deleted"))
 | |
| 	}
 | |
| 	return nil
 | |
| }
 |