Full Code of containerd/console for AI

main c8d962180f54 cached
26 files
55.3 KB
15.0k tokens
104 symbols
1 requests
Download .txt
Repository: containerd/console
Branch: main
Commit: c8d962180f54
Files: 26
Total size: 55.3 KB

Directory structure:
gitextract_xi0k0f2o/

├── .github/
│   └── workflows/
│       └── ci.yml
├── .golangci.yml
├── LICENSE
├── README.md
├── console.go
├── console_linux.go
├── console_linux_test.go
├── console_other.go
├── console_test.go
├── console_unix.go
├── console_windows.go
├── go.mod
├── go.sum
├── pty_freebsd_cgo.go
├── pty_freebsd_nocgo.go
├── pty_unix.go
├── pty_zos.go
├── tc_darwin.go
├── tc_freebsd_cgo.go
├── tc_freebsd_nocgo.go
├── tc_linux.go
├── tc_netbsd.go
├── tc_openbsd_cgo.go
├── tc_openbsd_nocgo.go
├── tc_unix.go
└── tc_zos.go

================================================
FILE CONTENTS
================================================

================================================
FILE: .github/workflows/ci.yml
================================================
name: CI

on:
  push:
    branches: [ main ]
  pull_request:
    branches: [ main ]

jobs:

  build:
    name: Console CI
    runs-on: ubuntu-22.04
    timeout-minutes: 5
    steps:

    - name: Set up Go
      uses: actions/setup-go@v3
      with:
        go-version: 1.19.x
      id: go

    - name: Setup Go binary path
      shell: bash
      run: |
        echo "GOPATH=${{ github.workspace }}" >> $GITHUB_ENV
        echo "${{ github.workspace }}/bin" >> $GITHUB_PATH

    - name: Check out code
      uses: actions/checkout@v3
      with:
        path: src/github.com/containerd/console
        fetch-depth: 25

    - name: Install dependencies
      run: |
        go install github.com/golangci/golangci-lint/cmd/golangci-lint@v1.50.1

    - name: Project Checks
      uses: containerd/project-checks@v1.2.2
      with:
        working-directory: src/github.com/containerd/console

    - name: Go Linting
      run: GOGC=75 golangci-lint run
      working-directory: src/github.com/containerd/console

    - name: Build & Test
      working-directory: src/github.com/containerd/console
      run: |
        go test -race
        GOOS=openbsd go build
        GOOS=windows go build


================================================
FILE: .golangci.yml
================================================
linters:
  enable:
    - gofmt
    - goimports
    - ineffassign
    - misspell
    - revive
    - staticcheck
    - structcheck
    - unconvert
    - unused
    - varcheck
    - vet
  disable:
    - errcheck

run:
  timeout: 3m
  skip-dirs:
    - vendor


================================================
FILE: LICENSE
================================================

                                 Apache License
                           Version 2.0, January 2004
                        https://www.apache.org/licenses/

   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION

   1. Definitions.

      "License" shall mean the terms and conditions for use, reproduction,
      and distribution as defined by Sections 1 through 9 of this document.

      "Licensor" shall mean the copyright owner or entity authorized by
      the copyright owner that is granting the License.

      "Legal Entity" shall mean the union of the acting entity and all
      other entities that control, are controlled by, or are under common
      control with that entity. For the purposes of this definition,
      "control" means (i) the power, direct or indirect, to cause the
      direction or management of such entity, whether by contract or
      otherwise, or (ii) ownership of fifty percent (50%) or more of the
      outstanding shares, or (iii) beneficial ownership of such entity.

      "You" (or "Your") shall mean an individual or Legal Entity
      exercising permissions granted by this License.

      "Source" form shall mean the preferred form for making modifications,
      including but not limited to software source code, documentation
      source, and configuration files.

      "Object" form shall mean any form resulting from mechanical
      transformation or translation of a Source form, including but
      not limited to compiled object code, generated documentation,
      and conversions to other media types.

      "Work" shall mean the work of authorship, whether in Source or
      Object form, made available under the License, as indicated by a
      copyright notice that is included in or attached to the work
      (an example is provided in the Appendix below).

      "Derivative Works" shall mean any work, whether in Source or Object
      form, that is based on (or derived from) the Work and for which the
      editorial revisions, annotations, elaborations, or other modifications
      represent, as a whole, an original work of authorship. For the purposes
      of this License, Derivative Works shall not include works that remain
      separable from, or merely link (or bind by name) to the interfaces of,
      the Work and Derivative Works thereof.

      "Contribution" shall mean any work of authorship, including
      the original version of the Work and any modifications or additions
      to that Work or Derivative Works thereof, that is intentionally
      submitted to Licensor for inclusion in the Work by the copyright owner
      or by an individual or Legal Entity authorized to submit on behalf of
      the copyright owner. For the purposes of this definition, "submitted"
      means any form of electronic, verbal, or written communication sent
      to the Licensor or its representatives, including but not limited to
      communication on electronic mailing lists, source code control systems,
      and issue tracking systems that are managed by, or on behalf of, the
      Licensor for the purpose of discussing and improving the Work, but
      excluding communication that is conspicuously marked or otherwise
      designated in writing by the copyright owner as "Not a Contribution."

      "Contributor" shall mean Licensor and any individual or Legal Entity
      on behalf of whom a Contribution has been received by Licensor and
      subsequently incorporated within the Work.

   2. Grant of Copyright License. Subject to the terms and conditions of
      this License, each Contributor hereby grants to You a perpetual,
      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
      copyright license to reproduce, prepare Derivative Works of,
      publicly display, publicly perform, sublicense, and distribute the
      Work and such Derivative Works in Source or Object form.

   3. Grant of Patent License. Subject to the terms and conditions of
      this License, each Contributor hereby grants to You a perpetual,
      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
      (except as stated in this section) patent license to make, have made,
      use, offer to sell, sell, import, and otherwise transfer the Work,
      where such license applies only to those patent claims licensable
      by such Contributor that are necessarily infringed by their
      Contribution(s) alone or by combination of their Contribution(s)
      with the Work to which such Contribution(s) was submitted. If You
      institute patent litigation against any entity (including a
      cross-claim or counterclaim in a lawsuit) alleging that the Work
      or a Contribution incorporated within the Work constitutes direct
      or contributory patent infringement, then any patent licenses
      granted to You under this License for that Work shall terminate
      as of the date such litigation is filed.

   4. Redistribution. You may reproduce and distribute copies of the
      Work or Derivative Works thereof in any medium, with or without
      modifications, and in Source or Object form, provided that You
      meet the following conditions:

      (a) You must give any other recipients of the Work or
          Derivative Works a copy of this License; and

      (b) You must cause any modified files to carry prominent notices
          stating that You changed the files; and

      (c) You must retain, in the Source form of any Derivative Works
          that You distribute, all copyright, patent, trademark, and
          attribution notices from the Source form of the Work,
          excluding those notices that do not pertain to any part of
          the Derivative Works; and

      (d) If the Work includes a "NOTICE" text file as part of its
          distribution, then any Derivative Works that You distribute must
          include a readable copy of the attribution notices contained
          within such NOTICE file, excluding those notices that do not
          pertain to any part of the Derivative Works, in at least one
          of the following places: within a NOTICE text file distributed
          as part of the Derivative Works; within the Source form or
          documentation, if provided along with the Derivative Works; or,
          within a display generated by the Derivative Works, if and
          wherever such third-party notices normally appear. The contents
          of the NOTICE file are for informational purposes only and
          do not modify the License. You may add Your own attribution
          notices within Derivative Works that You distribute, alongside
          or as an addendum to the NOTICE text from the Work, provided
          that such additional attribution notices cannot be construed
          as modifying the License.

      You may add Your own copyright statement to Your modifications and
      may provide additional or different license terms and conditions
      for use, reproduction, or distribution of Your modifications, or
      for any such Derivative Works as a whole, provided Your use,
      reproduction, and distribution of the Work otherwise complies with
      the conditions stated in this License.

   5. Submission of Contributions. Unless You explicitly state otherwise,
      any Contribution intentionally submitted for inclusion in the Work
      by You to the Licensor shall be under the terms and conditions of
      this License, without any additional terms or conditions.
      Notwithstanding the above, nothing herein shall supersede or modify
      the terms of any separate license agreement you may have executed
      with Licensor regarding such Contributions.

   6. Trademarks. This License does not grant permission to use the trade
      names, trademarks, service marks, or product names of the Licensor,
      except as required for reasonable and customary use in describing the
      origin of the Work and reproducing the content of the NOTICE file.

   7. Disclaimer of Warranty. Unless required by applicable law or
      agreed to in writing, Licensor provides the Work (and each
      Contributor provides its Contributions) on an "AS IS" BASIS,
      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
      implied, including, without limitation, any warranties or conditions
      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
      PARTICULAR PURPOSE. You are solely responsible for determining the
      appropriateness of using or redistributing the Work and assume any
      risks associated with Your exercise of permissions under this License.

   8. Limitation of Liability. In no event and under no legal theory,
      whether in tort (including negligence), contract, or otherwise,
      unless required by applicable law (such as deliberate and grossly
      negligent acts) or agreed to in writing, shall any Contributor be
      liable to You for damages, including any direct, indirect, special,
      incidental, or consequential damages of any character arising as a
      result of this License or out of the use or inability to use the
      Work (including but not limited to damages for loss of goodwill,
      work stoppage, computer failure or malfunction, or any and all
      other commercial damages or losses), even if such Contributor
      has been advised of the possibility of such damages.

   9. Accepting Warranty or Additional Liability. While redistributing
      the Work or Derivative Works thereof, You may choose to offer,
      and charge a fee for, acceptance of support, warranty, indemnity,
      or other liability obligations and/or rights consistent with this
      License. However, in accepting such obligations, You may act only
      on Your own behalf and on Your sole responsibility, not on behalf
      of any other Contributor, and only if You agree to indemnify,
      defend, and hold each Contributor harmless for any liability
      incurred by, or claims asserted against, such Contributor by reason
      of your accepting any such warranty or additional liability.

   END OF TERMS AND CONDITIONS

   Copyright The containerd Authors

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

       https://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.


