Exemple #1
0
// 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
		}
	}
}
Exemple #2
0
func OpenRawTerm() (Term, error) {
	t, err := term.Open(os.Stdin.Name(), term.RawMode)
	if err != nil {
		return nil, err
	}

	return t, nil
}
Exemple #3
0
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
}
Exemple #4
0
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
}
Exemple #5
0
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
}
Exemple #6
0
// 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
}
Exemple #7
0
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'
}
Exemple #8
0
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()
}
Exemple #9
0
// 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
}
Exemple #10
0
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)
}