Skip to content

Fix interactive shell job control by setting foreground process group#56

Merged
jy-tan merged 2 commits intoUse-Tusk:mainfrom
NiltonVolpato:fix/terminal-job-control
Feb 24, 2026
Merged

Fix interactive shell job control by setting foreground process group#56
jy-tan merged 2 commits intoUse-Tusk:mainfrom
NiltonVolpato:fix/terminal-job-control

Conversation

@NiltonVolpato
Copy link
Contributor

@NiltonVolpato NiltonVolpato commented Feb 24, 2026

Summary

Fixes fence bash (and other interactive shells) reporting "cannot set terminal process group" and "no job control in this shell".

Two root causes:

  1. Sandbox profile blocks terminal ioctl: The macOS sandbox profile only allows file-ioctl on /dev/ttys* when allowPty is enabled. But the inherited stdin/stdout/stderr point to a PTY slave device (/dev/ttysNNN), and basic terminal operations like isatty(), tcgetpgrp(), and tcsetpgrp() need file-ioctl on that device. Without it, bash can't even detect it has a terminal. Fix: always allow file-ioctl on /dev/ttys* — this permits ioctl on inherited terminal fds without enabling new PTY allocation (which remains gated by allowPty).

  2. No foreground process group handoff: The child process inherits fence's process group, so when bash creates its own process group and calls tcsetpgrp(), it fails with EPERM (only the foreground group can call tcsetpgrp). Fix: place the child in its own process group via Setpgid, then have the parent call tcsetpgrp() to hand terminal foreground to the child after Start(). After Wait(), the parent reclaims the foreground. SIGTTOU is ignored so the parent doesn't get stopped during reclaim.

Fixes #55

Test plan

  • go build ./... succeeds
  • go test ./... all pass
  • Manual: fence bash — no "cannot set terminal process group" warning, job control works (Ctrl+Z, fg, bg)
  • Manual: echo ls | fence bash — piped input still works
  • Manual: fence bash -c "echo hello" — non-interactive usage still works
  • Manual: fence --template code bash — works with explicit template

🤖 Generated with Claude Code

Two issues prevented job control in interactive shells (e.g. "fence bash"):

1. The macOS sandbox profile blocked file-ioctl on /dev/ttys* (the
   inherited PTY slave device) unless allowPty was enabled. This caused
   isatty(), tcgetpgrp(), and tcsetpgrp() to fail with ENOTTY inside the
   sandbox. Fix: always allow file-ioctl on /dev/ttys* since these are
   inherited terminal fds, not new PTY allocations.

2. The child process was not placed in its own process group, so bash
   could not call tcsetpgrp() to become the foreground group (EPERM).
   Fix: use Setpgid to give the child its own process group, then have
   the parent call tcsetpgrp() to hand terminal foreground to the child
   after Start(). After Wait(), the parent reclaims the foreground.
   SIGTTOU is ignored to prevent the parent from being stopped.

Fixes Use-Tusk#55

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@NiltonVolpato NiltonVolpato force-pushed the fix/terminal-job-control branch from 0057cde to c1e8d92 Compare February 24, 2026 13:33
Copy link

@cubic-dev-ai cubic-dev-ai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No issues found across 3 files

Copy link
Contributor

@jy-tan jy-tan left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the raising the issue and PR, overall looks good, just a comment.

- Save the terminal's actual foreground group via tcgetpgrp() instead of
  the parent's process group via Getpgrp(). More correct for restore.
- Use Getpgid(childPid) to get the child's process group instead of
  assuming pid == pgid.
- Add integration test that builds the fence binary and runs "fence bash"
  with a real PTY via creack/pty, verifying no "no job control" warning.
  The test fails without both fixes (sandbox profile + process group
  handoff) and passes with them.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Copy link

@cubic-dev-ai cubic-dev-ai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No issues found across 3 files

@jy-tan jy-tan merged commit f69a2d2 into Use-Tusk:main Feb 24, 2026
5 checks passed
@NiltonVolpato NiltonVolpato deleted the fix/terminal-job-control branch February 24, 2026 23:17
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Interactive shells lack job control: 'cannot set terminal process group'

2 participants