1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88
|
// Copyright 2021 Northern.tech AS
//
// 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 shell
import (
"errors"
"fmt"
"os"
"os/exec"
"os/user"
"syscall"
"unsafe"
"github.com/creack/pty"
log "github.com/sirupsen/logrus"
)
const defaultCmdDir = "/"
func ExecuteShell(uid uint32,
gid uint32,
homeDir string,
shell string,
termString string,
height uint16,
width uint16,
shellArguments []string) (pid int, pseudoTTY *os.File, cmd *exec.Cmd, err error) {
cmd = exec.Command(shell, shellArguments...)
currentUser, err := user.Current()
if err != nil {
log.Debugf("can't get current user: %s", err.Error())
return -1, nil, nil, errors.New("unknown error with exec.Command(" + shell + ")")
}
//in order to set uid and gid we have to be root, at the moment lets check
//if our uid is 0
if currentUser.Uid == "0" {
cmd.SysProcAttr = &syscall.SysProcAttr{}
cmd.SysProcAttr.Credential = &syscall.Credential{Uid: uid, Gid: gid}
}
if _, err := os.Stat(homeDir); !os.IsNotExist(err) {
cmd.Dir = homeDir
} else {
cmd.Dir = defaultCmdDir
}
cmd.Env = append(cmd.Env, fmt.Sprintf("HOME=%s", homeDir))
cmd.Env = append(cmd.Env, fmt.Sprintf("TERM=%s", termString))
pseudoTTY, err = pty.Start(cmd)
if err != nil {
return -1, nil, nil, err
}
ResizeShell(pseudoTTY, height, width)
pid = cmd.Process.Pid
log.Debugf("started shell: %s pid:%d", shell, pid)
return pid, pseudoTTY, cmd, nil
}
func ResizeShell(pseudoTTY *os.File, height uint16, width uint16) {
log.Debugf("resizing terminal %v to %dx%d", *pseudoTTY, height, width)
_, _, errno := syscall.Syscall(syscall.SYS_IOCTL, pseudoTTY.Fd(), uintptr(syscall.TIOCSWINSZ),
uintptr(unsafe.Pointer(&struct {
h, w, x, y uint16
}{
height, width, 0, 0,
})))
if errno != 0 {
log.Debugf("failed to resize terminal: %d", errno)
}
}
|