golang.org/x/sys@v0.9.0/windows/svc/mgr/config.go (about)

     1  // Copyright 2012 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  //go:build windows
     6  // +build windows
     7  
     8  package mgr
     9  
    10  import (
    11  	"syscall"
    12  	"unsafe"
    13  
    14  	"golang.org/x/sys/windows"
    15  )
    16  
    17  const (
    18  	// Service start types.
    19  	StartManual    = windows.SERVICE_DEMAND_START // the service must be started manually
    20  	StartAutomatic = windows.SERVICE_AUTO_START   // the service will start by itself whenever the computer reboots
    21  	StartDisabled  = windows.SERVICE_DISABLED     // the service cannot be started
    22  
    23  	// The severity of the error, and action taken,
    24  	// if this service fails to start.
    25  	ErrorCritical = windows.SERVICE_ERROR_CRITICAL
    26  	ErrorIgnore   = windows.SERVICE_ERROR_IGNORE
    27  	ErrorNormal   = windows.SERVICE_ERROR_NORMAL
    28  	ErrorSevere   = windows.SERVICE_ERROR_SEVERE
    29  )
    30  
    31  // TODO(brainman): Password is not returned by windows.QueryServiceConfig, not sure how to get it.
    32  
    33  type Config struct {
    34  	ServiceType      uint32
    35  	StartType        uint32
    36  	ErrorControl     uint32
    37  	BinaryPathName   string // fully qualified path to the service binary file, can also include arguments for an auto-start service
    38  	LoadOrderGroup   string
    39  	TagId            uint32
    40  	Dependencies     []string
    41  	ServiceStartName string // name of the account under which the service should run
    42  	DisplayName      string
    43  	Password         string
    44  	Description      string
    45  	SidType          uint32 // one of SERVICE_SID_TYPE, the type of sid to use for the service
    46  	DelayedAutoStart bool   // the service is started after other auto-start services are started plus a short delay
    47  }
    48  
    49  func toStringSlice(ps *uint16) []string {
    50  	r := make([]string, 0)
    51  	p := unsafe.Pointer(ps)
    52  
    53  	for {
    54  		s := windows.UTF16PtrToString((*uint16)(p))
    55  		if len(s) == 0 {
    56  			break
    57  		}
    58  
    59  		r = append(r, s)
    60  		offset := unsafe.Sizeof(uint16(0)) * (uintptr)(len(s)+1)
    61  		p = unsafe.Pointer(uintptr(p) + offset)
    62  	}
    63  
    64  	return r
    65  }
    66  
    67  // Config retrieves service s configuration paramteres.
    68  func (s *Service) Config() (Config, error) {
    69  	var p *windows.QUERY_SERVICE_CONFIG
    70  	n := uint32(1024)
    71  	for {
    72  		b := make([]byte, n)
    73  		p = (*windows.QUERY_SERVICE_CONFIG)(unsafe.Pointer(&b[0]))
    74  		err := windows.QueryServiceConfig(s.Handle, p, n, &n)
    75  		if err == nil {
    76  			break
    77  		}
    78  		if err.(syscall.Errno) != syscall.ERROR_INSUFFICIENT_BUFFER {
    79  			return Config{}, err
    80  		}
    81  		if n <= uint32(len(b)) {
    82  			return Config{}, err
    83  		}
    84  	}
    85  
    86  	b, err := s.queryServiceConfig2(windows.SERVICE_CONFIG_DESCRIPTION)
    87  	if err != nil {
    88  		return Config{}, err
    89  	}
    90  	p2 := (*windows.SERVICE_DESCRIPTION)(unsafe.Pointer(&b[0]))
    91  
    92  	b, err = s.queryServiceConfig2(windows.SERVICE_CONFIG_DELAYED_AUTO_START_INFO)
    93  	if err != nil {
    94  		return Config{}, err
    95  	}
    96  	p3 := (*windows.SERVICE_DELAYED_AUTO_START_INFO)(unsafe.Pointer(&b[0]))
    97  	delayedStart := false
    98  	if p3.IsDelayedAutoStartUp != 0 {
    99  		delayedStart = true
   100  	}
   101  
   102  	b, err = s.queryServiceConfig2(windows.SERVICE_CONFIG_SERVICE_SID_INFO)
   103  	if err != nil {
   104  		return Config{}, err
   105  	}
   106  	sidType := *(*uint32)(unsafe.Pointer(&b[0]))
   107  
   108  	return Config{
   109  		ServiceType:      p.ServiceType,
   110  		StartType:        p.StartType,
   111  		ErrorControl:     p.ErrorControl,
   112  		BinaryPathName:   windows.UTF16PtrToString(p.BinaryPathName),
   113  		LoadOrderGroup:   windows.UTF16PtrToString(p.LoadOrderGroup),
   114  		TagId:            p.TagId,
   115  		Dependencies:     toStringSlice(p.Dependencies),
   116  		ServiceStartName: windows.UTF16PtrToString(p.ServiceStartName),
   117  		DisplayName:      windows.UTF16PtrToString(p.DisplayName),
   118  		Description:      windows.UTF16PtrToString(p2.Description),
   119  		DelayedAutoStart: delayedStart,
   120  		SidType:          sidType,
   121  	}, nil
   122  }
   123  
   124  func updateDescription(handle windows.Handle, desc string) error {
   125  	d := windows.SERVICE_DESCRIPTION{Description: toPtr(desc)}
   126  	return windows.ChangeServiceConfig2(handle,
   127  		windows.SERVICE_CONFIG_DESCRIPTION, (*byte)(unsafe.Pointer(&d)))
   128  }
   129  
   130  func updateSidType(handle windows.Handle, sidType uint32) error {
   131  	return windows.ChangeServiceConfig2(handle, windows.SERVICE_CONFIG_SERVICE_SID_INFO, (*byte)(unsafe.Pointer(&sidType)))
   132  }
   133  
   134  func updateStartUp(handle windows.Handle, isDelayed bool) error {
   135  	var d windows.SERVICE_DELAYED_AUTO_START_INFO
   136  	if isDelayed {
   137  		d.IsDelayedAutoStartUp = 1
   138  	}
   139  	return windows.ChangeServiceConfig2(handle,
   140  		windows.SERVICE_CONFIG_DELAYED_AUTO_START_INFO, (*byte)(unsafe.Pointer(&d)))
   141  }
   142  
   143  // UpdateConfig updates service s configuration parameters.
   144  func (s *Service) UpdateConfig(c Config) error {
   145  	err := windows.ChangeServiceConfig(s.Handle, c.ServiceType, c.StartType,
   146  		c.ErrorControl, toPtr(c.BinaryPathName), toPtr(c.LoadOrderGroup),
   147  		nil, toStringBlock(c.Dependencies), toPtr(c.ServiceStartName),
   148  		toPtr(c.Password), toPtr(c.DisplayName))
   149  	if err != nil {
   150  		return err
   151  	}
   152  	err = updateSidType(s.Handle, c.SidType)
   153  	if err != nil {
   154  		return err
   155  	}
   156  
   157  	err = updateStartUp(s.Handle, c.DelayedAutoStart)
   158  	if err != nil {
   159  		return err
   160  	}
   161  
   162  	return updateDescription(s.Handle, c.Description)
   163  }
   164  
   165  // queryServiceConfig2 calls Windows QueryServiceConfig2 with infoLevel parameter and returns retrieved service configuration information.
   166  func (s *Service) queryServiceConfig2(infoLevel uint32) ([]byte, error) {
   167  	n := uint32(1024)
   168  	for {
   169  		b := make([]byte, n)
   170  		err := windows.QueryServiceConfig2(s.Handle, infoLevel, &b[0], n, &n)
   171  		if err == nil {
   172  			return b, nil
   173  		}
   174  		if err.(syscall.Errno) != syscall.ERROR_INSUFFICIENT_BUFFER {
   175  			return nil, err
   176  		}
   177  		if n <= uint32(len(b)) {
   178  			return nil, err
   179  		}
   180  	}
   181  }