File: shell.go

package info (click to toggle)
mender-connect 2.3.0%2Bds1-1
  • links: PTS, VCS
  • area: main
  • in suites: sid
  • size: 700 kB
  • sloc: makefile: 123; ansic: 66; sh: 21
file content (88 lines) | stat: -rw-r--r-- 2,344 bytes parent folder | download
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)
	}
}