<commit_before>// Package emulators contains functions to start and stop emulators, and utilities to work with the
// various *_EMULATOR_HOST environment variables.
//
// Unless otherwise specified, all functions in this package assume that there will be at most one
// instance of each emulator running at any given time.
package emulators

// This package uses "os/exec" as opposed to "go.skia.org/infra/go/exec" in order to avoid the
// following circular dependency:
//
//   //go/exec/exec_test.go -> //go/testutils/unittest/unittest.go -> //go/emulators/emulators.go

import (
	"bytes"
	"fmt"
	"io/ioutil"
	"net"
	"os"
	"os/exec"
	"regexp"
	"strings"

	"go.skia.org/infra/bazel/go/bazel"
	"go.skia.org/infra/go/skerr"
)

// Emulator represents a Google Cloud emulator, a test-only CockroachDB server, etc.
type Emulator string

const (
	// BigTable represents a Google Cloud BigTable emulator.
	BigTable = Emulator("BigTable")

	// CockroachDB represents a test-only CockroachDB instance.
	CockroachDB = Emulator("CockroachDB")

	// Datastore represents a Google Cloud Datastore emulator.
	Datastore = Emulator("Datastore")

	// Firestore represents a Google Cloud Firestore emulator.
	Firestore = Emulator("Firestore")

	// PubSub represents a Google Cloud PubSub emulator.
	PubSub = Emulator("PubSub")
)

// AllEmulators contains a list of all known emulators.
var AllEmulators = []Emulator{BigTable, CockroachDB, Datastore, Firestore, PubSub}

// emulatorInfo holds the information necessary to start an emulator and manage its lifecycle.
type emulatorInfo struct {
	cmd    string // Command and arguments to start the emulator on a developer workstation.
	envVar string // Name of the emulator's environment variable, e.g. "FOO_EMULATOR_HOST".
	port   int    // The emulator's TCP port when running locally. Ignored under RBE.
}

// cachedEmulatorInfos is populated by getCachedEmulatorInfo() on the first call. Do not use
// directly.
var cachedEmulatorInfos = map[Emulator]emulatorInfo{}

// getCachedEmulatorInfo builds and returns an emulatorInfo struct for the given emulator. The
// struct's contents will depend on whether we are running on Bazel and RBE or not. All structs are
// computed once and cached. Subsequent calls will return the same struct given the same input.
func getCachedEmulatorInfo(emulator Emulator) emulatorInfo {
	if len(cachedEmulatorInfos) == 0 {
		cachedEmulatorInfos = map[Emulator]emulatorInfo{
			BigTable:    makeEmulatorInfo(BigTable),
			CockroachDB: makeEmulatorInfo(CockroachDB),
			Datastore:   makeEmulatorInfo(Datastore),
			Firestore:   makeEmulatorInfo(Firestore),
			PubSub:      makeEmulatorInfo(PubSub),
		}
	}

	emulatorInfo, ok := cachedEmulatorInfos[emulator]
	if !ok {
		panic("Unknown emulator: " + emulator)
	}
	return emulatorInfo
}

// makeEmulatorInfo returns an emulatorInfo struct for the given emulator. Under RBE, the emulator
// port will be chosen by the OS to minimize chances of parallel tests from interfering with each
// other. This function returns a new struct every time it's called, so different calls under RBE
// RBE will return structs with different ports.
func makeEmulatorInfo(emulator Emulator) emulatorInfo {
	var info emulatorInfo
	switch emulator {
	case BigTable:
		info = emulatorInfo{
			cmd:    "gcloud beta emulators bigtable start --host-port=localhost:%d --project=test-project",
			envVar: "BIGTABLE_EMULATOR_HOST",
			port:   8892,
		}
	case CockroachDB:
		info = emulatorInfo{
			cmd:    computeCockroachDBCmd(),
			envVar: "COCKROACHDB_EMULATOR_HOST",
			port:   8895,
		}
	case Datastore:
		info = emulatorInfo{
			cmd:    "gcloud beta emulators datastore start --no-store-on-disk --host-port=localhost:%d --project=test-project",
			envVar: "DATASTORE_EMULATOR_HOST",
			port:   8891,
		}
	case Firestore:
		info = emulatorInfo{
			cmd:    "gcloud beta emulators firestore start --host-port=localhost:%d",
			envVar: "FIRESTORE_EMULATOR_HOST",
			port:   8894,
		}
	case PubSub:
		info = emulatorInfo{
			cmd:    "gcloud beta emulators pubsub start --host-port=localhost:%d --project=test-project",
			envVar: "PUBSUB_EMULATOR_HOST",
			port:   8893,
		}
	default:
		panic("Unknown emulator: " + emulator)
	}

	// Under Bazel and RBE, we choose an unused port to minimize the chances of parallel tests from
	// interfering with each other.
	if bazel.InRBE() {
		info.port = findUnusedTCPPort()
	}

	return info
}

func computeCockroachDBCmd() string {
	// Read the CockroachDB storage directory from an environment variable, or create a temp dir.
	cockroachDbStoreDir := os.Getenv("COCKROACHDB_EMULATOR_STORE_DIR")
	if cockroachDbStoreDir == "" {
		var err error
		cockroachDbStoreDir, err = ioutil.TempDir("", "crdb-emulator-*")
		if err != nil {
			panic("Error while creating temporary directory: " + skerr.Wrap(err).Error())
		}
	}

	cmd := fmt.Sprintf("cockroach start-single-node --insecure --listen-addr=localhost:%%d --store=%s", cockroachDbStoreDir)

	// Under RBE, we want the web UI to be served on a random TCP port. This minimizes the chance of
	// parallel tests from interfering with each other.
	if bazel.InRBE() {
		cmd += " --http-addr=localhost:0"
	}

	return cmd
}

// findUnusedTCPPort finds an unused TCP port by opening a TCP port on an unused port chosen by the
// operating system, recovering the port number and immediately closing the socket.
//
// This function does not guarantee that multiple calls will return different port numbers, so it
// might cause tests to flake out. However, the odds of this happening are low. In the future, we
// might decide to keep track of previously returned port numbers, and keep probing the OS until
// it returns a previously unseen port number.
func findUnusedTCPPort() int {
	listener, err := net.Listen("tcp", ":0")
	if err != nil {
		panic(skerr.Wrap(err))
	}
	port := listener.Addr().(*net.TCPAddr).Port
	if err = listener.Close(); err != nil {
		panic(skerr.Wrap(err))
	}
	return port
}

// GetEmulatorHostEnvVar returns the contents of the *_EMULATOR_HOST environment variable
// corresponding to the given emulator, or the empty string if the environment variable is unset.
func GetEmulatorHostEnvVar(emulator Emulator) string {
	return os.Getenv(getCachedEmulatorInfo(emulator).envVar)
}

// SetEmulatorHostEnvVar sets the *_EMULATOR_HOST environment variable for the given emulator to
// point to an emulator instance started via StartEmulatorIfNotRunning.
//
// It's OK to call this function before calling StartEmulatorIfNotRunning because both functions
// look up the emulator information (e.g. TCP port) from a package-private, global dictionary.
func SetEmulatorHostEnvVar(emulator Emulator) error {
	return setEmulatorHostEnvVarFromEmulatorInfo(getCachedEmulatorInfo(emulator))
}

func setEmulatorHostEnvVarFromEmulatorInfo(info emulatorInfo) error {
	return skerr.Wrap(os.Setenv(info.envVar, fmt.Sprintf("localhost:%d", info.port)))
}

// UnsetAllEmulatorHostEnvVars unsets the *_EMULATOR_HOST environment variables for all known
// emulators.
func UnsetAllEmulatorHostEnvVars() error {
	for _, emulator := range AllEmulators {
		if err := os.Setenv(getCachedEmulatorInfo(emulator).envVar, ""); err != nil {
			return skerr.Wrap(err)
		}
	}
	return nil
}

// GetEmulatorHostEnvVarName returns the name of the *_EMULATOR_HOST environment variable
// corresponding to the given emulator.
func GetEmulatorHostEnvVarName(emulator Emulator) string {
	return getCachedEmulatorInfo(emulator).envVar
}

// runningEmulators keeps track of which emulators have been started
var runningEmulators = map[Emulator]bool{}

// IsRunning returns true is the given emulator was started, or false if it hasn't been started or
// if it's been stopped.
func IsRunning(emulator Emulator) bool {
	return runningEmulators[emulator]
}

// StartEmulatorIfNotRunning starts an emulator if it's not already running. Returns true if it
// started the emulator, or false if the emulator was already running.
func StartEmulatorIfNotRunning(emulator Emulator) (bool, error) {
	if IsRunning(emulator) {
		return false, nil
	}
	if err := startEmulator(getCachedEmulatorInfo(emulator)); err != nil {
		return false, skerr.Wrap(err)
	}
	runningEmulators[emulator] = true
	return true, nil
}

// StartAdHocEmulatorInstanceAndSetEmulatorHostEnvVarBazelRBEOnly starts a new instance of the given
// emulator, regardless of whether a previous instance was already started, and sets the
// corresponding *_EMULATOR_HOST environment variable to point to the newly started instance. Any
// emulator instances started via this function will be ignored by StartEmulatorIfNotRunning.
//
// This only works under RBE because under RBE, emulators are assigned an unused TCP port chosen by
// the operating system, which makes it possible to run multiple instances of the same emulator in
// parallel (e.g. one instance started via this function, and another one started via
// StartEmulatorIfNotRunning). This function will panic if called outside of RBE.
func StartAdHocEmulatorInstanceAndSetEmulatorHostEnvVarBazelRBEOnly(emulator Emulator) error {
	if !bazel.InRBE() {
		panic("This function cannot be called outside of RBE.")
	}
	info := makeEmulatorInfo(emulator)
	if err := startEmulator(info); err != nil {
		return skerr.Wrap(err)
	}
	if err := setEmulatorHostEnvVarFromEmulatorInfo(info); err != nil {
		return skerr.Wrap(err)
	}
	return nil
}

// startEmulator starts an emulator using the command in the given struct.
func startEmulator(emulatorInfo emulatorInfo) error {
	programAndArgs := strings.Split(fmt.Sprintf(emulatorInfo.cmd, emulatorInfo.port), " ")
	cmd := exec.Command(programAndArgs[0], programAndArgs[1:]...)
	cmd.Stdout = os.Stdout
	cmd.Stderr = os.Stderr

	if bazel.InRBE() {
		// Force emulator child processes to die as soon as the parent process (e.g. the Go test runner)
		// dies. If we don't do this, the emulators will continue running indefinitely after the parent
		// process dies, eventually timing out.
		//
		// Note that this is only possible under Linux. The below function call will panic under
		// non-Linux operating systems. Running emulator tests under RBE on non-Linux OSes is therefore
		// not supported. This is OK because our RBE instance is currently Linux-only. See the comments
		// in the function body for alternative approaches if we ever decide to run emulator tests under
		// RBE on other operating systems.
		cmd.SysProcAttr = makeSysProcAttrWithPdeathsigSIGKILL()
	}

	if err := cmd.Start(); err != nil {
		return skerr.Wrap(err)
	}

	return nil
}

// StartAllEmulators starts all known emulators.
func StartAllEmulators() error {
	for _, emulator := range AllEmulators {
		if _, err := StartEmulatorIfNotRunning(emulator); err != nil {
			return skerr.Wrap(err)
		}
	}
	return nil
}

var emulatorProcsToKill = []*regexp.Regexp{
	regexp.MustCompile("[g]cloud\\.py"),
	regexp.MustCompile("[c]loud_datastore_emulator"),
	regexp.MustCompile("[C]loudDatastore.jar"),
	regexp.MustCompile("[c]btemulator"),
	regexp.MustCompile("[c]loud-pubsub-emulator"),
	regexp.MustCompile("[c]loud-firestore-emulator"),
	regexp.MustCompile("[c]ockroach"),
}

