init
This commit is contained in:
@@ -0,0 +1,22 @@
|
||||
# Compiled Object files, Static and Dynamic libs (Shared Objects)
|
||||
*.o
|
||||
*.a
|
||||
*.so
|
||||
|
||||
# Folders
|
||||
_obj
|
||||
_test
|
||||
|
||||
# Architecture specific extensions/prefixes
|
||||
*.[568vq]
|
||||
[568vq].out
|
||||
|
||||
*.cgo1.go
|
||||
*.cgo2.c
|
||||
_cgo_defun.c
|
||||
_cgo_gotypes.go
|
||||
_cgo_export.*
|
||||
|
||||
_testmain.go
|
||||
|
||||
*.exe
|
||||
+22
@@ -0,0 +1,22 @@
|
||||
The MIT License (MIT)
|
||||
Copyright (c) 2016 codeskyblue
|
||||
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
|
||||
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
|
||||
OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
|
||||
OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
+77
@@ -0,0 +1,77 @@
|
||||
# kexec
|
||||
[](https://godoc.org/github.com/codeskyblue/kexec)
|
||||
|
||||
This is a golang lib, add a `Terminate` command to exec.
|
||||
|
||||
Tested on _windows, linux, darwin._
|
||||
|
||||
This lib has been used in [fswatch](https://github.com/codeskyblue/fswatch).
|
||||
|
||||
## Usage
|
||||
|
||||
```
|
||||
go get -v github.com/codeskyblue/kexec
|
||||
```
|
||||
|
||||
|
||||
example1:
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import "github.com/codeskyblue/kexec"
|
||||
|
||||
func main(){
|
||||
p := kexec.Command("python", "flask_main.py")
|
||||
p.Start()
|
||||
p.Terminate(syscall.SIGINT)
|
||||
}
|
||||
```
|
||||
|
||||
example2: see more [examples](examples)
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/codeskyblue/kexec"
|
||||
)
|
||||
|
||||
func main() {
|
||||
// In unix will call: bash -c "python flask_main.py"
|
||||
// In windows will call: cmd /c "python flask_main.py"
|
||||
p := kexec.CommandString("python flask_main.py")
|
||||
p.Stdout = os.Stdout
|
||||
p.Stderr = os.Stderr
|
||||
p.Start()
|
||||
p.Terminate(syscall.SIGKILL)
|
||||
}
|
||||
```
|
||||
|
||||
example3:
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import "github.com/codeskyblue/kexec"
|
||||
|
||||
func main() {
|
||||
p := kexec.Command("whoami")
|
||||
p.SetUser("codeskyblue") // Only works on darwin and linux
|
||||
p.Run()
|
||||
}
|
||||
```
|
||||
|
||||
## Command line usage
|
||||
```
|
||||
$ go get -v github.com/codeskyblue/kexec/cmds/kexec
|
||||
$ kexec python main.py
|
||||
# Ctrl+C
|
||||
python is terminating ...
|
||||
```
|
||||
|
||||
## PS
|
||||
This lib also support you call `Wait()` twice, which is not support by `os/exec`
|
||||
|
||||
## LICENSE
|
||||
[MIT](LICENSE)
|
||||
+54
@@ -0,0 +1,54 @@
|
||||
package kexec
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"os/exec"
|
||||
"sync"
|
||||
)
|
||||
|
||||
type KCommand struct {
|
||||
*exec.Cmd
|
||||
|
||||
errCs []chan error
|
||||
err error
|
||||
finished bool
|
||||
once sync.Once
|
||||
mu sync.Mutex
|
||||
}
|
||||
|
||||
func (c *KCommand) Run() error {
|
||||
if err := c.Start(); err != nil {
|
||||
return err
|
||||
}
|
||||
return c.Wait()
|
||||
}
|
||||
|
||||
// This Wait wraps exec.Wait, but support multi call
|
||||
func (k *KCommand) Wait() error {
|
||||
if k.Process == nil {
|
||||
return errors.New("exec: not started")
|
||||
}
|
||||
k.once.Do(func() {
|
||||
if k.errCs == nil {
|
||||
k.errCs = make([]chan error, 0)
|
||||
}
|
||||
go func() {
|
||||
k.err = k.Cmd.Wait()
|
||||
k.mu.Lock()
|
||||
k.finished = true
|
||||
for _, errC := range k.errCs {
|
||||
errC <- k.err
|
||||
}
|
||||
k.mu.Unlock()
|
||||
}()
|
||||
})
|
||||
k.mu.Lock()
|
||||
if k.finished {
|
||||
k.mu.Unlock()
|
||||
return k.err
|
||||
}
|
||||
errC := make(chan error, 1)
|
||||
k.errCs = append(k.errCs, errC)
|
||||
k.mu.Unlock()
|
||||
return <-errC
|
||||
}
|
||||
+68
@@ -0,0 +1,68 @@
|
||||
// +build !windows
|
||||
|
||||
package kexec
|
||||
|
||||
import (
|
||||
"os"
|
||||
"os/exec"
|
||||
"os/user"
|
||||
"strconv"
|
||||
"syscall"
|
||||
)
|
||||
|
||||
func setupCmd(cmd *exec.Cmd) {
|
||||
cmd.SysProcAttr = &syscall.SysProcAttr{}
|
||||
cmd.SysProcAttr.Setsid = true
|
||||
}
|
||||
|
||||
func Command(name string, arg ...string) *KCommand {
|
||||
cmd := exec.Command(name, arg...)
|
||||
setupCmd(cmd)
|
||||
return &KCommand{
|
||||
Cmd: cmd,
|
||||
}
|
||||
}
|
||||
|
||||
func CommandString(command string) *KCommand {
|
||||
cmd := exec.Command("/bin/bash", "-c", command)
|
||||
setupCmd(cmd)
|
||||
//cmd.Stdout = os.Stdout
|
||||
//cmd.Stderr = os.Stderr
|
||||
return &KCommand{
|
||||
Cmd: cmd,
|
||||
}
|
||||
}
|
||||
|
||||
func (p *KCommand) Terminate(sig os.Signal) (err error) {
|
||||
if p.Process == nil {
|
||||
return
|
||||
}
|
||||
// find pgid, ref: http://unix.stackexchange.com/questions/14815/process-descendants
|
||||
group, err := os.FindProcess(-1 * p.Process.Pid)
|
||||
//log.Println(group)
|
||||
if err == nil {
|
||||
err = group.Signal(sig)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
// Ref: http://stackoverflow.com/questions/21705950/running-external-commands-through-os-exec-under-another-user
|
||||
func (k *KCommand) SetUser(name string) (err error) {
|
||||
u, err := user.Lookup(name)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
uid, err := strconv.Atoi(u.Uid)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
gid, err := strconv.Atoi(u.Gid)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if k.SysProcAttr == nil {
|
||||
k.SysProcAttr = &syscall.SysProcAttr{}
|
||||
}
|
||||
k.SysProcAttr.Credential = &syscall.Credential{Uid: uint32(uid), Gid: uint32(gid)}
|
||||
return nil
|
||||
}
|
||||
+40
@@ -0,0 +1,40 @@
|
||||
package kexec
|
||||
|
||||
import (
|
||||
"log"
|
||||
"os"
|
||||
"os/exec"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
func Command(name string, arg ...string) *KCommand {
|
||||
return &KCommand{
|
||||
Cmd: exec.Command(name, arg...),
|
||||
}
|
||||
}
|
||||
|
||||
func CommandString(command string) *KCommand {
|
||||
cmd := exec.Command("cmd", "/c", command)
|
||||
//cmd.Stdout = os.Stdout
|
||||
//cmd.Stderr = os.Stderr
|
||||
return &KCommand{
|
||||
Cmd: cmd,
|
||||
}
|
||||
}
|
||||
|
||||
func (p *KCommand) Terminate(sig os.Signal) (err error) {
|
||||
if p.Process == nil {
|
||||
return nil
|
||||
}
|
||||
pid := p.Process.Pid
|
||||
c := exec.Command("taskkill", "/t", "/f", "/pid", strconv.Itoa(pid))
|
||||
c.Stdout = os.Stdout
|
||||
c.Stderr = os.Stderr
|
||||
return c.Run()
|
||||
}
|
||||
|
||||
// SetUser not support on windws
|
||||
func (k *KCommand) SetUser(name string) (err error) {
|
||||
log.Printf("Can not set user(%s) on windows", name)
|
||||
return nil
|
||||
}
|
||||
Reference in New Issue
Block a user