Skip to content

Commit

Permalink
Merge pull request #1 from TerminalStudio/master
Browse files Browse the repository at this point in the history
Update Fork.
  • Loading branch information
devmil authored Mar 16, 2021
2 parents a850658 + 47f2712 commit d8365a8
Show file tree
Hide file tree
Showing 12 changed files with 292 additions and 236 deletions.
42 changes: 42 additions & 0 deletions .github/workflows/dart.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
name: Dart

on:
push:
branches: [ master ]
pull_request:
branches: [ master ]

jobs:
test:
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [ubuntu-latest, macos-latest, windows-latest]
# sdk: [stable, beta, dev, 2.10.3, 2.12.0-29.10.beta]
sdk: [stable, dev]

steps:
- uses: actions/checkout@v2
- uses: dart-lang/setup-dart@v1
with:
sdk: ${{ matrix.sdk }}

- name: Print Dart SDK version
run: dart --version

- name: Install dependencies
run: dart pub get

# Uncomment this step to verify the use of 'dart format' on each commit.
# - name: Verify formatting
# run: dart format --output=none --set-exit-if-changed .

# Consider passing '--fatal-infos' for slightly stricter analysis.
- name: Analyze project source
run: dart analyze

# Your project will need to have tests in test/ and a dependency on
# package:test for this step to succeed. Note that Flutter projects will
# want to change this to 'flutter test'.
- name: Run tests
run: dart test
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
## 0.2.0-pre

