github.com/SagerNet/gvisor@v0.0.0-20210707092255-7731c139d75c/pkg/sentry/fs/tty/terminal.go (about) 1 // Copyright 2018 The gVisor Authors. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package tty 16 17 import ( 18 "github.com/SagerNet/gvisor/pkg/abi/linux" 19 "github.com/SagerNet/gvisor/pkg/context" 20 "github.com/SagerNet/gvisor/pkg/marshal/primitive" 21 "github.com/SagerNet/gvisor/pkg/refs" 22 "github.com/SagerNet/gvisor/pkg/sentry/arch" 23 "github.com/SagerNet/gvisor/pkg/sentry/kernel" 24 ) 25 26 // LINT.IfChange 27 28 // Terminal is a pseudoterminal. 29 // 30 // +stateify savable 31 type Terminal struct { 32 refs.AtomicRefCount 33 34 // n is the terminal index. It is immutable. 35 n uint32 36 37 // d is the containing directory. It is immutable. 38 d *dirInodeOperations 39 40 // ld is the line discipline of the terminal. It is immutable. 41 ld *lineDiscipline 42 43 // masterKTTY contains the controlling process of the master end of 44 // this terminal. This field is immutable. 45 masterKTTY *kernel.TTY 46 47 // replicaKTTY contains the controlling process of the replica end of this 48 // terminal. This field is immutable. 49 replicaKTTY *kernel.TTY 50 } 51 52 func newTerminal(ctx context.Context, d *dirInodeOperations, n uint32) *Terminal { 53 termios := linux.DefaultReplicaTermios 54 t := Terminal{ 55 d: d, 56 n: n, 57 ld: newLineDiscipline(termios), 58 masterKTTY: &kernel.TTY{Index: n}, 59 replicaKTTY: &kernel.TTY{Index: n}, 60 } 61 t.EnableLeakCheck("tty.Terminal") 62 return &t 63 } 64 65 // setControllingTTY makes tm the controlling terminal of the calling thread 66 // group. 67 func (tm *Terminal) setControllingTTY(ctx context.Context, args arch.SyscallArguments, isMaster bool, readable bool) error { 68 task := kernel.TaskFromContext(ctx) 69 if task == nil { 70 panic("setControllingTTY must be called from a task context") 71 } 72 73 steal := args[2].Int() == 1 74 return task.ThreadGroup().SetControllingTTY(tm.tty(isMaster), steal, readable) 75 } 76 77 // releaseControllingTTY removes tm as the controlling terminal of the calling 78 // thread group. 79 func (tm *Terminal) releaseControllingTTY(ctx context.Context, args arch.SyscallArguments, isMaster bool) error { 80 task := kernel.TaskFromContext(ctx) 81 if task == nil { 82 panic("releaseControllingTTY must be called from a task context") 83 } 84 85 return task.ThreadGroup().ReleaseControllingTTY(tm.tty(isMaster)) 86 } 87 88 // foregroundProcessGroup gets the process group ID of tm's foreground process. 89 func (tm *Terminal) foregroundProcessGroup(ctx context.Context, args arch.SyscallArguments, isMaster bool) (uintptr, error) { 90 task := kernel.TaskFromContext(ctx) 91 if task == nil { 92 panic("foregroundProcessGroup must be called from a task context") 93 } 94 95 ret, err := task.ThreadGroup().ForegroundProcessGroup(tm.tty(isMaster)) 96 if err != nil { 97 return 0, err 98 } 99 100 // Write it out to *arg. 101 retP := primitive.Int32(ret) 102 _, err = retP.CopyOut(task, args[2].Pointer()) 103 return 0, err 104 } 105 106 // foregroundProcessGroup sets tm's foreground process. 107 func (tm *Terminal) setForegroundProcessGroup(ctx context.Context, args arch.SyscallArguments, isMaster bool) (uintptr, error) { 108 task := kernel.TaskFromContext(ctx) 109 if task == nil { 110 panic("setForegroundProcessGroup must be called from a task context") 111 } 112 113 // Read in the process group ID. 114 var pgid primitive.Int32 115 if _, err := pgid.CopyIn(task, args[2].Pointer()); err != nil { 116 return 0, err 117 } 118 119 ret, err := task.ThreadGroup().SetForegroundProcessGroup(tm.tty(isMaster), kernel.ProcessGroupID(pgid)) 120 return uintptr(ret), err 121 } 122 123 func (tm *Terminal) tty(isMaster bool) *kernel.TTY { 124 if isMaster { 125 return tm.masterKTTY 126 } 127 return tm.replicaKTTY 128 } 129 130 // LINT.ThenChange(../../fsimpl/devpts/terminal.go)