Use a new controlling terminal when reading shell environment
This is because some people do things in their rc files based on checking the name of the controlling terminal.
This commit is contained in:
@@ -118,6 +118,10 @@ def remove_cloexec(fd):
|
|||||||
fcntl.fcntl(fd, fcntl.F_SETFD, fcntl.fcntl(fd, fcntl.F_GETFD) & ~fcntl.FD_CLOEXEC)
|
fcntl.fcntl(fd, fcntl.F_SETFD, fcntl.fcntl(fd, fcntl.F_GETFD) & ~fcntl.FD_CLOEXEC)
|
||||||
|
|
||||||
|
|
||||||
|
def remove_blocking(fd):
|
||||||
|
os.set_blocking(fd, False)
|
||||||
|
|
||||||
|
|
||||||
def default_env():
|
def default_env():
|
||||||
try:
|
try:
|
||||||
return default_env.env
|
return default_env.env
|
||||||
@@ -132,6 +136,13 @@ def set_default_env(val=None):
|
|||||||
default_env.env = env
|
default_env.env = env
|
||||||
|
|
||||||
|
|
||||||
|
def openpty():
|
||||||
|
master, slave = os.openpty() # Note that master and slave are in blocking mode
|
||||||
|
remove_cloexec(slave)
|
||||||
|
fast_data_types.set_iutf8_fd(master, True)
|
||||||
|
return master, slave
|
||||||
|
|
||||||
|
|
||||||
class Child:
|
class Child:
|
||||||
|
|
||||||
child_fd = pid = None
|
child_fd = pid = None
|
||||||
@@ -178,9 +189,7 @@ class Child:
|
|||||||
if self.forked:
|
if self.forked:
|
||||||
return
|
return
|
||||||
self.forked = True
|
self.forked = True
|
||||||
master, slave = os.openpty() # Note that master and slave are in blocking mode
|
master, slave = openpty()
|
||||||
remove_cloexec(slave)
|
|
||||||
fast_data_types.set_iutf8_fd(master, True)
|
|
||||||
stdin, self.stdin = self.stdin, None
|
stdin, self.stdin = self.stdin, None
|
||||||
ready_read_fd, ready_write_fd = os.pipe()
|
ready_read_fd, ready_write_fd = os.pipe()
|
||||||
remove_cloexec(ready_read_fd)
|
remove_cloexec(ready_read_fd)
|
||||||
@@ -206,7 +215,7 @@ class Child:
|
|||||||
fast_data_types.thread_write(stdin_write_fd, stdin)
|
fast_data_types.thread_write(stdin_write_fd, stdin)
|
||||||
os.close(ready_read_fd)
|
os.close(ready_read_fd)
|
||||||
self.terminal_ready_fd = ready_write_fd
|
self.terminal_ready_fd = ready_write_fd
|
||||||
fcntl.fcntl(self.child_fd, fcntl.F_SETFL, fcntl.fcntl(self.child_fd, fcntl.F_GETFL) | os.O_NONBLOCK)
|
remove_blocking(self.child_fd)
|
||||||
return pid
|
return pid
|
||||||
|
|
||||||
def mark_terminal_ready(self):
|
def mark_terminal_ready(self):
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ from contextlib import contextmanager, suppress
|
|||||||
|
|
||||||
from .borders import load_borders_program
|
from .borders import load_borders_program
|
||||||
from .boss import Boss
|
from .boss import Boss
|
||||||
from .child import set_default_env
|
from .child import set_default_env, openpty, remove_blocking
|
||||||
from .cli import create_opts, parse_args
|
from .cli import create_opts, parse_args
|
||||||
from .config import cached_values_for, initial_window_size_func
|
from .config import cached_values_for, initial_window_size_func
|
||||||
from .constants import (
|
from .constants import (
|
||||||
@@ -203,23 +203,37 @@ def macos_cmdline(argv_args):
|
|||||||
return ans
|
return ans
|
||||||
|
|
||||||
|
|
||||||
def read_shell_environment(opts):
|
def read_shell_environment(opts=None):
|
||||||
if not hasattr(read_shell_environment, 'ans'):
|
if not hasattr(read_shell_environment, 'ans'):
|
||||||
import subprocess
|
import subprocess
|
||||||
from .session import resolved_shell
|
from .session import resolved_shell
|
||||||
shell = resolved_shell(opts)
|
shell = resolved_shell(opts)
|
||||||
p = subprocess.Popen(shell + ['-l', '-c', 'env'], stdout=subprocess.PIPE)
|
master, slave = openpty()
|
||||||
raw = p.stdout.read()
|
remove_blocking(master)
|
||||||
if p.wait() == 0:
|
p = subprocess.Popen(shell + ['-l', '-c', 'env'], stdout=slave, stdin=slave, stderr=slave, start_new_session=True, close_fds=True)
|
||||||
raw = raw.decode('utf-8', 'replace')
|
with os.fdopen(master, 'rb') as stdout, os.fdopen(slave, 'wb'):
|
||||||
ans = read_shell_environment.ans = {}
|
raw = b''
|
||||||
for line in raw.splitlines():
|
while p.wait(0.01) is None:
|
||||||
k, v = line.partition('=')[::2]
|
with suppress(Exception):
|
||||||
if k and v:
|
raw += stdout.read()
|
||||||
ans[k] = v
|
if p.returncode == 0:
|
||||||
else:
|
while True:
|
||||||
log_error('Failed to run shell to read its environment')
|
try:
|
||||||
read_shell_environment.ans = {}
|
x = stdout.read()
|
||||||
|
except Exception:
|
||||||
|
break
|
||||||
|
if not x:
|
||||||
|
break
|
||||||
|
raw += x
|
||||||
|
raw = raw.decode('utf-8', 'replace')
|
||||||
|
ans = read_shell_environment.ans = {}
|
||||||
|
for line in raw.splitlines():
|
||||||
|
k, v = line.partition('=')[::2]
|
||||||
|
if k and v:
|
||||||
|
ans[k] = v
|
||||||
|
else:
|
||||||
|
log_error('Failed to run shell to read its environment')
|
||||||
|
read_shell_environment.ans = {}
|
||||||
return read_shell_environment.ans
|
return read_shell_environment.ans
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -74,8 +74,8 @@ class Session:
|
|||||||
self.tabs[-1].cwd = val
|
self.tabs[-1].cwd = val
|
||||||
|
|
||||||
|
|
||||||
def resolved_shell(opts):
|
def resolved_shell(opts=None):
|
||||||
ans = opts.shell
|
ans = getattr(opts, 'shell', '.')
|
||||||
if ans == '.':
|
if ans == '.':
|
||||||
ans = [shell_path]
|
ans = [shell_path]
|
||||||
else:
|
else:
|
||||||
|
|||||||
Reference in New Issue
Block a user