================================================
FILE: README.md
================================================
# console

[![PkgGoDev](https://pkg.go.dev/badge/github.com/containerd/console)](https://pkg.go.dev/github.com/containerd/console)
[![Build Status](https://github.com/containerd/console/workflows/CI/badge.svg)](https://github.com/containerd/console/actions?query=workflow%3ACI)
[![Go Report Card](https://goreportcard.com/badge/github.com/containerd/console)](https://goreportcard.com/report/github.com/containerd/console)

Golang package for dealing with consoles.  Light on deps and a simple API.

## Modifying the current process

```go
current := console.Current()
defer current.Reset()

if err := current.SetRaw(); err != nil {
}
ws, err := current.Size()
current.Resize(ws)
```

## Project details

console is a containerd sub-project, licensed under the [Apache 2.0 license](./LICENSE).
As a containerd sub-project, you will find the:
 * [Project governance](https://github.com/containerd/project/blob/main/GOVERNANCE.md),
 * [Maintainers](https://github.com/containerd/project/blob/main/MAINTAINERS),
 * and [Contributing guidelines](https://github.com/containerd/project/blob/main/CONTRIBUTING.md)

information in our [`containerd/project`](https://github.com/containerd/project) repository.


================================================
FILE: console.go
================================================
/*
   Copyright The containerd Authors.

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.
*/

package console

import (
	"errors"
	"io"
	"os"
)

var (
	ErrNotAConsole    = errors.New("provided file is not a console")
	ErrNotImplemented = errors.New("not implemented")
)

type File interface {
	io.ReadWriteCloser

	// Fd returns its file descriptor
	Fd() uintptr
	// Name returns its file name
	Name() string
}

type Console interface {
	File

	// Resize resizes the console to the provided window size
	Resize(WinSize) error
	// ResizeFrom resizes the calling console to the size of the
	// provided console
	ResizeFrom(Console) error
	// SetRaw sets the console in raw mode
	SetRaw() error
	// DisableEcho disables echo on the console
	DisableEcho() error
	// Reset restores the console to its original state
	Reset() error
	// Size returns the window size of the console
	Size() (WinSize, error)
}

// WinSize specifies the window size of the console
type WinSize struct {
	// Height of the console
	Height uint16
	// Width of the console
	Width uint16
	x     uint16
	y     uint16
}

// Current returns the current process' console
func Current() (c Console) {
	var err error
	// Usually all three streams (stdin, stdout, and stderr)
	// are open to the same console, but some might be redirected,
	// so try all three.
	for _, s := range []*os.File{os.Stderr, os.Stdout, os.Stdin} {
		if c, err = ConsoleFromFile(s); err == nil {
			return c
		}
	}
	// One of the std streams should always be a console
	// for the design of this function.
	panic(err)
}

// ConsoleFromFile returns a console using the provided file
// nolint:revive
func ConsoleFromFile(f File) (Console, error) {
	if err := checkConsole(f); err != nil {
		return nil, err
	}
	return newMaster(f)
}


================================================
FILE: console_linux.go
================================================
//go:build linux
// +build linux

/*
   Copyright The containerd Authors.

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.
*/

package console

import (
	"io"
	"os"
	"sync"

	"golang.org/x/sys/unix"
)

const (
	maxEvents = 128
)

// Epoller manages multiple epoll consoles using edge-triggered epoll api so we
// dont have to deal with repeated wake-up of EPOLLER or EPOLLHUP.
// For more details, see:
// - https://github.com/systemd/systemd/pull/4262
// - https://github.com/moby/moby/issues/27202
//
// Example usage of Epoller and EpollConsole can be as follow:
//
//	epoller, _ := NewEpoller()
//	epollConsole, _ := epoller.Add(console)
//	go epoller.Wait()
//	var (
//		b  bytes.Buffer
//		wg sync.WaitGroup
//	)
//	wg.Add(1)
//	go func() {
//		io.Copy(&b, epollConsole)
//		wg.Done()
//	}()
//	// perform I/O on the console
//	epollConsole.Shutdown(epoller.CloseConsole)
//	wg.Wait()
//	epollConsole.Close()
type Epoller struct {
	efd       int
	mu        sync.Mutex
	fdMapping map[int]*EpollConsole
	closeOnce sync.Once
}

// NewEpoller returns an instance of epoller with a valid epoll fd.
func NewEpoller() (*Epoller, error) {
	efd, err := unix.EpollCreate1(unix.EPOLL_CLOEXEC)
	if err != nil {
		return nil, err
	}
	return &Epoller{
		efd:       efd,
		fdMapping: make(map[int]*EpollConsole),
	}, nil
}

// Add creates an epoll console based on the provided console. The console will
// be registered with EPOLLET (i.e. using edge-triggered notification) and its
// file descriptor will be set to non-blocking mode. After this, user should use
// the return console to perform I/O.
func (e *Epoller) Add(console Console) (*EpollConsole, error) {
	sysfd := int(console.Fd())
	// Set sysfd to non-blocking mode
	if err := unix.SetNonblock(sysfd, true); err != nil {
		return nil, err
	}

	ev := unix.EpollEvent{
		Events: unix.EPOLLIN | unix.EPOLLOUT | unix.EPOLLRDHUP | unix.EPOLLET,
		Fd:     int32(sysfd),
	}
	if err := unix.EpollCtl(e.efd, unix.EPOLL_CTL_ADD, sysfd, &ev); err != nil {
		return nil, err
	}
	ef := &EpollConsole{
		Console: console,
		sysfd:   sysfd,
		readc:   sync.NewCond(&sync.Mutex{}),
		writec:  sync.NewCond(&sync.Mutex{}),
	}
	e.mu.Lock()
	e.fdMapping[sysfd] = ef
	e.mu.Unlock()
	return ef, nil
}

// Wait starts the loop to wait for its consoles' notifications and signal
// appropriate console that it can perform I/O.
func (e *Epoller) Wait() error {
	events := make([]unix.EpollEvent, maxEvents)
	for {
		n, err := unix.EpollWait(e.efd, events, -1)
		if err != nil {
			// EINTR: The call was interrupted by a signal handler before either
			// any of the requested events occurred or the timeout expired
			if err == unix.EINTR {
				continue
			}
			return err
		}
		for i := 0; i < n; i++ {
			ev := &events[i]
			// the console is ready to be read from
			if ev.Events&(unix.EPOLLIN|unix.EPOLLHUP|unix.EPOLLERR) != 0 {
				if epfile := e.getConsole(int(ev.Fd)); epfile != nil {
					epfile.signalRead()
				}
			}
			// the console is ready to be written to
			if ev.Events&(unix.EPOLLOUT|unix.EPOLLHUP|unix.EPOLLERR) != 0 {
				if epfile := e.getConsole(int(ev.Fd)); epfile != nil {
					epfile.signalWrite()
				}
			}
		}
	}
}

// CloseConsole unregisters the console's file descriptor from epoll interface
func (e *Epoller) CloseConsole(fd int) error {
	e.mu.Lock()
	defer e.mu.Unlock()
	delete(e.fdMapping, fd)
	return unix.EpollCtl(e.efd, unix.EPOLL_CTL_DEL, fd, &unix.EpollEvent{})
}

func (e *Epoller) getConsole(sysfd int) *EpollConsole {
	e.mu.Lock()
	f := e.fdMapping[sysfd]
	e.mu.Unlock()
	return f
}

// Close closes the epoll fd
func (e *Epoller) Close() error {
	closeErr := os.ErrClosed // default to "file already closed"
	e.closeOnce.Do(func() {
		closeErr = unix.Close(e.efd)
	})
	return closeErr
}

// EpollConsole acts like a console but registers its file descriptor with an
// epoll fd and uses epoll API to perform I/O.
type EpollConsole struct {
	Console
	readc  *sync.Cond
	writec *sync.Cond
	sysfd  int
	closed bool
}

// Read reads up to len(p) bytes into p. It returns the number of bytes read
// (0 <= n <= len(p)) and any error encountered.
//
// If the console's read returns EAGAIN or EIO, we assume that it's a
// temporary error because the other side went away and wait for the signal
// generated by epoll event to continue.
func (ec *EpollConsole) Read(p []byte) (n int, err error) {
	var read int
	ec.readc.L.Lock()
	defer ec.readc.L.Unlock()
	for {
		read, err = ec.Console.Read(p[n:])
		n += read
		if err != nil {
			var hangup bool
			if perr, ok := err.(*os.PathError); ok {
				hangup = (perr.Err == unix.EAGAIN || perr.Err == unix.EIO)
			} else {
				hangup = (err == unix.EAGAIN || err == unix.EIO)
			}
			// if the other end disappear, assume this is temporary and wait for the
			// signal to continue again. Unless we didnt read anything and the
			// console is already marked as closed then we should exit
			if hangup && !(n == 0 && len(p) > 0 && ec.closed) {
				ec.readc.Wait()
				continue
			}
		}
		break
	}
	// if we didnt read anything then return io.EOF to end gracefully
	if n == 0 && len(p) > 0 && err == nil {
		err = io.EOF
	}
	// signal for others that we finished the read
	ec.readc.Signal()
	return n, err
}

// Writes len(p) bytes from p to the console. It returns the number of bytes
// written from p (0 <= n <= len(p)) and any error encountered that caused
// the write to stop early.
//
// If writes to the console returns EAGAIN or EIO, we assume that it's a
// temporary error because the other side went away and wait for the signal
// generated by epoll event to continue.
func (ec *EpollConsole) Write(p []byte) (n int, err error) {
	var written int
	ec.writec.L.Lock()
	defer ec.writec.L.Unlock()
	for {
		written, err = ec.Console.Write(p[n:])
		n += written
		if err != nil {
			var hangup bool
			if perr, ok := err.(*os.PathError); ok {
				hangup = (perr.Err == unix.EAGAIN || perr.Err == unix.EIO)
			} else {
				hangup = (err == unix.EAGAIN || err == unix.EIO)
			}
			// if the other end disappears, assume this is temporary and wait for the
			// signal to continue again.
			if hangup {
				ec.writec.Wait()
				continue
			}
		}
		// unrecoverable error, break the loop and return the error
		break
	}
	if n < len(p) && err == nil {
		err = io.ErrShortWrite
	}
	// signal for others that we finished the write
	ec.writec.Signal()
	return n, err
}

// Shutdown closes the file descriptor and signals call waiters for this fd.
// It accepts a callback which will be called with the console's fd. The
// callback typically will be used to do further cleanup such as unregister the
// console's fd from the epoll interface.
// User should call Shutdown and wait for all I/O operation to be finished
// before closing the console.
func (ec *EpollConsole) Shutdown(close func(int) error) error {
	ec.readc.L.Lock()
	defer ec.readc.L.Unlock()
	ec.writec.L.Lock()
	defer ec.writec.L.Unlock()

	ec.readc.Broadcast()
	ec.writec.Broadcast()
	ec.closed = true
	return close(ec.sysfd)
}

// signalRead signals that the console is readable.
func (ec *EpollConsole) signalRead() {
	ec.readc.L.Lock()
	ec.readc.Signal()
	ec.readc.L.Unlock()
}

// signalWrite signals that the console is writable.
func (ec *EpollConsole) signalWrite() {
	ec.writec.L.Lock()
	ec.writec.Signal()
	ec.writec.L.Unlock()
}


================================================
FILE: console_linux_test.go
================================================
/*
   Copyright The containerd Authors.

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.
*/

package console

import (
	"bytes"
	"fmt"
	"io"
	"os"
	"os/exec"
	"sync"
	"testing"
)

func TestEpollConsole(t *testing.T) {
	console, slavePath, err := NewPty()
	if err != nil {
		t.Fatal(err)
	}
	defer console.Close()

	slave, err := os.OpenFile(slavePath, os.O_RDWR, 0)
	if err != nil {
		t.Fatal(err)
	}
	defer slave.Close()

	iteration := 10

	cmd := exec.Command("sh", "-c", fmt.Sprintf("for x in `seq 1 %d`; do echo -n test; done", iteration))
	cmd.Stdin = slave
	cmd.Stdout = slave
	cmd.Stderr = slave

	epoller, err := NewEpoller()
	if err != nil {
		t.Fatal(err)
	}
	epollConsole, err := epoller.Add(console)
	if err != nil {
		t.Fatal(err)
	}
	go epoller.Wait()

	var (
		b  bytes.Buffer
		wg sync.WaitGroup
	)
	wg.Add(1)
	go func() {
		io.Copy(&b, epollConsole)
		wg.Done()
	}()

	if err := cmd.Run(); err != nil {
		t.Fatal(err)
	}
	slave.Close()
	if err := epollConsole.Shutdown(epoller.CloseConsole); err != nil {
		t.Fatal(err)
	}
	wg.Wait()
	if err := epollConsole.Close(); err != nil {
		t.Fatal(err)
	}

	expectedOutput := ""
	for i := 0; i < iteration; i++ {
		expectedOutput += "test"
	}
	if out := b.String(); out != expectedOutput {
		t.Errorf("unexpected output %q", out)
	}

	// make sure multiple Close calls return os.ErrClosed after the first
	if err := epoller.Close(); err != nil {
		t.Fatal(err)
	}
	if err := epoller.Close(); err != os.ErrClosed {
		t.Fatalf("unexpected error returned from second call to epoller.Close(): %v", err)
	}
}


================================================
FILE: console_other.go
================================================
//go:build !darwin && !freebsd && !linux && !netbsd && !openbsd && !windows && !zos
// +build !darwin,!freebsd,!linux,!netbsd,!openbsd,!windows,!zos

/*
   Copyright The containerd Authors.

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.
*/

package console

// NewPty creates a new pty pair
// The master is returned as the first console and a string
// with the path to the pty slave is returned as the second
func NewPty() (Console, string, error) {
	return nil, "", ErrNotImplemented
}

// checkConsole checks if the provided file is a console
func checkConsole(f File) error {
	return ErrNotAConsole
}

func newMaster(f File) (Console, error) {
	return nil, ErrNotImplemented
}


================================================
FILE: console_test.go
================================================
//go:build linux || zos || freebsd
// +build linux zos freebsd

/*
   Copyright The containerd Authors.

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.
*/

package console

import (
	"bytes"
	"io"
	"os"
	"os/exec"
	"sync"
	"testing"
)

func TestWinSize(t *testing.T) {
	c, _, err := NewPty()
	if err != nil {
		t.Fatal(err)
	}
	defer c.Close()
	if err := c.Resize(WinSize{
		Width:  11,
		Height: 10,
	}); err != nil {
		t.Error(err)
		return
	}
	size, err := c.Size()
	if err != nil {
		t.Error(err)
		return
	}
	if size.Width != 11 {
		t.Errorf("width should be 11 but received %d", size.Width)
	}
	if size.Height != 10 {
		t.Errorf("height should be 10 but received %d", size.Height)
	}
}

func testConsolePty(t *testing.T, newPty func() (Console, string, error)) {
	console, slavePath, err := newPty()
	if err != nil {
		t.Fatal(err)
	}
	defer console.Close()

	slave, err := os.OpenFile(slavePath, os.O_RDWR, 0)
	if err != nil {
		t.Fatal(err)
	}
	defer slave.Close()

	iteration := 10

	var (
		b  bytes.Buffer
		wg sync.WaitGroup
	)
	wg.Add(1)
	go func() {
		io.Copy(&b, console)
		wg.Done()
	}()

	for i := 0; i < iteration; i++ {
		cmd := exec.Command("sh", "-c", "printf test")
		cmd.Stdin = slave
		cmd.Stdout = slave
		cmd.Stderr = slave

		if err := cmd.Run(); err != nil {
			t.Fatal(err)
		}
	}
	slave.Close()
	wg.Wait()

	expectedOutput := ""
	for i := 0; i < iteration; i++ {
		expectedOutput += "test"
	}
	if out := b.String(); out != expectedOutput {
		t.Errorf("unexpected output %q", out)
	}
}

func TestConsolePty_NewPty(t *testing.T) {
	testConsolePty(t, NewPty)
}

func TestConsolePty_NewPtyFromFile(t *testing.T) {
	testConsolePty(t, func() (Console, string, error) {
		// Equivalent to NewPty().
		f, err := openpt()
		if err != nil {
			return nil, "", err
		}
		return NewPtyFromFile(f)
	})
}


================================================
FILE: console_unix.go
================================================
//go:build darwin || freebsd || linux || netbsd || openbsd || zos
// +build darwin freebsd linux netbsd openbsd zos

/*
   Copyright The containerd Authors.

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.
*/

package console

import (
	"golang.org/x/sys/unix"
)

// NewPty creates a new pty pair
// The master is returned as the first console and a string
// with the path to the pty slave is returned as the second
func NewPty() (Console, string, error) {
	f, err := openpt()
	if err != nil {
		return nil, "", err
	}
	return NewPtyFromFile(f)
}

// NewPtyFromFile creates a new pty pair, just like [NewPty] except that the
// provided [os.File] is used as the master rather than automatically creating
// a new master from /dev/ptmx. The ownership of [os.File] is passed to the
// returned [Console], so the caller must be careful to not call Close on the
// underlying file.
func NewPtyFromFile(f File) (Console, string, error) {
	slave, err := ptsname(f)
	if err != nil {
		return nil, "", err
	}
	if err := unlockpt(f); err != nil {
		return nil, "", err
	}
	m, err := newMaster(f)
	if err != nil {
		return nil, "", err
	}
	return m, slave, nil
}

type master struct {
	f        File
	original *unix.Termios
}

func (m *master) Read(b []byte) (int, error) {
	return m.f.Read(b)
}

func (m *master) Write(b []byte) (int, error) {
	return m.f.Write(b)
}

func (m *master) Close() error {
	return m.f.Close()
}

func (m *master) Resize(ws WinSize) error {
	return tcswinsz(m.f.Fd(), ws)
}

func (m *master) ResizeFrom(c Console) error {
	ws, err := c.Size()
	if err != nil {
		return err
	}
	return m.Resize(ws)
}

func (m *master) Reset() error {
	if m.original == nil {
		return nil
	}
	return tcset(m.f.Fd(), m.original)
}

func (m *master) getCurrent() (unix.Termios, error) {
	var termios unix.Termios
	if err := tcget(m.f.Fd(), &termios); err != nil {
		return unix.Termios{}, err
	}
	return termios, nil
}

func (m *master) SetRaw() error {
	rawState, err := m.getCurrent()
	if err != nil {
		return err
	}
	rawState = cfmakeraw(rawState)
	rawState.Oflag = rawState.Oflag | unix.OPOST
	return tcset(m.f.Fd(), &rawState)
}

func (m *master) DisableEcho() error {
	rawState, err := m.getCurrent()
	if err != nil {
		return err
	}
	rawState.Lflag = rawState.Lflag &^ unix.ECHO
	return tcset(m.f.Fd(), &rawState)
}

func (m *master) Size() (WinSize, error) {
	return tcgwinsz(m.f.Fd())
}

func (m *master) Fd() uintptr {
	return m.f.Fd()
}

func (m *master) Name() string {
	return m.f.Name()
}

// checkConsole checks if the provided file is a console
func checkConsole(f File) error {
	var termios unix.Termios
	if tcget(f.Fd(), &termios) != nil {
		return ErrNotAConsole
	}
	return nil
}

func newMaster(f File) (Console, error) {
	m := &master{
		f: f,
	}
	t, err := m.getCurrent()
	if err != nil {
		return nil, err
	}
	m.original = &t
	return m, nil
}

// ClearONLCR sets the necessary tty_ioctl(4)s to ensure that a pty pair
// created by us acts normally. In particular, a not-very-well-known default of
// Linux unix98 ptys is that they have +onlcr by default. While this isn't a
// problem for terminal emulators, because we relay data from the terminal we
// also relay that funky line discipline.
func ClearONLCR(fd uintptr) error {
	return setONLCR(fd, false)
}

// SetONLCR sets the necessary tty_ioctl(4)s to ensure that a pty pair
// created by us acts as intended for a terminal emulator.
func SetONLCR(fd uintptr) error {
	return setONLCR(fd, true)
}


================================================
FILE: console_windows.go
================================================
/*
   Copyright The containerd Authors.

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.
*/

package console

import (
	"errors"
	"fmt"
	"os"

	"golang.org/x/sys/windows"
)

var vtInputSupported bool

func (m *master) initStdios() {
	// Note: We discard console mode warnings, because in/out can be redirected.
	//
	// TODO: Investigate opening CONOUT$/CONIN$ to handle this correctly

	m.in = windows.Handle(os.Stdin.Fd())
	if err := windows.GetConsoleMode(m.in, &m.inMode); err == nil {
		// Validate that windows.ENABLE_VIRTUAL_TERMINAL_INPUT is supported, but do not set it.
		if err = windows.SetConsoleMode(m.in, m.inMode|windows.ENABLE_VIRTUAL_TERMINAL_INPUT); err == nil {
			vtInputSupported = true
		}
		// Unconditionally set the console mode back even on failure because SetConsoleMode
		// remembers invalid bits on input handles.
		windows.SetConsoleMode(m.in, m.inMode)
	}

	m.out = windows.Handle(os.Stdout.Fd())
	if err := windows.GetConsoleMode(m.out, &m.outMode); err == nil {
		if err := windows.SetConsoleMode(m.out, m.outMode|windows.ENABLE_VIRTUAL_TERMINAL_PROCESSING); err == nil {
			m.outMode |= windows.ENABLE_VIRTUAL_TERMINAL_PROCESSING
		} else {
			windows.SetConsoleMode(m.out, m.outMode)
		}
	}

	m.err = windows.Handle(os.Stderr.Fd())
	if err := windows.GetConsoleMode(m.err, &m.errMode); err == nil {
		if err := windows.SetConsoleMode(m.err, m.errMode|windows.ENABLE_VIRTUAL_TERMINAL_PROCESSING); err == nil {
			m.errMode |= windows.ENABLE_VIRTUAL_TERMINAL_PROCESSING
		} else {
			windows.SetConsoleMode(m.err, m.errMode)
		}
	}
}

type master struct {
	in     windows.Handle
	inMode uint32

	out     windows.Handle
	outMode uint32

	err     windows.Handle
	errMode uint32
}

func (m *master) SetRaw() error {
	if err := makeInputRaw(m.in, m.inMode); err != nil {
		return err
	}

	// Set StdOut and StdErr to raw mode, we ignore failures since
	// windows.DISABLE_NEWLINE_AUTO_RETURN might not be supported on this version of
	// Windows.

	windows.SetConsoleMode(m.out, m.outMode|windows.DISABLE_NEWLINE_AUTO_RETURN)

	windows.SetConsoleMode(m.err, m.errMode|windows.DISABLE_NEWLINE_AUTO_RETURN)

	return nil
}

func (m *master) Reset() error {
	var errs []error

	for _, s := range []struct {
		fd   windows.Handle
		mode uint32
	}{
		{m.in, m.inMode},
		{m.out, m.outMode},
		{m.err, m.errMode},
	} {
		if err := windows.SetConsoleMode(s.fd, s.mode); err != nil {
			// we can't just abort on the first error, otherwise we might leave
			// the console in an unexpected state.
			errs = append(errs, fmt.Errorf("unable to restore console mode: %w", err))
		}
	}

	if len(errs) > 0 {
		return errs[0]
	}

	return nil
}

func (m *master) Size() (WinSize, error) {
	var info windows.ConsoleScreenBufferInfo
	err := windows.GetConsoleScreenBufferInfo(m.out, &info)
	if err != nil {
		return WinSize{}, fmt.Errorf("unable to get console info: %w", err)
	}

	winsize := WinSize{
		Width:  uint16(info.Window.Right - info.Window.Left + 1),
		Height: uint16(info.Window.Bottom - info.Window.Top + 1),
	}

	return winsize, nil
}

func (m *master) Resize(ws WinSize) error {
	return ErrNotImplemented
}

func (m *master) ResizeFrom(c Console) error {
	return ErrNotImplemented
}

func (m *master) DisableEcho() error {
	mode := m.inMode &^ windows.ENABLE_ECHO_INPUT
	mode |= windows.ENABLE_PROCESSED_INPUT
	mode |= windows.ENABLE_LINE_INPUT

	if err := windows.SetConsoleMode(m.in, mode); err != nil {
		return fmt.Errorf("unable to set console to disable echo: %w", err)
	}

	return nil
}

func (m *master) Close() error {
	return nil
}

func (m *master) Read(b []byte) (int, error) {
	return os.Stdin.Read(b)
}

func (m *master) Write(b []byte) (int, error) {
	return os.Stdout.Write(b)
}

func (m *master) Fd() uintptr {
	return uintptr(m.in)
}

// on windows, console can only be made from os.Std{in,out,err}, hence there
// isnt a single name here we can use. Return a dummy "console" value in this
// case should be sufficient.
func (m *master) Name() string {
	return "console"
}

// makeInputRaw puts the terminal (Windows Console) connected to the given
// file descriptor into raw mode
func makeInputRaw(fd windows.Handle, mode uint32) error {
	// See
	// -- https://msdn.microsoft.com/en-us/library/windows/desktop/ms686033(v=vs.85).aspx
	// -- https://msdn.microsoft.com/en-us/library/windows/desktop/ms683462(v=vs.85).aspx

	// Disable these modes
	mode &^= windows.ENABLE_ECHO_INPUT
	mode &^= windows.ENABLE_LINE_INPUT
	mode &^= windows.ENABLE_MOUSE_INPUT
	mode &^= windows.ENABLE_WINDOW_INPUT
	mode &^= windows.ENABLE_PROCESSED_INPUT

	// Enable these modes
	mode |= windows.ENABLE_EXTENDED_FLAGS
	mode |= windows.ENABLE_INSERT_MODE
	mode |= windows.ENABLE_QUICK_EDIT_MODE

	if vtInputSupported {
		mode |= windows.ENABLE_VIRTUAL_TERMINAL_INPUT
	}

	if err := windows.SetConsoleMode(fd, mode); err != nil {
		return fmt.Errorf("unable to set console to raw mode: %w", err)
	}

	return nil
}

func checkConsole(f File) error {
	var mode uint32
	if err := windows.GetConsoleMode(windows.Handle(f.Fd()), &mode); err != nil {
		return err
	}
	return nil
}

func newMaster(f File) (Console, error) {
	if f != os.Stdin && f != os.Stdout && f != os.Stderr {
		return nil, errors.New("creating a console from a file is not supported on windows")
	}
	m := &master{}
	m.initStdios()
	return m, nil
}


================================================
FILE: go.mod
================================================
module github.com/containerd/console

go 1.13

require golang.org/x/sys v0.1.0


================================================
FILE: go.sum
================================================
golang.org/x/sys v0.1.0 h1:kunALQeHf1/185U1i0GOB/fy1IPRDDpuoOOqRReG57U=
golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=


================================================
FILE: pty_freebsd_cgo.go
================================================
//go:build freebsd && cgo
// +build freebsd,cgo

/*
   Copyright The containerd Authors.

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.
*/

package console

import (
	"fmt"
	"os"
)

/*
#include <fcntl.h>
#include <stdlib.h>
#include <unistd.h>
*/
import "C"

// openpt allocates a new pseudo-terminal and establishes a connection with its
// control device.
func openpt() (*os.File, error) {
	fd, err := C.posix_openpt(C.O_RDWR)
	if err != nil {
		return nil, fmt.Errorf("posix_openpt: %w", err)
	}
	if _, err := C.grantpt(fd); err != nil {
		C.close(fd)
		return nil, fmt.Errorf("grantpt: %w", err)
	}
	return os.NewFile(uintptr(fd), ""), nil
}


================================================
FILE: pty_freebsd_nocgo.go
================================================
//go:build freebsd && !cgo
// +build freebsd,!cgo

/*
   Copyright The containerd Authors.

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.
*/

package console

import (
	"os"
)

//
// Implementing the functions below requires cgo support.  Non-cgo stubs
// versions are defined below to enable cross-compilation of source code
// that depends on these functions, but the resultant cross-compiled
// binaries cannot actually be used.  If the stub function(s) below are
// actually invoked they will display an error message and cause the
// calling process to exit.
//

func openpt() (*os.File, error) {
	panic("openpt() support requires cgo.")
}


================================================
FILE: pty_unix.go
================================================
//go:build darwin || linux || netbsd || openbsd
// +build darwin linux netbsd openbsd

/*
   Copyright The containerd Authors.

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.
*/

package console

import (
	"os"

	"golang.org/x/sys/unix"
)

// openpt allocates a new pseudo-terminal by opening the /dev/ptmx device
func openpt() (*os.File, error) {
	return os.OpenFile("/dev/ptmx", unix.O_RDWR|unix.O_NOCTTY|unix.O_CLOEXEC, 0)
}


================================================
FILE: pty_zos.go
================================================
//go:build zos
// +build zos

/*
   Copyright The containerd Authors.

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.
*/

package console

import (
	"fmt"
	"os"
)

// openpt allocates a new pseudo-terminal by opening the first available /dev/ptypXX device
func openpt() (*os.File, error) {
	var f *os.File
	var err error
	for i := 0; ; i++ {
		ptyp := fmt.Sprintf("/dev/ptyp%04d", i)
		f, err = os.OpenFile(ptyp, os.O_RDWR, 0600)
		if err == nil {
			break
		}
		if os.IsNotExist(err) {
			return nil, err
		}
		// else probably Resource Busy
	}
	return f, nil
}


================================================
FILE: tc_darwin.go
================================================
/*
   Copyright The containerd Authors.

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.
*/

package console

import (
	"fmt"

	"golang.org/x/sys/unix"
)

const (
	cmdTcGet = unix.TIOCGETA
	cmdTcSet = unix.TIOCSETA
)

// unlockpt unlocks the slave pseudoterminal device corresponding to the master pseudoterminal referred to by f.
// unlockpt should be called before opening the slave side of a pty.
func unlockpt(f File) error {
	return unix.IoctlSetPointerInt(int(f.Fd()), unix.TIOCPTYUNLK, 0)
}

// ptsname retrieves the name of the first available pts for the given master.
func ptsname(f File) (string, error) {
	n, err := unix.IoctlGetInt(int(f.Fd()), unix.TIOCPTYGNAME)
	if err != nil {
		return "", err
	}
	return fmt.Sprintf("/dev/pts/%d", n), nil
}


================================================
FILE: tc_freebsd_cgo.go
================================================
//go:build freebsd && cgo
// +build freebsd,cgo

/*
   Copyright The containerd Authors.

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.
*/

package console

import (
	"fmt"

	"golang.org/x/sys/unix"
)

/*
#include <stdlib.h>
#include <unistd.h>
*/
import "C"

const (
	cmdTcGet = unix.TIOCGETA
	cmdTcSet = unix.TIOCSETA
)

// unlockpt unlocks the slave pseudoterminal device corresponding to the master pseudoterminal referred to by f.
// unlockpt should be called before opening the slave side of a pty.
func unlockpt(f File) error {
	fd := C.int(f.Fd())
	if _, err := C.unlockpt(fd); err != nil {
		C.close(fd)
		return fmt.Errorf("unlockpt: %w", err)
	}
	return nil
}

// ptsname retrieves the name of the first available pts for the given master.
func ptsname(f File) (string, error) {
	n, err := unix.IoctlGetInt(int(f.Fd()), unix.TIOCGPTN)
	if err != nil {
		return "", err
	}
	return fmt.Sprintf("/dev/pts/%d", n), nil
}


================================================
FILE: tc_freebsd_nocgo.go
================================================
//go:build freebsd && !cgo
// +build freebsd,!cgo

/*
   Copyright The containerd Authors.

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.
*/

package console

import (
	"fmt"

	"golang.org/x/sys/unix"
)

const (
	cmdTcGet = unix.TIOCGETA
	cmdTcSet = unix.TIOCSETA
)

//
// Implementing the functions below requires cgo support.  Non-cgo stubs
// versions are defined below to enable cross-compilation of source code
// that depends on these functions, but the resultant cross-compiled
// binaries cannot actually be used.  If the stub function(s) below are
// actually invoked they will display an error message and cause the
// calling process to exit.
//

// unlockpt unlocks the slave pseudoterminal device corresponding to the master pseudoterminal referred to by f.
// unlockpt should be called before opening the slave side of a pty.
func unlockpt(f File) error {
	panic("unlockpt() support requires cgo.")
}

// ptsname retrieves the name of the first available pts for the given master.
func ptsname(f File) (string, error) {
	n, err := unix.IoctlGetInt(int(f.Fd()), unix.TIOCGPTN)
	if err != nil {
		return "", err
	}
	return fmt.Sprintf("/dev/pts/%d", n), nil
}


================================================
FILE: tc_linux.go
================================================
/*
   Copyright The containerd Authors.

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.
*/

package console

import (
	"fmt"
	"unsafe"

	"golang.org/x/sys/unix"
)

const (
	cmdTcGet = unix.TCGETS
	cmdTcSet = unix.TCSETS
)

// unlockpt unlocks the slave pseudoterminal device corresponding to the master pseudoterminal referred to by f.
// unlockpt should be called before opening the slave side of a pty.
func unlockpt(f File) error {
	var u int32
	// XXX do not use unix.IoctlSetPointerInt here, see commit dbd69c59b81.
	if _, _, err := unix.Syscall(unix.SYS_IOCTL, f.Fd(), unix.TIOCSPTLCK, uintptr(unsafe.Pointer(&u))); err != 0 {
		return err
	}
	return nil
}

// ptsname retrieves the name of the first available pts for the given master.
func ptsname(f File) (string, error) {
	var u uint32
	// XXX do not use unix.IoctlGetInt here, see commit dbd69c59b81.
	if _, _, err := unix.Syscall(unix.SYS_IOCTL, f.Fd(), unix.TIOCGPTN, uintptr(unsafe.Pointer(&u))); err != 0 {
		return "", err
	}
	return fmt.Sprintf("/dev/pts/%d", u), nil
}


================================================
FILE: tc_netbsd.go
================================================
/*
   Copyright The containerd Authors.

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.
*/

package console

import (
	"bytes"

	"golang.org/x/sys/unix"
)

const (
	cmdTcGet = unix.TIOCGETA
	cmdTcSet = unix.TIOCSETA
)

// unlockpt unlocks the slave pseudoterminal device corresponding to the master pseudoterminal referred to by f.
// unlockpt should be called before opening the slave side of a pty.
// This does not exist on NetBSD, it does not allocate controlling terminals on open
func unlockpt(f File) error {
	return nil
}

// ptsname retrieves the name of the first available pts for the given master.
func ptsname(f File) (string, error) {
	ptm, err := unix.IoctlGetPtmget(int(f.Fd()), unix.TIOCPTSNAME)
	if err != nil {
		return "", err
	}
	return string(ptm.Sn[:bytes.IndexByte(ptm.Sn[:], 0)]), nil
}


================================================
FILE: tc_openbsd_cgo.go
================================================
//go:build openbsd && cgo
// +build openbsd,cgo

/*
   Copyright The containerd Authors.

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.
*/

package console

import (
	"golang.org/x/sys/unix"
)

//#include <stdlib.h>
import "C"

const (
	cmdTcGet = unix.TIOCGETA
	cmdTcSet = unix.TIOCSETA
)

// ptsname retrieves the name of the first available pts for the given master.
func ptsname(f File) (string, error) {
	ptspath, err := C.ptsname(C.int(f.Fd()))
	if err != nil {
		return "", err
	}
	return C.GoString(ptspath), nil
}

// unlockpt unlocks the slave pseudoterminal device corresponding to the master pseudoterminal referred to by f.
// unlockpt should be called before opening the slave side of a pty.
func unlockpt(f File) error {
	if _, err := C.grantpt(C.int(f.Fd())); err != nil {
		return err
	}
	return nil
}


================================================
FILE: tc_openbsd_nocgo.go
================================================
//go:build openbsd && !cgo
// +build openbsd,!cgo

/*
   Copyright The containerd Authors.

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.
*/

//
// Implementing the functions below requires cgo support.  Non-cgo stubs
// versions are defined below to enable cross-compilation of source code
// that depends on these functions, but the resultant cross-compiled
// binaries cannot actually be used.  If the stub function(s) below are
// actually invoked they will display an error message and cause the
// calling process to exit.
//

package console

import (
	"golang.org/x/sys/unix"
)

const (
	cmdTcGet = unix.TIOCGETA
	cmdTcSet = unix.TIOCSETA
)

func ptsname(f File) (string, error) {
	panic("ptsname() support requires cgo.")
}

func unlockpt(f File) error {
	panic("unlockpt() support requires cgo.")
}


================================================
FILE: tc_unix.go
================================================
//go:build darwin || freebsd || linux || netbsd || openbsd || zos
// +build darwin freebsd linux netbsd openbsd zos

/*
   Copyright The containerd Authors.

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.
*/

package console

import (
	"golang.org/x/sys/unix"
)

func tcget(fd uintptr, p *unix.Termios) error {
	termios, err := unix.IoctlGetTermios(int(fd), cmdTcGet)
	if err != nil {
		return err
	}
	*p = *termios
	return nil
}

func tcset(fd uintptr, p *unix.Termios) error {
	return unix.IoctlSetTermios(int(fd), cmdTcSet, p)
}

func tcgwinsz(fd uintptr) (WinSize, error) {
	var ws WinSize

	uws, err := unix.IoctlGetWinsize(int(fd), unix.TIOCGWINSZ)
	if err != nil {
		return ws, err
	}

	// Translate from unix.Winsize to console.WinSize
	ws.Height = uws.Row
	ws.Width = uws.Col
	ws.x = uws.Xpixel
	ws.y = uws.Ypixel
	return ws, nil
}

func tcswinsz(fd uintptr, ws WinSize) error {
	// Translate from console.WinSize to unix.Winsize

	var uws unix.Winsize
	uws.Row = ws.Height
	uws.Col = ws.Width
	uws.Xpixel = ws.x
	uws.Ypixel = ws.y

	return unix.IoctlSetWinsize(int(fd), unix.TIOCSWINSZ, &uws)
}

func setONLCR(fd uintptr, enable bool) error {
	var termios unix.Termios
	if err := tcget(fd, &termios); err != nil {
		return err
	}
	if enable {
		// Set +onlcr so we can act like a real terminal
		termios.Oflag |= unix.ONLCR
	} else {
		// Set -onlcr so we don't have to deal with \r.
		termios.Oflag &^= unix.ONLCR
	}
	return tcset(fd, &termios)
}

func cfmakeraw(t unix.Termios) unix.Termios {
	t.Iflag &^= (unix.IGNBRK | unix.BRKINT | unix.PARMRK | unix.ISTRIP | unix.INLCR | unix.IGNCR | unix.ICRNL | unix.IXON)
	t.Oflag &^= unix.OPOST
	t.Lflag &^= (unix.ECHO | unix.ECHONL | unix.ICANON | unix.ISIG | unix.IEXTEN)
	t.Cflag &^= (unix.CSIZE | unix.PARENB)
	t.Cflag |= unix.CS8
	t.Cc[unix.VMIN] = 1
	t.Cc[unix.VTIME] = 0

	return t
}


================================================
FILE: tc_zos.go
================================================
/*
   Copyright The containerd Authors.

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.
*/

package console

import (
	"strings"

	"golang.org/x/sys/unix"
)

const (
	cmdTcGet = unix.TCGETS
	cmdTcSet = unix.TCSETS
)

// unlockpt is a no-op on zos.
func unlockpt(File) error {
	return nil
}

// ptsname retrieves the name of the first available pts for the given master.
func ptsname(f File) (string, error) {
	return "/dev/ttyp" + strings.TrimPrefix(f.Name(), "/dev/ptyp"), nil
}
Download .txt
gitextract_xi0k0f2o/

├── .github/
│   └── workflows/
│       └── ci.yml
├── .golangci.yml
├── LICENSE
├── README.md
├── console.go
├── console_linux.go
├── console_linux_test.go
├── console_other.go
├── console_test.go
├── console_unix.go
├── console_windows.go
├── go.mod
├── go.sum
├── pty_freebsd_cgo.go
├── pty_freebsd_nocgo.go
├── pty_unix.go
├── pty_zos.go
├── tc_darwin.go
├── tc_freebsd_cgo.go
├── tc_freebsd_nocgo.go
├── tc_linux.go
├── tc_netbsd.go
├── tc_openbsd_cgo.go
├── tc_openbsd_nocgo.go
├── tc_unix.go
└── tc_zos.go
Download .txt
SYMBOL INDEX (104 symbols across 20 files)

FILE: console.go
  type File (line 30) | type File interface
  type Console (line 39) | type Console interface
  type WinSize (line 58) | type WinSize struct
  function Current (line 68) | func Current() (c Console) {
  function ConsoleFromFile (line 85) | func ConsoleFromFile(f File) (Console, error) {

FILE: console_linux.go
  constant maxEvents (line 31) | maxEvents = 128
  type Epoller (line 58) | type Epoller struct
    method Add (line 81) | func (e *Epoller) Add(console Console) (*EpollConsole, error) {
    method Wait (line 109) | func (e *Epoller) Wait() error {
    method CloseConsole (line 140) | func (e *Epoller) CloseConsole(fd int) error {
    method getConsole (line 147) | func (e *Epoller) getConsole(sysfd int) *EpollConsole {
    method Close (line 155) | func (e *Epoller) Close() error {
  function NewEpoller (line 66) | func NewEpoller() (*Epoller, error) {
  type EpollConsole (line 165) | type EpollConsole struct
    method Read (line 179) | func (ec *EpollConsole) Read(p []byte) (n int, err error) {
    method Write (line 219) | func (ec *EpollConsole) Write(p []byte) (n int, err error) {
    method Shutdown (line 257) | func (ec *EpollConsole) Shutdown(close func(int) error) error {
    method signalRead (line 270) | func (ec *EpollConsole) signalRead() {
    method signalWrite (line 277) | func (ec *EpollConsole) signalWrite() {

FILE: console_linux_test.go
  function TestEpollConsole (line 29) | func TestEpollConsole(t *testing.T) {

FILE: console_other.go
  function NewPty (line 25) | func NewPty() (Console, string, error) {
  function checkConsole (line 30) | func checkConsole(f File) error {
  function newMaster (line 34) | func newMaster(f File) (Console, error) {

FILE: console_test.go
  function TestWinSize (line 31) | func TestWinSize(t *testing.T) {
  function testConsolePty (line 57) | func testConsolePty(t *testing.T, newPty func() (Console, string, error)) {
  function TestConsolePty_NewPty (line 104) | func TestConsolePty_NewPty(t *testing.T) {
  function TestConsolePty_NewPtyFromFile (line 108) | func TestConsolePty_NewPtyFromFile(t *testing.T) {

FILE: console_unix.go
  function NewPty (line 29) | func NewPty() (Console, string, error) {
  function NewPtyFromFile (line 42) | func NewPtyFromFile(f File) (Console, string, error) {
  type master (line 57) | type master struct
    method Read (line 62) | func (m *master) Read(b []byte) (int, error) {
    method Write (line 66) | func (m *master) Write(b []byte) (int, error) {
    method Close (line 70) | func (m *master) Close() error {
    method Resize (line 74) | func (m *master) Resize(ws WinSize) error {
    method ResizeFrom (line 78) | func (m *master) ResizeFrom(c Console) error {
    method Reset (line 86) | func (m *master) Reset() error {
    method getCurrent (line 93) | func (m *master) getCurrent() (unix.Termios, error) {
    method SetRaw (line 101) | func (m *master) SetRaw() error {
    method DisableEcho (line 111) | func (m *master) DisableEcho() error {
    method Size (line 120) | func (m *master) Size() (WinSize, error) {
    method Fd (line 124) | func (m *master) Fd() uintptr {
    method Name (line 128) | func (m *master) Name() string {
  function checkConsole (line 133) | func checkConsole(f File) error {
  function newMaster (line 141) | func newMaster(f File) (Console, error) {
  function ClearONLCR (line 158) | func ClearONLCR(fd uintptr) error {
  function SetONLCR (line 164) | func SetONLCR(fd uintptr) error {

FILE: console_windows.go
  type master (line 64) | type master struct
    method initStdios (line 29) | func (m *master) initStdios() {
    method SetRaw (line 75) | func (m *master) SetRaw() error {
    method Reset (line 91) | func (m *master) Reset() error {
    method Size (line 116) | func (m *master) Size() (WinSize, error) {
    method Resize (line 131) | func (m *master) Resize(ws WinSize) error {
    method ResizeFrom (line 135) | func (m *master) ResizeFrom(c Console) error {
    method DisableEcho (line 139) | func (m *master) DisableEcho() error {
    method Close (line 151) | func (m *master) Close() error {
    method Read (line 155) | func (m *master) Read(b []byte) (int, error) {
    method Write (line 159) | func (m *master) Write(b []byte) (int, error) {
    method Fd (line 163) | func (m *master) Fd() uintptr {
    method Name (line 170) | func (m *master) Name() string {
  function makeInputRaw (line 176) | func makeInputRaw(fd windows.Handle, mode uint32) error {
  function checkConsole (line 204) | func checkConsole(f File) error {
  function newMaster (line 212) | func newMaster(f File) (Console, error) {

FILE: pty_freebsd_cgo.go
  function openpt (line 36) | func openpt() (*os.File, error) {

FILE: pty_freebsd_nocgo.go
  function openpt (line 35) | func openpt() (*os.File, error) {

FILE: pty_unix.go
  function openpt (line 29) | func openpt() (*os.File, error) {

FILE: pty_zos.go
  function openpt (line 28) | func openpt() (*os.File, error) {

FILE: tc_darwin.go
  constant cmdTcGet (line 26) | cmdTcGet = unix.TIOCGETA
  constant cmdTcSet (line 27) | cmdTcSet = unix.TIOCSETA
  function unlockpt (line 32) | func unlockpt(f File) error {
  function ptsname (line 37) | func ptsname(f File) (string, error) {

FILE: tc_freebsd_cgo.go
  constant cmdTcGet (line 35) | cmdTcGet = unix.TIOCGETA
  constant cmdTcSet (line 36) | cmdTcSet = unix.TIOCSETA
  function unlockpt (line 41) | func unlockpt(f File) error {
  function ptsname (line 51) | func ptsname(f File) (string, error) {

FILE: tc_freebsd_nocgo.go
  constant cmdTcGet (line 29) | cmdTcGet = unix.TIOCGETA
  constant cmdTcSet (line 30) | cmdTcSet = unix.TIOCSETA
  function unlockpt (line 44) | func unlockpt(f File) error {
  function ptsname (line 49) | func ptsname(f File) (string, error) {

FILE: tc_linux.go
  constant cmdTcGet (line 27) | cmdTcGet = unix.TCGETS
  constant cmdTcSet (line 28) | cmdTcSet = unix.TCSETS
  function unlockpt (line 33) | func unlockpt(f File) error {
  function ptsname (line 43) | func ptsname(f File) (string, error) {

FILE: tc_netbsd.go
  constant cmdTcGet (line 26) | cmdTcGet = unix.TIOCGETA
  constant cmdTcSet (line 27) | cmdTcSet = unix.TIOCSETA
  function unlockpt (line 33) | func unlockpt(f File) error {
  function ptsname (line 38) | func ptsname(f File) (string, error) {

FILE: tc_openbsd_cgo.go
  constant cmdTcGet (line 30) | cmdTcGet = unix.TIOCGETA
  constant cmdTcSet (line 31) | cmdTcSet = unix.TIOCSETA
  function ptsname (line 35) | func ptsname(f File) (string, error) {
  function unlockpt (line 45) | func unlockpt(f File) error {

FILE: tc_openbsd_nocgo.go
  constant cmdTcGet (line 36) | cmdTcGet = unix.TIOCGETA
  constant cmdTcSet (line 37) | cmdTcSet = unix.TIOCSETA
  function ptsname (line 40) | func ptsname(f File) (string, error) {
  function unlockpt (line 44) | func unlockpt(f File) error {

FILE: tc_unix.go
  function tcget (line 26) | func tcget(fd uintptr, p *unix.Termios) error {
  function tcset (line 35) | func tcset(fd uintptr, p *unix.Termios) error {
  function tcgwinsz (line 39) | func tcgwinsz(fd uintptr) (WinSize, error) {
  function tcswinsz (line 55) | func tcswinsz(fd uintptr, ws WinSize) error {
  function setONLCR (line 67) | func setONLCR(fd uintptr, enable bool) error {
  function cfmakeraw (line 82) | func cfmakeraw(t unix.Termios) unix.Termios {

FILE: tc_zos.go
  constant cmdTcGet (line 26) | cmdTcGet = unix.TCGETS
  constant cmdTcSet (line 27) | cmdTcSet = unix.TCSETS
  function unlockpt (line 31) | func unlockpt(File) error {
  function ptsname (line 36) | func ptsname(f File) (string, error) {
Condensed preview — 26 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (61K chars).
[
  {
    "path": ".github/workflows/ci.yml",
    "chars": 1190,
    "preview": "name: CI\n\non:\n  push:\n    branches: [ main ]\n  pull_request:\n    branches: [ main ]\n\njobs:\n\n  build:\n    name: Console C"
  },
  {
    "path": ".golangci.yml",
    "chars": 255,
    "preview": "linters:\n  enable:\n    - gofmt\n    - goimports\n    - ineffassign\n    - misspell\n    - revive\n    - staticcheck\n    - str"
  },
  {
    "path": "LICENSE",
    "chars": 10765,
    "preview": "\n                                 Apache License\n                           Version 2.0, January 2004\n                  "
  },
  {
    "path": "README.md",
    "chars": 1201,
    "preview": "# console\n\n[![PkgGoDev](https://pkg.go.dev/badge/github.com/containerd/console)](https://pkg.go.dev/github.com/container"
  },
  {
    "path": "console.go",
    "chars": 2272,
    "preview": "/*\n   Copyright The containerd Authors.\n\n   Licensed under the Apache License, Version 2.0 (the \"License\");\n   you may n"
  },
  {
    "path": "console_linux.go",
    "chars": 7826,
    "preview": "//go:build linux\n// +build linux\n\n/*\n   Copyright The containerd Authors.\n\n   Licensed under the Apache License, Version"
  },
  {
    "path": "console_linux_test.go",
    "chars": 2066,
    "preview": "/*\n   Copyright The containerd Authors.\n\n   Licensed under the Apache License, Version 2.0 (the \"License\");\n   you may n"
  },
  {
    "path": "console_other.go",
    "chars": 1187,
    "preview": "//go:build !darwin && !freebsd && !linux && !netbsd && !openbsd && !windows && !zos\n// +build !darwin,!freebsd,!linux,!n"
  },
  {
    "path": "console_test.go",
    "chars": 2325,
    "preview": "//go:build linux || zos || freebsd\n// +build linux zos freebsd\n\n/*\n   Copyright The containerd Authors.\n\n   Licensed und"
  },
  {
    "path": "console_unix.go",
    "chars": 3979,
    "preview": "//go:build darwin || freebsd || linux || netbsd || openbsd || zos\n// +build darwin freebsd linux netbsd openbsd zos\n\n/*\n"
  },
  {
    "path": "console_windows.go",
    "chars": 5839,
    "preview": "/*\n   Copyright The containerd Authors.\n\n   Licensed under the Apache License, Version 2.0 (the \"License\");\n   you may n"
  },
  {
    "path": "go.mod",
    "chars": 79,
    "preview": "module github.com/containerd/console\n\ngo 1.13\n\nrequire golang.org/x/sys v0.1.0\n"
  },
  {
    "path": "go.sum",
    "chars": 151,
    "preview": "golang.org/x/sys v0.1.0 h1:kunALQeHf1/185U1i0GOB/fy1IPRDDpuoOOqRReG57U=\ngolang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUe"
  },
  {
    "path": "pty_freebsd_cgo.go",
    "chars": 1151,
    "preview": "//go:build freebsd && cgo\n// +build freebsd,cgo\n\n/*\n   Copyright The containerd Authors.\n\n   Licensed under the Apache L"
  },
  {
    "path": "pty_freebsd_nocgo.go",
    "chars": 1150,
    "preview": "//go:build freebsd && !cgo\n// +build freebsd,!cgo\n\n/*\n   Copyright The containerd Authors.\n\n   Licensed under the Apache"
  },
  {
    "path": "pty_unix.go",
    "chars": 932,
    "preview": "//go:build darwin || linux || netbsd || openbsd\n// +build darwin linux netbsd openbsd\n\n/*\n   Copyright The containerd Au"
  },
  {
    "path": "pty_zos.go",
    "chars": 1067,
    "preview": "//go:build zos\n// +build zos\n\n/*\n   Copyright The containerd Authors.\n\n   Licensed under the Apache License, Version 2.0"
  },
  {
    "path": "tc_darwin.go",
    "chars": 1262,
    "preview": "/*\n   Copyright The containerd Authors.\n\n   Licensed under the Apache License, Version 2.0 (the \"License\");\n   you may n"
  },
  {
    "path": "tc_freebsd_cgo.go",
    "chars": 1433,
    "preview": "//go:build freebsd && cgo\n// +build freebsd,cgo\n\n/*\n   Copyright The containerd Authors.\n\n   Licensed under the Apache L"
  },
  {
    "path": "tc_freebsd_nocgo.go",
    "chars": 1677,
    "preview": "//go:build freebsd && !cgo\n// +build freebsd,!cgo\n\n/*\n   Copyright The containerd Authors.\n\n   Licensed under the Apache"
  },
  {
    "path": "tc_linux.go",
    "chars": 1541,
    "preview": "/*\n   Copyright The containerd Authors.\n\n   Licensed under the Apache License, Version 2.0 (the \"License\");\n   you may n"
  },
  {
    "path": "tc_netbsd.go",
    "chars": 1316,
    "preview": "/*\n   Copyright The containerd Authors.\n\n   Licensed under the Apache License, Version 2.0 (the \"License\");\n   you may n"
  },
  {
    "path": "tc_openbsd_cgo.go",
    "chars": 1324,
    "preview": "//go:build openbsd && cgo\n// +build openbsd,cgo\n\n/*\n   Copyright The containerd Authors.\n\n   Licensed under the Apache L"
  },
  {
    "path": "tc_openbsd_nocgo.go",
    "chars": 1314,
    "preview": "//go:build openbsd && !cgo\n// +build openbsd,!cgo\n\n/*\n   Copyright The containerd Authors.\n\n   Licensed under the Apache"
  },
  {
    "path": "tc_unix.go",
    "chars": 2349,
    "preview": "//go:build darwin || freebsd || linux || netbsd || openbsd || zos\n// +build darwin freebsd linux netbsd openbsd zos\n\n/*\n"
  },
  {
    "path": "tc_zos.go",
    "chars": 984,
    "preview": "/*\n   Copyright The containerd Authors.\n\n   Licensed under the Apache License, Version 2.0 (the \"License\");\n   you may n"
  }
]

About this extraction

This page contains the full source code of the containerd/console GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 26 files (55.3 KB), approximately 15.0k tokens, and a symbol index with 104 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!