From c5630a890652f7251aa63c3342813194cbf8b986 Mon Sep 17 00:00:00 2001 From: mpl Date: Mon, 18 Aug 2014 18:16:46 +0200 Subject: [PATCH] osutil: selfpath for windows, and make it public. Change-Id: Ic3e8de6e75651921cb29e3b5e91cdb9f5159896a --- pkg/osutil/restart_stub.go | 14 +++++++-- pkg/osutil/restart_unix.go | 17 +++++++---- pkg/osutil/restart_windows.go | 54 +++++++++++++++++++++++++++++++++++ 3 files changed, 77 insertions(+), 8 deletions(-) create mode 100644 pkg/osutil/restart_windows.go diff --git a/pkg/osutil/restart_stub.go b/pkg/osutil/restart_stub.go index 28d46ab8a..cfb51a6af 100644 --- a/pkg/osutil/restart_stub.go +++ b/pkg/osutil/restart_stub.go @@ -1,4 +1,4 @@ -// +build windows appengine +// +build appengine /* Copyright 2012 The Camlistore Authors. @@ -19,13 +19,21 @@ limitations under the License. package osutil import ( + "errors" "log" + "runtime" ) -// restartProcess returns an error if things couldn't be +// SelfPath returns the path of the executable for the currently running +// process. +func SelfPath() (string, error) { + return "", errors.New("SelfPath not implemented on App Engine.") +} + +// RestartProcess returns an error if things couldn't be // restarted. On success, this function never returns // because the process becomes the new process. func RestartProcess() error { - log.Print("RestartProcess not implemented on windows") + log.Print("RestartProcess not implemented on this platform.") return nil } diff --git a/pkg/osutil/restart_unix.go b/pkg/osutil/restart_unix.go index 61ad64cc9..3fba01f8e 100644 --- a/pkg/osutil/restart_unix.go +++ b/pkg/osutil/restart_unix.go @@ -21,6 +21,7 @@ package osutil import ( "errors" + "fmt" "os" "runtime" "syscall" @@ -29,7 +30,13 @@ import ( // if non-nil, osSelfPath is used from selfPath. var osSelfPath func() (string, error) -func selfPath() (string, error) { +// TODO(mpl): document the symlink behaviour in SelfPath for the BSDs when +// I know for sure. + +// SelfPath returns the path of the executable for the currently running +// process. At least on linux, the returned path is a symlink to the actual +// executable. +func SelfPath() (string, error) { if f := osSelfPath; f != nil { return f() } @@ -45,16 +52,16 @@ func selfPath() (string, error) { // See https://codereview.appspot.com/6736069/ return os.Args[0], nil } - return "", errors.New("No restart because selfPath() not implemented for " + runtime.GOOS) + return "", errors.New("SelfPath not implemented for " + runtime.GOOS) } -// restartProcess returns an error if things couldn't be +// RestartProcess returns an error if things couldn't be // restarted. On success, this function never returns // because the process becomes the new process. func RestartProcess() error { - path, err := selfPath() + path, err := SelfPath() if err != nil { - return err + return fmt.Errorf("RestartProcess failed: %v", err) } return syscall.Exec(path, os.Args, os.Environ()) } diff --git a/pkg/osutil/restart_windows.go b/pkg/osutil/restart_windows.go new file mode 100644 index 000000000..3363ad07f --- /dev/null +++ b/pkg/osutil/restart_windows.go @@ -0,0 +1,54 @@ +// +build windows + +/* +Copyright 2014 The Camlistore Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package osutil + +import ( + "log" + "syscall" + "unicode/utf16" + "unsafe" +) + +// SelfPath returns the path of the executable for the currently running +// process. +func SelfPath() (string, error) { + kernel32, err := syscall.LoadDLL("kernel32.dll") + if err != nil { + return "", err + } + sysproc, err := kernel32.FindProc("GetModuleFileNameW") + if err != nil { + return "", err + } + b := make([]uint16, syscall.MAX_PATH) + r, _, err := sysproc.Call(0, uintptr(unsafe.Pointer(&b[0])), uintptr(len(b))) + n := uint32(r) + if n == 0 { + return "", err + } + return string(utf16.Decode(b[0:n])), nil +} + +// RestartProcess returns an error if things couldn't be +// restarted. On success, this function never returns +// because the process becomes the new process. +func RestartProcess() error { + log.Print("RestartProcess not implemented on this platform.") + return nil +}