// StopAllEmulators stops all known emulators.
func StopAllEmulators() error {
	// List all processes.
	psCmd := exec.Command("ps", "aux")
	var psOut bytes.Buffer
	psCmd.Stdout = &psOut
	if err := psCmd.Run(); err != nil {
		return skerr.Wrap(err)
	}

	// Parse the output of the previous command.
	lines := strings.Split(psOut.String(), "\n")
	procs := make(map[string]string, len(lines))
	for _, line := range lines {
		fields := strings.Fields(line)
		if len(fields) < 11 {
			continue
		}
		procs[line] = fields[1]
	}

	signal := "SIGTERM"
	if bazel.InRBE() {
		// Under Bazel and RBE, we don't need graceful termination because the RBE containers are
		// ephemeral. Killing the emulators with SIGKILL is faster and simpler.
		signal = "SIGKILL"
	}

	// Kill each matching process.
	for _, re := range emulatorProcsToKill {
		for desc, id := range procs {
			if re.MatchString(desc) {
				if err := exec.Command("kill", "-s", signal, id).Run(); err != nil {
					return skerr.Wrap(err)
				}
				delete(procs, desc)
			}
		}
	}

	// After this function returns, IsRunning(emulator) should return false for all known emulators.
	for _, emulator := range AllEmulators {
		runningEmulators[emulator] = false
	}

	return nil
}
<commit_msg>emulators.go: Change CockroachDB web UI's TCP port.<commit_after>// Package emulators contains functions to start and stop emulators, and utilities to work with the
// various *_EMULATOR_HOST environment variables.
//
// Unless otherwise specified, all functions in this package assume that there will be at most one
// instance of each emulator running at any given time.
package emulators

// This package uses "os/exec" as opposed to "go.skia.org/infra/go/exec" in order to avoid the
// following circular dependency:
//
//   //go/exec/exec_test.go -> //go/testutils/unittest/unittest.go -> //go/emulators/emulators.go

import (
	"bytes"
	"fmt"
	"io/ioutil"
	"net"
	"os"
	"os/exec"
	"regexp"
	"strings"

	"go.skia.org/infra/bazel/go/bazel"
	"go.skia.org/infra/go/skerr"
)

// Emulator represents a Google Cloud emulator, a test-only CockroachDB server, etc.
type Emulator string

const (
	// BigTable represents a Google Cloud BigTable emulator.
	BigTable = Emulator("BigTable")

	// CockroachDB represents a test-only CockroachDB instance.
	CockroachDB = Emulator("CockroachDB")

	// Datastore represents a Google Cloud Datastore emulator.
	Datastore = Emulator("Datastore")

	// Firestore represents a Google Cloud Firestore emulator.
	Firestore = Emulator("Firestore")

	// PubSub represents a Google Cloud PubSub emulator.
	PubSub = Emulator("PubSub")
)

// AllEmulators contains a list of all known emulators.
var AllEmulators = []Emulator{BigTable, CockroachDB, Datastore, Firestore, PubSub}

// emulatorInfo holds the information necessary to start an emulator and manage its lifecycle.
type emulatorInfo struct {
	cmd    string // Command and arguments to start the emulator on a developer workstation.
	envVar string // Name of the emulator's environment variable, e.g. "FOO_EMULATOR_HOST".
	port   int    // The emulator's TCP port when running locally. Ignored under RBE.
}

// cachedEmulatorInfos is populated by getCachedEmulatorInfo() on the first call. Do not use
// directly.
var cachedEmulatorInfos = map[Emulator]emulatorInfo{}

// getCachedEmulatorInfo builds and returns an emulatorInfo struct for the given emulator. The
// struct's contents will depend on whether we are running on Bazel and RBE or not. All structs are
// computed once and cached. Subsequent calls will return the same struct given the same input.
func getCachedEmulatorInfo(emulator Emulator) emulatorInfo {
	if len(cachedEmulatorInfos) == 0 {
		cachedEmulatorInfos = map[Emulator]emulatorInfo{
			BigTable:    makeEmulatorInfo(BigTable),
			CockroachDB: makeEmulatorInfo(CockroachDB),
			Datastore:   makeEmulatorInfo(Datastore),
			Firestore:   makeEmulatorInfo(Firestore),
			PubSub:      makeEmulatorInfo(PubSub),
		}
	}

	emulatorInfo, ok := cachedEmulatorInfos[emulator]
	if !ok {
		panic("Unknown emulator: " + emulator)
	}
	return emulatorInfo
}

// makeEmulatorInfo returns an emulatorInfo struct for the given emulator. Under RBE, the emulator
// port will be chosen by the OS to minimize chances of parallel tests from interfering with each
// other. This function returns a new struct every time it's called, so different calls under RBE
// RBE will return structs with different ports.
func makeEmulatorInfo(emulator Emulator) emulatorInfo {
	var info emulatorInfo
	switch emulator {
	case BigTable:
		info = emulatorInfo{
			cmd:    "gcloud beta emulators bigtable start --host-port=localhost:%d --project=test-project",
			envVar: "BIGTABLE_EMULATOR_HOST",
			port:   8892,
		}
	case CockroachDB:
		info = emulatorInfo{
			cmd:    computeCockroachDBCmd(),
			envVar: "COCKROACHDB_EMULATOR_HOST",
			port:   8895,
		}
	case Datastore:
		info = emulatorInfo{
			cmd:    "gcloud beta emulators datastore start --no-store-on-disk --host-port=localhost:%d --project=test-project",
			envVar: "DATASTORE_EMULATOR_HOST",
			port:   8891,
		}
	case Firestore:
		info = emulatorInfo{
			cmd:    "gcloud beta emulators firestore start --host-port=localhost:%d",
			envVar: "FIRESTORE_EMULATOR_HOST",
			port:   8894,
		}
	case PubSub:
		info = emulatorInfo{
			cmd:    "gcloud beta emulators pubsub start --host-port=localhost:%d --project=test-project",
			envVar: "PUBSUB_EMULATOR_HOST",
			port:   8893,
		}
	default:
		panic("Unknown emulator: " + emulator)
	}

	// Under Bazel and RBE, we choose an unused port to minimize the chances of parallel tests from
	// interfering with each other.
	if bazel.InRBE() {
		info.port = findUnusedTCPPort()
	}

	return info
}

func computeCockroachDBCmd() string {
	// Read the CockroachDB storage directory from an environment variable, or create a temp dir.
	cockroachDbStoreDir := os.Getenv("COCKROACHDB_EMULATOR_STORE_DIR")
	if cockroachDbStoreDir == "" {
		var err error
		cockroachDbStoreDir, err = ioutil.TempDir("", "crdb-emulator-*")
		if err != nil {
			panic("Error while creating temporary directory: " + skerr.Wrap(err).Error())
		}
	}

	cmd := fmt.Sprintf("cockroach start-single-node --insecure --listen-addr=localhost:%%d --store=%s", cockroachDbStoreDir)

	// Under RBE, we want the web UI to be served on a random TCP port. This minimizes the chance of
	// parallel tests from interfering with each other.
	if bazel.InRBE() {
		cmd += " --http-addr=localhost:0"
	} else {
		// The default port for Cockroach's web UI 8080, but that is the same port at which we serve
		// demo pages during development.
		cmd += " --http-addr=localhost:9090"
	}

	return cmd
}

// findUnusedTCPPort finds an unused TCP port by opening a TCP port on an unused port chosen by the
// operating system, recovering the port number and immediately closing the socket.
//
// This function does not guarantee that multiple calls will return different port numbers, so it
// might cause tests to flake out. However, the odds of this happening are low. In the future, we
// might decide to keep track of previously returned port numbers, and keep probing the OS until
// it returns a previously unseen port number.
func findUnusedTCPPort() int {
	listener, err := net.Listen("tcp", ":0")
	if err != nil {
		panic(skerr.Wrap(err))
	}
	port := listener.Addr().(*net.TCPAddr).Port
	if err = listener.Close(); err != nil {
		panic(skerr.Wrap(err))
	}
	return port
}

// GetEmulatorHostEnvVar returns the contents of the *_EMULATOR_HOST environment variable
// corresponding to the given emulator, or the empty string if the environment variable is unset.
func GetEmulatorHostEnvVar(emulator Emulator) string {
	return os.Getenv(getCachedEmulatorInfo(emulator).envVar)
}

// SetEmulatorHostEnvVar sets the *_EMULATOR_HOST environment variable for the given emulator to
// point to an emulator instance started via StartEmulatorIfNotRunning.
//
// It's OK to call this function before calling StartEmulatorIfNotRunning because both functions
// look up the emulator information (e.g. TCP port) from a package-private, global dictionary.
func SetEmulatorHostEnvVar(emulator Emulator) error {
	return setEmulatorHostEnvVarFromEmulatorInfo(getCachedEmulatorInfo(emulator))
}

func setEmulatorHostEnvVarFromEmulatorInfo(info emulatorInfo) error {
	return skerr.Wrap(os.Setenv(info.envVar, fmt.Sprintf("localhost:%d", info.port)))
}

// UnsetAllEmulatorHostEnvVars unsets the *_EMULATOR_HOST environment variables for all known
// emulators.
func UnsetAllEmulatorHostEnvVars() error {
	for _, emulator := range AllEmulators {
		if err := os.Setenv(getCachedEmulatorInfo(emulator).envVar, ""); err != nil {
			return skerr.Wrap(err)
		}
	}
	return nil
}

// GetEmulatorHostEnvVarName returns the name of the *_EMULATOR_HOST environment variable
// corresponding to the given emulator.
func GetEmulatorHostEnvVarName(emulator Emulator) string {
	return getCachedEmulatorInfo(emulator).envVar
}

// runningEmulators keeps track of which emulators have been started
var runningEmulators = map[Emulator]bool{}

// IsRunning returns true is the given emulator was started, or false if it hasn't been started or
// if it's been stopped.
func IsRunning(emulator Emulator) bool {
	return runningEmulators[emulator]
}

// StartEmulatorIfNotRunning starts an emulator if it's not already running. Returns true if it
// started the emulator, or false if the emulator was already running.
func StartEmulatorIfNotRunning(emulator Emulator) (bool, error) {
	if IsRunning(emulator) {
		return false, nil
	}
	if err := startEmulator(getCachedEmulatorInfo(emulator)); err != nil {
		return false, skerr.Wrap(err)
	}
	runningEmulators[emulator] = true
	return true, nil
}

// StartAdHocEmulatorInstanceAndSetEmulatorHostEnvVarBazelRBEOnly starts a new instance of the given
// emulator, regardless of whether a previous instance was already started, and sets the
// corresponding *_EMULATOR_HOST environment variable to point to the newly started instance. Any
// emulator instances started via this function will be ignored by StartEmulatorIfNotRunning.
//
// This only works under RBE because under RBE, emulators are assigned an unused TCP port chosen by
// the operating system, which makes it possible to run multiple instances of the same emulator in
// parallel (e.g. one instance started via this function, and another one started via
// StartEmulatorIfNotRunning). This function will panic if called outside of RBE.
func StartAdHocEmulatorInstanceAndSetEmulatorHostEnvVarBazelRBEOnly(emulator Emulator) error {
	if !bazel.InRBE() {
		panic("This function cannot be called outside of RBE.")
	}
	info := makeEmulatorInfo(emulator)
	if err := startEmulator(info); err != nil {
		return skerr.Wrap(err)
	}
	if err := setEmulatorHostEnvVarFromEmulatorInfo(info); err != nil {
		return skerr.Wrap(err)
	}
	return nil
}