- Using forkpty to set up the pty connection [#2](https://github.com/TerminalStudio/pty/pull/2), thanks [@devmil](https://github.com/devmil)

## 0.1.1

- Fix pid reference
Expand Down
15 changes: 9 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,21 +1,24 @@
# pty

<p>
<img alt="GitHub repo size" src="https://img.shields.io/github/repo-size/TerminalStudio/pty">
<img alt="GitHub issues" src="https://img.shields.io/github/issues-raw/TerminalStudio/pty">
<img alt="GitHub pull requests" src="https://img.shields.io/github/issues-pr/TerminalStudio/pty">
<img alt="GitHub repo size" src="https://img.shields.io/github/repo-size/TerminalStudio/pty">
<img alt="GitHub issues" src="https://img.shields.io/github/issues-raw/TerminalStudio/pty">
<img alt="GitHub pull requests" src="https://img.shields.io/github/issues-pr/TerminalStudio/pty">
</p>

Pty for Dart and Flutter. Provides the ability to create processes with pseudo terminal file descriptors.

## Status

[![test](https://github.com/TerminalStudio/pty/actions/workflows/dart.yml/badge.svg)](https://github.com/TerminalStudio/pty/actions/workflows/dart.yml)


| **Platform** | **JIT(Debug)** | **AOT(Release)** |
| ------------- | :------------: | :--------------: |
| **Windows** | Crash | Passed |
| **Linux x64** | Passed | Passed |
| **Windows** | Crash | Works |
| **Linux x64** | Works | Works |
| **Linux x86** | Not tested | Not tested |
| **macOS** | Passed | Passed |
| **macOS** | Works | Works |

## Usage

Expand Down
125 changes: 54 additions & 71 deletions lib/src/impl/unix.dart
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,6 @@ void _setNonblock(int fd) {

flag |= consts.O_NONBLOCK;

print('flag $flag');

final ret = unix.fcntl3(fd, consts.F_SETFL, flag);
if (ret == -1) {
unix.perror(nullptr);
Expand All @@ -28,87 +26,73 @@ class PtyCoreUnix implements PtyCore {
String? workingDirectory,
Map<String, String>? environment,
}) {
final dev = '/dev/ptmx'.toNativeUtf8();
final ptm = unix.open(dev, consts.O_RDWR | consts.O_CLOEXEC);

if (unix.grantpt(ptm) != 0) {
throw PtyException('grantpt failed.');
}
var effectiveEnv = <String, String>{};

if (unix.unlockpt(ptm) != 0) {
throw PtyException('unlockpt failed.');
}
effectiveEnv['TERM'] = 'xterm-256color';
// Without this, tools like "vi" produce sequences that are not UTF-8 friendly
effectiveEnv['LANG'] = 'en_US.UTF-8';

final tios = calloc<termios>();
unix.tcgetattr(ptm, tios);
tios.ref.c_iflag |= consts.IUTF8;
tios.ref.c_iflag &= ~(consts.IXON | consts.IXOFF);
unix.tcsetattr(ptm, consts.TCSANOW, tios);
calloc.free(tios);
var envValuesToCopy = ['LOGNAME', 'USER', 'DISPLAY', 'LC_TYPE', 'HOME'];

final pid = unix.fork();
if (pid < 0) {
throw PtyException('fork failed.');
} else if (pid > 0) {
// call setsid() to make parent process become session leader.
unix.setsid();
_setNonblock(ptm);
return PtyCoreUnix._(pid, ptm);
for (var entry in Platform.environment.entries) {
if (envValuesToCopy.contains(entry.key)) {
effectiveEnv[entry.key] = entry.value;
}
}

// final signalsToUnblock = allocate<Uint64>();
// unistd.sigfillset(signalsToUnblock);
// unistd.sigprocmask(SIG_UNBLOCK, signalsToUnblock, nullptr);
// unistd.close(_ptm);
if (environment != null) {
for (var entry in environment.entries) {
effectiveEnv[entry.key] = entry.value;
}
}

// open slave side of the pty
final devname = unix.ptsname(ptm);
final pts = unix.open(devname, consts.O_RDWR);
unix.close(ptm);
final pPtm = calloc<Int32>();
pPtm.value = -1;

if (pts < 0) {
throw PtyException('open pts failed.');
}
final sz = calloc<winsize>();
sz.ref.ws_col = 80;
sz.ref.ws_row = 20;

// redirect stdin
if (unix.dup2(pts, 0) == -1) {
throw PtyException('fdup2(pts, 0) ailed.');
}
final pid = unix.forkpty(pPtm, nullptr, nullptr, sz);
calloc.free(sz);

// redirect stdout
if (unix.dup2(pts, 1) == -1) {
throw PtyException('fdup2(pts, 1) ailed.');
}
var ptm = pPtm.value;
calloc.free(pPtm);

// redirect stderr
if (unix.dup2(pts, 2) == -1) {
throw PtyException('fdup2(pts, 2) ailed.');
}
if (pid < 0) {
throw PtyException('fork failed.');
} else if (pid == 0) {
// set working directory
if (workingDirectory != null) {
unix.chdir(workingDirectory.toNativeUtf8());
}

unix.close(pts);
// build argv
final argv = calloc<Pointer<Utf8>>(arguments.length + 2);
argv.elementAt(0).value = executable.toNativeUtf8();
argv.elementAt(arguments.length + 1).value = nullptr;
for (var i = 0; i < arguments.length; i++) {
argv.elementAt(i + 1).value = arguments[i].toNativeUtf8();
}

// set working environment variables
if (environment != null) {
for (var env in environment.entries) {
unix.setenv(env.key.toNativeUtf8(), env.value.toNativeUtf8(), 1);
//build env
final env = calloc<Pointer<Utf8>>(effectiveEnv.length + 1);
env.elementAt(effectiveEnv.length).value = nullptr;
var cnt = 0;
for (var entry in effectiveEnv.entries) {
final envVal = '${entry.key}=${entry.value}';
env.elementAt(cnt).value = envVal.toNativeUtf8();
cnt++;
}
}

// set working directory
if (workingDirectory != null) {
unix.chdir(workingDirectory.toNativeUtf8());
}
unix.execve(executable.toNativeUtf8(), argv, env);
} else {
unix.setsid();

// build argv
final argv = calloc<Pointer<Utf8>>(arguments.length + 2);
argv.elementAt(0).value = executable.toNativeUtf8();
argv.elementAt(arguments.length + 1).value = nullptr;
for (var i = 0; i < arguments.length; i++) {
argv.elementAt(i + 1).value = arguments[i].toNativeUtf8();
_setNonblock(ptm);
return PtyCoreUnix._(pid, ptm);
}

unix.execvp(executable.toNativeUtf8(), argv);

throw PtyException('unreachable');
}

Expand All @@ -121,18 +105,17 @@ class PtyCoreUnix implements PtyCore {
final int _ptm;
// late final int _pts;

static const _bufferSize = 4096;
static const _bufferSize = 81920;
final _buffer = calloc<Int8>(_bufferSize + 1);

@override
String? readNonBlocking() {
List<int>? readNonBlocking() {
final readlen = unix.read(_ptm, _buffer.cast(), _bufferSize);

if (readlen == -1) {
if (readlen <= 0) {
return null;
}

return _buffer.cast<Utf8>().toDartString(length: readlen);
return _buffer.cast<Uint8>().asTypedList(readlen);
}

@override
Expand Down
Loading

0 comments on commit d8365a8

Please sign in to comment.