func setWindowSize(logger lager.Logger, pseudoTty *os.File, columns, rows uint32) error { logger.Info("new-size", lager.Data{"columns": columns, "rows": rows}) return term.SetWinsize(pseudoTty.Fd(), &term.Winsize{ Width: uint16(columns), Height: uint16(rows), }) }
func (s *GitDeploySuite) TestDevStdout(t *c.C) { r := s.newGitRepo(t, "empty-release") t.Assert(r.flynn("create"), Succeeds) t.Assert(r.flynn("env", "set", "BUILDPACK_URL=https://github.com/kr/heroku-buildpack-inline"), Succeeds) t.Assert(r.git("push", "flynn", "master"), Succeeds) // check slug jobs can write to /dev/stdout and /dev/stderr for _, dev := range []string{"/dev/stdout", "/dev/stderr"} { // check without a TTY echoFoo := fmt.Sprintf("echo foo > %s", dev) t.Assert(r.flynn("run", "bash", "-c", echoFoo), SuccessfulOutputContains, "foo") // check with a TTY cmd := flynnCmd(r.dir, "run", "bash", "-c", echoFoo) master, slave, err := pty.Open() t.Assert(err, c.IsNil) defer master.Close() defer slave.Close() t.Assert(term.SetWinsize(slave.Fd(), &term.Winsize{Height: 24, Width: 80}), c.IsNil) cmd.Stdin = slave cmd.Stdout = slave cmd.Stderr = slave t.Assert(cmd.Run(), c.IsNil) out := make([]byte, 3) _, err = io.ReadFull(master, out) t.Assert(err, c.IsNil) t.Assert(string(out), c.Equals, "foo") } }
func (t *tty) resize() error { if t.console == nil { return nil } ws, err := term.GetWinsize(os.Stdin.Fd()) if err != nil { return err } return term.SetWinsize(t.console.Fd(), ws) }
func (p *process) resizePty() error { if p.pty == nil { return nil } ws, err := term.GetWinsize(os.Stdin.Fd()) if err != nil { return err } return term.SetWinsize(p.pty.Fd(), ws) }
func (d *directProcess) Resize(w, h int) error { if d.console == nil { return nil } ws := term.Winsize{ Width: uint16(w), Height: uint16(h), } return term.SetWinsize(d.console.Fd(), &ws) }
func resizeTty(master *os.File) { if master == nil { return } ws, err := term.GetWinsize(os.Stdin.Fd()) if err != nil { return } if err := term.SetWinsize(master.Fd(), ws); err != nil { return } }
func (l *LibcontainerBackend) ResizeTTY(id string, height, width uint16) error { container, err := l.getContainer(id) if err != nil { return err } if !container.job.Config.TTY { return errors.New("job doesn't have a TTY") } pty, err := container.GetPtyMaster() if err != nil { return err } defer pty.Close() return term.SetWinsize(pty.Fd(), &term.Winsize{Height: height, Width: width}) }
// Resize implements Resize method of Terminal interface func (t *TtyConsole) Resize(h, w int) error { return term.SetWinsize(t.console.Fd(), &term.Winsize{Height: uint16(h), Width: uint16(w)}) }
func start(log *os.File) error { // start handling signals as soon as possible so that things are properly reaped // or if runtime exits before we hit the handler signals := make(chan os.Signal, 2048) signal.Notify(signals) // set the shim as the subreaper for all orphaned processes created by the container if err := osutils.SetSubreaper(1); err != nil { return err } // open the exit pipe f, err := os.OpenFile("exit", syscall.O_WRONLY, 0) if err != nil { return err } defer f.Close() control, err := os.OpenFile("control", syscall.O_RDWR, 0) if err != nil { return err } defer control.Close() p, err := newProcess(flag.Arg(0), flag.Arg(1), flag.Arg(2)) if err != nil { return err } defer func() { if err := p.Close(); err != nil { writeMessage(log, "warn", err) } }() if err := p.create(); err != nil { p.delete() return err } msgC := make(chan controlMessage, 32) go func() { for { var m controlMessage if _, err := fmt.Fscanf(control, "%d %d %d\n", &m.Type, &m.Width, &m.Height); err != nil { continue } msgC <- m } }() var exitShim bool for { select { case s := <-signals: switch s { case syscall.SIGCHLD: exits, _ := osutils.Reap() for _, e := range exits { // check to see if runtime is one of the processes that has exited if e.Pid == p.pid() { exitShim = true writeInt("exitStatus", e.Status) } } } // runtime has exited so the shim can also exit if exitShim { // Let containerd take care of calling the runtime delete f.Close() p.Wait() return nil } case msg := <-msgC: switch msg.Type { case 0: // close stdin if p.stdinCloser != nil { p.stdinCloser.Close() } case 1: if p.console == nil { continue } ws := term.Winsize{ Width: uint16(msg.Width), Height: uint16(msg.Height), } term.SetWinsize(p.console.Fd(), &ws) } } } return nil }
// SetSize sets the terminal size associated with fd. func SetSize(fd uintptr, size Size) error { return term.SetWinsize(fd, &term.Winsize{Height: size.Height, Width: size.Width}) }
func (l *LibcontainerBackend) Attach(req *AttachRequest) (err error) { client, err := l.getContainer(req.Job.Job.ID) if err != nil { if req.Job.Job.Config.TTY || req.Stdin != nil { return host.ErrJobNotRunning } // if the container has exited and logging was disabled, return EOF if req.Job.Job.Config.DisableLog { if req.Attached != nil { req.Attached <- struct{}{} } return io.EOF } } defer func() { if client != nil && (req.Job.Job.Config.TTY || req.Stream) && err == io.EOF { <-client.done job := l.state.GetJob(req.Job.Job.ID) if job.Status == host.StatusDone || job.Status == host.StatusCrashed { err = ExitError(*job.ExitStatus) return } err = errors.New(*job.Error) } }() if req.Job.Job.Config.TTY { pty, err := client.GetPtyMaster() if err != nil { return err } defer pty.Close() if err := term.SetWinsize(pty.Fd(), &term.Winsize{Height: req.Height, Width: req.Width}); err != nil { return err } if req.Attached != nil { req.Attached <- struct{}{} } done := make(chan struct{}, 2) if req.Stdin != nil { go func() { io.Copy(pty, req.Stdin) done <- struct{}{} }() } if req.Stdout != nil { go func() { io.Copy(req.Stdout, pty) done <- struct{}{} }() } <-done l.logger.Info("one side of the TTY went away, stopping job", "fn", "attach", "job.id", req.Job.Job.ID) client.Stop() return io.EOF } if req.Stdin != nil { stdinPipe, err := client.GetStdin() if err != nil { return err } go func() { io.Copy(stdinPipe, req.Stdin) stdinPipe.Close() }() } if req.Job.Job.Config.DisableLog { stdout, stderr, initLog, err := client.GetStreams() if err != nil { return err } defer stdout.Close() defer stderr.Close() defer initLog.Close() if req.Attached != nil { req.Attached <- struct{}{} } var wg sync.WaitGroup cp := func(w io.Writer, r io.Reader) { if w == nil { w = ioutil.Discard } wg.Add(1) go func() { io.Copy(w, r) wg.Done() }() } cp(req.InitLog, initLog) cp(req.Stdout, stdout) cp(req.Stderr, stderr) wg.Wait() return io.EOF } if req.Attached != nil { req.Attached <- struct{}{} } ch := make(chan *rfc5424.Message) stream, err := l.mux.StreamLog(req.Job.Job.Metadata["flynn-controller.app"], req.Job.Job.ID, req.Logs, req.Stream, ch) if err != nil { return err } defer stream.Close() for msg := range ch { var w io.Writer switch string(msg.MsgID) { case "ID1": w = req.Stdout case "ID2": w = req.Stderr case "ID3": w = req.InitLog } if w == nil { continue } if _, err := w.Write(append(msg.Msg, '\n')); err != nil { return nil } } return io.EOF }
BeforeEach(func() { stdin, _, stderr := terminalHelper.StdStreams() var err error master, slave, err = pty.Open() Expect(err).NotTo(HaveOccurred()) fakeTerminalHelper.IsTerminalStub = terminalHelper.IsTerminal fakeTerminalHelper.GetFdInfoStub = terminalHelper.GetFdInfo fakeTerminalHelper.GetWinsizeStub = terminalHelper.GetWinsize fakeTerminalHelper.StdStreamsReturns(stdin, slave, stderr) terminalHelper = fakeTerminalHelper winsize := &term.Winsize{Height: 100, Width: 100} err = term.SetWinsize(slave.Fd(), winsize) Expect(err).NotTo(HaveOccurred()) fakeSecureSession.WaitStub = func() error { fakeSecureSession.SendRequestCallCount() Expect(fakeSecureSession.SendRequestCallCount()).To(Equal(0)) // No dimension change for i := 0; i < 3; i++ { winsize := &term.Winsize{Height: 100, Width: 100} err = term.SetWinsize(slave.Fd(), winsize) Expect(err).NotTo(HaveOccurred()) } winsize := &term.Winsize{Height: 100, Width: 200} err = term.SetWinsize(slave.Fd(), winsize)
func (TermPkg) SetWinsize(fd uintptr, size *term.Winsize) error { return term.SetWinsize(fd, size) }