// startEmulator starts an emulator using the command in the given struct.
func startEmulator(emulatorInfo emulatorInfo) error {
	programAndArgs := strings.Split(fmt.Sprintf(emulatorInfo.cmd, emulatorInfo.port), " ")
	cmd := exec.Command(programAndArgs[0], programAndArgs[1:]...)
	cmd.Stdout = os.Stdout
	cmd.Stderr = os.Stderr

	if bazel.InRBE() {
		// Force emulator child processes to die as soon as the parent process (e.g. the Go test runner)
		// dies. If we don't do this, the emulators will continue running indefinitely after the parent
		// process dies, eventually timing out.
		//
		// Note that this is only possible under Linux. The below function call will panic under
		// non-Linux operating systems. Running emulator tests under RBE on non-Linux OSes is therefore
		// not supported. This is OK because our RBE instance is currently Linux-only. See the comments
		// in the function body for alternative approaches if we ever decide to run emulator tests under
		// RBE on other operating systems.
		cmd.SysProcAttr = makeSysProcAttrWithPdeathsigSIGKILL()
	}

	if err := cmd.Start(); err != nil {
		return skerr.Wrap(err)
	}

	return nil
}

// StartAllEmulators starts all known emulators.
func StartAllEmulators() error {
	for _, emulator := range AllEmulators {
		if _, err := StartEmulatorIfNotRunning(emulator); err != nil {
			return skerr.Wrap(err)
		}
	}
	return nil
}

var emulatorProcsToKill = []*regexp.Regexp{
	regexp.MustCompile("[g]cloud\\.py"),
	regexp.MustCompile("[c]loud_datastore_emulator"),
	regexp.MustCompile("[C]loudDatastore.jar"),
	regexp.MustCompile("[c]btemulator"),
	regexp.MustCompile("[c]loud-pubsub-emulator"),
	regexp.MustCompile("[c]loud-firestore-emulator"),
	regexp.MustCompile("[c]ockroach"),
}

// StopAllEmulators stops all known emulators.
func StopAllEmulators() error {
	// List all processes.
	psCmd := exec.Command("ps", "aux")
	var psOut bytes.Buffer
	psCmd.Stdout = &psOut
	if err := psCmd.Run(); err != nil {
		return skerr.Wrap(err)
	}

	// Parse the output of the previous command.
	lines := strings.Split(psOut.String(), "\n")
	procs := make(map[string]string, len(lines))
	for _, line := range lines {
		fields := strings.Fields(line)
		if len(fields) < 11 {
			continue
		}
		procs[line] = fields[1]
	}

	signal := "SIGTERM"
	if bazel.InRBE() {
		// Under Bazel and RBE, we don't need graceful termination because the RBE containers are
		// ephemeral. Killing the emulators with SIGKILL is faster and simpler.
		signal = "SIGKILL"
	}

	// Kill each matching process.
	for _, re := range emulatorProcsToKill {
		for desc, id := range procs {
			if re.MatchString(desc) {
				if err := exec.Command("kill", "-s", signal, id).Run(); err != nil {
					return skerr.Wrap(err)
				}
				delete(procs, desc)
			}
		}
	}

	// After this function returns, IsRunning(emulator) should return false for all known emulators.
	for _, emulator := range AllEmulators {
		runningEmulators[emulator] = false
	}

	return nil
}
<|endoftext|>


<commit_before>package makeupdater

// Note this package is exclusively compatible with Drupal 7 make files.

import (
	"fmt"
	"io/ioutil"
	"os"
	"os/exec"
	"strings"
)

// replaceTextInFile will replace a string of test in a file.
func replaceTextInFile(fullPath string, oldString string, newString string) {
	read, err := ioutil.ReadFile(fullPath)
	if err != nil {
		panic(err)
	}
	newContents := strings.Replace(string(read), oldString, newString, -1)
	err = ioutil.WriteFile(fullPath, []byte(newContents), 0)
	if err != nil {
		panic(err)
	}
}

// removeChar will remove particular characters from a string.
func removeChar(input string, chars ...string) string {
	for _, value := range chars {
		input = strings.Replace(input, value, "", -1)
	}
	return input
}

// inArray will return the quanity of specific input values in the input slice.
func inArray(input []string, subject string) int {
	counter := 0
	for _, value := range input {
		if value == subject {
			counter++
		}
	}
	return counter
}

// UpdateMake will update the version numbers in a specified make file
func UpdateMake(fullpath string) {
	_, err := os.Stat(fullpath)
	if err != nil {
		panic(err)
	}
	projects := GetProjectsFromMake(fullpath)
	count := 0
	for _, project := range projects {
		if project != "" {
			catCmd := "cat " + fullpath + " | grep \"projects\\[" + project + "\\]\" | grep version | cut -d '=' -f2"
			z, _ := exec.Command("sh", "-c", catCmd).Output()
			for _, stream := range strings.Split(string(z), "\n") {
				stream = strings.Replace(stream, " ", "", -1)
				stream = strings.Replace(stream, "\"", "", -1)
				if stream != "" {
					x, _ := exec.Command("sh", "-c", "drush pm-releases --pipe "+project+" | grep Recommended | cut -d',' -f2").Output()
					versionNew := removeChar(string(x), " ", "7.x-", "\"", "\n", "[", "]")
					if !strings.Contains(stream, versionNew) {
						fmt.Printf("Replacing %v v%v with v%v\n", project, stream, versionNew)
						replaceTextInFile(fullpath, fmt.Sprintf("projects[%v][version] = \"%v\"\n", project, stream), fmt.Sprintf("projects[%v][version] = \"%v\"\n", project, versionNew))
						count++
					}
				}
			}
		}
	}
	if count == 0 {
		fmt.Println(fullpath, "is already up to date.")
	}
}

// GetProjectsFromMake returns a list of projects from a given make file
func GetProjectsFromMake(fullpath string) []string {
	Projects := []string{}
	catCmd := "cat " + fullpath + " | grep projects | cut -d'[' -f2 | cut -d']' -f1 | uniq | sort"
	y, _ := exec.Command("sh", "-c", catCmd).Output()
	rawProjects := strings.Split(string(y), "\n")
	for _, project := range rawProjects {
		project = strings.Replace(project, " ", "", -1)
		if project != "" && project != "projects" {
			if inArray(Projects, project) == 0 {
				Projects = append(Projects, project)
			}
		}
	}
	return Projects
}

// GenerateMake takes a []string of projects and writes out a make file
// Modules are added with the latest recommended version.
func GenerateMake(Projects []string, File string) {
	headerLines := []string{}
	headerLines = append(headerLines, "; Generated by make-updater")
	headerLines = append(headerLines, "; Script created by Fubarhouse")
	headerLines = append(headerLines, "; Toolkit available at github.com/fubarhouse/golang-drush/...")
	headerLines = append(headerLines, "core = 7.x")
	headerLines = append(headerLines, "api = 2")
	headerLines = append(headerLines, "")

	// Rewrite core, if core is in the original Projects list.

	for _, Project := range Projects {
		coreAppended := 0
		if Project == "drupal" {
			if coreAppended == 0 {
				headerLines = append(headerLines, "; core")
				x, _ := exec.Command("sh", "-c", "drush pm-releases --pipe drupal | grep Recommended | cut -d',' -f2").Output()
				ProjectVersion := removeChar(string(x), " ", "7.x-", "\"", "\n", "[", "]")
				headerLines = append(headerLines, "projects[drupal][type] = \"core\"")
				headerLines = append(headerLines, fmt.Sprintf("projects[drupal][version] = \"%v\"", ProjectVersion))
				headerLines = append(headerLines, "projects[drupal][download][type] = \"get\"")
				headerLines = append(headerLines, fmt.Sprintf("projects[drupal][download][url] = \"https://ftp.drupal.org/files/projects/drupal-%v.tar.gz\"", ProjectVersion))
				headerLines = append(headerLines, "")
				coreAppended++
			}
		}
	}

	// Rewrite contrib
	headerLines = append(headerLines, "; modules")
	headerLines = append(headerLines, "defaults[projects][subdir] = contrib")
	headerLines = append(headerLines, "")

	for _, Project := range Projects {

		if Project != "drupal" {
			x, y := exec.Command("sh", "-c", "drush pm-releases --pipe "+Project+" | grep Recommended | cut -d',' -f2").Output()
			if y == nil {
				ProjectVersion := removeChar(string(x), " ", "7.x-", "\"", "\n", "[", "]")
				ProjectType := "contrib"
				if ProjectVersion == "" {
					ProjectType = "custom"
				}
				headerLines = append(headerLines, fmt.Sprintf("projects[%v][version] = \"%v\"", Project, ProjectVersion))
				headerLines = append(headerLines, fmt.Sprintf("projects[%v][type] = \"module\"", Project))
				headerLines = append(headerLines, fmt.Sprintf("projects[%v][subdir] = \"%v\"", Project, ProjectType))
				headerLines = append(headerLines, fmt.Sprint(""))
			}
		}
	}

	// Print to path File

	newFile, _ := os.Create(File)
	for _, line := range headerLines {
		fmt.Fprintln(newFile, line)
	}
	newFile.Sync()
	defer newFile.Close()

}
<commit_msg>Adjust UpdateMake footer to support printf and dupe function call.<commit_after>package makeupdater

// Note this package is exclusively compatible with Drupal 7 make files.

import (
	"fmt"
	"io/ioutil"
	"os"
	"os/exec"
	"strings"
)

// replaceTextInFile will replace a string of test in a file.
func replaceTextInFile(fullPath string, oldString string, newString string) {
	read, err := ioutil.ReadFile(fullPath)
	if err != nil {
		panic(err)
	}
	newContents := strings.Replace(string(read), oldString, newString, -1)
	err = ioutil.WriteFile(fullPath, []byte(newContents), 0)
	if err != nil {
		panic(err)
	}
}

// removeChar will remove particular characters from a string.
func removeChar(input string, chars ...string) string {
	for _, value := range chars {
		input = strings.Replace(input, value, "", -1)
	}
	return input
}

// inArray will return the quanity of specific input values in the input slice.
func inArray(input []string, subject string) int {
	counter := 0
	for _, value := range input {
		if value == subject {
			counter++
		}
	}
	return counter
}

// UpdateMake will update the version numbers in a specified make file
func UpdateMake(fullpath string) {
	_, err := os.Stat(fullpath)
	if err != nil {
		panic(err)
	}
	projects := GetProjectsFromMake(fullpath)
	count := 0
	for _, project := range projects {
		if project != "" {
			catCmd := "cat " + fullpath + " | grep \"projects\\[" + project + "\\]\" | grep version | cut -d '=' -f2"
			z, _ := exec.Command("sh", "-c", catCmd).Output()
			for _, stream := range strings.Split(string(z), "\n") {
				stream = strings.Replace(stream, " ", "", -1)
				stream = strings.Replace(stream, "\"", "", -1)
				if stream != "" {
					x, _ := exec.Command("sh", "-c", "drush pm-releases --pipe "+project+" | grep Recommended | cut -d',' -f2").Output()
					versionNew := removeChar(string(x), " ", "7.x-", "\"", "\n", "[", "]")
					if !strings.Contains(stream, versionNew) {
						fmt.Printf("Replacing %v v%v with v%v\n", project, stream, versionNew)
						replaceTextInFile(fullpath, fmt.Sprintf("projects[%v][version] = \"%v\"\n", project, stream), fmt.Sprintf("projects[%v][version] = \"%v\"\n", project, versionNew))
						count++
					}
				}
			}
		}
	}
	FindDuplicatesInMake(fullpath)
	if count == 0 {
		fmt.Printf("%v is already up to date.", fullpath)
	}
}
	}
}

// GetProjectsFromMake returns a list of projects from a given make file
func GetProjectsFromMake(fullpath string) []string {
	Projects := []string{}
	catCmd := "cat " + fullpath + " | grep projects | cut -d'[' -f2 | cut -d']' -f1 | uniq | sort"
	y, _ := exec.Command("sh", "-c", catCmd).Output()
	rawProjects := strings.Split(string(y), "\n")
	for _, project := range rawProjects {
		project = strings.Replace(project, " ", "", -1)
		if project != "" && project != "projects" {
			if inArray(Projects, project) == 0 {
				Projects = append(Projects, project)
			}
		}
	}
	return Projects
}

