// TODO(bep): check different OSs func readTerm(done, read chan bool, wg *sync.WaitGroup) { defer wg.Done() t, _ := term.Open("/dev/tty") defer t.Close() defer t.Restore() term.RawMode(t) for { select { case <-done: return default: b := make([]byte, 3) i, err := t.Read(b) if err != nil { return } if i == 1 && b[0] == 3 { // CTRL-C done <- true return } read <- true } } }
func OpenRawTerm() (Term, error) { t, err := term.Open(os.Stdin.Name(), term.RawMode) if err != nil { return nil, err } return t, nil }
func hijack(conn net.Conn, br *bufio.Reader) int { var in io.Reader term, err := term.Open(os.Stdin.Name()) if err == nil { err = term.SetRaw() if err != nil { log.Fatalln("failed to set raw:", term) } defer term.Restore() in = term } else { in = os.Stdin } encoder := json.NewEncoder(conn) decoder := json.NewDecoder(br) resized := make(chan os.Signal, 10) signal.Notify(resized, syscall.SIGWINCH) go func() { for { <-resized // TODO json race sendSize(encoder) } }() go io.Copy(&stdinWriter{encoder}, in) var exitStatus int for { var output atc.HijackOutput err := decoder.Decode(&output) if err != nil { break } if output.ExitStatus != nil { exitStatus = *output.ExitStatus } else if len(output.Error) > 0 { fmt.Fprintf(os.Stderr, "%s\n", ansi.Color(output.Error, "red+b")) exitStatus = 255 } else if len(output.Stdout) > 0 { os.Stdout.Write(output.Stdout) } else if len(output.Stderr) > 0 { os.Stderr.Write(output.Stderr) } } return exitStatus }
func New(f *os.File, options ...func(*Term) error) (*Term, error) { t, err := term.Open(f.Name()) if err != nil { return nil, err } tw := &Term{Term: t} if err := tw.SetOption(options...); err != nil { return nil, err } return tw, nil }
func NewOBD(serialPortName string) (*OBD, error) { port, err := term.Open(serialPortName, term.Speed(9600), term.RawMode) if err != nil { return nil, err } obd := &OBD{port, true} err = obd.Reset() if err != nil { return nil, err } err = obd.SendCommand([]byte("ate0")) // Turns off echo obd.ReadResult() return obd, err }
// Returns either an ascii code, or (if input is an arrow) a Javascript key code. func getChar() (ascii int, keyCode int, err error) { t, _ := term.Open("/dev/tty") term.RawMode(t) bytes := make([]byte, 3) var numRead int numRead, err = t.Read(bytes) if err != nil { return } if numRead == 3 && bytes[0] == 27 && bytes[1] == 91 { // Three-character control sequence, beginning with "ESC-[". // Since there are no ASCII codes for arrow keys, we use // Javascript key codes. if bytes[2] == 65 { // Up keyCode = 38 } else if bytes[2] == 66 { // Down keyCode = 40 } else if bytes[2] == 67 { // Right keyCode = 39 } else if bytes[2] == 68 { // Left keyCode = 37 } } else if numRead == 1 { ascii = int(bytes[0]) } else { // Two characters read?? } if ascii == 3 { fmt.Printf("BREAK") t.Write([]byte("\r\n")) } term.CBreakMode(t) t.Restore() t.Close() return }
func askToConfirm(prompt string) bool { fmt.Printf("%s (y/n): ", prompt) var in io.Reader t, err := term.Open(os.Stdin.Name()) if err == nil { err = t.SetRaw() if err != nil { log.Fatalln("failed to set raw:", err) } in = t } else { in = os.Stdin } ans := make([]byte, 1) n, err := in.Read(ans) if t != nil { err = t.Restore() if err != nil { println("failed to restore terminal: " + err.Error()) } t.Write(ans) t.Write([]byte("\n")) } if err != nil { log.Fatalln("failed to read response:", err) } if n == 0 { log.Fatalln("no response") } return ans[0] == 'y' }
func main() { var baud int var dev string cmd := &cobra.Command{ Use: "junkterm", Short: "junkterm is a quick and dirty serial terminal.", Run: func(cmd *cobra.Command, args []string) { term, err := term.Open(dev, term.Speed(baud), term.RawMode) if err != nil { log.Fatal(err) } go io.Copy(os.Stdout, term) io.Copy(term, os.Stdin) }, } cmd.Flags().IntVarP(&baud, "baud", "b", 115200, "baud rate") cmd.Flags().StringVarP(&dev, "dev", "d", "/dev/USB0", "device") cmd.Execute() }
// Open opens a connection to a BitScope instrument. // // If the ID string returned by the BitScope is not recognized as one of the // supported ones, an error is returned. func Open(dev string) (*Scope, error) { const base string = "/dev/ttyUSB" switch len(dev) { case 0: dev = base + "0" case 1: fallthrough case 2: dev = base + dev } tty, err := term.Open(dev) if err != nil { return nil, err } tty.SetRaw() bs := Scope{tty, "", "", 0} bs.ID = bs.Id() if strings.HasPrefix(bs.ID, "BS0010") { bs.Model = "bs10" } else if strings.HasPrefix(bs.ID, "BS0005") { bs.Model = "bs05" } else { tty.Close() return nil, errors.New("Unsupported model: " + bs.ID) } return &bs, nil }
func main() { app := cli.NewApp() app.Name = "gaol" app.Usage = "a cli for garden" app.Version = "0.0.1" app.Author = "Chris Brown" app.Email = "*****@*****.**" app.EnableBashCompletion = true app.Flags = []cli.Flag{ cli.StringFlag{ Name: "target, t", Value: "localhost:7777", Usage: "server to which commands are sent", EnvVar: "GAOL_TARGET", }, } app.Commands = []cli.Command{ { Name: "ping", Usage: "check if the server is running", Action: func(c *cli.Context) { err := client(c).Ping() failIf(err) }, }, { Name: "create", Usage: "create a container", Flags: []cli.Flag{ cli.StringFlag{ Name: "handle, n", Usage: "name to give container", }, cli.StringFlag{ Name: "rootfs, r", Usage: "rootfs image with which to create the container", }, cli.StringSliceFlag{ Name: "env, e", Usage: "set environment variables", Value: &cli.StringSlice{}, }, cli.DurationFlag{ Name: "grace, g", Usage: "grace time (resetting ttl) of container", Value: 5 * time.Minute, }, cli.BoolFlag{ Name: "privileged, p", Usage: "privileged user in container is privileged in host", }, cli.StringSliceFlag{ Name: "bind-mount, m", Usage: "bind-mount host-path:container-path", Value: &cli.StringSlice{}, }, }, Action: func(c *cli.Context) { handle := c.String("handle") grace := c.Duration("grace") rootfs := c.String("rootfs") env := c.StringSlice("env") privileged := c.Bool("privileged") mounts := c.StringSlice("bind-mount") var bindMounts []garden.BindMount for _, pair := range mounts { segs := strings.SplitN(pair, ":", 2) if len(segs) != 2 { fail(fmt.Errorf("invalid bind-mount segment (must be host-path:container-path): %s", pair)) } bindMounts = append(bindMounts, garden.BindMount{ SrcPath: segs[0], DstPath: segs[1], Mode: garden.BindMountModeRW, Origin: garden.BindMountOriginHost, }) } container, err := client(c).Create(garden.ContainerSpec{ Handle: handle, GraceTime: grace, RootFSPath: rootfs, Privileged: privileged, Env: env, BindMounts: bindMounts, }) failIf(err) fmt.Println(container.Handle()) }, }, { Name: "destroy", Usage: "destroy a container", BashComplete: handleComplete, Action: func(c *cli.Context) { client := client(c) handles := c.Args() for _, handle := range handles { err := client.Destroy(handle) failIf(err) } }, }, { Name: "list", Usage: "get a list of running containers", Flags: []cli.Flag{ cli.StringSliceFlag{ Name: "properties, p", Usage: "filter by properties (name=val)", Value: &cli.StringSlice{}, }, cli.BoolFlag{ Name: "verbose, v", Usage: "print additional details about each container", }, cli.StringFlag{ Name: "separator", Usage: "separator to print between containers in verbose mode", Value: "\n", }, }, Action: func(c *cli.Context) { separator := c.String("separator") properties := garden.Properties{} for _, prop := range c.StringSlice("properties") { segs := strings.SplitN(prop, "=", 2) if len(segs) < 2 { fail(errors.New("malformed property pair (must be name=value)")) } properties[segs[0]] = segs[1] } containers, err := client(c).Containers(properties) failIf(err) verbose := c.Bool("verbose") for _, container := range containers { fmt.Println(container.Handle()) if verbose { props, _ := container.Properties() for k, v := range props { fmt.Printf(" %s=%s\n", k, v) } fmt.Print(separator) } } }, }, { Name: "run", Usage: "run a command in a container", Flags: []cli.Flag{ cli.BoolFlag{ Name: "attach, a", Usage: "attach to the process after it is started", }, cli.StringFlag{ Name: "dir, d", Usage: "current working directory of process", }, cli.StringFlag{ Name: "user, u", Usage: "user to run the process as", }, cli.StringFlag{ Name: "command, c", Usage: "the command to run", }, cli.StringSliceFlag{ Name: "env, e", Usage: "set environment variables", Value: &cli.StringSlice{}, }, }, BashComplete: handleComplete, Action: func(c *cli.Context) { attach := c.Bool("attach") dir := c.String("dir") user := c.String("user") command := c.String("command") env := c.StringSlice("env") handle := handle(c) container, err := client(c).Lookup(handle) failIf(err) var processIo garden.ProcessIO if attach { processIo = garden.ProcessIO{ Stdin: os.Stdin, Stdout: os.Stdout, Stderr: os.Stderr, } } else { processIo = garden.ProcessIO{} } args, err := shellwords.Parse(command) failIf(err) process, err := container.Run(garden.ProcessSpec{ Path: args[0], Args: args[1:], Dir: dir, User: user, Env: env, }, processIo) failIf(err) if attach { status, err := process.Wait() failIf(err) os.Exit(status) } else { fmt.Println(process.ID()) } }, }, { Name: "attach", Usage: "attach to command running in the container", Flags: []cli.Flag{ cli.IntFlag{ Name: "pid, p", Usage: "process id to connect to", }, }, BashComplete: handleComplete, Action: func(c *cli.Context) { pid := uint32(c.Int("pid")) if pid == 0 { err := errors.New("must specify pid to attach to") failIf(err) } handle := handle(c) container, err := client(c).Lookup(handle) failIf(err) process, err := container.Attach(pid, garden.ProcessIO{ Stdin: os.Stdin, Stdout: os.Stdout, Stderr: os.Stderr, }) failIf(err) _, err = process.Wait() failIf(err) }, }, { Name: "shell", Usage: "open a shell inside the running container", Flags: []cli.Flag{ cli.StringFlag{ Name: "user, u", Usage: "user to open shell as", }, }, BashComplete: handleComplete, Action: func(c *cli.Context) { container, err := client(c).Lookup(handle(c)) failIf(err) term, err := term.Open(os.Stdin.Name()) failIf(err) err = term.SetRaw() failIf(err) rows, cols, err := pty.Getsize(os.Stdin) failIf(err) process, err := container.Run(garden.ProcessSpec{ User: c.String("user"), Path: "/bin/sh", Args: []string{"-l"}, Env: []string{"TERM=" + os.Getenv("TERM")}, TTY: &garden.TTYSpec{ WindowSize: &garden.WindowSize{ Rows: rows, Columns: cols, }, }, }, garden.ProcessIO{ Stdin: term, Stdout: term, Stderr: term, }) if err != nil { term.Restore() failIf(err) } resized := make(chan os.Signal, 10) signal.Notify(resized, syscall.SIGWINCH) go func() { for { <-resized rows, cols, err := pty.Getsize(os.Stdin) if err == nil { process.SetTTY(garden.TTYSpec{ WindowSize: &garden.WindowSize{ Rows: rows, Columns: cols, }, }) } } }() process.Wait() term.Restore() }, }, { Name: "stream-in", Usage: "stream data into the container", Flags: []cli.Flag{ cli.StringFlag{ Name: "destination, d", Usage: "destination path in the container", }, }, BashComplete: handleComplete, Action: func(c *cli.Context) { handle := handle(c) dst := c.String("destination") if dst == "" { fail(errors.New("missing --destination flag")) } container, err := client(c).Lookup(handle) failIf(err) streamInSpec := garden.StreamInSpec{ Path: dst, TarStream: os.Stdin, } err = container.StreamIn(streamInSpec) failIf(err) }, }, { Name: "stream-out", Usage: "stream data out of the container", Flags: []cli.Flag{ cli.StringFlag{ Name: "source, s", Usage: "source path in the container", }, }, BashComplete: handleComplete, Action: func(c *cli.Context) { handle := handle(c) src := c.String("source") if src == "" { fail(errors.New("missing --source flag")) } container, err := client(c).Lookup(handle) failIf(err) streamOutSpec := garden.StreamOutSpec{Path: src} output, err := container.StreamOut(streamOutSpec) failIf(err) io.Copy(os.Stdout, output) }, }, { Name: "net-in", Usage: "map a port on the host to a port in the container", Flags: []cli.Flag{ cli.IntFlag{ Name: "port, p", Usage: "container port", }, }, BashComplete: handleComplete, Action: func(c *cli.Context) { target := c.GlobalString("target") requestedContainerPort := uint32(c.Int("port")) if target == "" { fail(errors.New("target must be set")) } handle := handle(c) container, err := client(c).Lookup(handle) failIf(err) hostPort, _, err := container.NetIn(0, requestedContainerPort) failIf(err) host, _, err := net.SplitHostPort(target) failIf(err) fmt.Println(net.JoinHostPort(host, fmt.Sprintf("%d", hostPort))) }, }, } app.Run(os.Args) }