@@ -23,6 +23,7 @@ import Foundation
2323import LCShim
2424import Logging
2525import Musl
26+ import Glibc
2627
2728struct RunCommand : ParsableCommand {
2829 static let configuration = CommandConfiguration (
@@ -95,6 +96,32 @@ struct RunCommand: ParsableCommand {
9596
9697 try childRootSetup ( rootfs: root, mounts: spec. mounts, log: log, process: process)
9798
99+ var hostFd : Int32 = - 1
100+
101+ if process. terminal {
102+ hostFd = 0
103+ var containerFd : Int32 = 0
104+ var ws = winsize ( ws_row: 40 . ws_col: 120 , ws_xpixel: 0 , ws_ypixel: 0 )
105+ guard openpty ( & hostFd, & containerFd, nil , nil , & ws) == 0 else {
106+ throw App . Errno ( stage: " openpty() " )
107+ }
108+
109+ guard dup3 ( containerFd, 0 , 0 ) != - 1 else {
110+ throw App . Errno ( stage: " dup3(slave->stdin) " )
111+ }
112+ guard dup3 ( containerFd, 1 , 0 ) != - 1 else {
113+ throw App . Errno ( stage: " dup3(slave->stdout) " )
114+ }
115+ guard dup3 ( containerFd, 2 , 0 ) != - 1 else {
116+ throw App . Errno ( stage: " dup3(slave->stderr) " )
117+ }
118+ _ = close ( containerFd)
119+
120+ guard ioctl ( 0 , UInt ( TIOCSCTTY) , 0 ) != - 1 else {
121+ throw App . Errno ( stage: " setctty() " )
122+ }
123+ }
124+
98125 if !spec. hostname. isEmpty {
99126 let errCode = spec. hostname. withCString { ptr in
100127 Musl . sethostname ( ptr, spec. hostname. count)
@@ -104,11 +131,17 @@ struct RunCommand: ParsableCommand {
104131 }
105132 }
106133
134+ var fdCopy = hostFd
135+ var fdData = Data ( bytes: & fdCopy, count: MemoryLayout . size ( ofValue: fdCopy) )
136+ try childPipe. fileHandleForWriting. write ( contentsOf: fdData)
137+ try childPipe. fileHandleForWriting. close ( )
138+
107139 // Apply O_CLOEXEC to all file descriptors except stdio.
108140 // This ensures that all unwanted fds we may have accidentally
109141 // inherited are marked close-on-exec so they stay out of the
110142 // container.
111- try App . applyCloseExecOnFDs ( )
143+ let preserve : Set < Int32 > = hostFd >= 0 ? [ hostFd] : [ ]
144+ try App . applyCloseExecOnFDs ( preserve: preserve)
112145
113146 try App . setRLimits ( rlimits: process. rlimits)
114147
@@ -129,9 +162,9 @@ struct RunCommand: ParsableCommand {
129162 _ = try childPipe. fileHandleForReading. readToEnd ( )
130163 try childPipe. fileHandleForReading. close ( )
131164
132- // send our child's pid to our parent before we exit.
133- var childPid = processID
134- let data = Data ( bytes: & childPid , count: MemoryLayout . size ( ofValue : childPid ) )
165+ // send our child's pid and the host fd to our parent before we exit.
166+ var payload = [ Int32 ( processID) , hostFd ]
167+ let data = Data ( bytes: & payload , count: MemoryLayout < Int32 > . size * 2 )
135168
136169 try syncfd. write ( contentsOf: data)
137170 try syncfd. close ( )
0 commit comments