// GenerateMake takes a []string of projects and writes out a make file
// Modules are added with the latest recommended version.
func GenerateMake(Projects []string, File string) {
	headerLines := []string{}
	headerLines = append(headerLines, "; Generated by make-updater")
	headerLines = append(headerLines, "; Script created by Fubarhouse")
	headerLines = append(headerLines, "; Toolkit available at github.com/fubarhouse/golang-drush/...")
	headerLines = append(headerLines, "core = 7.x")
	headerLines = append(headerLines, "api = 2")
	headerLines = append(headerLines, "")

	// Rewrite core, if core is in the original Projects list.

	for _, Project := range Projects {
		coreAppended := 0
		if Project == "drupal" {
			if coreAppended == 0 {
				headerLines = append(headerLines, "; core")
				x, _ := exec.Command("sh", "-c", "drush pm-releases --pipe drupal | grep Recommended | cut -d',' -f2").Output()
				ProjectVersion := removeChar(string(x), " ", "7.x-", "\"", "\n", "[", "]")
				headerLines = append(headerLines, "projects[drupal][type] = \"core\"")
				headerLines = append(headerLines, fmt.Sprintf("projects[drupal][version] = \"%v\"", ProjectVersion))
				headerLines = append(headerLines, "projects[drupal][download][type] = \"get\"")
				headerLines = append(headerLines, fmt.Sprintf("projects[drupal][download][url] = \"https://ftp.drupal.org/files/projects/drupal-%v.tar.gz\"", ProjectVersion))
				headerLines = append(headerLines, "")
				coreAppended++
			}
		}
	}

	// Rewrite contrib
	headerLines = append(headerLines, "; modules")
	headerLines = append(headerLines, "defaults[projects][subdir] = contrib")
	headerLines = append(headerLines, "")

	for _, Project := range Projects {

		if Project != "drupal" {
			x, y := exec.Command("sh", "-c", "drush pm-releases --pipe "+Project+" | grep Recommended | cut -d',' -f2").Output()
			if y == nil {
				ProjectVersion := removeChar(string(x), " ", "7.x-", "\"", "\n", "[", "]")
				ProjectType := "contrib"
				if ProjectVersion == "" {
					ProjectType = "custom"
				}
				headerLines = append(headerLines, fmt.Sprintf("projects[%v][version] = \"%v\"", Project, ProjectVersion))
				headerLines = append(headerLines, fmt.Sprintf("projects[%v][type] = \"module\"", Project))
				headerLines = append(headerLines, fmt.Sprintf("projects[%v][subdir] = \"%v\"", Project, ProjectType))
				headerLines = append(headerLines, fmt.Sprint(""))
			}
		}
	}

	// Print to path File

	newFile, _ := os.Create(File)
	for _, line := range headerLines {
		fmt.Fprintln(newFile, line)
	}
	newFile.Sync()
	defer newFile.Close()

}
<|endoftext|>


<commit_before>package main

import (
	"encoding/binary"
	"fmt"
	"github.com/ghodss/yaml"
	"github.com/thoj/go-ircevent"
	"io/ioutil"
	"log"
	"os"
	"regexp"
	"strconv"
	"strings"
)

func codeToBytes(code int) []byte {
	bs := make([]byte, 4)
	binary.LittleEndian.PutUint32(bs, uint32(code))
	fmt.Printf("DEBUG: code: %v, bytes: %v\n", code, bs)
	return bs
}

func (bot *Bot) WriteCode(code int) {
	bs := codeToBytes(code)
	fmt.Printf("Sending %v\n", bs)
	fi, err := os.OpenFile(bot.SerialPort, os.O_WRONLY, os.ModeDevice)
	if err != nil {
		panic(err)
	}
	_, err2 := fi.Write(bs)
	if err2 != nil {
		panic(err2)
	}
	fi.Sync()
	fi.Close()
}

type Bot struct {
	Name       string
	Channels   []string
	Server     string
	Port       int
	Con        *irc.Connection
	SerialPort string
	Commands   map[string]int
}

func (bot *Bot) Address() string {
	return fmt.Sprintf("%s:%d", bot.Server, bot.Port)
}

func ExtractCommandAndArgument(msg string, name string) (command string, argument string) {
	regex := fmt.Sprintf(`^%s[:]?.* (\w+) (\w+)`, name)
	command_regexp := regexp.MustCompile(regex)
	matches := command_regexp.FindStringSubmatch(msg)
	if len(matches) != 3 {
		command = "unknown"
		argument = "unknown"
	} else {
		command = matches[1]
		argument = matches[2]
	}
	return
}

func (bot *Bot) ParseAndReply(channel string, msg string, user string) {
	command, argument := ExtractCommandAndArgument(msg, bot.Name)
	if command == "code" {
		code, err := strconv.Atoi(argument)
		if err == nil {
			reply := fmt.Sprintf("Sent out code %v", code)
			bot.WriteCode(code)
			bot.Con.Privmsg(channel, reply)
			return
		} else {
			reply := fmt.Sprintf("%v doesn't look like a valid code", argument)
			bot.Con.Privmsg(channel, reply)
			return
		}
	} else {
		bot.Con.Privmsg(user, fmt.Sprintf("%v is not a valid command", command))
		bot.Con.Privmsg(user, "Try something like:")
		bot.Con.Privmsg(user, "powerbot code 1234")
		return
	}
}

func (bot *Bot) Run() {
	bot.Con = irc.IRC(bot.Name, bot.Name)
	err := bot.Con.Connect(bot.Address())
	if err != nil {
		log.Fatal("Couldn't connect to %s: %s", bot.Address, err)
	}
	for _, channel := range bot.Channels {
		bot.Con.AddCallback("001", func(e *irc.Event) {
			bot.Con.Join(channel)
		})
	}
	bot.Con.AddCallback("PRIVMSG", func(e *irc.Event) {
		channel := e.Arguments[0]
		msg := e.Arguments[1]
		if strings.HasPrefix(msg, bot.Name) {
			bot.ParseAndReply(channel, msg, e.Nick)
		}
	})
	bot.Con.Loop()
}

type IrcConfig struct {
	Hostname string `yaml:"hostname"`
	Port     int    `yaml:"port"`
	SSL      bool   `yaml:"ssl"`
}

func (c *IrcConfig) UnmarshalYAML(b []byte) error {
	return yaml.Unmarshal(b, c)
}

type Config struct {
	SerialPort string         `yaml:"serial_port"`
	IrcServer  IrcConfig      `yaml:"ircserver"`
	Nick       string         `yaml:"nick"`
	Channels   []string       `yaml:"channels"`
	Commands   map[string]int `yaml:"commands"`
}

func (c *Config) Parse(data []byte) error {
	err := yaml.Unmarshal([]byte(data), c)
	if err != nil {
		return err
	}
	if c.IrcServer.Hostname == "" {
		log.Fatalf("error: ircserver hostname not set")
	}
	return nil
}

func main() {
	filename := "powerbot.yaml"
	data, err := ioutil.ReadFile(filename)
	if err != nil {
		log.Fatalf("error: %v", err)
	}
	var config Config
	err = config.Parse(data)
	if err != nil {
		log.Fatalf("error: %v", err)
	}
	bot := Bot{
		Name:       config.Nick,
		Channels:   config.Channels,
		Server:     config.IrcServer.Hostname,
		Port:       config.IrcServer.Port,
		SerialPort: config.SerialPort}
	bot.Run()
}
<commit_msg>Added a bit more logging<commit_after>package main

import (
	"encoding/binary"
	"fmt"
	"github.com/ghodss/yaml"
	"github.com/thoj/go-ircevent"
	"io/ioutil"
	"log"
	"os"
	"regexp"
	"strconv"
	"strings"
)

func codeToBytes(code int) []byte {
	bs := make([]byte, 4)
	binary.LittleEndian.PutUint32(bs, uint32(code))
	fmt.Printf("DEBUG: code: %v, bytes: %v\n", code, bs)
	return bs
}

func (bot *Bot) WriteCode(code int) {
	bs := codeToBytes(code)
	fmt.Printf("Sending %v\n", bs)
	fi, err := os.OpenFile(bot.SerialPort, os.O_WRONLY, os.ModeDevice)
	if err != nil {
		panic(err)
	}
	_, err2 := fi.Write(bs)
	if err2 != nil {
		panic(err2)
	}
	fi.Sync()
	fi.Close()
}

type Bot struct {
	Name       string
	Channels   []string
	Server     string
	Port       int
	Con        *irc.Connection
	SerialPort string
	Commands   map[string]int
}

func (bot *Bot) Address() string {
	return fmt.Sprintf("%s:%d", bot.Server, bot.Port)
}

func ExtractCommandAndArgument(msg string, name string) (command string, argument string) {
	regex := fmt.Sprintf(`^%s[:]?.* (\w+) (\w+)`, name)
	command_regexp := regexp.MustCompile(regex)
	matches := command_regexp.FindStringSubmatch(msg)
	if len(matches) != 3 {
		command = "unknown"
		argument = "unknown"
	} else {
		command = matches[1]
		argument = matches[2]
	}
	return
}

func (bot *Bot) ParseAndReply(channel string, msg string, user string) {
	command, argument := ExtractCommandAndArgument(msg, bot.Name)
	if command == "code" {
		code, err := strconv.Atoi(argument)
		if err == nil {
			reply := fmt.Sprintf("Sent out code %v", code)
			bot.WriteCode(code)
			bot.Con.Privmsg(channel, reply)
			return
		} else {
			reply := fmt.Sprintf("%v doesn't look like a valid code", argument)
			bot.Con.Privmsg(channel, reply)
			return
		}
	} else {
		bot.Con.Privmsg(user, fmt.Sprintf("%v is not a valid command", command))
		bot.Con.Privmsg(user, "Try something like:")
		bot.Con.Privmsg(user, "powerbot code 1234")
		return
	}
}

func (bot *Bot) Run() {
	bot.Con = irc.IRC(bot.Name, bot.Name)
	err := bot.Con.Connect(bot.Address())
	if err != nil {
		log.Fatal("Couldn't connect to %s: %s", bot.Address(), err)
	}
	bot.Con.Nick(bot.Name)
	log.Printf("Connected to %v as %v", bot.Address(), bot.Name)
	for _, channel := range bot.Channels {
		log.Printf("Joining %v", channel)
		bot.Con.AddCallback("001", func(e *irc.Event) {
			bot.Con.Join(channel)
		})
	}
	bot.Con.AddCallback("PRIVMSG", func(e *irc.Event) {
		channel := e.Arguments[0]
		msg := e.Arguments[1]
		if strings.HasPrefix(msg, bot.Name) {
			bot.ParseAndReply(channel, msg, e.Nick)
		}
	})
	bot.Con.Loop()
}

type IrcConfig struct {
	Hostname string `yaml:"hostname"`
	Port     int    `yaml:"port"`
	SSL      bool   `yaml:"ssl"`
}

func (c *IrcConfig) UnmarshalYAML(b []byte) error {
	return yaml.Unmarshal(b, c)
}

type Config struct {
	SerialPort string         `yaml:"serial_port"`
	IrcServer  IrcConfig      `yaml:"ircserver"`
	Nick       string         `yaml:"nick"`
	Channels   []string       `yaml:"channels"`
	Commands   map[string]int `yaml:"commands"`
}

func (c *Config) Parse(data []byte) error {
	err := yaml.Unmarshal([]byte(data), c)
	if err != nil {
		return err
	}
	if c.IrcServer.Hostname == "" {
		log.Fatalf("error: ircserver hostname not set")
	}
	return nil
}

