github.com/ie310mu/ie310go/forks/golang.org/x/sys@v0.0.0-20190821095322-9a46783d4de5/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  // +build windows
     6  
     7  package mgr
     8  
     9  import (
    10  	"syscall"
    11  	"unicode/utf16"
    12  	"unsafe"
    13  
    14  	"github.com/ie310mu/ie310go/forks/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  }
    47  
    48  func toString(p *uint16) string {
    49  	if p == nil {
    50  		return ""
    51  	}
    52  	return syscall.UTF16ToString((*[4096]uint16)(unsafe.Pointer(p))[:])
    53  }
    54  
    55  func toStringSlice(ps *uint16) []string {
    56  	if ps == nil {
    57  		return nil
    58  	}
    59  	r := make([]string, 0)
    60  	for from, i, p := 0, 0, (*[1 << 24]uint16)(unsafe.Pointer(ps)); true; i++ {
    61  		if p[i] == 0 {
    62  			// empty string marks the end
    63  			if i <= from {
    64  				break
    65  			}
    66  			r = append(r, string(utf16.Decode(p[from:i])))
    67  			from = i + 1
    68  		}
    69  	}
    70  	return r
    71  }
    72  
    73  // Config retrieves service s configuration paramteres.
    74  func (s *Service) Config() (Config, error) {
    75  	var p *windows.QUERY_SERVICE_CONFIG
    76  	n := uint32(1024)
    77  	for {
    78  		b := make([]byte, n)
    79  		p = (*windows.QUERY_SERVICE_CONFIG)(unsafe.Pointer(&b[0]))
    80  		err := windows.QueryServiceConfig(s.Handle, p, n, &n)
    81  		if err == nil {
    82  			break
    83  		}
    84  		if err.(syscall.Errno) != syscall.ERROR_INSUFFICIENT_BUFFER {
    85  			return Config{}, err
    86  		}
    87  		if n <= uint32(len(b)) {
    88  			return Config{}, err
    89  		}
    90  	}
    91  
    92  	b, err := s.queryServiceConfig2(windows.SERVICE_CONFIG_DESCRIPTION)
    93  	if err != nil {
    94  		return Config{}, err
    95  	}
    96  	p2 := (*windows.SERVICE_DESCRIPTION)(unsafe.Pointer(&b[0]))
    97  
    98  	return Config{
    99  		ServiceType:      p.ServiceType,
   100  		StartType:        p.StartType,
   101  		ErrorControl:     p.ErrorControl,
   102  		BinaryPathName:   toString(p.BinaryPathName),
   103  		LoadOrderGroup:   toString(p.LoadOrderGroup),
   104  		TagId:            p.TagId,
   105  		Dependencies:     toStringSlice(p.Dependencies),
   106  		ServiceStartName: toString(p.ServiceStartName),
   107  		DisplayName:      toString(p.DisplayName),
   108  		Description:      toString(p2.Description),
   109  	}, nil
   110  }
   111  
   112  func updateDescription(handle windows.Handle, desc string) error {
   113  	d := windows.SERVICE_DESCRIPTION{Description: toPtr(desc)}
   114  	return windows.ChangeServiceConfig2(handle,
   115  		windows.SERVICE_CONFIG_DESCRIPTION, (*byte)(unsafe.Pointer(&d)))
   116  }
   117  
   118  func updateSidType(handle windows.Handle, sidType uint32) error {
   119  	return windows.ChangeServiceConfig2(handle, windows.SERVICE_CONFIG_SERVICE_SID_INFO, (*byte)(unsafe.Pointer(&sidType)))
   120  }
   121  
   122  // UpdateConfig updates service s configuration parameters.
   123  func (s *Service) UpdateConfig(c Config) error {
   124  	err := windows.ChangeServiceConfig(s.Handle, c.ServiceType, c.StartType,
   125  		c.ErrorControl, toPtr(c.BinaryPathName), toPtr(c.LoadOrderGroup),
   126  		nil, toStringBlock(c.Dependencies), toPtr(c.ServiceStartName),
   127  		toPtr(c.Password), toPtr(c.DisplayName))
   128  	if err != nil {
   129  		return err
   130  	}
   131  	err = updateSidType(s.Handle, c.SidType)
   132  	if err != nil {
   133  		return err
   134  	}
   135  	return updateDescription(s.Handle, c.Description)
   136  }
   137  
   138  // queryServiceConfig2 calls Windows QueryServiceConfig2 with infoLevel parameter and returns retrieved service configuration information.
   139  func (s *Service) queryServiceConfig2(infoLevel uint32) ([]byte, error) {
   140  	n := uint32(1024)
   141  	for {
   142  		b := make([]byte, n)
   143  		err := windows.QueryServiceConfig2(s.Handle, infoLevel, &b[0], n, &n)
   144  		if err == nil {
   145  			return b, nil
   146  		}
   147  		if err.(syscall.Errno) != syscall.ERROR_INSUFFICIENT_BUFFER {
   148  			return nil, err
   149  		}
   150  		if n <= uint32(len(b)) {
   151  			return nil, err
   152  		}
   153  	}
   154  }