<commit_before>// A simple tool for log rotation.
/*
   Copyright (C) 2016, Library of the University of Tübingen

   This program is free software: you can redistribute it and/or modify
   it under the terms of the GNU Affero General Public License as
   published by the Free Software Foundation, either version 3 of the
   License, or (at your option) any later version.

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU Affero General Public License for more details.

   You should have received a copy of the GNU Affero General Public License
   along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/
package main

import "flag"
import "fmt"
import "os"
import "path"
import "path/filepath"
import "strconv"

// Handle command-line arguments.
func processFlags(maxRotationCount **int) {
	flag.Usage = func() {
		fmt.Fprintf(os.Stderr, "usage: %s [--max-rotation-count max_rotations] log_base_names\n", path.Base(os.Args[0]))
		flag.PrintDefaults()
		os.Exit(1)
	}
	*maxRotationCount = flag.Int("max-rotation-count", 5, "The maximum number of log file rotations.")
	flag.Parse()
	if **maxRotationCount < 1 {
		fmt.Fprintf(os.Stderr, "%s: max-rotation-count must be positive!\n", path.Base(os.Args[0]))
		os.Exit(1)
	}
}

// Either return the log file names provided on the command-line, or, if there are none,
// return a list of files matching "*.log".
func getLogNames() []string {
	logNames := flag.Args()
	if len(logNames) == 0 {
		logNames, _ = filepath.Glob("*.log")
	}
	return logNames
}

func Exists(path string) bool {
	_, err := os.Stat(path)
	return err == nil
}

func processName(logFileName string, maxRotationCount int) {
	if !Exists(logFileName) {
		return
	} else {
		os.Remove(logFileName + "." + strconv.Itoa(maxRotationCount))
	}

	for countSuffix := maxRotationCount; countSuffix > 1; countSuffix-- {
		os.Rename(logFileName+"."+strconv.Itoa(countSuffix-1), logFileName+"."+strconv.Itoa(countSuffix))
	}
	os.Rename(logFileName, logFileName+".1")
}

func main() {
	var maxRotationCount *int
	processFlags(&maxRotationCount)
	logNames := getLogNames()
	for _, name := range logNames {
		processName(name, *maxRotationCount)
	}
}
<commit_msg>Removed a pointer indirection level.<commit_after>// A simple tool for log rotation.
/*
   Copyright (C) 2016, Library of the University of Tübingen

   This program is free software: you can redistribute it and/or modify
   it under the terms of the GNU Affero General Public License as
   published by the Free Software Foundation, either version 3 of the
   License, or (at your option) any later version.

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU Affero General Public License for more details.

   You should have received a copy of the GNU Affero General Public License
   along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/
package main

import "flag"
import "fmt"
import "os"
import "path"
import "path/filepath"
import "strconv"

// Handle command-line arguments.
func processFlags(maxRotationCount *int) {
	flag.Usage = func() {
		fmt.Fprintf(os.Stderr, "usage: %s [--max-rotation-count max_rotations] log_base_names\n", path.Base(os.Args[0]))
		flag.PrintDefaults()
		os.Exit(1)
	}
	localMaxRotationCount := flag.Int("max-rotation-count", 5, "The maximum number of log file rotations.")
	flag.Parse()
	if *localMaxRotationCount < 1 {
		fmt.Fprintf(os.Stderr, "%s: max-rotation-count must be positive!\n", path.Base(os.Args[0]))
		os.Exit(1)
	}
	*maxRotationCount = *localMaxRotationCount
}

// Either return the log file names provided on the command-line, or, if there are none,
// return a list of files matching "*.log".
func getLogNames() []string {
	logNames := flag.Args()
	if len(logNames) == 0 {
		logNames, _ = filepath.Glob("*.log")
	}
	return logNames
}

func Exists(path string) bool {
	_, err := os.Stat(path)
	return err == nil
}

func processName(logFileName string, maxRotationCount int) {
	if !Exists(logFileName) {
		return
	} else {
		os.Remove(logFileName + "." + strconv.Itoa(maxRotationCount))
	}

	for countSuffix := maxRotationCount; countSuffix > 1; countSuffix-- {
		os.Rename(logFileName+"."+strconv.Itoa(countSuffix-1), logFileName+"."+strconv.Itoa(countSuffix))
	}
	os.Rename(logFileName, logFileName+".1")
}

func main() {
	var maxRotationCount int
	processFlags(&maxRotationCount)
	fmt.Printf("maxRotationCount = %d\n", maxRotationCount)
	logNames := getLogNames()
	for _, name := range logNames {
		processName(name, maxRotationCount)
	}
}
<|endoftext|>


<commit_before>package aws

import (
	"testing"

	"github.com/aws/aws-sdk-go/service/ec2"
	"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"
	"github.com/hashicorp/terraform-plugin-sdk/v2/terraform"
)

func TestAccAWSDefaultSubnet_basic(t *testing.T) {
	var v ec2.Subnet

	resource.ParallelTest(t, resource.TestCase{
		PreCheck:     func() { testAccPreCheck(t) },
		Providers:    testAccProviders,
		CheckDestroy: testAccCheckAWSDefaultSubnetDestroy,
		Steps: []resource.TestStep{
			{
				Config: testAccAWSDefaultSubnetConfigBasic,
				Check: resource.ComposeTestCheckFunc(
					testAccCheckSubnetExists("aws_default_subnet.foo", &v),
					resource.TestCheckResourceAttr(
						"aws_default_subnet.foo", "availability_zone", "us-west-2a"),
					resource.TestCheckResourceAttrSet(
						"aws_default_subnet.foo", "availability_zone_id"),
					resource.TestCheckResourceAttr(
						"aws_default_subnet.foo", "assign_ipv6_address_on_creation", "false"),
					resource.TestCheckResourceAttr(
						"aws_default_subnet.foo", "tags.%", "1"),
					resource.TestCheckResourceAttr(
						"aws_default_subnet.foo", "tags.Name", "terraform-testacc-default-subnet"),
					testAccCheckResourceAttrAccountID("aws_default_subnet.foo", "owner_id"),
				),
			},
		},
	})
}

func TestAccAWSDefaultSubnet_publicIp(t *testing.T) {
	var v ec2.Subnet

	resource.ParallelTest(t, resource.TestCase{
		PreCheck:     func() { testAccPreCheck(t) },
		Providers:    testAccProviders,
		CheckDestroy: testAccCheckAWSDefaultSubnetDestroy,
		Steps: []resource.TestStep{
			{
				Config: testAccAWSDefaultSubnetConfigPublicIp,
				Check: resource.ComposeTestCheckFunc(
					testAccCheckSubnetExists("aws_default_subnet.foo", &v),
					resource.TestCheckResourceAttr(
						"aws_default_subnet.foo", "availability_zone", "us-west-2b"),
					resource.TestCheckResourceAttr(
						"aws_default_subnet.foo", "map_public_ip_on_launch", "true"),
					resource.TestCheckResourceAttr(
						"aws_default_subnet.foo", "assign_ipv6_address_on_creation", "false"),
					resource.TestCheckResourceAttr(
						"aws_default_subnet.foo", "tags.%", "1"),
					resource.TestCheckResourceAttr(
						"aws_default_subnet.foo", "tags.Name", "terraform-testacc-default-subnet"),
				),
			},
			{
				Config: testAccAWSDefaultSubnetConfigNoPublicIp,
				Check: resource.ComposeTestCheckFunc(
					testAccCheckSubnetExists("aws_default_subnet.foo", &v),
					resource.TestCheckResourceAttr(
						"aws_default_subnet.foo", "availability_zone", "us-west-2b"),
					resource.TestCheckResourceAttr(
						"aws_default_subnet.foo", "map_public_ip_on_launch", "false"),
					resource.TestCheckResourceAttr(
						"aws_default_subnet.foo", "assign_ipv6_address_on_creation", "false"),
					resource.TestCheckResourceAttr(
						"aws_default_subnet.foo", "tags.%", "1"),
					resource.TestCheckResourceAttr(
						"aws_default_subnet.foo", "tags.Name", "terraform-testacc-default-subnet"),
				),
			},
		},
	})
}

func testAccCheckAWSDefaultSubnetDestroy(s *terraform.State) error {
	// We expect subnet to still exist
	return nil
}

const testAccAWSDefaultSubnetConfigBasic = `
resource "aws_default_subnet" "foo" {
  availability_zone = "us-west-2a"
  tags = {
    Name = "terraform-testacc-default-subnet"
  }
}
`

const testAccAWSDefaultSubnetConfigPublicIp = `
resource "aws_default_subnet" "foo" {
  availability_zone = "us-west-2b"
  map_public_ip_on_launch = true
  tags = {
    Name = "terraform-testacc-default-subnet"
  }
}
`

const testAccAWSDefaultSubnetConfigNoPublicIp = `
resource "aws_default_subnet" "foo" {
  availability_zone = "us-west-2b"
  map_public_ip_on_launch = false
  tags = {
    Name = "terraform-testacc-default-subnet"
  }
}
`
<commit_msg>tests/provider: Update hardcoded AZs (Default Subnet)<commit_after>package aws

import (
	"fmt"
	"testing"

	"github.com/aws/aws-sdk-go/service/ec2"
	"github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest"
	"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"
	"github.com/hashicorp/terraform-plugin-sdk/v2/terraform"
)

func TestAccAWSDefaultSubnet_basic(t *testing.T) {
	var v ec2.Subnet

	resourceName := "aws_default_subnet.foo"
	availabilityZonesDataSourceName := "data.aws_availability_zones.available"
	rInt := acctest.RandInt()

	resource.ParallelTest(t, resource.TestCase{
		PreCheck:     func() { testAccPreCheck(t) },
		Providers:    testAccProviders,
		CheckDestroy: testAccCheckAWSDefaultSubnetDestroy,
		Steps: []resource.TestStep{
			{
				Config: testAccAWSDefaultSubnetConfigBasic(rInt),
				Check: resource.ComposeTestCheckFunc(
					testAccCheckSubnetExists(resourceName, &v),
					resource.TestCheckResourceAttrPair(
						resourceName, "availability_zone", availabilityZonesDataSourceName, "names.0"),
					resource.TestCheckResourceAttrSet(
						resourceName, "availability_zone_id"),
					resource.TestCheckResourceAttr(
						resourceName, "assign_ipv6_address_on_creation", "false"),
					resource.TestCheckResourceAttr(
						resourceName, "tags.%", "1"),
					resource.TestCheckResourceAttr(
						resourceName, "tags.Name", fmt.Sprintf("terraform-testacc-default-subnet-%d", rInt)),
					testAccCheckResourceAttrAccountID(resourceName, "owner_id"),
				),
			},
		},
	})
}

func TestAccAWSDefaultSubnet_publicIp(t *testing.T) {
	var v ec2.Subnet

	resourceName := "aws_default_subnet.foo"
	availabilityZonesDataSourceName := "data.aws_availability_zones.available"
	rInt := acctest.RandInt()

	resource.ParallelTest(t, resource.TestCase{
		PreCheck:     func() { testAccPreCheck(t) },
		Providers:    testAccProviders,
		CheckDestroy: testAccCheckAWSDefaultSubnetDestroy,
		Steps: []resource.TestStep{
			{
				Config: testAccAWSDefaultSubnetConfigPublicIp(rInt),
				Check: resource.ComposeTestCheckFunc(
					testAccCheckSubnetExists(resourceName, &v),
					resource.TestCheckResourceAttrPair(
						resourceName, "availability_zone", availabilityZonesDataSourceName, "names.1"),
					resource.TestCheckResourceAttr(
						resourceName, "map_public_ip_on_launch", "true"),
					resource.TestCheckResourceAttr(
						resourceName, "assign_ipv6_address_on_creation", "false"),
					resource.TestCheckResourceAttr(
						resourceName, "tags.%", "1"),
					resource.TestCheckResourceAttr(
						resourceName, "tags.Name", fmt.Sprintf("terraform-testacc-default-subnet-%d", rInt)),
				),
			},
			{
				Config: testAccAWSDefaultSubnetConfigNoPublicIp(rInt),
				Check: resource.ComposeTestCheckFunc(
					testAccCheckSubnetExists(resourceName, &v),
					resource.TestCheckResourceAttrPair(
						resourceName, "availability_zone", availabilityZonesDataSourceName, "names.1"),
					resource.TestCheckResourceAttr(
						resourceName, "map_public_ip_on_launch", "false"),
					resource.TestCheckResourceAttr(
						resourceName, "assign_ipv6_address_on_creation", "false"),
					resource.TestCheckResourceAttr(
						resourceName, "tags.%", "1"),
					resource.TestCheckResourceAttr(
						resourceName, "tags.Name", fmt.Sprintf("terraform-testacc-default-subnet-%d", rInt)),
				),
			},
		},
	})
}

func testAccCheckAWSDefaultSubnetDestroy(s *terraform.State) error {
	// We expect subnet to still exist
	return nil
}

func testAccAWSDefaultSubnetConfigBasic(rInt int) string {
	return composeConfig(testAccAvailableAZsNoOptInConfig(), fmt.Sprintf(`
resource "aws_default_subnet" "foo" {
  availability_zone = data.aws_availability_zones.available.names[0]

  tags = {
    Name = "terraform-testacc-default-subnet-%d"
  }
}
`, rInt))
}

func testAccAWSDefaultSubnetConfigPublicIp(rInt int) string {
	return composeConfig(testAccAvailableAZsNoOptInConfig(), fmt.Sprintf(`
resource "aws_default_subnet" "foo" {
  availability_zone       = data.aws_availability_zones.available.names[1]
  map_public_ip_on_launch = true

  tags = {
    Name = "terraform-testacc-default-subnet-%d"
  }
}
`, rInt))
}

func testAccAWSDefaultSubnetConfigNoPublicIp(rInt int) string {
	return composeConfig(testAccAvailableAZsNoOptInConfig(), fmt.Sprintf(`
resource "aws_default_subnet" "foo" {
  availability_zone       = data.aws_availability_zones.available.names[1]
  map_public_ip_on_launch = false

  tags = {
    Name = "terraform-testacc-default-subnet-%d"
  }
}
`, rInt))
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"github.com/gophergala2016/goad/sqsadaptor"
	"io/ioutil"
	"net"
	"net/http"
	"net/url"
	"os"
	"strconv"
	"strings"
	"sync"
	"time"
)

func main() {
	address := os.Args[1]
	concurrencycount, err := strconv.Atoi(os.Args[2])
	if err != nil {
		fmt.Printf("ERROR %s\n", err)
		return
	}
	maxRequestCount, err := strconv.Atoi(os.Args[3])
	sqsurl := os.Args[4]
	awsregion := os.Args[5]

	if err != nil {
		fmt.Printf("ERROR %s\n", err)
		return
	}
	client := &http.Client{}
	clientTimeout, _ := time.ParseDuration("1s")
	client.Timeout = clientTimeout
	fmt.Printf("Will spawn %d workers making %d requests to %s\n", concurrencycount, maxRequestCount, address)
	runLoadTest(client, sqsurl, address, maxRequestCount, concurrencycount, awsregion)
}

type Job struct{}

type RequestResult struct {
	Time             int64  `json:"time"`
	Host             string `json:"host"`
	Type             string `json:"type"`
	Status           int    `json:"status"`
	ElapsedFirstByte int64  `json:"elapsed-first-byte"`
	ElapsedLastByte  int64  `json:"elapsed-last-byte"`
	Elapsed          int64  `json:"elapsed"`
	Bytes            int    `json:"bytes"`
	Timeout          bool   `json:"timeout"`
	State            string `json:"state"`
}

func runLoadTest(client *http.Client, sqsurl string, url string, totalRequests int, concurrencycount int, awsregion string) {
	sqsAdaptor := sqsadaptor.NewSQSAdaptor(sqsurl)
	jobs := make(chan Job, totalRequests)
	ch := make(chan RequestResult, totalRequests)
	var wg sync.WaitGroup
	loadTestStartTime := time.Now()
	var requestsSoFar int
	for i := 0; i < totalRequests; i++ {
		jobs <- Job{}
	}
	close(jobs)
	for i := 0; i < concurrencycount; i++ {
		wg.Add(1)
		go fetch(loadTestStartTime, client, url, totalRequests, jobs, ch, &wg, awsregion)
	}
	fmt.Println("Waiting for results…")

	for requestsSoFar < totalRequests {
		var agg [100]RequestResult
		aggRequestCount := len(agg)
		i := 0

		var timeToFirstTotal int64
		var requestTimeTotal int64
		totBytesRead := 0
		statuses := make(map[string]int)
		var firstRequestTime int64
		var lastRequestTime int64
		var slowest int64
		var fastest int64
		var totalTimedOut int
		for ; i < aggRequestCount && requestsSoFar < totalRequests; i++ {
			r := <-ch
			agg[i] = r
			requestsSoFar++
			if requestsSoFar%10 == 0 {
				fmt.Printf("\r%.2f%% done (%d requests out of %d)", (float64(requestsSoFar)/float64(totalRequests))*100.0, requestsSoFar, totalRequests)
			}
			if r.Timeout {
				totalTimedOut++
				continue
			}

			if firstRequestTime == 0 {
				firstRequestTime = r.Time
			}
			if r.ElapsedLastByte > slowest {
				slowest = r.ElapsedLastByte
			}
			if fastest == 0 {
				fastest = r.ElapsedLastByte
			} else {
				if r.ElapsedLastByte < fastest {
					fastest = r.ElapsedLastByte
				}
			}

			lastRequestTime = r.Time
			timeToFirstTotal += r.ElapsedFirstByte
			totBytesRead += r.Bytes
			statusStr := strconv.Itoa(r.Status)
			_, ok := statuses[statusStr]
			if !ok {
				statuses[statusStr] = 1
			} else {
				statuses[statusStr]++
			}
			requestTimeTotal += r.Elapsed
		}
		if i == 0 {
			continue
		}
		durationNanoSeconds := lastRequestTime - firstRequestTime
		durationSeconds := float32(durationNanoSeconds) / float32(1000000000)
		aggData := sqsadaptor.AggData{
			i,
			totalTimedOut,
			timeToFirstTotal / int64(i),
			totBytesRead,
			statuses,
			requestTimeTotal / int64(i),
			float32(i) / durationSeconds,
			slowest,
			fastest,
			awsregion,
		}
		sqsAdaptor.SendResult(aggData)
	}
	fmt.Printf("\nWaiting for workers…")
	wg.Wait()
	fmt.Printf("\nYay🎈  - %d requests completed\n", requestsSoFar)

}

func fetch(loadTestStartTime time.Time, client *http.Client, address string, requestcount int, jobs <-chan Job, ch chan RequestResult, wg *sync.WaitGroup, awsregion string) {
	defer wg.Done()
	fmt.Printf("Fetching %s\n", address)
	for _ = range jobs {
		start := time.Now()
		req, err := http.NewRequest("GET", address, nil)
		req.Header.Add("User-Agent", "GOAD/0.1")
		response, err := client.Do(req)
		var status string
		var elapsedFirstByte time.Duration
		var elapsedLastByte time.Duration
		var elapsed time.Duration
		var statusCode int
		var bytesRead int
		buf := []byte(" ")
		timedOut := false
		if err != nil {
			status = fmt.Sprintf("ERROR: %s\n", err)
			//fmt.Println(status)
			switch err := err.(type) {
			case *url.Error:
				if err, ok := err.Err.(net.Error); ok && err.Timeout() {
					timedOut = true
				}
			case net.Error:
				if err.Timeout() {
					timedOut = true
				}
			}

			if err != nil && strings.Contains(err.Error(), "use of closed network connection") {
				fmt.Println("Could be from a Transport.CancelRequest")
			}
		} else {
			statusCode = response.StatusCode
			_, err = response.Body.Read(buf)
			if err != nil {
				status = fmt.Sprintf("reading first byte failed: %s\n", err)
			}
			elapsedFirstByte = time.Since(start)
			body, err := ioutil.ReadAll(response.Body)
			bytesRead = len(body) + 1
			elapsedLastByte = time.Since(start)
			if err != nil {
				status = fmt.Sprintf("reading response body failed: %s\n", err)
			} else {
				status = "Success"
			}
			elapsed = time.Since(start)
		}
		result := RequestResult{
			start.Sub(loadTestStartTime).Nanoseconds(),
			req.URL.Host,
			req.Method,
			statusCode,
			elapsed.Nanoseconds(),
			elapsedFirstByte.Nanoseconds(),
			elapsedLastByte.Nanoseconds(),
			bytesRead,
			timedOut,
			status,
		}
		ch <- result
	}
}
<commit_msg>Fix lambda for awsConfig<commit_after>package main

import (
	"fmt"
	"io/ioutil"
	"net"
	"net/http"
	"net/url"
	"os"
	"strconv"
	"strings"
	"sync"
	"time"

	"github.com/aws/aws-sdk-go/aws"
	"github.com/gophergala2016/goad/sqsadaptor"
)

func main() {
	address := os.Args[1]
	concurrencycount, err := strconv.Atoi(os.Args[2])
	if err != nil {
		fmt.Printf("ERROR %s\n", err)
		return
	}
	maxRequestCount, err := strconv.Atoi(os.Args[3])
	sqsurl := os.Args[4]
	awsregion := os.Args[5]

	if err != nil {
		fmt.Printf("ERROR %s\n", err)
		return
	}
	client := &http.Client{}
	clientTimeout, _ := time.ParseDuration("1s")
	client.Timeout = clientTimeout
	fmt.Printf("Will spawn %d workers making %d requests to %s\n", concurrencycount, maxRequestCount, address)
	runLoadTest(client, sqsurl, address, maxRequestCount, concurrencycount, awsregion)
}

type Job struct{}

type RequestResult struct {
	Time             int64  `json:"time"`
	Host             string `json:"host"`
	Type             string `json:"type"`
	Status           int    `json:"status"`
	ElapsedFirstByte int64  `json:"elapsed-first-byte"`
	ElapsedLastByte  int64  `json:"elapsed-last-byte"`
	Elapsed          int64  `json:"elapsed"`
	Bytes            int    `json:"bytes"`
	Timeout          bool   `json:"timeout"`
	State            string `json:"state"`
}

func runLoadTest(client *http.Client, sqsurl string, url string, totalRequests int, concurrencycount int, awsregion string) {
	awsConfig := aws.NewConfig().WithRegion(awsregion)
	sqsAdaptor := sqsadaptor.NewSQSAdaptor(awsConfig, sqsurl)
	jobs := make(chan Job, totalRequests)
	ch := make(chan RequestResult, totalRequests)
	var wg sync.WaitGroup
	loadTestStartTime := time.Now()
	var requestsSoFar int
	for i := 0; i < totalRequests; i++ {
		jobs <- Job{}
	}
	close(jobs)
	for i := 0; i < concurrencycount; i++ {
		wg.Add(1)
		go fetch(loadTestStartTime, client, url, totalRequests, jobs, ch, &wg, awsregion)
	}
	fmt.Println("Waiting for results…")

	for requestsSoFar < totalRequests {
		var agg [100]RequestResult
		aggRequestCount := len(agg)
		i := 0

		var timeToFirstTotal int64
		var requestTimeTotal int64
		totBytesRead := 0
		statuses := make(map[string]int)
		var firstRequestTime int64
		var lastRequestTime int64
		var slowest int64
		var fastest int64
		var totalTimedOut int
		for ; i < aggRequestCount && requestsSoFar < totalRequests; i++ {
			r := <-ch
			agg[i] = r
			requestsSoFar++
			if requestsSoFar%10 == 0 {
				fmt.Printf("\r%.2f%% done (%d requests out of %d)", (float64(requestsSoFar)/float64(totalRequests))*100.0, requestsSoFar, totalRequests)
			}
			if r.Timeout {
				totalTimedOut++
				continue
			}

			if firstRequestTime == 0 {
				firstRequestTime = r.Time
			}
			if r.ElapsedLastByte > slowest {
				slowest = r.ElapsedLastByte
			}
			if fastest == 0 {
				fastest = r.ElapsedLastByte
			} else {
				if r.ElapsedLastByte < fastest {
					fastest = r.ElapsedLastByte
				}
			}

			lastRequestTime = r.Time
			timeToFirstTotal += r.ElapsedFirstByte
			totBytesRead += r.Bytes
			statusStr := strconv.Itoa(r.Status)
			_, ok := statuses[statusStr]
			if !ok {
				statuses[statusStr] = 1
			} else {
				statuses[statusStr]++
			}
			requestTimeTotal += r.Elapsed
		}
		if i == 0 {
			continue
		}
		durationNanoSeconds := lastRequestTime - firstRequestTime
		durationSeconds := float32(durationNanoSeconds) / float32(1000000000)
		aggData := sqsadaptor.AggData{
			i,
			totalTimedOut,
			timeToFirstTotal / int64(i),
			totBytesRead,
			statuses,
			requestTimeTotal / int64(i),
			float32(i) / durationSeconds,
			slowest,
			fastest,
			awsregion,
		}
		sqsAdaptor.SendResult(aggData)
	}
	fmt.Printf("\nWaiting for workers…")
	wg.Wait()
	fmt.Printf("\nYay🎈  - %d requests completed\n", requestsSoFar)

}

func fetch(loadTestStartTime time.Time, client *http.Client, address string, requestcount int, jobs <-chan Job, ch chan RequestResult, wg *sync.WaitGroup, awsregion string) {
	defer wg.Done()
	fmt.Printf("Fetching %s\n", address)
	for _ = range jobs {
		start := time.Now()
		req, err := http.NewRequest("GET", address, nil)
		req.Header.Add("User-Agent", "GOAD/0.1")
		response, err := client.Do(req)
		var status string
		var elapsedFirstByte time.Duration
		var elapsedLastByte time.Duration
		var elapsed time.Duration
		var statusCode int
		var bytesRead int
		buf := []byte(" ")
		timedOut := false
		if err != nil {
			status = fmt.Sprintf("ERROR: %s\n", err)
			//fmt.Println(status)
			switch err := err.(type) {
			case *url.Error:
				if err, ok := err.Err.(net.Error); ok && err.Timeout() {
					timedOut = true
				}
			case net.Error:
				if err.Timeout() {
					timedOut = true
				}
			}

			if err != nil && strings.Contains(err.Error(), "use of closed network connection") {
				fmt.Println("Could be from a Transport.CancelRequest")
			}
		} else {
			statusCode = response.StatusCode
			_, err = response.Body.Read(buf)
			if err != nil {
				status = fmt.Sprintf("reading first byte failed: %s\n", err)
			}
			elapsedFirstByte = time.Since(start)
			body, err := ioutil.ReadAll(response.Body)
			bytesRead = len(body) + 1
			elapsedLastByte = time.Since(start)
			if err != nil {
				status = fmt.Sprintf("reading response body failed: %s\n", err)
			} else {
				status = "Success"
			}
			elapsed = time.Since(start)
		}
		result := RequestResult{
			start.Sub(loadTestStartTime).Nanoseconds(),
			req.URL.Host,
			req.Method,
			statusCode,
			elapsed.Nanoseconds(),
			elapsedFirstByte.Nanoseconds(),
			elapsedLastByte.Nanoseconds(),
			bytesRead,
			timedOut,
			status,
		}
		ch <- result
	}
}
<|endoftext|>


<commit_before>/*
Copyright 2018 Google LLC

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 main

import (
	"bytes"
	"fmt"
	"os/exec"
	"strings"
	"time"

	"github.com/grafeas/kritis/pkg/kritis/install"
	kubernetesutil "github.com/grafeas/kritis/pkg/kritis/kubernetes"
	"github.com/sirupsen/logrus"
)

func waitForPreinstallPod() {
	client, err := kubernetesutil.GetClientset()
	if err != nil {
		logrus.Fatalf("error getting kubernetes client: %v", err)
	}
	if err := kubernetesutil.WaitForPodComplete(client.CoreV1().Pods(namespace), "kritis-preinstall"); err != nil {
		logrus.Fatalf("preinstall pod didn't complete: %v", err)
	}
}

func waitForTLSSecret() {
	foundSecret := false
	var secretErr error
	for i := 0; i < 20; i++ {
		tlsSecretCmd := exec.Command("kubectl", "get", "secret", tlsSecretName, "--namespace", namespace)
		_, err := tlsSecretCmd.CombinedOutput()
		if err == nil {
			foundSecret = true
			break
		}
		secretErr = err
		time.Sleep(500 * time.Millisecond)
	}
	if !foundSecret {
		logrus.Fatalf("couldn't find csr : %v", secretErr)
	}
}

func getCaBundle() {
	certCmd := exec.Command("kubectl", "get", "secret", tlsSecretName, "-o", "jsonpath='{.data.tls\\.crt}'", "--namespace", namespace)
	output := install.RunCommand(certCmd)
	certificate = string(output)
	certificate = strings.TrimPrefix(certificate, "'")
	certificate = strings.TrimSuffix(certificate, "'")
	logrus.Infof("got cert from secret %s: %s", tlsSecretName, certificate)
}

func createValidationWebhook() {
	webhookSpec := `apiVersion: admissionregistration.k8s.io/v1beta1
kind: ValidatingWebhookConfiguration
metadata:
  name: %s
  labels:
    %s: ""
webhooks:
  - name: kritis-validation-hook.grafeas.io
    rules:
      - apiGroups:
          - ""
        apiVersions:
          - v1
        operations:
          - CREATE
          - UPDATE
        resources:
          - pods
    failurePolicy: Fail
    clientConfig:
      caBundle: %s
      service:
        name: %s
        namespace: %s`

	webhookSpec = fmt.Sprintf(webhookSpec, webhookName, kritisInstallLabel, certificate, serviceName, namespace)
	fmt.Println(webhookSpec)
	webhookCmd := exec.Command("kubectl", "apply", "-f", "-")
	webhookCmd.Stdin = bytes.NewReader([]byte(webhookSpec))
	install.RunCommand(webhookCmd)
}

func createValidationDeploymentWebhook() {
	webhookSpec := `apiVersion: admissionregistration.k8s.io/v1beta1
kind: ValidatingWebhookConfiguration
metadata:
  name: %s
  labels:
    %s: ""
webhooks:
  - name: kritis-validation-hook-deployments.grafeas.io
    rules:
      - apiGroups:
        - "*" # TODO(aaron-prindle) minimize this capture group
        apiVersions:
        - "*" # TODO(aaron-prindle) minimize this capture group
        operations:
          - CREATE
          # - UPDATE # TODO(aaron-prindle) add back update when allowlist and helm do not collide
        resources:
          - deployments
          - replicasets
    failurePolicy: Fail
    clientConfig:
      caBundle: %s
      service:
        name: %s
        namespace: %s`
	webhookSpec = fmt.Sprintf(webhookSpec, deploymentWebhookName, kritisInstallLabel, certificate, serviceName, namespace)
	fmt.Println(webhookSpec)
	webhookCmd := exec.Command("kubectl", "apply", "-f", "-")
	webhookCmd.Stdin = bytes.NewReader([]byte(webhookSpec))
	install.RunCommand(webhookCmd)
}
<commit_msg>Use namespaceSelector in kritis webhook to ignore important namespaces such as kube-system<commit_after>/*
Copyright 2018 Google LLC

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 main

import (
	"bytes"
	"fmt"
	"os/exec"
	"strings"
	"time"

	"github.com/grafeas/kritis/pkg/kritis/install"
	kubernetesutil "github.com/grafeas/kritis/pkg/kritis/kubernetes"
	"github.com/sirupsen/logrus"
)

func waitForPreinstallPod() {
	client, err := kubernetesutil.GetClientset()
	if err != nil {
		logrus.Fatalf("error getting kubernetes client: %v", err)
	}
	if err := kubernetesutil.WaitForPodComplete(client.CoreV1().Pods(namespace), "kritis-preinstall"); err != nil {
		logrus.Fatalf("preinstall pod didn't complete: %v", err)
	}
}

func waitForTLSSecret() {
	foundSecret := false
	var secretErr error
	for i := 0; i < 20; i++ {
		tlsSecretCmd := exec.Command("kubectl", "get", "secret", tlsSecretName, "--namespace", namespace)
		_, err := tlsSecretCmd.CombinedOutput()
		if err == nil {
			foundSecret = true
			break
		}
		secretErr = err
		time.Sleep(500 * time.Millisecond)
	}
	if !foundSecret {
		logrus.Fatalf("couldn't find csr : %v", secretErr)
	}
}

func getCaBundle() {
	certCmd := exec.Command("kubectl", "get", "secret", tlsSecretName, "-o", "jsonpath='{.data.tls\\.crt}'", "--namespace", namespace)
	output := install.RunCommand(certCmd)
	certificate = string(output)
	certificate = strings.TrimPrefix(certificate, "'")
	certificate = strings.TrimSuffix(certificate, "'")
	logrus.Infof("got cert from secret %s: %s", tlsSecretName, certificate)
}

func createValidationWebhook() {
	webhookSpec := `apiVersion: admissionregistration.k8s.io/v1beta1
kind: ValidatingWebhookConfiguration
metadata:
  name: %s
  labels:
    %s: ""
webhooks:
  - name: kritis-validation-hook.grafeas.io
    rules:
      - apiGroups:
          - ""
        apiVersions:
          - v1
        operations:
          - CREATE
          - UPDATE
        resources:
          - pods
    failurePolicy: Fail
    namespaceSelector:
      matchExpressions:
      - {key: kritis-validation, operator: NotIn, values: [disabled]}
    clientConfig:
      caBundle: %s
      service:
        name: %s
        namespace: %s`

	webhookSpec = fmt.Sprintf(webhookSpec, webhookName, kritisInstallLabel, certificate, serviceName, namespace)
	fmt.Println(webhookSpec)
	webhookCmd := exec.Command("kubectl", "apply", "-f", "-")
	webhookCmd.Stdin = bytes.NewReader([]byte(webhookSpec))
	install.RunCommand(webhookCmd)
}

func createValidationDeploymentWebhook() {
	webhookSpec := `apiVersion: admissionregistration.k8s.io/v1beta1
kind: ValidatingWebhookConfiguration
metadata:
  name: %s
  labels:
    %s: ""
webhooks:
  - name: kritis-validation-hook-deployments.grafeas.io
    rules:
      - apiGroups:
        - "*" # TODO(aaron-prindle) minimize this capture group
        apiVersions:
        - "*" # TODO(aaron-prindle) minimize this capture group
        operations:
          - CREATE
          # - UPDATE # TODO(aaron-prindle) add back update when allowlist and helm do not collide
        resources:
          - deployments
          - replicasets
    failurePolicy: Fail
    namespaceSelector:
      matchExpressions:
      - {key: kritis-validation, operator: NotIn, values: [disabled]}
    clientConfig:
      caBundle: %s
      service:
        name: %s
        namespace: %s`
	webhookSpec = fmt.Sprintf(webhookSpec, deploymentWebhookName, kritisInstallLabel, certificate, serviceName, namespace)
	fmt.Println(webhookSpec)
	webhookCmd := exec.Command("kubectl", "apply", "-f", "-")
	webhookCmd.Stdin = bytes.NewReader([]byte(webhookSpec))
	install.RunCommand(webhookCmd)
}
<|endoftext|>


<commit_before>package main

import (
	"os"
	"unicode/utf8"

	log "github.com/Sirupsen/logrus"
	"github.com/caarlos0/env"
	"github.com/fgrehm/go-dockerpty"
	"github.com/fsouza/go-dockerclient"
)

type environment struct {
	Image              string `env:"DUPLICITY_DOCKER_IMAGE" envDefault:"camptocamp/duplicity:latest"`
	DuplicityTargetURL string `env:"DUPLICITY_TARGET_URL"`
	AWSAccessKeyID     string `env:"AWS_ACCESS_KEY_ID"`
	AWSSecretAccessKey string `env:"AWS_SECRET_ACCESS_KEY"`
	SwiftUsername      string `env:"SWIFT_USERNAME"`
	SwiftPassword      string `env:"SWIFT_PASSWORD"`
	SwiftAuthURL       string `env:"SWIFT_AUTHURL"`
	SwiftTenantName    string `env:"SWIFT_TENANTNAME"`
	SwiftRegionName    string `env:"SWIFT_REGIONNAME"`
}

type conplicity struct {
	*docker.Client
	*environment
	Hostname string
}

func main() {
	log.Infof("Starting backup...")

	var err error

	c := &conplicity{}

	c.getEnv()

	c.Hostname, err = os.Hostname()
	checkErr(err, "Failed to get hostname: %v", 1)

	endpoint := "unix:///var/run/docker.sock"

	c.Client, err = docker.NewClient(endpoint)
	checkErr(err, "Failed to create Docker client: %v", 1)

	vols, err := c.ListVolumes(docker.ListVolumesOptions{})
	checkErr(err, "Failed to list Docker volumes: %v", 1)

	err = c.pullImage()
	checkErr(err, "Failed to pull image: %v", 1)

	for _, vol := range vols {
		err = c.backupVolume(vol)
		checkErr(err, "Failed to process volume "+vol.Name+": %v", -1)
	}

	log.Infof("End backup...")
}

func (c *conplicity) getEnv() (err error) {
	c.environment = &environment{}
	env.Parse(c.environment)

	return
}

func (c *conplicity) backupVolume(vol docker.Volume) (err error) {
	if utf8.RuneCountInString(vol.Name) == 64 {
		log.Infof("Ignoring volume " + vol.Name)
		return
	}

	// TODO: detect if it's a Database volume (PostgreSQL, MySQL, OpenLDAP...) and launch DUPLICITY_PRECOMMAND instead of backuping the volume
	log.Infof("ID: " + vol.Name)
	log.Infof("Driver: " + vol.Driver)
	log.Infof("Mountpoint: " + vol.Mountpoint)
	log.Infof("Creating duplicity container...")
	container, err := c.CreateContainer(
		docker.CreateContainerOptions{
			Config: &docker.Config{
				Cmd: []string{
					"--full-if-older-than", "15D",
					"--s3-use-new-style",
					"--no-encryption",
					"--allow-source-mismatch",
					"/var/backups",
					c.DuplicityTargetURL + "/" + c.Hostname + "/" + vol.Name,
				},
				Env: []string{
					"AWS_ACCESS_KEY_ID=" + c.AWSAccessKeyID,
					"AWS_SECRET_ACCESS_KEY=" + c.AWSSecretAccessKey,
					"SWIFT_USERNAME=" + c.SwiftUsername,
					"SWIFT_PASSWORD=" + c.SwiftPassword,
					"SWIFT_AUTHURL=" + c.SwiftAuthURL,
					"SWIFT_TENANTNAME=" + c.SwiftTenantName,
					"SWIFT_REGIONNAME=" + c.SwiftRegionName,
					"SWIFT_AUTHVERSION=2",
				},
				Image:        c.Image,
				OpenStdin:    true,
				StdinOnce:    true,
				AttachStdin:  true,
				AttachStdout: true,
				AttachStderr: true,
				Tty:          true,
			},
		},
	)

	checkErr(err, "Failed to create container for volume "+vol.Name+": %v", 1)

	defer func() {
		c.RemoveContainer(docker.RemoveContainerOptions{
			ID:    container.ID,
			Force: true,
		})
	}()

	binds := []string{
		vol.Mountpoint + ":/var/backups:ro",
	}

	err = dockerpty.Start(c.Client, container, &docker.HostConfig{
		Binds: binds,
	})
	checkErr(err, "Failed to start container for volume "+vol.Name+": %v", -1)
	return
}

func (c *conplicity) pullImage() (err error) {
	if _, err = c.InspectImage(c.Image); err != nil {
		// TODO: output pull to logs
		log.Infof("Pulling image %v", c.Image)
		err = c.PullImage(docker.PullImageOptions{
			Repository: c.Image,
		}, docker.AuthConfiguration{})
	}

	return err
}

func checkErr(err error, msg string, exit int) {
	if err != nil {
		log.Errorf(msg, err)

		if exit != -1 {
			os.Exit(exit)
		}
	}
}
<commit_msg>Ignore volumes marked as io.conplicity.<vol>.ignore=true<commit_after>package main

import (
	"os"
	"unicode/utf8"

	log "github.com/Sirupsen/logrus"
	"github.com/caarlos0/env"
	"github.com/fgrehm/go-dockerpty"
	"github.com/fsouza/go-dockerclient"
)

const labelPrefix string = "io.conplicity"

type environment struct {
	Image              string `env:"DUPLICITY_DOCKER_IMAGE" envDefault:"camptocamp/duplicity:latest"`
	DuplicityTargetURL string `env:"DUPLICITY_TARGET_URL"`
	AWSAccessKeyID     string `env:"AWS_ACCESS_KEY_ID"`
	AWSSecretAccessKey string `env:"AWS_SECRET_ACCESS_KEY"`
	SwiftUsername      string `env:"SWIFT_USERNAME"`
	SwiftPassword      string `env:"SWIFT_PASSWORD"`
	SwiftAuthURL       string `env:"SWIFT_AUTHURL"`
	SwiftTenantName    string `env:"SWIFT_TENANTNAME"`
	SwiftRegionName    string `env:"SWIFT_REGIONNAME"`
}

type conplicity struct {
	*docker.Client
	*environment
	Hostname string
}

func main() {
	log.Infof("Starting backup...")

	var err error

	c := &conplicity{}

	c.getEnv()

	c.Hostname, err = os.Hostname()
	checkErr(err, "Failed to get hostname: %v", 1)

	endpoint := "unix:///var/run/docker.sock"

	c.Client, err = docker.NewClient(endpoint)
	checkErr(err, "Failed to create Docker client: %v", 1)

	vols, err := c.ListVolumes(docker.ListVolumesOptions{})
	checkErr(err, "Failed to list Docker volumes: %v", 1)

	err = c.pullImage()
	checkErr(err, "Failed to pull image: %v", 1)

	for _, vol := range vols {
		voll, _ := c.InspectVolume(vol.Name)
		checkErr(err, "Failed to inspect volume "+vol.Name+": %v", -1)
		err = c.backupVolume(*voll)
		checkErr(err, "Failed to process volume "+vol.Name+": %v", -1)
	}

	log.Infof("End backup...")
}

func (c *conplicity) getEnv() (err error) {
	c.environment = &environment{}
	env.Parse(c.environment)

	return
}

func (c *conplicity) backupVolume(vol docker.Volume) (err error) {
	if utf8.RuneCountInString(vol.Name) == 64 {
		log.Infof("Ignoring unnamed volume " + vol.Name)
		return
	}

	if vol.Labels[labelPrefix+".ignore"] == "true" {
		log.Infof("Ignoring blacklisted volume " + vol.Name)
		return
	}

	// TODO: detect if it's a Database volume (PostgreSQL, MySQL, OpenLDAP...) and launch DUPLICITY_PRECOMMAND instead of backuping the volume
	log.Infof("ID: " + vol.Name)
	log.Infof("Driver: " + vol.Driver)
	log.Infof("Mountpoint: " + vol.Mountpoint)
	log.Infof("Creating duplicity container...")
	container, err := c.CreateContainer(
		docker.CreateContainerOptions{
			Config: &docker.Config{
				Cmd: []string{
					"--full-if-older-than", "15D",
					"--s3-use-new-style",
					"--no-encryption",
					"--allow-source-mismatch",
					"/var/backups",
					c.DuplicityTargetURL + "/" + c.Hostname + "/" + vol.Name,
				},
				Env: []string{
					"AWS_ACCESS_KEY_ID=" + c.AWSAccessKeyID,
					"AWS_SECRET_ACCESS_KEY=" + c.AWSSecretAccessKey,
					"SWIFT_USERNAME=" + c.SwiftUsername,
					"SWIFT_PASSWORD=" + c.SwiftPassword,
					"SWIFT_AUTHURL=" + c.SwiftAuthURL,
					"SWIFT_TENANTNAME=" + c.SwiftTenantName,
					"SWIFT_REGIONNAME=" + c.SwiftRegionName,
					"SWIFT_AUTHVERSION=2",
				},
				Image:        c.Image,
				OpenStdin:    true,
				StdinOnce:    true,
				AttachStdin:  true,
				AttachStdout: true,
				AttachStderr: true,
				Tty:          true,
			},
		},
	)

	checkErr(err, "Failed to create container for volume "+vol.Name+": %v", 1)

	defer func() {
		c.RemoveContainer(docker.RemoveContainerOptions{
			ID:    container.ID,
			Force: true,
		})
	}()

	binds := []string{
		vol.Mountpoint + ":/var/backups:ro",
	}

	err = dockerpty.Start(c.Client, container, &docker.HostConfig{
		Binds: binds,
	})
	checkErr(err, "Failed to start container for volume "+vol.Name+": %v", -1)
	return
}

func (c *conplicity) pullImage() (err error) {
	if _, err = c.InspectImage(c.Image); err != nil {
		// TODO: output pull to logs
		log.Infof("Pulling image %v", c.Image)
		err = c.PullImage(docker.PullImageOptions{
			Repository: c.Image,
		}, docker.AuthConfiguration{})
	}

	return err
}

func checkErr(err error, msg string, exit int) {
	if err != nil {
		log.Errorf(msg, err)

		if exit != -1 {
			os.Exit(exit)
		}
	}
}
<|endoftext|>


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

// This package implements a basic LISP interpretor for embedding in a go program for scripting.
// This file implements primitive functions.

package golisp

import (
	"fmt"
	"strings"
)

type PrimitiveFunction struct {
	Name         string
	Special      bool
	NumberOfArgs string
	Body         func(d *Data, env *SymbolTableFrame) (*Data, error)
	IsRestricted bool
}

func MakePrimitiveFunction(name string, argCount string, function func(*Data, *SymbolTableFrame) (*Data, error)) {
	f := &PrimitiveFunction{Name: name, Special: false, NumberOfArgs: argCount, Body: function, IsRestricted: false}
	sym := Global.Intern(name)
	Global.BindTo(sym, PrimitiveWithNameAndFunc(name, f))
}

func MakeRestrictedPrimitiveFunction(name string, argCount string, function func(*Data, *SymbolTableFrame) (*Data, error)) {
	f := &PrimitiveFunction{Name: name, Special: false, NumberOfArgs: argCount, Body: function, IsRestricted: true}
	sym := Global.Intern(name)
	Global.BindTo(sym, PrimitiveWithNameAndFunc(name, f))
}

func MakeSpecialForm(name string, argCount string, function func(*Data, *SymbolTableFrame) (*Data, error)) {
	f := &PrimitiveFunction{Name: name, Special: true, NumberOfArgs: argCount, Body: function, IsRestricted: false}
	sym := Global.Intern(name)
	Global.BindTo(sym, PrimitiveWithNameAndFunc(name, f))
}

func MakeRestrictedSpecialForm(name string, argCount string, function func(*Data, *SymbolTableFrame) (*Data, error)) {
	f := &PrimitiveFunction{Name: name, Special: true, NumberOfArgs: argCount, Body: function, IsRestricted: true}
	sym := Global.Intern(name)
	Global.BindTo(sym, PrimitiveWithNameAndFunc(name, f))
}

func (self *PrimitiveFunction) String() string {
	return fmt.Sprintf("<prim: %s, %v>", self.Name, self.Body)
}

func (self *PrimitiveFunction) checkArgumentCount(argCount int) bool {
	if self.NumberOfArgs == "*" {
		return true
	}

	for _, term := range strings.Split(self.NumberOfArgs, "|") {
		var intTerm int
		n, _ := fmt.Sscanf(term, "%d", &intTerm)
		if n == 1 && argCount == intTerm {
			return true
		}
		n, _ = fmt.Sscanf(term, ">=%d", &intTerm)
		if n == 1 && argCount >= intTerm {
			return true
		}
		var lo int
		var hi int
		n, _ = fmt.Sscanf(term, "(%d,%d)", &lo, &hi)
		if n == 2 && lo <= argCount && argCount <= hi {
			return true
		}
	}
	return false
}

func (self *PrimitiveFunction) Apply(args *Data, env *SymbolTableFrame) (result *Data, err error) {
	if !self.checkArgumentCount(Length(args)) {
		err = fmt.Errorf("Wrong number of args to %s. Expected %s but got %d.\n", self.Name, self.NumberOfArgs, Length(args))
		return
	}

	argArray := make([]*Data, 0)
	var argValue *Data
	for a := args; NotNilP(a); a = Cdr(a) {
		if self.Special {
			argValue = Car(a)
		} else {
			argValue, err = Eval(Car(a), env)
			if err != nil {
				return
			}
		}

		argArray = append(argArray, argValue)
	}

	if self.IsRestricted && env.IsRestricted {
		err = fmt.Errorf("The %s primitive is restricted from execution in this environment\n", self.Name)
		return
	}

	localGuid := ProfileGUID
	ProfileGUID++
	ProfileEnter("prim", self.Name, localGuid)

	result, err = (self.Body)(ArrayToList(argArray), env)

	ProfileExit("prim", self.Name, localGuid)

	return
}

func (self *PrimitiveFunction) ApplyWithoutEval(args *Data, env *SymbolTableFrame) (result *Data, err error) {
	if self.Special {
		return self.Apply(args, env)
	} else {
		return self.Apply(QuoteAll(args), env)
	}
}
<commit_msg>Bail immediately when prim/form is restricted.<commit_after>// Copyright 2014 SteelSeries ApS.  All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// This package implements a basic LISP interpretor for embedding in a go program for scripting.
// This file implements primitive functions.

package golisp

import (
	"fmt"
	"strings"
)

type PrimitiveFunction struct {
	Name         string
	Special      bool
	NumberOfArgs string
	Body         func(d *Data, env *SymbolTableFrame) (*Data, error)
	IsRestricted bool
}

func MakePrimitiveFunction(name string, argCount string, function func(*Data, *SymbolTableFrame) (*Data, error)) {
	f := &PrimitiveFunction{Name: name, Special: false, NumberOfArgs: argCount, Body: function, IsRestricted: false}
	sym := Global.Intern(name)
	Global.BindTo(sym, PrimitiveWithNameAndFunc(name, f))
}

func MakeRestrictedPrimitiveFunction(name string, argCount string, function func(*Data, *SymbolTableFrame) (*Data, error)) {
	f := &PrimitiveFunction{Name: name, Special: false, NumberOfArgs: argCount, Body: function, IsRestricted: true}
	sym := Global.Intern(name)
	Global.BindTo(sym, PrimitiveWithNameAndFunc(name, f))
}

func MakeSpecialForm(name string, argCount string, function func(*Data, *SymbolTableFrame) (*Data, error)) {
	f := &PrimitiveFunction{Name: name, Special: true, NumberOfArgs: argCount, Body: function, IsRestricted: false}
	sym := Global.Intern(name)
	Global.BindTo(sym, PrimitiveWithNameAndFunc(name, f))
}

func MakeRestrictedSpecialForm(name string, argCount string, function func(*Data, *SymbolTableFrame) (*Data, error)) {
	f := &PrimitiveFunction{Name: name, Special: true, NumberOfArgs: argCount, Body: function, IsRestricted: true}
	sym := Global.Intern(name)
	Global.BindTo(sym, PrimitiveWithNameAndFunc(name, f))
}

func (self *PrimitiveFunction) String() string {
	return fmt.Sprintf("<prim: %s, %v>", self.Name, self.Body)
}

func (self *PrimitiveFunction) checkArgumentCount(argCount int) bool {
	if self.NumberOfArgs == "*" {
		return true
	}

	for _, term := range strings.Split(self.NumberOfArgs, "|") {
		var intTerm int
		n, _ := fmt.Sscanf(term, "%d", &intTerm)
		if n == 1 && argCount == intTerm {
			return true
		}
		n, _ = fmt.Sscanf(term, ">=%d", &intTerm)
		if n == 1 && argCount >= intTerm {
			return true
		}
		var lo int
		var hi int
		n, _ = fmt.Sscanf(term, "(%d,%d)", &lo, &hi)
		if n == 2 && lo <= argCount && argCount <= hi {
			return true
		}
	}
	return false
}

func (self *PrimitiveFunction) Apply(args *Data, env *SymbolTableFrame) (result *Data, err error) {
	if self.IsRestricted && env.IsRestricted {
		err = fmt.Errorf("The %s primitive is restricted from execution in this environment\n", self.Name)
		return
	}

	if !self.checkArgumentCount(Length(args)) {
		err = fmt.Errorf("Wrong number of args to %s. Expected %s but got %d.\n", self.Name, self.NumberOfArgs, Length(args))
		return
	}

	argArray := make([]*Data, 0)
	var argValue *Data
	for a := args; NotNilP(a); a = Cdr(a) {
		if self.Special {
			argValue = Car(a)
		} else {
			argValue, err = Eval(Car(a), env)
			if err != nil {
				return
			}
		}

		argArray = append(argArray, argValue)
	}

	localGuid := ProfileGUID
	ProfileGUID++
	ProfileEnter("prim", self.Name, localGuid)

	result, err = (self.Body)(ArrayToList(argArray), env)

	ProfileExit("prim", self.Name, localGuid)

	return
}

func (self *PrimitiveFunction) ApplyWithoutEval(args *Data, env *SymbolTableFrame) (result *Data, err error) {
	if self.Special {
		return self.Apply(args, env)
	} else {
		return self.Apply(QuoteAll(args), env)
	}
}
<|endoftext|>


<commit_before>// Copyright 2016 syzkaller project authors. All rights reserved.
// Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file.

// Package gce allows to use Google Compute Engine (GCE) virtual machines as VMs.
// It is assumed that syz-manager also runs on GCE as VMs are created in the current project/zone.
//
// See https://cloud.google.com/compute/docs for details.
// In particular, how to build GCE-compatible images:
// https://cloud.google.com/compute/docs/tutorials/building-images
// Working with serial console:
// https://cloud.google.com/compute/docs/instances/interacting-with-serial-console
package gce

import (
	"fmt"
	"io/ioutil"
	"log"
	"os"
	"os/exec"
	"path/filepath"
	"sync"
	"time"

	"github.com/google/syzkaller/gce"
	"github.com/google/syzkaller/vm"
)

func init() {
	vm.Register("gce", ctor)
}

type instance struct {
	cfg     *vm.Config
	name    string
	ip      string
	offset  int64
	sshkey  string // per-instance private ssh key
	workdir string
	closed  chan bool
}

var (
	initOnce sync.Once
	GCE      *gce.Context
)

func initGCE() {
	GCE, err := gce.NewContext()
	if err != nil {
		log.Fatalf("failed to init gce: %v", err)
	}
	log.Printf("gce initialized: running on %v, internal IP, %v project %v, zone %v", GCE.Instance, GCE.InternalIP, GCE.ProjectID, GCE.ZoneID)
}

func ctor(cfg *vm.Config) (vm.Instance, error) {
	initOnce.Do(initGCE)
	name := fmt.Sprintf("syzkaller-%v", cfg.Index)
	ok := false
	defer func() {
		if !ok {
			os.RemoveAll(cfg.Workdir)
		}
	}()

	// Create SSH key for the instance.
	sshkey := filepath.Join(cfg.Workdir, "key")
	keygen := exec.Command("ssh-keygen", "-t", "rsa", "-b", "2048", "-N", "", "-C", "syzkaller", "-f", sshkey)
	if out, err := keygen.CombinedOutput(); err != nil {
		return nil, fmt.Errorf("failed to execute ssh-keygen: %v\n%s", err, out)
	}
	sshkeyPub, err := ioutil.ReadFile(sshkey + ".pub")
	if err != nil {
		return nil, fmt.Errorf("failed to read file: %v", err)
	}

	log.Printf("deleting instance: %v", name)
	if err := GCE.DeleteInstance(name); err != nil {
		return nil, err
	}
	log.Printf("creating instance: %v", name)
	ip, err := GCE.CreateInstance(name, cfg.MachineType, cfg.Image, string(sshkeyPub))
	if err != nil {
		return nil, err
	}
	defer func() {
		if !ok {
			GCE.DeleteInstance(name)
		}
	}()
	log.Printf("wait instance to boot: %v (%v)", name, ip)
	if err := waitInstanceBoot(ip, cfg.Sshkey); err != nil {
		return nil, err
	}
	ok = true
	inst := &instance{
		cfg:    cfg,
		name:   name,
		ip:     ip,
		sshkey: sshkey,
		closed: make(chan bool),
	}
	return inst, nil
}

func (inst *instance) Close() {
	close(inst.closed)
	GCE.DeleteInstance(inst.name)
	os.RemoveAll(inst.cfg.Workdir)
}

func (inst *instance) Forward(port int) (string, error) {
	return fmt.Sprintf("%v:%v", GCE.InternalIP, port), nil
}

func (inst *instance) Copy(hostSrc string) (string, error) {
	vmDst := filepath.Join("/", filepath.Base(hostSrc))
	args := append(sshArgs(inst.cfg.Sshkey, "-P", 22), hostSrc, "root@"+inst.name+":"+vmDst)
	cmd := exec.Command("scp", args...)
	if err := cmd.Start(); err != nil {
		return "", err
	}
	done := make(chan bool)
	go func() {
		select {
		case <-time.After(time.Minute):
			cmd.Process.Kill()
		case <-done:
		}
	}()
	err := cmd.Wait()
	close(done)
	if err != nil {
		return "", err
	}
	return vmDst, nil
}

func (inst *instance) Run(timeout time.Duration, command string) (<-chan []byte, <-chan error, error) {
	conRpipe, conWpipe, err := vm.LongPipe()
	if err != nil {
		return nil, nil, err
	}

	conAddr := fmt.Sprintf("%v.%v.%v.syzkaller.port=1@ssh-serialport.googleapis.com", GCE.ProjectID, GCE.ZoneID, inst.name)
	conArgs := append(sshArgs(inst.sshkey, "-p", 9600), conAddr)
	con := exec.Command("ssh", conArgs...)
	con.Env = []string{}
	con.Stdout = conWpipe
	con.Stderr = conWpipe
	if _, err := con.StdinPipe(); err != nil { // SSH would close connection on stdin EOF
		conRpipe.Close()
		conWpipe.Close()
		return nil, nil, err
	}
	if err := con.Start(); err != nil {
		conRpipe.Close()
		conWpipe.Close()
		return nil, nil, fmt.Errorf("failed to connect to console server: %v", err)

	}
	conWpipe.Close()
	conDone := make(chan error, 1)
	go func() {
		err := con.Wait()
		conDone <- fmt.Errorf("console connection closed: %v", err)
	}()

	sshRpipe, sshWpipe, err := vm.LongPipe()
	if err != nil {
		con.Process.Kill()
		sshRpipe.Close()
		return nil, nil, err
	}
	args := append(sshArgs(inst.cfg.Sshkey, "-p", 22), "root@"+inst.name, command)
	ssh := exec.Command("ssh", args...)
	ssh.Stdout = sshWpipe
	ssh.Stderr = sshWpipe
	if err := ssh.Start(); err != nil {
		con.Process.Kill()
		conRpipe.Close()
		sshRpipe.Close()
		sshWpipe.Close()
		return nil, nil, fmt.Errorf("failed to connect to instance: %v", err)
	}
	sshWpipe.Close()
	sshDone := make(chan error, 1)
	go func() {
		err := ssh.Wait()
		sshDone <- fmt.Errorf("ssh exited: %v", err)
	}()

	merger := vm.NewOutputMerger(nil)
	merger.Add(conRpipe)
	merger.Add(sshRpipe)

	errc := make(chan error, 1)
	signal := func(err error) {
		select {
		case errc <- err:
		default:
		}
	}

	go func() {
		select {
		case <-time.After(timeout):
			signal(vm.TimeoutErr)
			con.Process.Kill()
			ssh.Process.Kill()
		case <-inst.closed:
			signal(fmt.Errorf("instance closed"))
			con.Process.Kill()
			ssh.Process.Kill()
		case err := <-conDone:
			signal(err)
			ssh.Process.Kill()
		case err := <-sshDone:
			signal(err)
			con.Process.Kill()
		}
		merger.Wait()
	}()
	return merger.Output, errc, nil
}

func waitInstanceBoot(ip, sshkey string) error {
	for i := 0; i < 100; i++ {
		if !vm.SleepInterruptible(5 * time.Second) {
			return fmt.Errorf("shutdown in progress")
		}
		cmd := exec.Command("ssh", append(sshArgs(sshkey, "-p", 22), "root@"+ip, "pwd")...)
		if _, err := cmd.CombinedOutput(); err == nil {
			return nil
		}
	}
	return fmt.Errorf("can't ssh into the instance")
}

func sshArgs(sshKey, portArg string, port int) []string {
	return []string{
		portArg, fmt.Sprint(port),
		"-i", sshKey,
		"-F", "/dev/null",
		"-o", "UserKnownHostsFile=/dev/null",
		"-o", "BatchMode=yes",
		"-o", "IdentitiesOnly=yes",
		"-o", "StrictHostKeyChecking=no",
		"-o", "ConnectTimeout=5",
	}
}
<commit_msg>vm/gce: fix bug introduced during refactoring<commit_after>// Copyright 2016 syzkaller project authors. All rights reserved.
// Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file.

// Package gce allows to use Google Compute Engine (GCE) virtual machines as VMs.
// It is assumed that syz-manager also runs on GCE as VMs are created in the current project/zone.
//
// See https://cloud.google.com/compute/docs for details.
// In particular, how to build GCE-compatible images:
// https://cloud.google.com/compute/docs/tutorials/building-images
// Working with serial console:
// https://cloud.google.com/compute/docs/instances/interacting-with-serial-console
package gce

import (
	"fmt"
	"io/ioutil"
	"log"
	"os"
	"os/exec"
	"path/filepath"
	"sync"
	"time"

	"github.com/google/syzkaller/gce"
	"github.com/google/syzkaller/vm"
)

func init() {
	vm.Register("gce", ctor)
}

type instance struct {
	cfg     *vm.Config
	name    string
	ip      string
	offset  int64
	sshkey  string // per-instance private ssh key
	workdir string
	closed  chan bool
}

var (
	initOnce sync.Once
	GCE      *gce.Context
)

func initGCE() {
	var err error
	GCE, err = gce.NewContext()
	if err != nil {
		log.Fatalf("failed to init gce: %v", err)
	}
	log.Printf("gce initialized: running on %v, internal IP, %v project %v, zone %v", GCE.Instance, GCE.InternalIP, GCE.ProjectID, GCE.ZoneID)
}

func ctor(cfg *vm.Config) (vm.Instance, error) {
	initOnce.Do(initGCE)
	name := fmt.Sprintf("syzkaller-%v", cfg.Index)
	ok := false
	defer func() {
		if !ok {
			os.RemoveAll(cfg.Workdir)
		}
	}()

	// Create SSH key for the instance.
	sshkey := filepath.Join(cfg.Workdir, "key")
	keygen := exec.Command("ssh-keygen", "-t", "rsa", "-b", "2048", "-N", "", "-C", "syzkaller", "-f", sshkey)
	if out, err := keygen.CombinedOutput(); err != nil {
		return nil, fmt.Errorf("failed to execute ssh-keygen: %v\n%s", err, out)
	}
	sshkeyPub, err := ioutil.ReadFile(sshkey + ".pub")
	if err != nil {
		return nil, fmt.Errorf("failed to read file: %v", err)
	}

	log.Printf("deleting instance: %v", name)
	if err := GCE.DeleteInstance(name); err != nil {
		return nil, err
	}
	log.Printf("creating instance: %v", name)
	ip, err := GCE.CreateInstance(name, cfg.MachineType, cfg.Image, string(sshkeyPub))
	if err != nil {
		return nil, err
	}
	defer func() {
		if !ok {
			GCE.DeleteInstance(name)
		}
	}()
	log.Printf("wait instance to boot: %v (%v)", name, ip)
	if err := waitInstanceBoot(ip, cfg.Sshkey); err != nil {
		return nil, err
	}
	ok = true
	inst := &instance{
		cfg:    cfg,
		name:   name,
		ip:     ip,
		sshkey: sshkey,
		closed: make(chan bool),
	}
	return inst, nil
}

func (inst *instance) Close() {
	close(inst.closed)
	GCE.DeleteInstance(inst.name)
	os.RemoveAll(inst.cfg.Workdir)
}

func (inst *instance) Forward(port int) (string, error) {
	return fmt.Sprintf("%v:%v", GCE.InternalIP, port), nil
}

func (inst *instance) Copy(hostSrc string) (string, error) {
	vmDst := filepath.Join("/", filepath.Base(hostSrc))
	args := append(sshArgs(inst.cfg.Sshkey, "-P", 22), hostSrc, "root@"+inst.name+":"+vmDst)
	cmd := exec.Command("scp", args...)
	if err := cmd.Start(); err != nil {
		return "", err
	}
	done := make(chan bool)
	go func() {
		select {
		case <-time.After(time.Minute):
			cmd.Process.Kill()
		case <-done:
		}
	}()
	err := cmd.Wait()
	close(done)
	if err != nil {
		return "", err
	}
	return vmDst, nil
}

func (inst *instance) Run(timeout time.Duration, command string) (<-chan []byte, <-chan error, error) {
	conRpipe, conWpipe, err := vm.LongPipe()
	if err != nil {
		return nil, nil, err
	}

	conAddr := fmt.Sprintf("%v.%v.%v.syzkaller.port=1@ssh-serialport.googleapis.com", GCE.ProjectID, GCE.ZoneID, inst.name)
	conArgs := append(sshArgs(inst.sshkey, "-p", 9600), conAddr)
	con := exec.Command("ssh", conArgs...)
	con.Env = []string{}
	con.Stdout = conWpipe
	con.Stderr = conWpipe
	if _, err := con.StdinPipe(); err != nil { // SSH would close connection on stdin EOF
		conRpipe.Close()
		conWpipe.Close()
		return nil, nil, err
	}
	if err := con.Start(); err != nil {
		conRpipe.Close()
		conWpipe.Close()
		return nil, nil, fmt.Errorf("failed to connect to console server: %v", err)

	}
	conWpipe.Close()
	conDone := make(chan error, 1)
	go func() {
		err := con.Wait()
		conDone <- fmt.Errorf("console connection closed: %v", err)
	}()

	sshRpipe, sshWpipe, err := vm.LongPipe()
	if err != nil {
		con.Process.Kill()
		sshRpipe.Close()
		return nil, nil, err
	}
	args := append(sshArgs(inst.cfg.Sshkey, "-p", 22), "root@"+inst.name, command)
	ssh := exec.Command("ssh", args...)
	ssh.Stdout = sshWpipe
	ssh.Stderr = sshWpipe
	if err := ssh.Start(); err != nil {
		con.Process.Kill()
		conRpipe.Close()
		sshRpipe.Close()
		sshWpipe.Close()
		return nil, nil, fmt.Errorf("failed to connect to instance: %v", err)
	}
	sshWpipe.Close()
	sshDone := make(chan error, 1)
	go func() {
		err := ssh.Wait()
		sshDone <- fmt.Errorf("ssh exited: %v", err)
	}()

	merger := vm.NewOutputMerger(nil)
	merger.Add(conRpipe)
	merger.Add(sshRpipe)

	errc := make(chan error, 1)
	signal := func(err error) {
		select {
		case errc <- err:
		default:
		}
	}

	go func() {
		select {
		case <-time.After(timeout):
			signal(vm.TimeoutErr)
			con.Process.Kill()
			ssh.Process.Kill()
		case <-inst.closed:
			signal(fmt.Errorf("instance closed"))
			con.Process.Kill()
			ssh.Process.Kill()
		case err := <-conDone:
			signal(err)
			ssh.Process.Kill()
		case err := <-sshDone:
			signal(err)
			con.Process.Kill()
		}
		merger.Wait()
	}()
	return merger.Output, errc, nil
}

func waitInstanceBoot(ip, sshkey string) error {
	for i := 0; i < 100; i++ {
		if !vm.SleepInterruptible(5 * time.Second) {
			return fmt.Errorf("shutdown in progress")
		}
		cmd := exec.Command("ssh", append(sshArgs(sshkey, "-p", 22), "root@"+ip, "pwd")...)
		if _, err := cmd.CombinedOutput(); err == nil {
			return nil
		}
	}
	return fmt.Errorf("can't ssh into the instance")
}

func sshArgs(sshKey, portArg string, port int) []string {
	return []string{
		portArg, fmt.Sprint(port),
		"-i", sshKey,
		"-F", "/dev/null",
		"-o", "UserKnownHostsFile=/dev/null",
		"-o", "BatchMode=yes",
		"-o", "IdentitiesOnly=yes",
		"-o", "StrictHostKeyChecking=no",
		"-o", "ConnectTimeout=5",
	}
}
<|endoftext|>


<commit_before>package vm

import (
	"errors"
	"fmt"
	"strconv"
)

const (
	memory_size  = 1000
	program_size = 800
)

var (
	memory [memory_size]Word
	result string
	pc     int // program counter
	sp     int // stack pointer
	reg_a  int
	reg_b  int
	reg_c  int
)

func Process(program []Word, option Option) (string, error) {
	memory = [memory_size]Word{}
	result = ""
	pc = 0
	sp = memory_size - 1
	if len(program) > program_size {
		return result, errors.New("lines of program must be 800 or less")
	}
	copy(memory[:], program[:])
	for {
		word := memory[pc]
		pc++
		switch word.category {
		case W_value:
			return result, processing_error("can not execute value")
		case W_load:
			v := word.value.([2]int)
			switch v[0] {
			case Reg_A:
				reg_a = v[1]
			case Reg_B:
				reg_b = v[1]
			case Reg_C:
				reg_c = v[1]
			}
		case W_load_mem:
			v := word.value.([2]int)
			n := memory[v[1]+1]
			if n.category != W_value {
				return result, processing_error("is not a value")
			}
			switch v[0] {
			case Reg_A:
				reg_a = n.value.(int)
			case Reg_B:
				reg_b = n.value.(int)
			case Reg_C:
				reg_c = n.value.(int)
			}
		case W_store_mem:
			v := word.value.([2]int)
			switch v[0] {
			case Reg_A:
				memory[v[1]+1] = newWord(W_value, reg_a)
			case Reg_B:
				memory[v[1]+1] = newWord(W_value, reg_b)
			case Reg_C:
				memory[v[1]+1] = newWord(W_value, reg_c)
			}
		case W_store_ref:
			v := word.value.([2]int)
			var ad int
			switch v[1] {
			case Reg_A:
				ad = reg_a
			case Reg_B:
				ad = reg_b
			case Reg_C:
				ad = reg_c
			}
			switch v[0] {
			case Reg_A:
				memory[ad+1] = newWord(W_value, reg_a)
			case Reg_B:
				memory[ad+1] = newWord(W_value, reg_b)
			case Reg_C:
				memory[ad+1] = newWord(W_value, reg_c)
			}
		case W_push:
			if sp == 0 {
				return result, processing_error("can not push into stack")
			}
			switch word.value.(int) {
			case Reg_A:
				memory[sp] = newWord(W_value, reg_a)
			case Reg_B:
				memory[sp] = newWord(W_value, reg_b)
			case Reg_C:
				memory[sp] = newWord(W_value, reg_c)
			}
			sp-- // push
		case W_pop:
			if sp == memory_size-1 {
				return result, processing_error("can not pop from stack")
			}
			sp++ // pop
			popped := memory[sp]
			if popped.category != W_value {
				return result, processing_error("can not pop which is not a value from stack")
			}
			switch word.value.(int) {
			case Reg_A:
				reg_a = popped.value.(int)
			case Reg_B:
				reg_b = popped.value.(int)
			case Reg_C:
				reg_c = popped.value.(int)
			}
		case W_plus:
			reg_c = reg_a + reg_b
		case W_minus:
			reg_c = reg_a - reg_b
		case W_multi:
			reg_c = reg_a * reg_b
		case W_div:
			reg_c = reg_a / reg_b
		case W_cmpodd:
			if reg_a%2 == 1 {
				reg_c = 1
			} else {
				reg_c = 0
			}
		case W_cmpeq:
			if reg_a == reg_b {
				reg_c = 1
			} else {
				reg_c = 0
			}
		case W_cmplt:
			if reg_a < reg_b {
				reg_c = 1
			} else {
				reg_c = 0
			}
		case W_cmpgt:
			if reg_a > reg_b {
				reg_c = 1
			} else {
				reg_c = 0
			}
		case W_cmpnoteq:
			if reg_a != reg_b {
				reg_c = 1
			} else {
				reg_c = 0
			}
		case W_cmple:
			if reg_a <= reg_b {
				reg_c = 1
			} else {
				reg_c = 0
			}
		case W_cmpge:
			if reg_a >= reg_b {
				reg_c = 1
			} else {
				reg_c = 0
			}
		case W_jmp:
			pc = word.value.(int) + 1
		case W_jpc:
			if reg_c == 0 {
				pc = word.value.(int) + 1
			}
		case W_print:
			switch word.value.(int) {
			case Reg_A:
				result += strconv.Itoa(reg_a)
			case Reg_B:
				result += strconv.Itoa(reg_b)
			case Reg_C:
				result += strconv.Itoa(reg_c)
			}
		case W_println:
			result += "\n"
		case W_end:
			return result, nil
		default:
			return result, processing_error("wrong command")
		}
	}
}

func processing_error(str string) error {
	return errors.New(fmt.Sprintf("[%d] %s", pc-1, str))
}
<commit_msg>Fix the bug<commit_after>package vm

import (
	"errors"
	"fmt"
	"strconv"
)

const (
	memory_size  = 1000
	program_size = 800
)

var (
	memory [memory_size]Word
	result string
	pc     int // program counter
	sp     int // stack pointer
	reg_a  int
	reg_b  int
	reg_c  int
)

func Process(program []Word, option Option) (string, error) {
	memory = [memory_size]Word{}
	result = ""
	pc = 0
	sp = memory_size - 1
	if len(program) > program_size {
		return result, errors.New("lines of program must be 800 or less")
	}
	copy(memory[:], program[:])
	for {
		word := memory[pc]
		pc++
		switch word.category {
		case W_value:
			return result, processing_error("can not execute value")
		case W_load:
			v := word.value.([2]int)
			switch v[0] {
			case Reg_A:
				reg_a = v[1]
			case Reg_B:
				reg_b = v[1]
			case Reg_C:
				reg_c = v[1]
			}
		case W_load_mem:
			v := word.value.([2]int)
			n := memory[v[1]+1]
			if n.category != W_value {
				return result, processing_error("is not a value")
			}
			switch v[0] {
			case Reg_A:
				reg_a = n.value.(int)
			case Reg_B:
				reg_b = n.value.(int)
			case Reg_C:
				reg_c = n.value.(int)
			}
		case W_store_mem:
			v := word.value.([2]int)
			switch v[0] {
			case Reg_A:
				memory[v[1]+1] = newWord(W_value, reg_a)
			case Reg_B:
				memory[v[1]+1] = newWord(W_value, reg_b)
			case Reg_C:
				memory[v[1]+1] = newWord(W_value, reg_c)
			}
		case W_store_ref:
			v := word.value.([2]int)
			var ad int
			switch v[1] {
			case Reg_A:
				ad = reg_a
			case Reg_B:
				ad = reg_b
			case Reg_C:
				ad = reg_c
			}
			switch v[0] {
			case Reg_A:
				memory[ad+1] = newWord(W_value, reg_a)
			case Reg_B:
				memory[ad+1] = newWord(W_value, reg_b)
			case Reg_C:
				memory[ad+1] = newWord(W_value, reg_c)
			}
		case W_push:
			if sp == 0 {
				return result, processing_error("can not push into stack")
			}
			switch word.value.(int) {
			case Reg_A:
				memory[sp] = newWord(W_value, reg_a)
			case Reg_B:
				memory[sp] = newWord(W_value, reg_b)
			case Reg_C:
				memory[sp] = newWord(W_value, reg_c)
			}
			sp-- // push
		case W_pop:
			if sp == memory_size-1 {
				return result, processing_error("can not pop from stack")
			}
			sp++ // pop
			popped := memory[sp]
			if popped.category != W_value {
				return result, processing_error("can not pop which is not a value from stack")
			}
			switch word.value.(int) {
			case Reg_A:
				reg_a = popped.value.(int)
			case Reg_B:
				reg_b = popped.value.(int)
			case Reg_C:
				reg_c = popped.value.(int)
			}
		case W_plus:
			reg_c = reg_a + reg_b
		case W_minus:
			reg_c = reg_a - reg_b
		case W_multi:
			reg_c = reg_a * reg_b
		case W_div:
			reg_c = reg_a / reg_b
		case W_cmpodd:
			if reg_a%2 == 1 {
				reg_c = 1
			} else {
				reg_c = 0
			}
		case W_cmpeq:
			if reg_a == reg_b {
				reg_c = 1
			} else {
				reg_c = 0
			}
		case W_cmplt:
			if reg_a < reg_b {
				reg_c = 1
			} else {
				reg_c = 0
			}
		case W_cmpgt:
			if reg_a > reg_b {
				reg_c = 1
			} else {
				reg_c = 0
			}
		case W_cmpnoteq:
			if reg_a != reg_b {
				reg_c = 1
			} else {
				reg_c = 0
			}
		case W_cmple:
			if reg_a <= reg_b {
				reg_c = 1
			} else {
				reg_c = 0
			}
		case W_cmpge:
			if reg_a >= reg_b {
				reg_c = 1
			} else {
				reg_c = 0
			}
		case W_jmp:
			pc = word.value.(int) - 1
		case W_jpc:
			if reg_c == 0 {
				pc = word.value.(int) - 1
			}
		case W_print:
			switch word.value.(int) {
			case Reg_A:
				result += strconv.Itoa(reg_a)
			case Reg_B:
				result += strconv.Itoa(reg_b)
			case Reg_C:
				result += strconv.Itoa(reg_c)
			}
		case W_println:
			result += "\n"
		case W_end:
			return result, nil
		default:
			return result, processing_error("wrong command")
		}
	}
}

func processing_error(str string) error {
	return errors.New(fmt.Sprintf("[%d] %s", pc-1, str))
}
<|endoftext|>


<commit_before>// Copyright 2020 syzkaller project authors. All rights reserved.
// Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file.

// +build amd64 386 arm64 arm mips64le ppc64le

package prog

import "encoding/binary"

var HostEndian = binary.LittleEndian
<commit_msg>prog: add support for riscv64<commit_after>// Copyright 2020 syzkaller project authors. All rights reserved.
// Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file.

// +build amd64 386 arm64 arm mips64le ppc64le riscv64

package prog

import "encoding/binary"

var HostEndian = binary.LittleEndian
<|endoftext|>


<commit_before>// Copyright 2016 syzkaller project authors. All rights reserved.
// Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file.

package state

import (
	"fmt"
	"io/ioutil"
	"os"
	"path/filepath"
	"sort"
	"strconv"
	"time"

	"github.com/google/syzkaller/pkg/db"
	"github.com/google/syzkaller/pkg/hash"
	. "github.com/google/syzkaller/pkg/log"
	"github.com/google/syzkaller/pkg/osutil"
	"github.com/google/syzkaller/prog"
)

// State holds all internal syz-hub state including corpus,
// reproducers and information about managers.
// It is persisted to and can be restored from a directory.
type State struct {
	corpusSeq uint64
	reproSeq  uint64
	dir       string
	Corpus    *db.DB
	Repros    *db.DB
	Managers  map[string]*Manager
}

// Manager represents one syz-manager instance.
type Manager struct {
	name          string
	corpusSeq     uint64
	reproSeq      uint64
	corpusFile    string
	corpusSeqFile string
	reproSeqFile  string
	ownRepros     map[string]bool
	Connected     time.Time
	Added         int
	Deleted       int
	New           int
	SentRepros    int
	RecvRepros    int
	Calls         map[string]struct{}
	Corpus        *db.DB
}

// Make creates State and initializes it from dir.
func Make(dir string) (*State, error) {
	st := &State{
		dir:      dir,
		Managers: make(map[string]*Manager),
	}

	osutil.MkdirAll(st.dir)
	st.Corpus, st.corpusSeq = loadDB(filepath.Join(st.dir, "corpus.db"), "corpus")
	st.Repros, st.reproSeq = loadDB(filepath.Join(st.dir, "repro.db"), "repro")

	managersDir := filepath.Join(st.dir, "manager")
	osutil.MkdirAll(managersDir)
	managers, err := ioutil.ReadDir(managersDir)
	if err != nil {
		return nil, fmt.Errorf("failed to read %v dir: %v", managersDir, err)
	}
	for _, manager := range managers {
		_, err := st.createManager(manager.Name())
		if err != nil {
			return nil, err
		}
	}
	Logf(0, "purging corpus...")
	st.purgeCorpus()
	Logf(0, "done, %v programs", len(st.Corpus.Records))

	return st, err
}

func loadDB(file, name string) (*db.DB, uint64) {
	Logf(0, "reading %v...", name)
	db, err := db.Open(file)
	if err != nil {
		Fatalf("failed to open %v database: %v", name, err)
	}
	Logf(0, "read %v programs", len(db.Records))
	var maxSeq uint64
	for key, rec := range db.Records {
		if _, err := prog.CallSet(rec.Val); err != nil {
			Logf(0, "bad file: can't parse call set: %v", err)
			db.Delete(key)
			continue
		}
		if sig := hash.Hash(rec.Val); sig.String() != key {
			Logf(0, "bad file: hash %v, want hash %v", key, sig.String())
			db.Delete(key)
			continue
		}
		if maxSeq < rec.Seq {
			maxSeq = rec.Seq
		}
	}
	if err := db.Flush(); err != nil {
		Fatalf("failed to flush corpus database: %v", err)
	}
	return db, maxSeq
}

func (st *State) createManager(name string) (*Manager, error) {
	dir := filepath.Join(st.dir, "manager", name)
	osutil.MkdirAll(dir)
	mgr := &Manager{
		name:          name,
		corpusFile:    filepath.Join(dir, "corpus.db"),
		corpusSeqFile: filepath.Join(dir, "seq"),
		reproSeqFile:  filepath.Join(dir, "repro.seq"),
		ownRepros:     make(map[string]bool),
	}
	mgr.corpusSeq = loadSeqFile(mgr.corpusSeqFile)
	if st.corpusSeq < mgr.corpusSeq {
		st.corpusSeq = mgr.corpusSeq
	}
	mgr.reproSeq = loadSeqFile(mgr.reproSeqFile)
	if st.reproSeq < mgr.reproSeq {
		st.reproSeq = mgr.reproSeq
	}
	var err error
	mgr.Corpus, err = db.Open(mgr.corpusFile)
	if err != nil {
		return nil, fmt.Errorf("failed to open manager corpus %v: %v", mgr.corpusFile, err)
	}
	Logf(0, "created manager %v: corpus=%v, corpusSeq=%v, reproSeq=%v",
		mgr.name, len(mgr.Corpus.Records), mgr.corpusSeq, mgr.reproSeq)
	st.Managers[name] = mgr
	return mgr, nil
}

func (st *State) Connect(name string, fresh bool, calls []string, corpus [][]byte) error {
	mgr := st.Managers[name]
	if mgr == nil {
		var err error
		mgr, err = st.createManager(name)
		if err != nil {
			return err
		}
	}
	mgr.Connected = time.Now()
	if fresh {
		mgr.corpusSeq = 0
		mgr.reproSeq = 0
	}
	saveSeqFile(mgr.corpusSeqFile, mgr.corpusSeq)
	saveSeqFile(mgr.reproSeqFile, mgr.reproSeq)

	mgr.Calls = make(map[string]struct{})
	for _, c := range calls {
		mgr.Calls[c] = struct{}{}
	}

	os.Remove(mgr.corpusFile)
	var err error
	mgr.Corpus, err = db.Open(mgr.corpusFile)
	if err != nil {
		Logf(0, "failed to open corpus database: %v", err)
		return err
	}
	st.addInputs(mgr, corpus)
	st.purgeCorpus()
	return nil
}

func (st *State) Sync(name string, add [][]byte, del []string) ([][]byte, int, error) {
	mgr := st.Managers[name]
	if mgr == nil || mgr.Connected.IsZero() {
		return nil, 0, fmt.Errorf("unconnected manager %v", name)
	}
	if len(del) != 0 {
		for _, sig := range del {
			mgr.Corpus.Delete(sig)
		}
		if err := mgr.Corpus.Flush(); err != nil {
			Logf(0, "failed to flush corpus database: %v", err)
		}
		st.purgeCorpus()
	}
	st.addInputs(mgr, add)
	progs, more, err := st.pendingInputs(mgr)
	mgr.Added += len(add)
	mgr.Deleted += len(del)
	mgr.New += len(progs)
	return progs, more, err
}

func (st *State) AddRepro(name string, repro []byte) error {
	mgr := st.Managers[name]
	if mgr == nil || mgr.Connected.IsZero() {
		return fmt.Errorf("unconnected manager %v", name)
	}
	if _, err := prog.CallSet(repro); err != nil {
		Logf(0, "manager %v: failed to extract call set: %v, program:\n%v",
			mgr.name, err, string(repro))
		return nil
	}
	sig := hash.String(repro)
	if _, ok := st.Repros.Records[sig]; ok {
		return nil
	}
	mgr.ownRepros[sig] = true
	mgr.SentRepros++
	if mgr.reproSeq == st.reproSeq {
		mgr.reproSeq++
		saveSeqFile(mgr.reproSeqFile, mgr.reproSeq)
	}
	st.reproSeq++
	st.Repros.Save(sig, repro, st.reproSeq)
	if err := st.Repros.Flush(); err != nil {
		Logf(0, "failed to flush repro database: %v", err)
	}
	return nil
}

func (st *State) PendingRepro(name string) ([]byte, error) {
	mgr := st.Managers[name]
	if mgr == nil || mgr.Connected.IsZero() {
		return nil, fmt.Errorf("unconnected manager %v", name)
	}
	if mgr.reproSeq == st.reproSeq {
		return nil, nil
	}
	var repro []byte
	minSeq := ^uint64(0)
	for key, rec := range st.Repros.Records {
		if mgr.reproSeq >= rec.Seq {
			continue
		}
		if mgr.ownRepros[key] {
			continue
		}
		calls, err := prog.CallSet(rec.Val)
		if err != nil {
			return nil, fmt.Errorf("failed to extract call set: %v\nprogram: %s", err, rec.Val)
		}
		if !managerSupportsAllCalls(mgr.Calls, calls) {
			continue
		}
		if minSeq > rec.Seq {
			minSeq = rec.Seq
			repro = rec.Val
		}
	}
	if repro == nil {
		mgr.reproSeq = st.reproSeq
		saveSeqFile(mgr.reproSeqFile, mgr.reproSeq)
		return nil, nil
	}
	mgr.RecvRepros++
	mgr.reproSeq = minSeq
	saveSeqFile(mgr.reproSeqFile, mgr.reproSeq)
	return repro, nil
}

func (st *State) pendingInputs(mgr *Manager) ([][]byte, int, error) {
	if mgr.corpusSeq == st.corpusSeq {
		return nil, 0, nil
	}
	var records []db.Record
	for key, rec := range st.Corpus.Records {
		if mgr.corpusSeq >= rec.Seq {
			continue
		}
		if _, ok := mgr.Corpus.Records[key]; ok {
			continue
		}
		calls, err := prog.CallSet(rec.Val)
		if err != nil {
			return nil, 0, fmt.Errorf("failed to extract call set: %v\nprogram: %s", err, rec.Val)
		}
		if !managerSupportsAllCalls(mgr.Calls, calls) {
			continue
		}
		records = append(records, rec)
	}
	maxSeq := st.corpusSeq
	more := 0
	// Send at most that many records (rounded up to next seq number).
	const maxRecords = 1000
	if len(records) > maxRecords {
		sort.Sort(recordSeqSorter(records))
		pos := maxRecords
		maxSeq = records[pos].Seq
		for pos+1 < len(records) && records[pos+1].Seq == maxSeq {
			pos++
		}
		pos++
		more = len(records) - pos
		records = records[:pos]
	}
	progs := make([][]byte, len(records))
	for _, rec := range records {
		progs = append(progs, rec.Val)
	}
	mgr.corpusSeq = maxSeq
	saveSeqFile(mgr.corpusSeqFile, mgr.corpusSeq)
	return progs, more, nil
}

func (st *State) addInputs(mgr *Manager, inputs [][]byte) {
	if len(inputs) == 0 {
		return
	}
	st.corpusSeq++
	for _, input := range inputs {
		st.addInput(mgr, input)
	}
	if err := mgr.Corpus.Flush(); err != nil {
		Logf(0, "failed to flush corpus database: %v", err)
	}
	if err := st.Corpus.Flush(); err != nil {
		Logf(0, "failed to flush corpus database: %v", err)
	}
}

func (st *State) addInput(mgr *Manager, input []byte) {
	if _, err := prog.CallSet(input); err != nil {
		Logf(0, "manager %v: failed to extract call set: %v, program:\n%v", mgr.name, err, string(input))
		return
	}
	sig := hash.String(input)
	mgr.Corpus.Save(sig, nil, 0)
	if _, ok := st.Corpus.Records[sig]; !ok {
		st.Corpus.Save(sig, input, st.corpusSeq)
	}
}

func (st *State) purgeCorpus() {
	used := make(map[string]bool)
	for _, mgr := range st.Managers {
		for sig := range mgr.Corpus.Records {
			used[sig] = true
		}
	}
	for key := range st.Corpus.Records {
		if used[key] {
			continue
		}
		st.Corpus.Delete(key)
	}
	if err := st.Corpus.Flush(); err != nil {
		Logf(0, "failed to flush corpus database: %v", err)
	}
}

func managerSupportsAllCalls(mgr, prog map[string]struct{}) bool {
	for c := range prog {
		if _, ok := mgr[c]; !ok {
			return false
		}
	}
	return true
}

func writeFile(name string, data []byte) {
	if err := osutil.WriteFile(name, data); err != nil {
		Logf(0, "failed to write file %v: %v", name, err)
	}
}

func saveSeqFile(filename string, seq uint64) {
	writeFile(filename, []byte(fmt.Sprint(seq)))
}

func loadSeqFile(filename string) uint64 {
	str, _ := ioutil.ReadFile(filename)
	seq, _ := strconv.ParseUint(string(str), 10, 64)
	return seq
}

type recordSeqSorter []db.Record

func (a recordSeqSorter) Len() int {
	return len(a)
}

func (a recordSeqSorter) Less(i, j int) bool {
	return a[i].Seq < a[j].Seq
}

func (a recordSeqSorter) Swap(i, j int) {
	a[i], a[j] = a[j], a[i]
}
<commit_msg>syz-hub: don't send all repros to new managers<commit_after>// Copyright 2016 syzkaller project authors. All rights reserved.
// Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file.

package state

import (
	"fmt"
	"io/ioutil"
	"os"
	"path/filepath"
	"sort"
	"strconv"
	"time"

	"github.com/google/syzkaller/pkg/db"
	"github.com/google/syzkaller/pkg/hash"
	. "github.com/google/syzkaller/pkg/log"
	"github.com/google/syzkaller/pkg/osutil"
	"github.com/google/syzkaller/prog"
)

// State holds all internal syz-hub state including corpus,
// reproducers and information about managers.
// It is persisted to and can be restored from a directory.
type State struct {
	corpusSeq uint64
	reproSeq  uint64
	dir       string
	Corpus    *db.DB
	Repros    *db.DB
	Managers  map[string]*Manager
}

// Manager represents one syz-manager instance.
type Manager struct {
	name          string
	corpusSeq     uint64
	reproSeq      uint64
	corpusFile    string
	corpusSeqFile string
	reproSeqFile  string
	ownRepros     map[string]bool
	Connected     time.Time
	Added         int
	Deleted       int
	New           int
	SentRepros    int
	RecvRepros    int
	Calls         map[string]struct{}
	Corpus        *db.DB
}

// Make creates State and initializes it from dir.
func Make(dir string) (*State, error) {
	st := &State{
		dir:      dir,
		Managers: make(map[string]*Manager),
	}

	osutil.MkdirAll(st.dir)
	st.Corpus, st.corpusSeq = loadDB(filepath.Join(st.dir, "corpus.db"), "corpus")
	st.Repros, st.reproSeq = loadDB(filepath.Join(st.dir, "repro.db"), "repro")

	managersDir := filepath.Join(st.dir, "manager")
	osutil.MkdirAll(managersDir)
	managers, err := ioutil.ReadDir(managersDir)
	if err != nil {
		return nil, fmt.Errorf("failed to read %v dir: %v", managersDir, err)
	}
	for _, manager := range managers {
		_, err := st.createManager(manager.Name())
		if err != nil {
			return nil, err
		}
	}
	Logf(0, "purging corpus...")
	st.purgeCorpus()
	Logf(0, "done, %v programs", len(st.Corpus.Records))

	return st, err
}

func loadDB(file, name string) (*db.DB, uint64) {
	Logf(0, "reading %v...", name)
	db, err := db.Open(file)
	if err != nil {
		Fatalf("failed to open %v database: %v", name, err)
	}
	Logf(0, "read %v programs", len(db.Records))
	var maxSeq uint64
	for key, rec := range db.Records {
		if _, err := prog.CallSet(rec.Val); err != nil {
			Logf(0, "bad file: can't parse call set: %v", err)
			db.Delete(key)
			continue
		}
		if sig := hash.Hash(rec.Val); sig.String() != key {
			Logf(0, "bad file: hash %v, want hash %v", key, sig.String())
			db.Delete(key)
			continue
		}
		if maxSeq < rec.Seq {
			maxSeq = rec.Seq
		}
	}
	if err := db.Flush(); err != nil {
		Fatalf("failed to flush corpus database: %v", err)
	}
	return db, maxSeq
}

func (st *State) createManager(name string) (*Manager, error) {
	dir := filepath.Join(st.dir, "manager", name)
	osutil.MkdirAll(dir)
	mgr := &Manager{
		name:          name,
		corpusFile:    filepath.Join(dir, "corpus.db"),
		corpusSeqFile: filepath.Join(dir, "seq"),
		reproSeqFile:  filepath.Join(dir, "repro.seq"),
		ownRepros:     make(map[string]bool),
	}
	mgr.corpusSeq = loadSeqFile(mgr.corpusSeqFile)
	if st.corpusSeq < mgr.corpusSeq {
		st.corpusSeq = mgr.corpusSeq
	}
	mgr.reproSeq = loadSeqFile(mgr.reproSeqFile)
	if mgr.reproSeq == 0 {
		mgr.reproSeq = st.reproSeq
	}
	if st.reproSeq < mgr.reproSeq {
		st.reproSeq = mgr.reproSeq
	}
	var err error
	mgr.Corpus, err = db.Open(mgr.corpusFile)
	if err != nil {
		return nil, fmt.Errorf("failed to open manager corpus %v: %v", mgr.corpusFile, err)
	}
	Logf(0, "created manager %v: corpus=%v, corpusSeq=%v, reproSeq=%v",
		mgr.name, len(mgr.Corpus.Records), mgr.corpusSeq, mgr.reproSeq)
	st.Managers[name] = mgr
	return mgr, nil
}

func (st *State) Connect(name string, fresh bool, calls []string, corpus [][]byte) error {
	mgr := st.Managers[name]
	if mgr == nil {
		var err error
		mgr, err = st.createManager(name)
		if err != nil {
			return err
		}
	}
	mgr.Connected = time.Now()
	if fresh {
		mgr.corpusSeq = 0
		mgr.reproSeq = st.reproSeq
	}
	saveSeqFile(mgr.corpusSeqFile, mgr.corpusSeq)
	saveSeqFile(mgr.reproSeqFile, mgr.reproSeq)

	mgr.Calls = make(map[string]struct{})
	for _, c := range calls {
		mgr.Calls[c] = struct{}{}
	}

	os.Remove(mgr.corpusFile)
	var err error
	mgr.Corpus, err = db.Open(mgr.corpusFile)
	if err != nil {
		Logf(0, "failed to open corpus database: %v", err)
		return err
	}
	st.addInputs(mgr, corpus)
	st.purgeCorpus()
	return nil
}

func (st *State) Sync(name string, add [][]byte, del []string) ([][]byte, int, error) {
	mgr := st.Managers[name]
	if mgr == nil || mgr.Connected.IsZero() {
		return nil, 0, fmt.Errorf("unconnected manager %v", name)
	}
	if len(del) != 0 {
		for _, sig := range del {
			mgr.Corpus.Delete(sig)
		}
		if err := mgr.Corpus.Flush(); err != nil {
			Logf(0, "failed to flush corpus database: %v", err)
		}
		st.purgeCorpus()
	}
	st.addInputs(mgr, add)
	progs, more, err := st.pendingInputs(mgr)
	mgr.Added += len(add)
	mgr.Deleted += len(del)
	mgr.New += len(progs)
	return progs, more, err
}

func (st *State) AddRepro(name string, repro []byte) error {
	mgr := st.Managers[name]
	if mgr == nil || mgr.Connected.IsZero() {
		return fmt.Errorf("unconnected manager %v", name)
	}
	if _, err := prog.CallSet(repro); err != nil {
		Logf(0, "manager %v: failed to extract call set: %v, program:\n%v",
			mgr.name, err, string(repro))
		return nil
	}
	sig := hash.String(repro)
	if _, ok := st.Repros.Records[sig]; ok {
		return nil
	}
	mgr.ownRepros[sig] = true
	mgr.SentRepros++
	if mgr.reproSeq == st.reproSeq {
		mgr.reproSeq++
		saveSeqFile(mgr.reproSeqFile, mgr.reproSeq)
	}
	st.reproSeq++
	st.Repros.Save(sig, repro, st.reproSeq)
	if err := st.Repros.Flush(); err != nil {
		Logf(0, "failed to flush repro database: %v", err)
	}
	return nil
}

func (st *State) PendingRepro(name string) ([]byte, error) {
	mgr := st.Managers[name]
	if mgr == nil || mgr.Connected.IsZero() {
		return nil, fmt.Errorf("unconnected manager %v", name)
	}
	if mgr.reproSeq == st.reproSeq {
		return nil, nil
	}
	var repro []byte
	minSeq := ^uint64(0)
	for key, rec := range st.Repros.Records {
		if mgr.reproSeq >= rec.Seq {
			continue
		}
		if mgr.ownRepros[key] {
			continue
		}
		calls, err := prog.CallSet(rec.Val)
		if err != nil {
			return nil, fmt.Errorf("failed to extract call set: %v\nprogram: %s", err, rec.Val)
		}
		if !managerSupportsAllCalls(mgr.Calls, calls) {
			continue
		}
		if minSeq > rec.Seq {
			minSeq = rec.Seq
			repro = rec.Val
		}
	}
	if repro == nil {
		mgr.reproSeq = st.reproSeq
		saveSeqFile(mgr.reproSeqFile, mgr.reproSeq)
		return nil, nil
	}
	mgr.RecvRepros++
	mgr.reproSeq = minSeq
	saveSeqFile(mgr.reproSeqFile, mgr.reproSeq)
	return repro, nil
}

func (st *State) pendingInputs(mgr *Manager) ([][]byte, int, error) {
	if mgr.corpusSeq == st.corpusSeq {
		return nil, 0, nil
	}
	var records []db.Record
	for key, rec := range st.Corpus.Records {
		if mgr.corpusSeq >= rec.Seq {
			continue
		}
		if _, ok := mgr.Corpus.Records[key]; ok {
			continue
		}
		calls, err := prog.CallSet(rec.Val)
		if err != nil {
			return nil, 0, fmt.Errorf("failed to extract call set: %v\nprogram: %s", err, rec.Val)
		}
		if !managerSupportsAllCalls(mgr.Calls, calls) {
			continue
		}
		records = append(records, rec)
	}
	maxSeq := st.corpusSeq
	more := 0
	// Send at most that many records (rounded up to next seq number).
	const maxRecords = 1000
	if len(records) > maxRecords {
		sort.Sort(recordSeqSorter(records))
		pos := maxRecords
		maxSeq = records[pos].Seq
		for pos+1 < len(records) && records[pos+1].Seq == maxSeq {
			pos++
		}
		pos++
		more = len(records) - pos
		records = records[:pos]
	}
	progs := make([][]byte, len(records))
	for _, rec := range records {
		progs = append(progs, rec.Val)
	}
	mgr.corpusSeq = maxSeq
	saveSeqFile(mgr.corpusSeqFile, mgr.corpusSeq)
	return progs, more, nil
}

func (st *State) addInputs(mgr *Manager, inputs [][]byte) {
	if len(inputs) == 0 {
		return
	}
	st.corpusSeq++
	for _, input := range inputs {
		st.addInput(mgr, input)
	}
	if err := mgr.Corpus.Flush(); err != nil {
		Logf(0, "failed to flush corpus database: %v", err)
	}
	if err := st.Corpus.Flush(); err != nil {
		Logf(0, "failed to flush corpus database: %v", err)
	}
}

func (st *State) addInput(mgr *Manager, input []byte) {
	if _, err := prog.CallSet(input); err != nil {
		Logf(0, "manager %v: failed to extract call set: %v, program:\n%v", mgr.name, err, string(input))
		return
	}
	sig := hash.String(input)
	mgr.Corpus.Save(sig, nil, 0)
	if _, ok := st.Corpus.Records[sig]; !ok {
		st.Corpus.Save(sig, input, st.corpusSeq)
	}
}

func (st *State) purgeCorpus() {
	used := make(map[string]bool)
	for _, mgr := range st.Managers {
		for sig := range mgr.Corpus.Records {
			used[sig] = true
		}
	}
	for key := range st.Corpus.Records {
		if used[key] {
			continue
		}
		st.Corpus.Delete(key)
	}
	if err := st.Corpus.Flush(); err != nil {
		Logf(0, "failed to flush corpus database: %v", err)
	}
}

func managerSupportsAllCalls(mgr, prog map[string]struct{}) bool {
	for c := range prog {
		if _, ok := mgr[c]; !ok {
			return false
		}
	}
	return true
}

func writeFile(name string, data []byte) {
	if err := osutil.WriteFile(name, data); err != nil {
		Logf(0, "failed to write file %v: %v", name, err)
	}
}

func saveSeqFile(filename string, seq uint64) {
	writeFile(filename, []byte(fmt.Sprint(seq)))
}

func loadSeqFile(filename string) uint64 {
	str, _ := ioutil.ReadFile(filename)
	seq, _ := strconv.ParseUint(string(str), 10, 64)
	return seq
}

type recordSeqSorter []db.Record

func (a recordSeqSorter) Len() int {
	return len(a)
}

func (a recordSeqSorter) Less(i, j int) bool {
	return a[i].Seq < a[j].Seq
}

func (a recordSeqSorter) Swap(i, j int) {
	a[i], a[j] = a[j], a[i]
}
<|endoftext|>


<commit_before>package denon

import "net"
import "fmt"
import "time"

import "github.com/cnf/go-claw/clog"
import "github.com/cnf/go-claw/targets"

type Denon struct {
    name string
    addr *net.TCPAddr
    commands map[string]Commander
    last time.Time
    wait time.Duration
}

func Register() {
    targets.RegisterTarget("denon", Create)
}

func Create(name string, params map[string]string) (t targets.Target, ok bool) {
    // TODO: VALIDATE PARAMS
    if val, ok := params["address"]; ok {
        d := setup(name, val, 23)
        d.commands = AVRX2000
        d.wait = time.Duration(100 * time.Millisecond)
        return d, true
    }
    return nil, false
}

func setup(name string, host string, port int) *Denon {
    clog.Debug("Initializing Denon")
    tmp, err := net.ResolveTCPAddr("tcp", fmt.Sprintf("%s:%d", host, port))
    if err != nil {
        clog.Error("Could not Initialize Denon: %s", err)
        return nil
    }
    return &Denon{addr: tmp, name: name}

}

func (self *Denon) SendCommand(cmd string, args ...string) bool {
    switch cmd {
    default:
        clog.Debug("Looking up %s in the map", cmd)
        // clog.Debug(">>>>>>>>> %# v", self.commands)
        if val, ok := self.commands[cmd]; ok {
            cstr, err := val.Command(args...)
            if err != nil {
                return false
            }
            clog.Debug(">>>>>>>>> %# v", cstr)
            return self.socketSend(cstr)
        }
    }
    return false
}

func (self *Denon) Capabilities() []string {
    return []string{}
}

func (self *Denon) socketSend(str string) bool {
    if self.addr == nil {
        clog.Warn("No address to sent Denon command to.")
        return false
    }

    tdiff := time.Since(self.last)
    if tdiff < self.wait {
        // time.Sleep(self.wait)
        clog.Debug("+++++ Waiting %# v", self.wait - tdiff)
        time.Sleep(self.wait - tdiff)
    }

    conn, err := net.DialTCP("tcp", nil, self.addr)
    if err != nil {
        clog.Error("Connection failed: %s", err)
        if conn != nil {
            conn.Close()
        }
        return false
    }
    clog.Debug("Sending %s to %s", str, self.name)
    fmt.Fprintf(conn, "%s\r", str)
    conn.Close()
    self.last = time.Now()
    return true
}
<commit_msg>added togglemute<commit_after>package denon

import "net"
import "fmt"
import "time"
import "errors"
import "strings"

import "github.com/cnf/go-claw/clog"
import "github.com/cnf/go-claw/targets"

type Denon struct {
    name string
    addr *net.TCPAddr
    commands map[string]Commander
    last time.Time
    wait time.Duration
}

func Register() {
    targets.RegisterTarget("denon", Create)
}

func Create(name string, params map[string]string) (t targets.Target, ok bool) {
    // TODO: VALIDATE PARAMS
    if val, ok := params["address"]; ok {
        d := setup(name, val, 23)
        d.commands = AVRX2000
        d.wait = time.Duration(100 * time.Millisecond)
        return d, true
    }
    return nil, false
}

func setup(name string, host string, port int) *Denon {
    clog.Debug("Initializing Denon")
    tmp, err := net.ResolveTCPAddr("tcp", fmt.Sprintf("%s:%d", host, port))
    if err != nil {
        clog.Error("Could not Initialize Denon: %s", err)
        return nil
    }
    return &Denon{addr: tmp, name: name}

}

func (self *Denon) SendCommand(cmd string, args ...string) bool {
    switch cmd {
    case "Mute":
        return self.toggleMute()
    default:
        // clog.Debug(">>>>>>>>> %# v", self.commands)
        cstr, err := self.getCommand(cmd, args...)
        if err != nil { return false }
        clog.Debug(">>>>>>>>> %# v", cstr)
        _, serr := self.socketSend(cstr)
        if serr != nil { return false }
    }
    return false
}

func (self *Denon) Capabilities() []string {
    return []string{}
}

func (self *Denon) getCommand(cmd string, args ...string) (string, error) {
    clog.Debug("Looking up %s in the map", cmd)
    if val, ok := self.commands[cmd]; ok {
        cstr, err := val.Command(args...)
        if err != nil {
            return "", err
        }
        return cstr, nil
    }
    return "", errors.New("Could not get command")
}

func (self *Denon) socketSend(str string) (cmd string, err error) {
    if self.addr == nil {
        clog.Warn("No address to sent Denon command to.")
        return "", errors.New("No address set")
    }

    tdiff := time.Since(self.last)
    if tdiff < self.wait {
        // time.Sleep(self.wait)
        clog.Debug("+++++ Waiting %# v", self.wait - tdiff)
        time.Sleep(self.wait - tdiff)
    }

    conn, err := net.DialTCP("tcp", nil, self.addr)
    if err != nil {
        clog.Error("Connection failed: %s", err)
        if conn != nil {
            conn.Close()
        }
        return "", err
    }
    conn.SetReadDeadline(time.Now().Add(100 * time.Millisecond))
    clog.Debug("Sending %s to %s", str, self.name)
    fmt.Fprintf(conn, "%s\r", str)
    reply := make([]byte, 32)
    l, err := conn.Read(reply)
    if err != nil { return "", err }
    conn.Close()
    self.last = time.Now()
    return string(reply[0:l]), nil
}

func (self *Denon) toggleMute() bool {
    r, err := self.socketSend("MU?")
    // MuteOn
    if err != nil { return false }
    r = strings.TrimSpace(r)
    clog.Debug("Found: %# v", r)
    // _, serr := self.socketSend("MU?")
    // if serr != nil { return false }
    if r == "MUOFF" {
        clog.Debug("MU OFF!")
        cmd, err := self.getCommand("MuteOn")
        if err != nil { return false }
        _, serr := self.socketSend(cmd)
        if serr != nil { return false }
    } else if r == "MUON" {
        clog.Debug("MU ON!")
        cmd, err := self.getCommand("MuteOff")
        if err != nil { return false }
        _, serr := self.socketSend(cmd)
        if serr != nil { return false }
        // _, serr := self.socketSend("MUOFF")
    }
    return true
}
<|endoftext|>


<commit_before>// Copyright 2020 The Ebiten Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

// +build dragonfly freebsd linux netbsd openbsd solaris
// +build !js
// +build !android

package devicescale

import (
	"encoding/xml"
	"os"
	"os/exec"
	"path/filepath"
	"strconv"
)

type xmlBool bool

func (b *xmlBool) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error {
	var s string
	if err := d.DecodeElement(&s, &start); err != nil {
		return err
	}
	*b = xmlBool(s == "yes")
	return nil
}

func cinnamonScaleFromXML() (float64, error) {
	type cinnamonMonitors struct {
		XMLName       xml.Name `xml:"monitors"`
		Version       string   `xml:"version,attr"`
		Configuration struct {
			BaseScale float64 `xml:"base_scale"`
			Output    []struct {
				Scale   float64 `xml:"scale"`
				Primary xmlBool `xml:"primary"`
			} `xml:"output"`
		} `xml:"configuration"`
	}

	home, err := os.UserHomeDir()
	if err != nil {
		return 0, err
	}
	f, err := os.Open(filepath.Join(home, ".config", "cinnamon-monitors.xml"))
	if err != nil {
		return 0, err
	}
	defer f.Close()

	d := xml.NewDecoder(f)

	var monitors cinnamonMonitors
	if err = d.Decode(&monitors); err != nil {
		return 0, err
	}

	scale := monitors.Configuration.BaseScale
	for _, v := range monitors.Configuration.Output {
		// TODO: Get the monitor at the specified position.
		if v.Primary {
			if v.Scale != 0.0 {
				scale = v.Scale
			}
			break
		}
	}
	return scale, nil
}

func cinnamonScale() float64 {
	if s, err := cinnamonScaleFromXML(); err == nil && s > 0 {
		return s
	}

	out, err := exec.Command("gsettings", "get", "org.cinnamon.desktop.interface", "scaling-factor").Output()
	if err != nil {
		if err == exec.ErrNotFound {
			return 0
		}
		if _, ok := err.(*exec.ExitError); ok {
			return 0
		}
		panic(err)
	}
	m := gsettingsRe.FindStringSubmatch(string(out))
	s, err := strconv.Atoi(m[1])
	if err != nil {
		return 0
	}
	return float64(s)
}
<commit_msg>devicescale: Bug fix: Base-scale should be multiplied on Cinnamon<commit_after>// Copyright 2020 The Ebiten Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

// +build dragonfly freebsd linux netbsd openbsd solaris
// +build !js
// +build !android

package devicescale

import (
	"encoding/xml"
	"os"
	"os/exec"
	"path/filepath"
	"strconv"
)

type xmlBool bool

func (b *xmlBool) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error {
	var s string
	if err := d.DecodeElement(&s, &start); err != nil {
		return err
	}
	*b = xmlBool(s == "yes")
	return nil
}

func cinnamonScaleFromXML() (float64, error) {
	type cinnamonMonitors struct {
		XMLName       xml.Name `xml:"monitors"`
		Version       string   `xml:"version,attr"`
		Configuration []struct {
			BaseScale float64 `xml:"base_scale"`
			Output    []struct {
				Scale   float64 `xml:"scale"`
				Primary xmlBool `xml:"primary"`
			} `xml:"output"`
		} `xml:"configuration"`
	}

	home, err := os.UserHomeDir()
	if err != nil {
		return 0, err
	}
	f, err := os.Open(filepath.Join(home, ".config", "cinnamon-monitors.xml"))
	if err != nil {
		return 0, err
	}
	defer f.Close()

	d := xml.NewDecoder(f)

	var monitors cinnamonMonitors
	if err = d.Decode(&monitors); err != nil {
		return 0, err
	}

	// TODO: Choose the correct configuration.
	c := monitors.Configuration[0]
	for _, v := range c.Output {
		// TODO: Get the monitor at the specified position.
		if v.Primary && v.Scale != 0.0 {
			return c.BaseScale * v.Scale, nil
		}
	}
	return c.BaseScale, nil
}

func cinnamonScale() float64 {
	if s, err := cinnamonScaleFromXML(); err == nil && s > 0 {
		return s
	}

	out, err := exec.Command("gsettings", "get", "org.cinnamon.desktop.interface", "scaling-factor").Output()
	if err != nil {
		if err == exec.ErrNotFound {
			return 0
		}
		if _, ok := err.(*exec.ExitError); ok {
			return 0
		}
		panic(err)
	}
	m := gsettingsRe.FindStringSubmatch(string(out))
	s, err := strconv.Atoi(m[1])
	if err != nil {
		return 0
	}
	return float64(s)
}
<|endoftext|>