func main() {
	filename := "powerbot.yaml"
	data, err := ioutil.ReadFile(filename)
	if err != nil {
		log.Fatalf("error: %v", err)
	}
	var config Config
	err = config.Parse(data)
	if err != nil {
		log.Fatalf("error: %v", err)
	}
	bot := Bot{
		Name:       config.Nick,
		Channels:   config.Channels,
		Server:     config.IrcServer.Hostname,
		Port:       config.IrcServer.Port,
		SerialPort: config.SerialPort}
	bot.Run()
}
<|endoftext|>


<commit_before>package posix

import (
	"github.com/lunixbochs/usercorn/go/kernel/common"
	"github.com/lunixbochs/usercorn/go/models"
)

type PosixKernel struct {
	common.KernelBase
	Unpack func(common.Buf, interface{})
}

func packAddrs(u models.Usercorn, addrs []uint64) ([]byte, error) {
	buf := make([]byte, int(u.Bits())/8*(len(addrs)+1))
	pos := buf
	for _, v := range addrs {
		x, err := u.PackAddr(pos, v)
		if err != nil {
			return nil, err
		}
		pos = pos[len(x):]
	}
	return buf, nil
}

func pushStrings(u models.Usercorn, args ...string) ([]uint64, error) {
	addrs := make([]uint64, 0, len(args)+1)
	for _, arg := range args {
		if addr, err := u.PushBytes([]byte(arg + "\x00")); err != nil {
			return nil, err
		} else {
			addrs = append(addrs, addr)
		}
	}
	return addrs, nil
}

func StackInit(u models.Usercorn, args, env []string, auxv []byte) error {
	// push argv and envp strings
	envp, err := pushStrings(u, env...)
	if err != nil {
		return err
	}
	argv, err := pushStrings(u, args...)
	if err != nil {
		return err
	}
	// precalc envp -> argc for stack alignment
	envpb, err := packAddrs(u, envp)
	if err != nil {
		return err
	}
	argvb, err := packAddrs(u, argv)
	if err != nil {
		return err
	}
	var tmp [8]byte
	argcb, err := u.PackAddr(tmp[:], uint64(len(argv)))
	init := append(argcb, argvb...)
	init = append(init, envpb...)
	// align stack pointer
	sp, _ := u.RegRead(u.Arch().SP)
	sp &= ^uint64(15)
	off := len(init) & 15
	if off > 0 {
		sp -= uint64(16 - off)
	}
	u.RegWrite(u.Arch().SP, sp)
	// auxv
	if len(auxv) > 0 {
		if _, err := u.PushBytes(auxv); err != nil {
			return err
		}
	}
	// write envp -> argc
	u.PushBytes(init)
	return err
}
<commit_msg>conform stack behavior<commit_after>package posix

import (
	"github.com/lunixbochs/usercorn/go/kernel/common"
	"github.com/lunixbochs/usercorn/go/models"
)

type PosixKernel struct {
	common.KernelBase
	Unpack func(common.Buf, interface{})
}

func packAddrs(u models.Usercorn, addrs []uint64) ([]byte, error) {
	buf := make([]byte, int(u.Bits())/8*(len(addrs)+1))
	pos := buf
	for _, v := range addrs {
		x, err := u.PackAddr(pos, v)
		if err != nil {
			return nil, err
		}
		pos = pos[len(x):]
	}
	return buf, nil
}

func pushStrings(u models.Usercorn, args ...string) ([]uint64, error) {
	addrs := make([]uint64, 0, len(args)+1)
	for _, arg := range args {
		if addr, err := u.PushBytes([]byte(arg + "\x00")); err != nil {
			return nil, err
		} else {
			addrs = append(addrs, addr)
		}
	}
	return addrs, nil
}

func StackInit(u models.Usercorn, args, env []string, auxv []byte) error {
	if _, err := u.Push(0); err != nil {
		return err
	}
	if len(args) > 0 {
		if _, err := u.PushBytes([]byte(args[0] + "\x00")); err != nil {
			return err
		}
	}
	// push argv and envp strings
	envp, err := pushStrings(u, env...)
	if err != nil {
		return err
	}
	argv, err := pushStrings(u, args...)
	if err != nil {
		return err
	}
	// precalc envp -> argc for stack alignment
	envpb, err := packAddrs(u, envp)
	if err != nil {
		return err
	}
	argvb, err := packAddrs(u, argv)
	if err != nil {
		return err
	}
	var tmp [8]byte
	argcb, err := u.PackAddr(tmp[:], uint64(len(argv)))
	init := append(argcb, argvb...)
	init = append(init, envpb...)
	// align stack pointer
	sp, _ := u.RegRead(u.Arch().SP)
	sp &= ^uint64(15)
	off := len(init) & 15
	if off > 0 {
		sp -= uint64(16 - off)
	}
	u.RegWrite(u.Arch().SP, sp)
	// auxv
	if len(auxv) > 0 {
		if _, err := u.PushBytes(auxv); err != nil {
			return err
		}
	}
	// write envp -> argc
	u.PushBytes(init)
	return err
}
<|endoftext|>


<commit_before>/*
   Copyright 2017 Shlomi Noach, GitHub Inc.

   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 logic

import (
	"bytes"
	"compress/gzip"
	"encoding/json"
	"io"

	"github.com/github/orchestrator/go/db"
	"github.com/github/orchestrator/go/inst"

	"github.com/openark/golib/log"
	"github.com/openark/golib/sqlutils"
)

type SnapshotData struct {
	Keys             []inst.InstanceKey // Kept for backwards comapatibility
	MinimalInstances []inst.MinimalInstance
	RecoveryDisabled bool

	ClusterAlias,
	ClusterAliasOverride,
	ClusterDomainName,
	HostAttributes,
	AccessToken,
	PoolInstances,
	InjectedPseudoGTIDInstances,
	HostnameResolves,
	HostnameUnresolves,
	DowntimedInstances,
	Candidates,
	Detections,
	KVStore,
	Recovery,
	RecoverySteps sqlutils.NamedResultData
}

func NewSnapshotData() *SnapshotData {
	return &SnapshotData{}
}

func readTableData(tableName string, data *sqlutils.NamedResultData) error {
	orcdb, err := db.OpenOrchestrator()
	if err != nil {
		return log.Errore(err)
	}
	*data, err = sqlutils.ScanTable(orcdb, tableName)
	return log.Errore(err)
}

func writeTableData(tableName string, data *sqlutils.NamedResultData) error {
	orcdb, err := db.OpenOrchestrator()
	if err != nil {
		return log.Errore(err)
	}
	err = sqlutils.WriteTable(orcdb, tableName, *data)
	return log.Errore(err)
}

func CreateSnapshotData() *SnapshotData {
	snapshotData := NewSnapshotData()

	// keys
	snapshotData.MinimalInstances, _ = inst.ReadAllMinimalInstances()
	snapshotData.RecoveryDisabled, _ = IsRecoveryDisabled()

	readTableData("cluster_alias", &snapshotData.ClusterAlias)
	readTableData("cluster_alias_override", &snapshotData.ClusterAliasOverride)
	readTableData("cluster_domain_name", &snapshotData.ClusterDomainName)
	readTableData("access_token", &snapshotData.AccessToken)
	readTableData("host_attributes", &snapshotData.HostAttributes)
	readTableData("database_instance_pool", &snapshotData.PoolInstances)
	readTableData("hostname_resolve", &snapshotData.HostnameResolves)
	readTableData("hostname_unresolve", &snapshotData.HostnameUnresolves)
	readTableData("database_instance_downtime", &snapshotData.DowntimedInstances)
	readTableData("candidate_database_instance", &snapshotData.Candidates)
	readTableData("topology_failure_detection", &snapshotData.Detections)
	readTableData("kv_store", &snapshotData.KVStore)
	readTableData("topology_recovery", &snapshotData.Recovery)
	readTableData("topology_recovery_steps", &snapshotData.RecoverySteps)
	readTableData("database_instance_injected_pseudo_gtid", &snapshotData.InjectedPseudoGTIDInstances)

	log.Debugf("raft snapshot data created")
	return snapshotData
}

type SnapshotDataCreatorApplier struct {
}

func NewSnapshotDataCreatorApplier() *SnapshotDataCreatorApplier {
	generator := &SnapshotDataCreatorApplier{}
	return generator
}

func (this *SnapshotDataCreatorApplier) GetData() (data []byte, err error) {
	snapshotData := CreateSnapshotData()
	b, err := json.Marshal(snapshotData)
	if err != nil {
		return b, err
	}
	var buf bytes.Buffer
	zw := gzip.NewWriter(&buf)
	if _, err := zw.Write(b); err != nil {
		return b, err
	}
	if err := zw.Close(); err != nil {
		return b, err
	}
	return buf.Bytes(), nil
}

func (this *SnapshotDataCreatorApplier) Restore(rc io.ReadCloser) error {
	snapshotData := NewSnapshotData()
	zr, err := gzip.NewReader(rc)
	if err != nil {
		return err
	}
	if err := json.NewDecoder(zr).Decode(&snapshotData); err != nil {
		return err
	}

	// keys
	{
		snapshotInstanceKeyMap := inst.NewInstanceKeyMap()
		snapshotInstanceKeyMap.AddKeys(snapshotData.Keys)
		for _, minimalInstance := range snapshotData.MinimalInstances {
			snapshotInstanceKeyMap.AddKey(minimalInstance.Key)
		}

		discardedKeys := 0
		// Forget instances that were not in snapshot
		existingKeys, _ := inst.ReadAllInstanceKeys()
		for _, existingKey := range existingKeys {
			if !snapshotInstanceKeyMap.HasKey(existingKey) {
				inst.ForgetInstance(&existingKey)
				discardedKeys++
			}
		}
		log.Debugf("raft snapshot restore: discarded %+v keys", discardedKeys)
		existingKeysMap := inst.NewInstanceKeyMap()
		existingKeysMap.AddKeys(existingKeys)

		// Discover instances that are in snapshot and not in our own database.
		// Instances that _are_ in our own database will self-discover. No need
		// to explicitly discover them.
		discoveredKeys := 0
		// v2: read keys + master keys
		for _, minimalInstance := range snapshotData.MinimalInstances {
			if !existingKeysMap.HasKey(minimalInstance.Key) {
				if err := inst.WriteInstance(minimalInstance.ToInstance(), false, nil); err == nil {
					discoveredKeys++
				} else {
					log.Errore(err)
				}
			}
		}
		if len(snapshotData.MinimalInstances) == 0 {
			// v1: read keys (backwards support)
			for _, snapshotKey := range snapshotData.Keys {
				if !existingKeysMap.HasKey(snapshotKey) {
					snapshotKey := snapshotKey
					go func() {
						snapshotDiscoveryKeys <- snapshotKey
					}()
					discoveredKeys++
				}
			}
		}
		log.Debugf("raft snapshot restore: discovered %+v keys", discoveredKeys)
	}
	writeTableData("cluster_alias", &snapshotData.ClusterAlias)
	writeTableData("cluster_alias_override", &snapshotData.ClusterAliasOverride)
	writeTableData("cluster_domain_name", &snapshotData.ClusterDomainName)
	writeTableData("access_token", &snapshotData.AccessToken)
	writeTableData("host_attributes", &snapshotData.HostAttributes)
	writeTableData("database_instance_pool", &snapshotData.PoolInstances)
	writeTableData("hostname_resolve", &snapshotData.HostnameResolves)
	writeTableData("hostname_unresolve", &snapshotData.HostnameUnresolves)
	writeTableData("database_instance_downtime", &snapshotData.DowntimedInstances)
	writeTableData("candidate_database_instance", &snapshotData.Candidates)
	writeTableData("kv_store", &snapshotData.KVStore)
	writeTableData("topology_recovery", &snapshotData.Recovery)
	writeTableData("topology_failure_detection", &snapshotData.Detections)
	writeTableData("topology_recovery_steps", &snapshotData.RecoverySteps)
	writeTableData("database_instance_injected_pseudo_gtid", &snapshotData.InjectedPseudoGTIDInstances)

	// recovery disable
	{
		SetRecoveryDisabled(snapshotData.RecoveryDisabled)
	}
	log.Debugf("raft snapshot restore applied")
	return nil
}
<commit_msg>exporting Keys for v1 compatibility<commit_after>/*
   Copyright 2017 Shlomi Noach, GitHub Inc.

   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 logic

import (
	"bytes"
	"compress/gzip"
	"encoding/json"
	"io"

	"github.com/github/orchestrator/go/db"
	"github.com/github/orchestrator/go/inst"

	"github.com/openark/golib/log"
	"github.com/openark/golib/sqlutils"
)

type SnapshotData struct {
	Keys             []inst.InstanceKey // Kept for backwards comapatibility
	MinimalInstances []inst.MinimalInstance
	RecoveryDisabled bool

	ClusterAlias,
	ClusterAliasOverride,
	ClusterDomainName,
	HostAttributes,
	AccessToken,
	PoolInstances,
	InjectedPseudoGTIDInstances,
	HostnameResolves,
	HostnameUnresolves,
	DowntimedInstances,
	Candidates,
	Detections,
	KVStore,
	Recovery,
	RecoverySteps sqlutils.NamedResultData
}

func NewSnapshotData() *SnapshotData {
	return &SnapshotData{}
}

func readTableData(tableName string, data *sqlutils.NamedResultData) error {
	orcdb, err := db.OpenOrchestrator()
	if err != nil {
		return log.Errore(err)
	}
	*data, err = sqlutils.ScanTable(orcdb, tableName)
	return log.Errore(err)
}

func writeTableData(tableName string, data *sqlutils.NamedResultData) error {
	orcdb, err := db.OpenOrchestrator()
	if err != nil {
		return log.Errore(err)
	}
	err = sqlutils.WriteTable(orcdb, tableName, *data)
	return log.Errore(err)
}

func CreateSnapshotData() *SnapshotData {
	snapshotData := NewSnapshotData()

	// keys
	snapshotData.Keys, _ = inst.ReadAllInstanceKeys()
	snapshotData.MinimalInstances, _ = inst.ReadAllMinimalInstances()
	snapshotData.RecoveryDisabled, _ = IsRecoveryDisabled()

	readTableData("cluster_alias", &snapshotData.ClusterAlias)
	readTableData("cluster_alias_override", &snapshotData.ClusterAliasOverride)
	readTableData("cluster_domain_name", &snapshotData.ClusterDomainName)
	readTableData("access_token", &snapshotData.AccessToken)
	readTableData("host_attributes", &snapshotData.HostAttributes)
	readTableData("database_instance_pool", &snapshotData.PoolInstances)
	readTableData("hostname_resolve", &snapshotData.HostnameResolves)
	readTableData("hostname_unresolve", &snapshotData.HostnameUnresolves)
	readTableData("database_instance_downtime", &snapshotData.DowntimedInstances)
	readTableData("candidate_database_instance", &snapshotData.Candidates)
	readTableData("topology_failure_detection", &snapshotData.Detections)
	readTableData("kv_store", &snapshotData.KVStore)
	readTableData("topology_recovery", &snapshotData.Recovery)
	readTableData("topology_recovery_steps", &snapshotData.RecoverySteps)
	readTableData("database_instance_injected_pseudo_gtid", &snapshotData.InjectedPseudoGTIDInstances)

	log.Debugf("raft snapshot data created")
	return snapshotData
}

type SnapshotDataCreatorApplier struct {
}

func NewSnapshotDataCreatorApplier() *SnapshotDataCreatorApplier {
	generator := &SnapshotDataCreatorApplier{}
	return generator
}

func (this *SnapshotDataCreatorApplier) GetData() (data []byte, err error) {
	snapshotData := CreateSnapshotData()
	b, err := json.Marshal(snapshotData)
	if err != nil {
		return b, err
	}
	var buf bytes.Buffer
	zw := gzip.NewWriter(&buf)
	if _, err := zw.Write(b); err != nil {
		return b, err
	}
	if err := zw.Close(); err != nil {
		return b, err
	}
	return buf.Bytes(), nil
}

func (this *SnapshotDataCreatorApplier) Restore(rc io.ReadCloser) error {
	snapshotData := NewSnapshotData()
	zr, err := gzip.NewReader(rc)
	if err != nil {
		return err
	}
	if err := json.NewDecoder(zr).Decode(&snapshotData); err != nil {
		return err
	}

	// keys
	{
		snapshotInstanceKeyMap := inst.NewInstanceKeyMap()
		snapshotInstanceKeyMap.AddKeys(snapshotData.Keys)
		for _, minimalInstance := range snapshotData.MinimalInstances {
			snapshotInstanceKeyMap.AddKey(minimalInstance.Key)
		}

		discardedKeys := 0
		// Forget instances that were not in snapshot
		existingKeys, _ := inst.ReadAllInstanceKeys()
		for _, existingKey := range existingKeys {
			if !snapshotInstanceKeyMap.HasKey(existingKey) {
				inst.ForgetInstance(&existingKey)
				discardedKeys++
			}
		}
		log.Debugf("raft snapshot restore: discarded %+v keys", discardedKeys)
		existingKeysMap := inst.NewInstanceKeyMap()
		existingKeysMap.AddKeys(existingKeys)

		// Discover instances that are in snapshot and not in our own database.
		// Instances that _are_ in our own database will self-discover. No need
		// to explicitly discover them.
		discoveredKeys := 0
		// v2: read keys + master keys
		for _, minimalInstance := range snapshotData.MinimalInstances {
			if !existingKeysMap.HasKey(minimalInstance.Key) {
				if err := inst.WriteInstance(minimalInstance.ToInstance(), false, nil); err == nil {
					discoveredKeys++
				} else {
					log.Errore(err)
				}
			}
		}
		if len(snapshotData.MinimalInstances) == 0 {
			// v1: read keys (backwards support)
			for _, snapshotKey := range snapshotData.Keys {
				if !existingKeysMap.HasKey(snapshotKey) {
					snapshotKey := snapshotKey
					go func() {
						snapshotDiscoveryKeys <- snapshotKey
					}()
					discoveredKeys++
				}
			}
		}
		log.Debugf("raft snapshot restore: discovered %+v keys", discoveredKeys)
	}
	writeTableData("cluster_alias", &snapshotData.ClusterAlias)
	writeTableData("cluster_alias_override", &snapshotData.ClusterAliasOverride)
	writeTableData("cluster_domain_name", &snapshotData.ClusterDomainName)
	writeTableData("access_token", &snapshotData.AccessToken)
	writeTableData("host_attributes", &snapshotData.HostAttributes)
	writeTableData("database_instance_pool", &snapshotData.PoolInstances)
	writeTableData("hostname_resolve", &snapshotData.HostnameResolves)
	writeTableData("hostname_unresolve", &snapshotData.HostnameUnresolves)
	writeTableData("database_instance_downtime", &snapshotData.DowntimedInstances)
	writeTableData("candidate_database_instance", &snapshotData.Candidates)
	writeTableData("kv_store", &snapshotData.KVStore)
	writeTableData("topology_recovery", &snapshotData.Recovery)
	writeTableData("topology_failure_detection", &snapshotData.Detections)
	writeTableData("topology_recovery_steps", &snapshotData.RecoverySteps)
	writeTableData("database_instance_injected_pseudo_gtid", &snapshotData.InjectedPseudoGTIDInstances)

	// recovery disable
	{
		SetRecoveryDisabled(snapshotData.RecoveryDisabled)
	}
	log.Debugf("raft snapshot restore applied")
	return nil
}
<|endoftext|>


<commit_before>package dma

import (
	"unsafe"

	"stm32/hal/raw/mmap"
)

//emgo:const
var (
	DMA1 = (*DMA)(unsafe.Pointer(mmap.DMA1_BASE))
	DMA2 = (*DMA)(unsafe.Pointer(mmap.DMA2_BASE))
)

type DMA dmaperiph

func (p *DMA) EnableClock(lp bool) {
	p.enableClock(lp)
}

func (p *DMA) DisableClock() {
	p.disableClock()
}

func (p *DMA) Reset() {
	p.reset()
}

// Channel returns value that represents sn-th stream (channel in F1/L1 series
// nomenclature) and cn-th channel (ignored in case of F1/L1 series).
func (p *DMA) Channel(sn, cn int) *Channel {
	return p.getChannel(sn, cn)
}

type Channel channel

type Event byte

const (
	Complete     Event = trce // Transfer Complete Event.
	HalfComplete Event = htce // Half Transfer Complete Event.

	EvAll = Complete | HalfComplete
)

type Error byte

const (
	ErrTransfer   Error = trerr // Transfer Error.
	ErrDirectMode Error = dmerr // Direct Mode Error.
	ErrFIFO       Error = fferr // FIFO Error.

	ErrAll = ErrTransfer | ErrDirectMode | ErrFIFO
)

func (e Error) Error() string {
	var (
		s string
		d Error
	)
	switch {
	case e&ErrTransfer != 0:
		d = ErrTransfer
		s = "DMA transfer+"
	case e&ErrDirectMode != 0:
		d = ErrDirectMode
		s = "DMA direct mode+"
	case e&ErrFIFO != 0:
		d = ErrFIFO
		s = "DMA FIFO+"
	default:
		return ""
	}
	if e&^d == 0 {
		s = s[:len(s)-1]
	}
	return s
}

// Status returns current event and error flags.
func (ch *Channel) Status() (Event, Error) {
	flags := ch.status()
	return Event(flags) & EvAll, Error(flags) & ErrAll
}

// ClearEvents clears specified event flags.
func (ch *Channel) Clear(ev Event, err Error) {
	ch.clear(byte(ev) | byte(err))
}

// Enable enables channel.
func (ch *Channel) Enable() {
	ch.enable()
}

// Disable disables channel.
func (ch *Channel) Disable() {
	ch.disable()
}

// Returns true if channel is enabled.
func (ch *Channel) Enabled() bool {
	return ch.enabled()
}

// IntEnabled returns events that are enabled to generate interrupts.
func (ch *Channel) IntEnabled() (Event, Error) {
	flags := ch.intEnabled()
	return Event(flags) & EvAll, Error(flags) & ErrAll
}

// EnableInt enables interrupt generation by events.
func (ch *Channel) EnableInt(ev Event, err Error) {
	ch.enableInt(byte(ev) | byte(err))
}

// DisableInt disables interrupt generation by events.
func (ch *Channel) DisableInt(ev Event, err Error) {
	ch.disableInt(byte(ev) | byte(err))
}

type Mode uint32

const (
	PTM Mode = 0   // Read from peripheral, write to memory.
	MTP Mode = mtp // Read from memory, write to peripheral.
	MTM Mode = mtm // Read from memory (AddrP), write to memory.

	Circ Mode = circ // Enable circular mode.
	IncP Mode = incP // Peripheral increment mode.
	IncM Mode = incM // Memory increment mode.

	PrioL Mode = 0     // Stream priority level: Low.
	PrioM Mode = prioM // Stream priority level: Medium.
	PrioH Mode = prioH // Stream priority level: High.
	PrioV Mode = prioV // Stream priority level: Very high.

	Direct   Mode = 0        // Direct mode.
	FIFO_1_4 Mode = fifo_1_4 // FIFO mode, threshold 1/4.
	FIFO_2_4 Mode = fifo_2_4 // FIFO mode, threshold 2/4.
	FIFO_3_4 Mode = fifo_3_4 // FIFO mode, threshold 3/4.
	FIFO_4_4 Mode = fifo_4_4 // FIFO mode, threshold 4/4.
)

// Setup configures channel.
func (ch *Channel) Setup(m Mode) {
	ch.setup(m)
}

// WordSize returns the current word size (in bytes) for peripheral and memory
// side of transfer.
func (ch *Channel) WordSize() (p, m uintptr) {
	return ch.wordSize()
}

// SetWordSize sets the word size (in bytes) for peripheral and memory side of
// transfer.
func (ch *Channel) SetWordSize(p, m uintptr) {
	ch.setWordSize(p, m)
}

// Len returns current number of words to transfer.
func (ch *Channel) Len() int {
	return ch.len()
}

// SetLen sets number of words to transfer (n <= 65535).
func (ch *Channel) SetLen(n int) {
	ch.setLen(n)
}

// SetAddrP sets peripheral address (or memory source address in case of MTM).
func (ch *Channel) SetAddrP(a unsafe.Pointer) {
	ch.setAddrP(a)
}

// SetAddrM sets memory address.
func (ch *Channel) SetAddrM(a unsafe.Pointer) {
	ch.setAddrM(a)
}
<commit_msg>stm32/hal/dma: Better explain Channel concept.<commit_after>package dma

import (
	"unsafe"

	"stm32/hal/raw/mmap"
)

//emgo:const
var (
	DMA1 = (*DMA)(unsafe.Pointer(mmap.DMA1_BASE))
	DMA2 = (*DMA)(unsafe.Pointer(mmap.DMA2_BASE))
)

type DMA dmaperiph

func (p *DMA) EnableClock(lp bool) {
	p.enableClock(lp)
}

func (p *DMA) DisableClock() {
	p.disableClock()
}

func (p *DMA) Reset() {
	p.reset()
}

// Channel returns value that represents sn-th stream (channel in F1/L1 series
// nomenclature) with cn-th request channel set (ignored in case of F1/L1
// series). Channels with the same sn points to the same DMA stream so they can
// not be used concurently.
func (p *DMA) Channel(sn, cn int) *Channel {
	return p.getChannel(sn, cn)
}

type Channel channel

type Event byte

const (
	Complete     Event = trce // Transfer Complete Event.
	HalfComplete Event = htce // Half Transfer Complete Event.

	EvAll = Complete | HalfComplete
)

type Error byte

const (
	ErrTransfer   Error = trerr // Transfer Error.
	ErrDirectMode Error = dmerr // Direct Mode Error.
	ErrFIFO       Error = fferr // FIFO Error.

	ErrAll = ErrTransfer | ErrDirectMode | ErrFIFO
)

func (e Error) Error() string {
	var (
		s string
		d Error
	)
	switch {
	case e&ErrTransfer != 0:
		d = ErrTransfer
		s = "DMA transfer+"
	case e&ErrDirectMode != 0:
		d = ErrDirectMode
		s = "DMA direct mode+"
	case e&ErrFIFO != 0:
		d = ErrFIFO
		s = "DMA FIFO+"
	default:
		return ""
	}
	if e&^d == 0 {
		s = s[:len(s)-1]
	}
	return s
}

// Status returns current event and error flags.
func (ch *Channel) Status() (Event, Error) {
	flags := ch.status()
	return Event(flags) & EvAll, Error(flags) & ErrAll
}

// ClearEvents clears specified event flags.
func (ch *Channel) Clear(ev Event, err Error) {
	ch.clear(byte(ev) | byte(err))
}

// Enable enables channel.
func (ch *Channel) Enable() {
	ch.enable()
}

// Disable disables channel.
func (ch *Channel) Disable() {
	ch.disable()
}

// Returns true if channel is enabled.
func (ch *Channel) Enabled() bool {
	return ch.enabled()
}

// IntEnabled returns events that are enabled to generate interrupts.
func (ch *Channel) IntEnabled() (Event, Error) {
	flags := ch.intEnabled()
	return Event(flags) & EvAll, Error(flags) & ErrAll
}

// EnableInt enables interrupt generation by events.
func (ch *Channel) EnableInt(ev Event, err Error) {
	ch.enableInt(byte(ev) | byte(err))
}

// DisableInt disables interrupt generation by events.
func (ch *Channel) DisableInt(ev Event, err Error) {
	ch.disableInt(byte(ev) | byte(err))
}

type Mode uint32

const (
	PTM Mode = 0   // Read from peripheral, write to memory.
	MTP Mode = mtp // Read from memory, write to peripheral.
	MTM Mode = mtm // Read from memory (AddrP), write to memory.

	Circ Mode = circ // Enable circular mode.
	IncP Mode = incP // Peripheral increment mode.
	IncM Mode = incM // Memory increment mode.

	PrioL Mode = 0     // Stream priority level: Low.
	PrioM Mode = prioM // Stream priority level: Medium.
	PrioH Mode = prioH // Stream priority level: High.
	PrioV Mode = prioV // Stream priority level: Very high.

	Direct   Mode = 0        // Direct mode.
	FIFO_1_4 Mode = fifo_1_4 // FIFO mode, threshold 1/4.
	FIFO_2_4 Mode = fifo_2_4 // FIFO mode, threshold 2/4.
	FIFO_3_4 Mode = fifo_3_4 // FIFO mode, threshold 3/4.
	FIFO_4_4 Mode = fifo_4_4 // FIFO mode, threshold 4/4.
)

// Setup configures channel.
func (ch *Channel) Setup(m Mode) {
	ch.setup(m)
}

// WordSize returns the current word size (in bytes) for peripheral and memory
// side of transfer.
func (ch *Channel) WordSize() (p, m uintptr) {
	return ch.wordSize()
}

// SetWordSize sets the word size (in bytes) for peripheral and memory side of
// transfer.
func (ch *Channel) SetWordSize(p, m uintptr) {
	ch.setWordSize(p, m)
}

// Len returns current number of words to transfer.
func (ch *Channel) Len() int {
	return ch.len()
}

// SetLen sets number of words to transfer (n <= 65535).
func (ch *Channel) SetLen(n int) {
	ch.setLen(n)
}

// SetAddrP sets peripheral address (or memory source address in case of MTM).
func (ch *Channel) SetAddrP(a unsafe.Pointer) {
	ch.setAddrP(a)
}

// SetAddrM sets memory address.
func (ch *Channel) SetAddrM(a unsafe.Pointer) {
	ch.setAddrM(a)
}
<|endoftext|>


<commit_before>package diffsquares
<commit_msg>Solve difference of squares<commit_after>package diffsquares

// SquareOfSum returns (1 + 2 + ... + n) ^ 2
func SquareOfSum(n int) int {
	sum := 0
	for i := 0; i <= n; i++ {
		sum += i
	}
	return sum * sum
}

// SumOfSquares returns 1^2 + 2^2 + ... + n^2
func SumOfSquares(n int) int {
	sum := 0
	for i := 0; i <= n; i++ {
		sum += i * i
	}
	return sum
}

// Difference returns the difference between the SquareOfSum(n) and SumOfSquares(n)
func Difference(n int) int {
	return SquareOfSum(n) - SumOfSquares(n)
}
<|endoftext|>


<commit_before>// Copyright 2010 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// Package smtp implements the Simple Mail Transfer Protocol as defined in RFC 5321.
// It also implements the following extensions:
//	8BITMIME  RFC 1652
//	AUTH      RFC 2554
//	STARTTLS  RFC 3207
// Additional extensions may be handled by clients.
package smtp

import (
	"crypto/tls"
	"encoding/base64"
	"io"
	"os"
	"net"
	"net/textproto"
	"strings"
)

// A Client represents a client connection to an SMTP server.
type Client struct {
	// Text is the textproto.Conn used by the Client. It is exported to allow for
	// clients to add extensions.
	Text *textproto.Conn
	// keep a reference to the connection so it can be used to create a TLS
	// connection later
	conn net.Conn
	// whether the Client is using TLS
	tls        bool
	serverName string
	// map of supported extensions
	ext map[string]string
	// supported auth mechanisms
	auth []string
}

// Dial returns a new Client connected to an SMTP server at addr.
func Dial(addr string) (*Client, os.Error) {
	conn, err := net.Dial("tcp", "", addr)
	if err != nil {
		return nil, err
	}
	host := addr[:strings.Index(addr, ":")]
	return NewClient(conn, host)
}

// NewClient returns a new Client using an existing connection and host as a
// server name to be used when authenticating.
func NewClient(conn net.Conn, host string) (*Client, os.Error) {
	text := textproto.NewConn(conn)
	_, msg, err := text.ReadResponse(220)
	if err != nil {
		text.Close()
		return nil, err
	}
	c := &Client{Text: text, conn: conn, serverName: host}
	if strings.Contains(msg, "ESMTP") {
		err = c.ehlo()
	} else {
		err = c.helo()
	}
	return c, err
}

// cmd is a convenience function that sends a command and returns the response
func (c *Client) cmd(expectCode int, format string, args ...interface{}) (int, string, os.Error) {
	id, err := c.Text.Cmd(format, args...)
	if err != nil {
		return 0, "", err
	}
	c.Text.StartResponse(id)
	defer c.Text.EndResponse(id)
	code, msg, err := c.Text.ReadResponse(expectCode)
	return code, msg, err
}

// helo sends the HELO greeting to the server. It should be used only when the
// server does not support ehlo.
func (c *Client) helo() os.Error {
	c.ext = nil
	_, _, err := c.cmd(250, "HELO localhost")
	return err
}

// ehlo sends the EHLO (extended hello) greeting to the server. It
// should be the preferred greeting for servers that support it.
func (c *Client) ehlo() os.Error {
	_, msg, err := c.cmd(250, "EHLO localhost")
	if err != nil {
		return err
	}
	ext := make(map[string]string)
	extList := strings.Split(msg, "\n", -1)
	if len(extList) > 1 {
		extList = extList[1:]
		for _, line := range extList {
			args := strings.Split(line, " ", 2)
			if len(args) > 1 {
				ext[args[0]] = args[1]
			} else {
				ext[args[0]] = ""
			}
		}
	}
	if mechs, ok := ext["AUTH"]; ok {
		c.auth = strings.Split(mechs, " ", -1)
	}
	c.ext = ext
	return err
}

// StartTLS sends the STARTTLS command and encrypts all further communication.
// Only servers that advertise the STARTTLS extension support this function.
func (c *Client) StartTLS() os.Error {
	_, _, err := c.cmd(220, "STARTTLS")
	if err != nil {
		return err
	}
	c.conn = tls.Client(c.conn, nil)
	c.Text = textproto.NewConn(c.conn)
	c.tls = true
	return c.ehlo()
}

// Verify checks the validity of an email address on the server.
// If Verify returns nil, the address is valid. A non-nil return
// does not necessarily indicate an invalid address. Many servers
// will not verify addresses for security reasons.
func (c *Client) Verify(addr string) os.Error {
	_, _, err := c.cmd(250, "VRFY %s", addr)
	return err
}

// Auth authenticates a client using the provided authentication mechanism.
// A failed authentication closes the connection.
// Only servers that advertise the AUTH extension support this function.
func (c *Client) Auth(a Auth) os.Error {
	encoding := base64.StdEncoding
	mech, resp, err := a.Start(&ServerInfo{c.serverName, c.tls, c.auth})
	if err != nil {
		c.Quit()
		return err
	}
	resp64 := make([]byte, encoding.EncodedLen(len(resp)))
	encoding.Encode(resp64, resp)
	code, msg64, err := c.cmd(0, "AUTH %s %s", mech, resp64)
	for err == nil {
		var msg []byte
		switch code {
		case 334:
			msg = make([]byte, encoding.DecodedLen(len(msg64)))
			_, err = encoding.Decode(msg, []byte(msg64))
		case 235:
			// the last message isn't base64 because it isn't a challenge
			msg = []byte(msg64)
		default:
			err = &textproto.Error{code, msg64}
		}
		resp, err = a.Next(msg, code == 334)
		if err != nil {
			// abort the AUTH
			c.cmd(501, "*")
			c.Quit()
			break
		}
		if resp == nil {
			break
		}
		resp64 = make([]byte, encoding.EncodedLen(len(resp)))
		encoding.Encode(resp64, resp)
		code, msg64, err = c.cmd(0, string(resp64))
	}
	return err
}

// Mail issues a MAIL command to the server using the provided email address.
// If the server supports the 8BITMIME extension, Mail adds the BODY=8BITMIME
// parameter.
// This initiates a mail transaction and is followed by one or more Rcpt calls.
func (c *Client) Mail(from string) os.Error {
	cmdStr := "MAIL FROM:<%s>"
	if c.ext != nil {
		if _, ok := c.ext["8BITMIME"]; ok {
			cmdStr += " BODY=8BITMIME"
		}
	}
	_, _, err := c.cmd(250, cmdStr, from)
	return err
}

// Rcpt issues a RCPT command to the server using the provided email address.
// A call to Rcpt must be preceded by a call to Mail and may be followed by
// a Data call or another Rcpt call.
func (c *Client) Rcpt(to string) os.Error {
	_, _, err := c.cmd(25, "RCPT TO:<%s>", to)
	return err
}

type dataCloser struct {
	c *Client
	io.WriteCloser
}

func (d *dataCloser) Close() os.Error {
	d.WriteCloser.Close()
	_, _, err := d.c.Text.ReadResponse(250)
	return err
}

// Data issues a DATA command to the server and returns a writer that
// can be used to write the data. The caller should close the writer
// before calling any more methods on c.
// A call to Data must be preceded by one or more calls to Rcpt.
func (c *Client) Data() (io.WriteCloser, os.Error) {
	_, _, err := c.cmd(354, "DATA")
	if err != nil {
		return nil, err
	}
	return &dataCloser{c, c.Text.DotWriter()}, nil
}

// SendMail connects to the server at addr, switches to TLS if possible,
// authenticates with mechanism a if possible, and then sends an email from
// address from, to addresses to, with message msg.
func SendMail(addr string, a Auth, from string, to []string, msg []byte) os.Error {
	c, err := Dial(addr)
	if err != nil {
		return err
	}
	if ok, _ := c.Extension("STARTTLS"); ok {
		if err = c.StartTLS(); err != nil {
			return err
		}
	}
	if a != nil && c.ext != nil {
		if _, ok := c.ext["AUTH"]; ok {
			if err = c.Auth(a); err != nil {
				return err
			}
		}
	}
	if err = c.Mail(from); err != nil {
		return err
	}
	for _, addr := range to {
		if err = c.Rcpt(addr); err != nil {
			return err
		}
	}
	w, err := c.Data()
	if err != nil {
		return err
	}
	_, err = w.Write(msg)
	if err != nil {
		return err
	}
	err = w.Close()
	if err != nil {
		return err
	}
	return c.Quit()
}

// Extension reports whether an extension is support by the server.
// The extension name is case-insensitive. If the extension is supported,
// Extension also returns a string that contains any parameters the
// server specifies for the extension.
func (c *Client) Extension(ext string) (bool, string) {
	if c.ext == nil {
		return false, ""
	}
	ext = strings.ToUpper(ext)
	param, ok := c.ext[ext]
	return ok, param
}

// Reset sends the RSET command to the server, aborting the current mail
// transaction.
func (c *Client) Reset() os.Error {
	_, _, err := c.cmd(250, "RSET")
	return err
}

// Quit sends the QUIT command and closes the connection to the server.
func (c *Client) Quit() os.Error {
	_, _, err := c.cmd(221, "QUIT")
	if err != nil {
		return err
	}
	return c.Text.Close()
}
<commit_msg>smtp: add *tls.Config argument to StartTLS<commit_after>// Copyright 2010 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// Package smtp implements the Simple Mail Transfer Protocol as defined in RFC 5321.
// It also implements the following extensions:
//	8BITMIME  RFC 1652
//	AUTH      RFC 2554
//	STARTTLS  RFC 3207
// Additional extensions may be handled by clients.
package smtp

import (
	"crypto/tls"
	"encoding/base64"
	"io"
	"os"
	"net"
	"net/textproto"
	"strings"
)

// A Client represents a client connection to an SMTP server.
type Client struct {
	// Text is the textproto.Conn used by the Client. It is exported to allow for
	// clients to add extensions.
	Text *textproto.Conn
	// keep a reference to the connection so it can be used to create a TLS
	// connection later
	conn net.Conn
	// whether the Client is using TLS
	tls        bool
	serverName string
	// map of supported extensions
	ext map[string]string
	// supported auth mechanisms
	auth []string
}

// Dial returns a new Client connected to an SMTP server at addr.
func Dial(addr string) (*Client, os.Error) {
	conn, err := net.Dial("tcp", "", addr)
	if err != nil {
		return nil, err
	}
	host := addr[:strings.Index(addr, ":")]
	return NewClient(conn, host)
}

// NewClient returns a new Client using an existing connection and host as a
// server name to be used when authenticating.
func NewClient(conn net.Conn, host string) (*Client, os.Error) {
	text := textproto.NewConn(conn)
	_, msg, err := text.ReadResponse(220)
	if err != nil {
		text.Close()
		return nil, err
	}
	c := &Client{Text: text, conn: conn, serverName: host}
	if strings.Contains(msg, "ESMTP") {
		err = c.ehlo()
	} else {
		err = c.helo()
	}
	return c, err
}

// cmd is a convenience function that sends a command and returns the response
func (c *Client) cmd(expectCode int, format string, args ...interface{}) (int, string, os.Error) {
	id, err := c.Text.Cmd(format, args...)
	if err != nil {
		return 0, "", err
	}
	c.Text.StartResponse(id)
	defer c.Text.EndResponse(id)
	code, msg, err := c.Text.ReadResponse(expectCode)
	return code, msg, err
}

// helo sends the HELO greeting to the server. It should be used only when the
// server does not support ehlo.
func (c *Client) helo() os.Error {
	c.ext = nil
	_, _, err := c.cmd(250, "HELO localhost")
	return err
}

// ehlo sends the EHLO (extended hello) greeting to the server. It
// should be the preferred greeting for servers that support it.
func (c *Client) ehlo() os.Error {
	_, msg, err := c.cmd(250, "EHLO localhost")
	if err != nil {
		return err
	}
	ext := make(map[string]string)
	extList := strings.Split(msg, "\n", -1)
	if len(extList) > 1 {
		extList = extList[1:]
		for _, line := range extList {
			args := strings.Split(line, " ", 2)
			if len(args) > 1 {
				ext[args[0]] = args[1]
			} else {
				ext[args[0]] = ""
			}
		}
	}
	if mechs, ok := ext["AUTH"]; ok {
		c.auth = strings.Split(mechs, " ", -1)
	}
	c.ext = ext
	return err
}

// StartTLS sends the STARTTLS command and encrypts all further communication.
// Only servers that advertise the STARTTLS extension support this function.
func (c *Client) StartTLS(config *tls.Config) os.Error {
	_, _, err := c.cmd(220, "STARTTLS")
	if err != nil {
		return err
	}
	c.conn = tls.Client(c.conn, config)
	c.Text = textproto.NewConn(c.conn)
	c.tls = true
	return c.ehlo()
}

// Verify checks the validity of an email address on the server.
// If Verify returns nil, the address is valid. A non-nil return
// does not necessarily indicate an invalid address. Many servers
// will not verify addresses for security reasons.
func (c *Client) Verify(addr string) os.Error {
	_, _, err := c.cmd(250, "VRFY %s", addr)
	return err
}

// Auth authenticates a client using the provided authentication mechanism.
// A failed authentication closes the connection.
// Only servers that advertise the AUTH extension support this function.
func (c *Client) Auth(a Auth) os.Error {
	encoding := base64.StdEncoding
	mech, resp, err := a.Start(&ServerInfo{c.serverName, c.tls, c.auth})
	if err != nil {
		c.Quit()
		return err
	}
	resp64 := make([]byte, encoding.EncodedLen(len(resp)))
	encoding.Encode(resp64, resp)
	code, msg64, err := c.cmd(0, "AUTH %s %s", mech, resp64)
	for err == nil {
		var msg []byte
		switch code {
		case 334:
			msg = make([]byte, encoding.DecodedLen(len(msg64)))
			_, err = encoding.Decode(msg, []byte(msg64))
		case 235:
			// the last message isn't base64 because it isn't a challenge
			msg = []byte(msg64)
		default:
			err = &textproto.Error{code, msg64}
		}
		resp, err = a.Next(msg, code == 334)
		if err != nil {
			// abort the AUTH
			c.cmd(501, "*")
			c.Quit()
			break
		}
		if resp == nil {
			break
		}
		resp64 = make([]byte, encoding.EncodedLen(len(resp)))
		encoding.Encode(resp64, resp)
		code, msg64, err = c.cmd(0, string(resp64))
	}
	return err
}

// Mail issues a MAIL command to the server using the provided email address.
// If the server supports the 8BITMIME extension, Mail adds the BODY=8BITMIME
// parameter.
// This initiates a mail transaction and is followed by one or more Rcpt calls.
func (c *Client) Mail(from string) os.Error {
	cmdStr := "MAIL FROM:<%s>"
	if c.ext != nil {
		if _, ok := c.ext["8BITMIME"]; ok {
			cmdStr += " BODY=8BITMIME"
		}
	}
	_, _, err := c.cmd(250, cmdStr, from)
	return err
}

// Rcpt issues a RCPT command to the server using the provided email address.
// A call to Rcpt must be preceded by a call to Mail and may be followed by
// a Data call or another Rcpt call.
func (c *Client) Rcpt(to string) os.Error {
	_, _, err := c.cmd(25, "RCPT TO:<%s>", to)
	return err
}

type dataCloser struct {
	c *Client
	io.WriteCloser
}

func (d *dataCloser) Close() os.Error {
	d.WriteCloser.Close()
	_, _, err := d.c.Text.ReadResponse(250)
	return err
}

// Data issues a DATA command to the server and returns a writer that
// can be used to write the data. The caller should close the writer
// before calling any more methods on c.
// A call to Data must be preceded by one or more calls to Rcpt.
func (c *Client) Data() (io.WriteCloser, os.Error) {
	_, _, err := c.cmd(354, "DATA")
	if err != nil {
		return nil, err
	}
	return &dataCloser{c, c.Text.DotWriter()}, nil
}

// SendMail connects to the server at addr, switches to TLS if possible,
// authenticates with mechanism a if possible, and then sends an email from
// address from, to addresses to, with message msg.
func SendMail(addr string, a Auth, from string, to []string, msg []byte) os.Error {
	c, err := Dial(addr)
	if err != nil {
		return err
	}
	if ok, _ := c.Extension("STARTTLS"); ok {
		if err = c.StartTLS(nil); err != nil {
			return err
		}
	}
	if a != nil && c.ext != nil {
		if _, ok := c.ext["AUTH"]; ok {
			if err = c.Auth(a); err != nil {
				return err
			}
		}
	}
	if err = c.Mail(from); err != nil {
		return err
	}
	for _, addr := range to {
		if err = c.Rcpt(addr); err != nil {
			return err
		}
	}
	w, err := c.Data()
	if err != nil {
		return err
	}
	_, err = w.Write(msg)
	if err != nil {
		return err
	}
	err = w.Close()
	if err != nil {
		return err
	}
	return c.Quit()
}

// Extension reports whether an extension is support by the server.
// The extension name is case-insensitive. If the extension is supported,
// Extension also returns a string that contains any parameters the
// server specifies for the extension.
func (c *Client) Extension(ext string) (bool, string) {
	if c.ext == nil {
		return false, ""
	}
	ext = strings.ToUpper(ext)
	param, ok := c.ext[ext]
	return ok, param
}

// Reset sends the RSET command to the server, aborting the current mail
// transaction.
func (c *Client) Reset() os.Error {
	_, _, err := c.cmd(250, "RSET")
	return err
}

// Quit sends the QUIT command and closes the connection to the server.
func (c *Client) Quit() os.Error {
	_, _, err := c.cmd(221, "QUIT")
	if err != nil {
		return err
	}
	return c.Text.Close()
}
<|endoftext|>