<commit_before>package driver

import (
	"fmt"
	"github.com/hashicorp/nomad/client/config"
	"github.com/hashicorp/nomad/nomad/structs"
	lxc "gopkg.in/lxc/go-lxc.v2"
	"log"
)

type LXCDriver struct {
	DriverContext
}

type lxcHandle struct {
	logger *log.Logger
	Name   string
	waitCh chan error
	doneCh chan struct{}
}

func NewLXCDriver(ctx *DriverContext) Driver {
	return &LXCDriver{*ctx}
}

func (d *LXCDriver) Fingerprint(cfg *config.Config, node *structs.Node) (bool, error) {
	node.Attributes["driver.lxc.version"] = lxc.Version()
	node.Attributes["driver.lxc"] = "1"
	d.logger.Printf("[DEBUG] lxc.version: %s", node.Attributes["lxc.version"])
	return true, nil
}

func (d *LXCDriver) Start(ctx *ExecContext, task *structs.Task) (DriverHandle, error) {
	var lxcpath = lxc.DefaultConfigPath()
	path, ok := task.Config["lxcpath"]
	if ok && path != "" {
		lxcpath = path
	}
	d.logger.Printf("[DEBUG] Using lxcpath: %s", lxcpath)
	name, ok := task.Config["name"]
	if !ok || name == "" {
		return nil, fmt.Errorf("Missing container name for lxc driver")
	}
	d.logger.Printf("[DEBUG] Using lxc name: %s", name)
	template, ok := task.Config["template"]
	if !ok || template == "" {
		return nil, fmt.Errorf("Missing template name for lxc driver")
	}
	d.logger.Printf("[DEBUG] Using lxc template: %s", template)
	distro, ok := task.Config["distro"]
	if !ok || distro == "" {
		return nil, fmt.Errorf("Missing distro name for lxc driver")
	}
	d.logger.Printf("[DEBUG] Using lxc templare option, distro: %s", distro)
	release, ok := task.Config["release"]
	if !ok || release == "" {
		return nil, fmt.Errorf("Missing release name for lxc driver")
	}
	d.logger.Printf("[DEBUG] Using lxc templare option, release: %s", release)
	arch, ok := task.Config["arch"]
	if !ok || arch == "" {
		return nil, fmt.Errorf("Missing arch name for lxc driver")
	}
	d.logger.Printf("[DEBUG] Using lxc templare option, arch: %s", arch)
	options := lxc.TemplateOptions{
		Template:             template,
		Distro:               distro,
		Release:              release,
		Arch:                 arch,
		FlushCache:           false,
		DisableGPGValidation: false,
	}
	c, err := lxc.NewContainer(name, lxcpath)
	if err != nil {
		d.logger.Printf("[WARN] Failed to initialize container object %s", err)
		return nil, err
	}
	if err := c.Create(options); err != nil {
		d.logger.Printf("[WARN] Failed to create container %s", err)
		return nil, err
	}
	if err := c.Start(); err != nil {
		d.logger.Printf("[WARN] Failed to start container %s", err)
		return nil, err
	}
	h := &lxcHandle{
		Name:   name,
		logger: d.logger,
		doneCh: make(chan struct{}),
		waitCh: make(chan error, 1),
	}
	return h, nil
}

func (d *LXCDriver) Open(ctx *ExecContext, name string) (DriverHandle, error) {
	lxcpath := lxc.DefaultConfigPath()
	c, err := lxc.NewContainer(name, lxcpath)
	if err != nil {
		d.logger.Printf("[WARN] Failed to start container %s", err)
		return nil, err
	}
	if err := c.Start(); err != nil {
		d.logger.Printf("[WARN] Failed to start container %s", err)
		return nil, err
	}
	h := &lxcHandle{
		Name:   name,
		logger: d.logger,
		doneCh: make(chan struct{}),
		waitCh: make(chan error, 1),
	}
	if err := c.Start(); err != nil {
		return nil, err
	}
	return h, nil
}

func (h *lxcHandle) ID() string {
	return h.Name
}

func (h *lxcHandle) WaitCh() chan error {
	return h.waitCh
}

func (h *lxcHandle) Kill() error {
	lxcpath := lxc.DefaultConfigPath()
	c, err := lxc.NewContainer(h.Name, lxcpath)
	if err != nil {
		h.logger.Printf("[WARN] Failed to initialize container %s", err)
		return err
	}
	if err := c.Stop(); err != nil {
		h.logger.Printf("[WARN] Failed to stop container %s", err)
		return err
	}
	if err := c.Destroy(); err != nil {
		h.logger.Printf("[WARN] Failed to destroy container %s", err)
		return err
	}
	return nil
}

func (h *lxcHandle) Update(task *structs.Task) error {
	return fmt.Errorf("Update is not supported by lxc driver")
}
<commit_msg>dont try to stop non existing container<commit_after>package driver

import (
	"fmt"
	"github.com/hashicorp/nomad/client/config"
	"github.com/hashicorp/nomad/nomad/structs"
	lxc "gopkg.in/lxc/go-lxc.v2"
	"log"
)

type LXCDriver struct {
	DriverContext
}

type lxcHandle struct {
	logger *log.Logger
	Name   string
	waitCh chan error
	doneCh chan struct{}
}

func NewLXCDriver(ctx *DriverContext) Driver {
	return &LXCDriver{*ctx}
}

func (d *LXCDriver) Fingerprint(cfg *config.Config, node *structs.Node) (bool, error) {
	node.Attributes["driver.lxc.version"] = lxc.Version()
	node.Attributes["driver.lxc"] = "1"
	d.logger.Printf("[DEBUG] lxc.version: %s", node.Attributes["lxc.version"])
	return true, nil
}

func (d *LXCDriver) Start(ctx *ExecContext, task *structs.Task) (DriverHandle, error) {
	var lxcpath = lxc.DefaultConfigPath()
	path, ok := task.Config["lxcpath"]
	if ok && path != "" {
		lxcpath = path
	}
	d.logger.Printf("[DEBUG] Using lxcpath: %s", lxcpath)
	name, ok := task.Config["name"]
	if !ok || name == "" {
		return nil, fmt.Errorf("Missing container name for lxc driver")
	}
	d.logger.Printf("[DEBUG] Using lxc name: %s", name)
	template, ok := task.Config["template"]
	if !ok || template == "" {
		return nil, fmt.Errorf("Missing template name for lxc driver")
	}
	d.logger.Printf("[DEBUG] Using lxc template: %s", template)
	distro, ok := task.Config["distro"]
	if !ok || distro == "" {
		return nil, fmt.Errorf("Missing distro name for lxc driver")
	}
	d.logger.Printf("[DEBUG] Using lxc templare option, distro: %s", distro)
	release, ok := task.Config["release"]
	if !ok || release == "" {
		return nil, fmt.Errorf("Missing release name for lxc driver")
	}
	d.logger.Printf("[DEBUG] Using lxc templare option, release: %s", release)
	arch, ok := task.Config["arch"]
	if !ok || arch == "" {
		return nil, fmt.Errorf("Missing arch name for lxc driver")
	}
	d.logger.Printf("[DEBUG] Using lxc templare option, arch: %s", arch)
	options := lxc.TemplateOptions{
		Template:             template,
		Distro:               distro,
		Release:              release,
		Arch:                 arch,
		FlushCache:           false,
		DisableGPGValidation: false,
	}
	c, err := lxc.NewContainer(name, lxcpath)
	if err != nil {
		d.logger.Printf("[WARN] Failed to initialize container object %s", err)
		return nil, err
	}
	if err := c.Create(options); err != nil {
		d.logger.Printf("[WARN] Failed to create container %s", err)
		return nil, err
	}
	if err := c.Start(); err != nil {
		d.logger.Printf("[WARN] Failed to start container %s", err)
		return nil, err
	}
	h := &lxcHandle{
		Name:   name,
		logger: d.logger,
		doneCh: make(chan struct{}),
		waitCh: make(chan error, 1),
	}
	return h, nil
}

func (d *LXCDriver) Open(ctx *ExecContext, name string) (DriverHandle, error) {
	lxcpath := lxc.DefaultConfigPath()
	c, err := lxc.NewContainer(name, lxcpath)
	if err != nil {
		d.logger.Printf("[WARN] Failed to start container %s", err)
		return nil, err
	}
	if err := c.Start(); err != nil {
		d.logger.Printf("[WARN] Failed to start container %s", err)
		return nil, err
	}
	h := &lxcHandle{
		Name:   name,
		logger: d.logger,
		doneCh: make(chan struct{}),
		waitCh: make(chan error, 1),
	}
	if err := c.Start(); err != nil {
		return nil, err
	}
	return h, nil
}

func (h *lxcHandle) ID() string {
	return h.Name
}

func (h *lxcHandle) WaitCh() chan error {
	return h.waitCh
}

func (h *lxcHandle) Kill() error {
	lxcpath := lxc.DefaultConfigPath()
	c, err := lxc.NewContainer(h.Name, lxcpath)
	if err != nil {
		h.logger.Printf("[WARN] Failed to initialize container %s", err)
		return err
	}
	if c.Defined() {
		if c.State() == lxc.RUNNING {
			if err := c.Stop(); err != nil {
				h.logger.Printf("[WARN] Failed to stop container %s", err)
				return err
			}
		} else {
			h.logger.Println("[WARN] Container is not running. Skipping stop call")

		}
		if err := c.Destroy(); err != nil {
			h.logger.Printf("[WARN] Failed to destroy container %s", err)
			return err
		}
	} else {
		h.logger.Println("[WARN] Cant kill non-existent container")
	}

	return nil
}

func (h *lxcHandle) Update(task *structs.Task) error {
	return fmt.Errorf("Update is not supported by lxc driver")
}
<|endoftext|>


<commit_before>package file

import (
	"context"
	"encoding/json"
	"errors"
	"fmt"
	"log"
	"os"
	"time"
	"golang.org/x/sync/semaphore"

	"github.com/karimra/gnmic/collector"
	"github.com/karimra/gnmic/formatters"
	"github.com/karimra/gnmic/outputs"
	"github.com/prometheus/client_golang/prometheus"
	"google.golang.org/protobuf/proto"
)

const (
	defaultFormat           = "json"
	defaultWriteConcurrency = 1000
	defaultSeparator        = "\n"
)

func init() {
	outputs.Register("file", func() outputs.Output {
		return &File{
			Cfg: &Config{},
			metrics: []prometheus.Collector{
				NumberOfWrittenBytes,
				NumberOfReceivedMsgs,
				NumberOfWrittenMsgs,
			},
		}
	})
}

// File //
type File struct {
	Cfg     *Config
	file    *os.File
	logger  *log.Logger
	metrics []prometheus.Collector
	mo      *collector.MarshalOptions
	sem     *semaphore.Weighted
	evps    []formatters.EventProcessor
}

// Config //
type Config struct {
	FileName        string   `mapstructure:"filename,omitempty"`
	FileType        string   `mapstructure:"file-type,omitempty"`
	Format          string   `mapstructure:"format,omitempty"`
	Multiline       bool     `mapstructure:"multiline,omitempty"`
	Indent          string   `mapstructure:"indent,omitempty"`
	Separator       string   `mapstructure:"separator,omitempty"`
	EventProcessors []string `mapstructure:"event-processors,omitempty"`
  ConcurrencyLimit int    `mapstructure:"concurrency-limit,omitempty"`
}

func (f *File) String() string {
	b, err := json.Marshal(f)
	if err != nil {
		return ""
	}
	return string(b)
}

func (f *File) SetEventProcessors(ps map[string]map[string]interface{}, log *log.Logger) {
	for _, epName := range f.Cfg.EventProcessors {
		if epCfg, ok := ps[epName]; ok {
			epType := ""
			for k := range epCfg {
				epType = k
				break
			}
			if in, ok := formatters.EventProcessors[epType]; ok {
				ep := in()
				err := ep.Init(epCfg[epType], log)
				if err != nil {
					f.logger.Printf("failed initializing event processor '%s' of type='%s': %v", epName, epType, err)
					continue
				}
				f.evps = append(f.evps, ep)
				f.logger.Printf("added event processor '%s' of type=%s to file output", epName, epType)
			}
		}
	}
}

func (f *File) SetLogger(logger *log.Logger) {
	if logger != nil {
		f.logger = log.New(logger.Writer(), "file_output ", logger.Flags())
		return
	}
	f.logger = log.New(os.Stderr, "file_output ", log.LstdFlags|log.Lmicroseconds)
}

// Init //
func (f *File) Init(ctx context.Context, cfg map[string]interface{}, opts ...outputs.Option) error {
	err := outputs.DecodeConfig(cfg, f.Cfg)
	if err != nil {
		f.logger.Printf("file output config decode failed: %v", err)
		return err
	}
	for _, opt := range opts {
		opt(f)
	}
	if f.Cfg.Format == "proto" {
		f.logger.Printf("proto format not supported in output type 'file'")
		return fmt.Errorf("proto format not supported in output type 'file'")
	}
	if f.Cfg.Separator == "" {
		f.Cfg.Separator = defaultSeparator
	}
	if f.Cfg.FileName == "" && f.Cfg.FileType == "" {
		f.Cfg.FileType = "stdout"
	}
	switch f.Cfg.FileType {
	case "stdout":
		f.file = os.Stdout
	case "stderr":
		f.file = os.Stderr
	default:
	CRFILE:
		f.file, err = os.OpenFile(f.Cfg.FileName, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666)
		if err != nil {
			f.logger.Printf("failed to create file: %v", err)
			time.Sleep(10 * time.Second)
			goto CRFILE
		}
	}

	if f.Cfg.Format == "" {
		f.Cfg.Format = defaultFormat
	}
	if f.Cfg.FileType == "stdout" || f.Cfg.FileType == "stderr" {
		f.Cfg.Indent = "  "
		f.Cfg.Multiline = true
	}
	if f.Cfg.Multiline && f.Cfg.Indent == "" {
		f.Cfg.Indent = "  "
	}
	if f.Cfg.ConcurrencyLimit < 1 {
		f.Cfg.ConcurrencyLimit = defaultWriteConcurrency
	}

	f.sem = semaphore.NewWeighted(int64(f.Cfg.ConcurrencyLimit))

	f.mo = &formatters.MarshalOptions{Multiline: f.Cfg.Multiline, Indent: f.Cfg.Indent, Format: f.Cfg.Format}

	f.logger.Printf("initialized file output: %s", f.String())
	go func() {
		<-ctx.Done()
		f.Close()
	}()
	return nil
}

// Write //
func (f *File) Write(ctx context.Context, rsp proto.Message, meta outputs.Meta) {
	err := f.sem.Acquire(ctx, 1)
	if errors.Is(err, context.Canceled) {
		return
	}

	if err != nil {
		f.logger.Printf("failed marshaling proto msg: %v", err)
		return
	}
	defer f.sem.Release(1)

	if rsp == nil {
		return
	}
	NumberOfReceivedMsgs.WithLabelValues(f.file.Name()).Inc()
	b, err := f.mo.Marshal(rsp, meta, f.evps...)
	if err != nil {
		f.logger.Printf("failed marshaling proto msg: %v", err)
		return
	}
	n, err := f.file.Write(append(b, []byte(f.Cfg.Separator)...))
	if err != nil {
		f.logger.Printf("failed to write to file '%s': %v", f.file.Name(), err)
		return
	}
	NumberOfWrittenBytes.WithLabelValues(f.file.Name()).Add(float64(n))
	NumberOfWrittenMsgs.WithLabelValues(f.file.Name()).Inc()
}

// Close //
func (f *File) Close() error {
	f.logger.Printf("closing file '%s' output", f.file.Name())
	return f.file.Close()
}

// Metrics //
func (f *File) Metrics() []prometheus.Collector { return f.metrics }
<commit_msg>fix import<commit_after>package file

import (
	"context"
	"encoding/json"
	"errors"
	"fmt"
	"log"
	"os"
	"time"

	"golang.org/x/sync/semaphore"

	"github.com/karimra/gnmic/formatters"
	"github.com/karimra/gnmic/outputs"
	"github.com/prometheus/client_golang/prometheus"
	"google.golang.org/protobuf/proto"
)

const (
	defaultFormat           = "json"
	defaultWriteConcurrency = 1000
	defaultSeparator        = "\n"
)

func init() {
	outputs.Register("file", func() outputs.Output {
		return &File{
			Cfg: &Config{},
			metrics: []prometheus.Collector{
				NumberOfWrittenBytes,
				NumberOfReceivedMsgs,
				NumberOfWrittenMsgs,
			},
		}
	})
}

// File //
type File struct {
	Cfg     *Config
	file    *os.File
	logger  *log.Logger
	metrics []prometheus.Collector
	mo      *formatters.MarshalOptions
	sem     *semaphore.Weighted
	evps    []formatters.EventProcessor
}

// Config //
type Config struct {
	FileName         string   `mapstructure:"filename,omitempty"`
	FileType         string   `mapstructure:"file-type,omitempty"`
	Format           string   `mapstructure:"format,omitempty"`
	Multiline        bool     `mapstructure:"multiline,omitempty"`
	Indent           string   `mapstructure:"indent,omitempty"`
	Separator        string   `mapstructure:"separator,omitempty"`
	EventProcessors  []string `mapstructure:"event-processors,omitempty"`
	ConcurrencyLimit int      `mapstructure:"concurrency-limit,omitempty"`
}

func (f *File) String() string {
	b, err := json.Marshal(f)
	if err != nil {
		return ""
	}
	return string(b)
}

func (f *File) SetEventProcessors(ps map[string]map[string]interface{}, log *log.Logger) {
	for _, epName := range f.Cfg.EventProcessors {
		if epCfg, ok := ps[epName]; ok {
			epType := ""
			for k := range epCfg {
				epType = k
				break
			}
			if in, ok := formatters.EventProcessors[epType]; ok {
				ep := in()
				err := ep.Init(epCfg[epType], log)
				if err != nil {
					f.logger.Printf("failed initializing event processor '%s' of type='%s': %v", epName, epType, err)
					continue
				}
				f.evps = append(f.evps, ep)
				f.logger.Printf("added event processor '%s' of type=%s to file output", epName, epType)
			}
		}
	}
}

func (f *File) SetLogger(logger *log.Logger) {
	if logger != nil {
		f.logger = log.New(logger.Writer(), "file_output ", logger.Flags())
		return
	}
	f.logger = log.New(os.Stderr, "file_output ", log.LstdFlags|log.Lmicroseconds)
}

// Init //
func (f *File) Init(ctx context.Context, cfg map[string]interface{}, opts ...outputs.Option) error {
	err := outputs.DecodeConfig(cfg, f.Cfg)
	if err != nil {
		f.logger.Printf("file output config decode failed: %v", err)
		return err
	}
	for _, opt := range opts {
		opt(f)
	}
	if f.Cfg.Format == "proto" {
		f.logger.Printf("proto format not supported in output type 'file'")
		return fmt.Errorf("proto format not supported in output type 'file'")
	}
	if f.Cfg.Separator == "" {
		f.Cfg.Separator = defaultSeparator
	}
	if f.Cfg.FileName == "" && f.Cfg.FileType == "" {
		f.Cfg.FileType = "stdout"
	}
	switch f.Cfg.FileType {
	case "stdout":
		f.file = os.Stdout
	case "stderr":
		f.file = os.Stderr
	default:
	CRFILE:
		f.file, err = os.OpenFile(f.Cfg.FileName, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666)
		if err != nil {
			f.logger.Printf("failed to create file: %v", err)
			time.Sleep(10 * time.Second)
			goto CRFILE
		}
	}

	if f.Cfg.Format == "" {
		f.Cfg.Format = defaultFormat
	}
	if f.Cfg.FileType == "stdout" || f.Cfg.FileType == "stderr" {
		f.Cfg.Indent = "  "
		f.Cfg.Multiline = true
	}
	if f.Cfg.Multiline && f.Cfg.Indent == "" {
		f.Cfg.Indent = "  "
	}
	if f.Cfg.ConcurrencyLimit < 1 {
		f.Cfg.ConcurrencyLimit = defaultWriteConcurrency
	}

	f.sem = semaphore.NewWeighted(int64(f.Cfg.ConcurrencyLimit))

	f.mo = &formatters.MarshalOptions{Multiline: f.Cfg.Multiline, Indent: f.Cfg.Indent, Format: f.Cfg.Format}

	f.logger.Printf("initialized file output: %s", f.String())
	go func() {
		<-ctx.Done()
		f.Close()
	}()
	return nil
}

// Write //
func (f *File) Write(ctx context.Context, rsp proto.Message, meta outputs.Meta) {
	err := f.sem.Acquire(ctx, 1)
	if errors.Is(err, context.Canceled) {
		return
	}

	if err != nil {
		f.logger.Printf("failed marshaling proto msg: %v", err)
		return
	}
	defer f.sem.Release(1)

	if rsp == nil {
		return
	}
	NumberOfReceivedMsgs.WithLabelValues(f.file.Name()).Inc()
	b, err := f.mo.Marshal(rsp, meta, f.evps...)
	if err != nil {
		f.logger.Printf("failed marshaling proto msg: %v", err)
		return
	}
	n, err := f.file.Write(append(b, []byte(f.Cfg.Separator)...))
	if err != nil {
		f.logger.Printf("failed to write to file '%s': %v", f.file.Name(), err)
		return
	}
	NumberOfWrittenBytes.WithLabelValues(f.file.Name()).Add(float64(n))
	NumberOfWrittenMsgs.WithLabelValues(f.file.Name()).Inc()
}

// Close //
func (f *File) Close() error {
	f.logger.Printf("closing file '%s' output", f.file.Name())
	return f.file.Close()
}

// Metrics //
func (f *File) Metrics() []prometheus.Collector { return f.metrics }
<|endoftext|>


<commit_before>package app

import (
	"time"

	"github.com/fragmenta/server/config"
	"github.com/kennygrant/gohackernews/src/lib/twitter"
	"github.com/kennygrant/gohackernews/src/stories/actions"
)

// SetupServices sets up external services from our config file
func SetupServices() {

	// Don't send if not on production server
	if !config.Production() {
		return
	}

	now := time.Now().UTC()

	// Set up twitter if available, and schedule tweets
	if config.Get("twitter_secret") != "" {
		twitter.Setup(config.Get("twitter_key"), config.Get("twitter_secret"), config.Get("twitter_token"), config.Get("twitter_token_secret"))

		tweetTime := time.Date(now.Year(), now.Month(), now.Day(), 6, 0, 0, 0, time.UTC)
		tweetInterval := 5 * time.Hour

		// For testing
		//tweetTime = now.Add(time.Second * 5)

		ScheduleAt(storyactions.TweetTopStory, tweetTime, tweetInterval)
	}
	/*
		// Set up mail
		if config.Get("mail_secret") != "" {
			mail.Setup(config.Get("mail_secret"), config.Get("mail_from"))

			// Schedule emails to go out at 09:00 every day, starting from the next occurance
			emailTime := time.Date(now.Year(), now.Month(), now.Day(), 10, 10, 10, 10, time.UTC)
			emailInterval := 7 * 24 * time.Hour // Send Emails weekly

			// For testing send immediately on launch
			//emailTime = now.Add(time.Second * 2)

			schedule.At(useractions.DailyEmail, context, emailTime, emailInterval)
		}
	*/
}

// ScheduleAt schedules execution for a particular time and at intervals thereafter.
// If interval is 0, the function will be called only once.
// Callers should call close(task) before exiting the app or to stop repeating the action.
func ScheduleAt(f func(), t time.Time, i time.Duration) chan struct{} {
	task := make(chan struct{})
	now := time.Now().UTC()

	// Check that t is not in the past, if it is increment it by interval until it is not
	for now.Sub(t) > 0 {
		t = t.Add(i)
	}

	// We ignore the timer returned by AfterFunc - so no cancelling, perhaps rethink this
	tillTime := t.Sub(now)
	time.AfterFunc(tillTime, func() {
		// Call f at least once at the time specified
		go f()

		// If we have an interval, call it again repeatedly after interval
		// stopping if the caller calls stop(task) on returned channel
		if i > 0 {
			ticker := time.NewTicker(i)
			go func() {
				for {
					select {
					case <-ticker.C:
						go f()
					case <-task:
						ticker.Stop()
						return
					}
				}
			}()
		}
	})

	return task // call close(task) to stop executing the task for repeated tasks
}
<commit_msg>Adjust interval to 3 hours<commit_after>package app

import (
	"time"

	"github.com/fragmenta/server/config"
	"github.com/kennygrant/gohackernews/src/lib/twitter"
	"github.com/kennygrant/gohackernews/src/stories/actions"
)

// SetupServices sets up external services from our config file
func SetupServices() {

	// Don't send if not on production server
	if !config.Production() {
		return
	}

	now := time.Now().UTC()

	// Set up twitter if available, and schedule tweets
	if config.Get("twitter_secret") != "" {
		twitter.Setup(config.Get("twitter_key"), config.Get("twitter_secret"), config.Get("twitter_token"), config.Get("twitter_token_secret"))

		tweetTime := time.Date(now.Year(), now.Month(), now.Day(), 6, 0, 0, 0, time.UTC)
		tweetInterval := 51 * 3 * time.Minute

		// For testing
		//tweetTime = now.Add(time.Second * 5)

		ScheduleAt(storyactions.TweetTopStory, tweetTime, tweetInterval)
	}
	/*
		// Set up mail
		if config.Get("mail_secret") != "" {
			mail.Setup(config.Get("mail_secret"), config.Get("mail_from"))

			// Schedule emails to go out at 09:00 every day, starting from the next occurance
			emailTime := time.Date(now.Year(), now.Month(), now.Day(), 10, 10, 10, 10, time.UTC)
			emailInterval := 7 * 24 * time.Hour // Send Emails weekly

			// For testing send immediately on launch
			//emailTime = now.Add(time.Second * 2)

			schedule.At(useractions.DailyEmail, context, emailTime, emailInterval)
		}
	*/
}

// ScheduleAt schedules execution for a particular time and at intervals thereafter.
// If interval is 0, the function will be called only once.
// Callers should call close(task) before exiting the app or to stop repeating the action.
func ScheduleAt(f func(), t time.Time, i time.Duration) chan struct{} {
	task := make(chan struct{})
	now := time.Now().UTC()

	// Check that t is not in the past, if it is increment it by interval until it is not
	for now.Sub(t) > 0 {
		t = t.Add(i)
	}

	// We ignore the timer returned by AfterFunc - so no cancelling, perhaps rethink this
	tillTime := t.Sub(now)
	time.AfterFunc(tillTime, func() {
		// Call f at least once at the time specified
		go f()

		// If we have an interval, call it again repeatedly after interval
		// stopping if the caller calls stop(task) on returned channel
		if i > 0 {
			ticker := time.NewTicker(i)
			go func() {
				for {
					select {
					case <-ticker.C:
						go f()
					case <-task:
						ticker.Stop()
						return
					}
				}
			}()
		}
	})

	return task // call close(task) to stop executing the task for repeated tasks
}
<|endoftext|>


<commit_before>package lxd

import (
	"encoding/json"
	"fmt"
	"sync"

	"github.com/gorilla/websocket"

	"github.com/lxc/lxd/shared/api"
)

// The Operation type represents an ongoing LXD operation (asynchronous processing)
type Operation struct {
	api.Operation

	r            *ProtocolLXD
	listener     *EventListener
	handlerReady bool
	handlerLock  sync.Mutex

	chActive chan bool
}

// AddHandler adds a function to be called whenever an event is received
func (op *Operation) AddHandler(function func(api.Operation)) (*EventTarget, error) {
	// Make sure we have a listener setup
	err := op.setupListener()
	if err != nil {
		return nil, err
	}

	// Make sure we're not racing with ourselves
	op.handlerLock.Lock()
	defer op.handlerLock.Unlock()

	// If we're done already, just return
	if op.StatusCode.IsFinal() {
		return nil, nil
	}

	// Wrap the function to filter unwanted messages
	wrapped := func(data interface{}) {
		newOp := op.extractOperation(data)
		if newOp == nil {
			return
		}

		function(*newOp)
	}

	return op.listener.AddHandler([]string{"operation"}, wrapped)
}

// Cancel will request that LXD cancels the operation (if supported)
func (op *Operation) Cancel() error {
	return op.r.DeleteOperation(op.ID)
}

// GetWebsocket returns a raw websocket connection from the operation
func (op *Operation) GetWebsocket(secret string) (*websocket.Conn, error) {
	return op.r.GetOperationWebsocket(op.ID, secret)
}

// RemoveHandler removes a function to be called whenever an event is received
func (op *Operation) RemoveHandler(target *EventTarget) error {
	// Make sure we're not racing with ourselves
	op.handlerLock.Lock()
	defer op.handlerLock.Unlock()

	// If the listener is gone, just return
	if op.listener == nil {
		return nil
	}

	return op.listener.RemoveHandler(target)
}

// Refresh pulls the current version of the operation and updates the struct
func (op *Operation) Refresh() error {
	// Don't bother with a manual update if we are listening for events
	if op.handlerReady {
		return nil
	}

	// Get the current version of the operation
	newOp, _, err := op.r.GetOperation(op.ID)
	if err != nil {
		return err
	}

	// Update the operation struct
	op.Operation = *newOp

	return nil
}

// Wait lets you wait until the operation reaches a final state
func (op *Operation) Wait() error {
	// Check if not done already
	if op.StatusCode.IsFinal() {
		if op.Err != "" {
			return fmt.Errorf(op.Err)
		}

		return nil
	}

	// Make sure we have a listener setup
	err := op.setupListener()
	if err != nil {
		return err
	}

	<-op.chActive

	// We're done, parse the result
	if op.Err != "" {
		return fmt.Errorf(op.Err)
	}

	return nil
}

func (op *Operation) setupListener() error {
	// Make sure we're not racing with ourselves
	op.handlerLock.Lock()
	defer op.handlerLock.Unlock()

	// We already have a listener setup
	if op.handlerReady {
		return nil
	}

	// Get a new listener
	if op.listener == nil {
		listener, err := op.r.GetEvents()
		if err != nil {
			return err
		}

		op.listener = listener
	}

	// Setup the handler
	chReady := make(chan bool)
	_, err := op.listener.AddHandler([]string{"operation"}, func(data interface{}) {
		<-chReady

		// Get an operation struct out of this data
		newOp := op.extractOperation(data)
		if newOp == nil {
			return
		}

		// We don't want concurrency while processing events
		op.handlerLock.Lock()
		defer op.handlerLock.Unlock()

		// Check if we're done already (because of another event)
		if op.listener == nil {
			return
		}

		// Update the struct
		op.Operation = *newOp

		// And check if we're done
		if op.StatusCode.IsFinal() {
			op.listener.Disconnect()
			op.listener = nil
			close(op.chActive)
			return
		}
	})
	if err != nil {
		op.listener.Disconnect()
		return err
	}

	// And do a manual refresh to avoid races
	err = op.Refresh()
	if err != nil {
		op.listener.Disconnect()
		return err
	}

	// Check if not done already
	if op.StatusCode.IsFinal() {
		op.listener.Disconnect()
		close(op.chActive)

		if op.Err != "" {
			return fmt.Errorf(op.Err)
		}

		return nil
	}

	// Start processing background updates
	op.handlerReady = true
	close(chReady)

	return nil
}

func (op *Operation) extractOperation(data interface{}) *api.Operation {
	// Extract the metadata
	meta, ok := data.(map[string]interface{})["metadata"]
	if !ok {
		return nil
	}

	// And attempt to decode it as JSON operation data
	encoded, err := json.Marshal(meta)
	if err != nil {
		return nil
	}

	newOp := api.Operation{}
	err = json.Unmarshal(encoded, &newOp)
	if err != nil {
		return nil
	}

	// And now check that it's what we want
	if newOp.ID != op.ID {
		return nil
	}

	return &newOp
}

// The RemoteOperation type represents an ongoing LXD operation between two servers
type RemoteOperation struct {
	targetOp *Operation

	handlers []func(api.Operation)

	chDone chan bool
	chPost chan bool
	err    error
}

// AddHandler adds a function to be called whenever an event is received
func (op *RemoteOperation) AddHandler(function func(api.Operation)) (*EventTarget, error) {
	var err error
	var target *EventTarget

	// Attach to the existing target operation
	if op.targetOp != nil {
		target, err = op.targetOp.AddHandler(function)
		if err != nil {
			return nil, err
		}
	} else {
		// Generate a mock EventTarget
		target = &EventTarget{
			function: func(interface{}) { function(api.Operation{}) },
			types:    []string{"operation"},
		}
	}

	// Add the handler to our list
	op.handlers = append(op.handlers, function)

	return target, nil
}

// CancelTarget attempts to cancel the target operation
func (op *RemoteOperation) CancelTarget() error {
	if op.targetOp == nil {
		return fmt.Errorf("No associated target operation")
	}

	return op.targetOp.Cancel()
}

// GetTarget returns the target operation
func (op *RemoteOperation) GetTarget() (*api.Operation, error) {
	if op.targetOp == nil {
		return nil, fmt.Errorf("No associated target operation")
	}

	return &op.targetOp.Operation, nil
}

// Wait lets you wait until the operation reaches a final state
func (op *RemoteOperation) Wait() error {
	<-op.chDone

	if op.chPost != nil {
		<-op.chPost
	}

	return op.err
}
<commit_msg>client: Fix race condition in operation handling<commit_after>package lxd

import (
	"encoding/json"
	"fmt"
	"sync"

	"github.com/gorilla/websocket"

	"github.com/lxc/lxd/shared/api"
)

// The Operation type represents an ongoing LXD operation (asynchronous processing)
type Operation struct {
	api.Operation

	r            *ProtocolLXD
	listener     *EventListener
	handlerReady bool
	handlerLock  sync.Mutex

	chActive chan bool
}

// AddHandler adds a function to be called whenever an event is received
func (op *Operation) AddHandler(function func(api.Operation)) (*EventTarget, error) {
	// Make sure we have a listener setup
	err := op.setupListener()
	if err != nil {
		return nil, err
	}

	// Make sure we're not racing with ourselves
	op.handlerLock.Lock()
	defer op.handlerLock.Unlock()

	// If we're done already, just return
	if op.StatusCode.IsFinal() {
		return nil, nil
	}

	// Wrap the function to filter unwanted messages
	wrapped := func(data interface{}) {
		newOp := op.extractOperation(data)
		if newOp == nil {
			return
		}

		function(*newOp)
	}

	return op.listener.AddHandler([]string{"operation"}, wrapped)
}

// Cancel will request that LXD cancels the operation (if supported)
func (op *Operation) Cancel() error {
	return op.r.DeleteOperation(op.ID)
}

// GetWebsocket returns a raw websocket connection from the operation
func (op *Operation) GetWebsocket(secret string) (*websocket.Conn, error) {
	return op.r.GetOperationWebsocket(op.ID, secret)
}

// RemoveHandler removes a function to be called whenever an event is received
func (op *Operation) RemoveHandler(target *EventTarget) error {
	// Make sure we're not racing with ourselves
	op.handlerLock.Lock()
	defer op.handlerLock.Unlock()

	// If the listener is gone, just return
	if op.listener == nil {
		return nil
	}

	return op.listener.RemoveHandler(target)
}

// Refresh pulls the current version of the operation and updates the struct
func (op *Operation) Refresh() error {
	// Don't bother with a manual update if we are listening for events
	if op.handlerReady {
		return nil
	}

	// Get the current version of the operation
	newOp, _, err := op.r.GetOperation(op.ID)
	if err != nil {
		return err
	}

	// Update the operation struct
	op.Operation = *newOp

	return nil
}

// Wait lets you wait until the operation reaches a final state
func (op *Operation) Wait() error {
	// Check if not done already
	if op.StatusCode.IsFinal() {
		if op.Err != "" {
			return fmt.Errorf(op.Err)
		}

		return nil
	}

	// Make sure we have a listener setup
	err := op.setupListener()
	if err != nil {
		return err
	}

	<-op.chActive

	// We're done, parse the result
	if op.Err != "" {
		return fmt.Errorf(op.Err)
	}

	return nil
}

func (op *Operation) setupListener() error {
	// Make sure we're not racing with ourselves
	op.handlerLock.Lock()
	defer op.handlerLock.Unlock()

	// We already have a listener setup
	if op.handlerReady {
		return nil
	}

	// Get a new listener
	if op.listener == nil {
		listener, err := op.r.GetEvents()
		if err != nil {
			return err
		}

		op.listener = listener
	}

	// Setup the handler
	chReady := make(chan bool)
	_, err := op.listener.AddHandler([]string{"operation"}, func(data interface{}) {
		<-chReady

		// Get an operation struct out of this data
		newOp := op.extractOperation(data)
		if newOp == nil {
			return
		}

		// We don't want concurrency while processing events
		op.handlerLock.Lock()
		defer op.handlerLock.Unlock()

		// Check if we're done already (because of another event)
		if op.listener == nil {
			return
		}

		// Update the struct
		op.Operation = *newOp

		// And check if we're done
		if op.StatusCode.IsFinal() {
			op.listener.Disconnect()
			op.listener = nil
			close(op.chActive)
			return
		}
	})
	if err != nil {
		op.listener.Disconnect()
		op.listener = nil
		close(op.chActive)
		close(chReady)

		return err
	}

	// And do a manual refresh to avoid races
	err = op.Refresh()
	if err != nil {
		op.listener.Disconnect()
		op.listener = nil
		close(op.chActive)
		close(chReady)

		return err
	}

	// Check if not done already
	if op.StatusCode.IsFinal() {
		op.listener.Disconnect()
		op.listener = nil
		close(op.chActive)

		op.handlerReady = true
		close(chReady)

		if op.Err != "" {
			return fmt.Errorf(op.Err)
		}

		return nil
	}

	// Start processing background updates
	op.handlerReady = true
	close(chReady)

	return nil
}

func (op *Operation) extractOperation(data interface{}) *api.Operation {
	// Extract the metadata
	meta, ok := data.(map[string]interface{})["metadata"]
	if !ok {
		return nil
	}

	// And attempt to decode it as JSON operation data
	encoded, err := json.Marshal(meta)
	if err != nil {
		return nil
	}

	newOp := api.Operation{}
	err = json.Unmarshal(encoded, &newOp)
	if err != nil {
		return nil
	}

	// And now check that it's what we want
	if newOp.ID != op.ID {
		return nil
	}

	return &newOp
}

// The RemoteOperation type represents an ongoing LXD operation between two servers
type RemoteOperation struct {
	targetOp *Operation

	handlers []func(api.Operation)

	chDone chan bool
	chPost chan bool
	err    error
}

// AddHandler adds a function to be called whenever an event is received
func (op *RemoteOperation) AddHandler(function func(api.Operation)) (*EventTarget, error) {
	var err error
	var target *EventTarget

	// Attach to the existing target operation
	if op.targetOp != nil {
		target, err = op.targetOp.AddHandler(function)
		if err != nil {
			return nil, err
		}
	} else {
		// Generate a mock EventTarget
		target = &EventTarget{
			function: func(interface{}) { function(api.Operation{}) },
			types:    []string{"operation"},
		}
	}

	// Add the handler to our list
	op.handlers = append(op.handlers, function)

	return target, nil
}

// CancelTarget attempts to cancel the target operation
func (op *RemoteOperation) CancelTarget() error {
	if op.targetOp == nil {
		return fmt.Errorf("No associated target operation")
	}

	return op.targetOp.Cancel()
}

// GetTarget returns the target operation
func (op *RemoteOperation) GetTarget() (*api.Operation, error) {
	if op.targetOp == nil {
		return nil, fmt.Errorf("No associated target operation")
	}

	return &op.targetOp.Operation, nil
}

// Wait lets you wait until the operation reaches a final state
func (op *RemoteOperation) Wait() error {
	<-op.chDone

	if op.chPost != nil {
		<-op.chPost
	}

	return op.err
}
<|endoftext|>


<commit_before>package seccomp

import (
	"bytes"
	"encoding/json"
	"flag"
	"fmt"
	"github.com/subgraph/oz"
	"github.com/subgraph/oz/fs"
	"golang.org/x/sys/unix"
	"io"
	"os"
	"os/exec"
	"os/user"
	"path"
	"syscall"
)

// #include "sys/ptrace.h"
import "C"

const (
	STRINGARG = iota + 1
	PTRARG
	INTARG
)

type SystemCallArgs []int

func Tracer() {

	var train = false
	var cmd string
	var cmdArgs []string
	var p *oz.Profile

	var noprofile = flag.Bool("train", false, "Training mode")
	var debug = flag.Bool("debug", false, "Debug")
	var appendpolicy = flag.Bool("append", false, "Append to existing policy if exists")
	var trainingoutput = flag.String("output", "", "Training policy output file")

	flag.Parse()

	var args = flag.Args()

	if *noprofile == true {
		train = true
		cmd = "/usr/local/bin/oz-seccomp"
		cmdArgs = append([]string{"-mode=train"}, args...)
	} else {
		p = new(oz.Profile)
		if err := json.NewDecoder(os.Stdin).Decode(&p); err != nil {
			log.Error("unable to decode profile data: %v", err)
			os.Exit(1)
		}
		if p.Seccomp.Mode == oz.PROFILE_SECCOMP_TRAIN {
			train = true
		}
		*debug = p.Seccomp.Debug
		cmd = args[0]
		cmdArgs = args[1:]
	}

	var cpid = 0
	done := false

	log.Info("Tracer running command (%v) arguments (%v)\n", cmd, cmdArgs)
	c := exec.Command(cmd)
	c.SysProcAttr = &syscall.SysProcAttr{Ptrace: true}
	c.Env = os.Environ()
	c.Args = append(c.Args, cmdArgs...)

	if *noprofile == false {

		pi, err := c.StdinPipe()
		if err != nil {
			fmt.Errorf("error creating stdin pipe for tracer process: %v", err)
			os.Exit(1)
		}
		jdata, err := json.Marshal(p)
		if err != nil {
			fmt.Errorf("Unable to marshal seccomp state: %+v", err)
			os.Exit(1)
		}
		io.Copy(pi, bytes.NewBuffer(jdata))
		pi.Close()
	}
	children := make(map[int]bool)
	renderFunctions := getRenderingFunctions()

	trainingset := make(map[int]bool)
	trainingargs := make(map[int]map[int][]uint)

	if err := c.Start(); err == nil {
		cpid = c.Process.Pid
		children[c.Process.Pid] = true
		var s syscall.WaitStatus
		pid, err := syscall.Wait4(-1, &s, syscall.WALL, nil)
		children[pid] = true
		if err != nil {
			log.Error("Error (wait4) err:%v pid:%i", err, pid)
		}
		log.Info("Tracing child pid: %v\n", pid)
		for done == false {
			pflags := unix.PTRACE_O_TRACESECCOMP
			pflags |= unix.PTRACE_O_TRACEFORK
			pflags |= unix.PTRACE_O_TRACEVFORK
			pflags |= unix.PTRACE_O_TRACECLONE
			pflags |= C.PTRACE_O_EXITKILL

			syscall.PtraceSetOptions(pid, pflags)
			syscall.PtraceCont(pid, 0)
			pid, err = syscall.Wait4(-1, &s, syscall.WALL, nil)
			if err != nil {
				log.Error("Error (wait4) err:%v pid:%i children:%v\n", err, pid, children)
				done = true
				continue
			}
			children[pid] = true
			if s.Exited() == true {
				delete(children, pid)
				log.Info("Child pid %v finished.\n", pid)
				if len(children) == 0 {
					done = true
				}
				continue
			}
			if s.Signaled() == true {
				log.Error("Pid signaled, pid: %v signal: %v", pid, s)
				delete(children, pid)
				continue
			}
			switch uint32(s) >> 8 {

			case uint32(unix.SIGTRAP) | (unix.PTRACE_EVENT_SECCOMP << 8):
				var regs syscall.PtraceRegs
				err = syscall.PtraceGetRegs(pid, &regs)

				if err != nil {
					log.Error("Error (ptrace): %v", err)
				}

				systemcall, err := syscallByNum(getSyscallNumber(regs))
				if err != nil {
					log.Error("Error: %v", err)
					continue
				}

				/* Render the system call invocation */

				r := getSyscallRegisterArgs(regs)
				call := ""

				if train == true {
					trainingset[getSyscallNumber(regs)] = true
					if systemcall.captureArgs != nil {
						for c, i := range systemcall.captureArgs {
							if i == 1 {
								if trainingargs[getSyscallNumber(regs)] == nil {
									trainingargs[getSyscallNumber(regs)] = make(map[int][]uint)
								}
								if contains(trainingargs[getSyscallNumber(regs)][c], uint(r[c])) == false {
									trainingargs[getSyscallNumber(regs)][c] = append(trainingargs[getSyscallNumber(regs)][c], uint(r[c]))
								}
							}
						}
					}
				}

				if f, ok := renderFunctions[getSyscallNumber(regs)]; ok {
					call, err = f(pid, r)
					if err != nil {
						log.Info("%v", err)
						continue
					}
					if *debug == true {
						call += "\n  " + renderSyscallBasic(pid, systemcall, regs)
					}
				} else {
					call = renderSyscallBasic(pid, systemcall, regs)
				}

				log.Info("seccomp hit on sandbox pid %v (%v) syscall %v (%v):\n  %s", pid, getProcessCmdLine(pid), systemcall.name, systemcall.num, call)
				continue

			case uint32(unix.SIGTRAP) | (unix.PTRACE_EVENT_EXIT << 8):
				if *debug == true {
					log.Error("Ptrace exit event detected pid %v (%s)", pid, getProcessCmdLine(pid))
				}
				delete(children, pid)
				continue

			case uint32(unix.SIGTRAP) | (unix.PTRACE_EVENT_CLONE << 8):
				newpid, err := syscall.PtraceGetEventMsg(pid)
				if err != nil {
					log.Error("PTrace event message retrieval failed: %v", err)
				}
				children[int(newpid)] = true
				if *debug == true {
					log.Error("Ptrace clone event detected pid %v (%s)", pid, getProcessCmdLine(pid))
				}
				continue
			case uint32(unix.SIGTRAP) | (unix.PTRACE_EVENT_FORK << 8):
				if *debug == true {
					log.Error("PTrace fork event detected pid %v (%s)", pid, getProcessCmdLine(pid))
				}
				newpid, err := syscall.PtraceGetEventMsg(pid)
				if err != nil {
					log.Error("PTrace event message retrieval failed: %v", err)
				}
				children[int(newpid)] = true
				continue
			case uint32(unix.SIGTRAP) | (unix.PTRACE_EVENT_VFORK << 8):
				if *debug == true {
					log.Error("Ptrace vfork event detected pid %v (%s)", pid, getProcessCmdLine(pid))
				}
				newpid, err := syscall.PtraceGetEventMsg(pid)
				if err != nil {
					log.Error("PTrace event message retrieval failed: %v", err)
				}
				children[int(newpid)] = true
				continue
			case uint32(unix.SIGTRAP) | (unix.PTRACE_EVENT_VFORK_DONE << 8):
				if *debug == true {
					log.Error("Ptrace vfork done event detected pid %v (%s)", pid, getProcessCmdLine(pid))
				}
				newpid, err := syscall.PtraceGetEventMsg(pid)
				if err != nil {
					log.Error("PTrace event message retrieval failed: %v", err)
				}
				children[int(newpid)] = true

				continue
			case uint32(unix.SIGTRAP) | (unix.PTRACE_EVENT_EXEC << 8):
				if *debug == true {
					log.Error("Ptrace exec event detected pid %v (%s)", pid, getProcessCmdLine(pid))
				}
				continue
			case uint32(unix.SIGTRAP) | (unix.PTRACE_EVENT_STOP << 8):
				if *debug == true {
					log.Error("Ptrace stop event detected pid %v (%s)", pid, getProcessCmdLine(pid))
				}
				continue
			case uint32(unix.SIGTRAP):
				if *debug == true {
					log.Error("SIGTRAP detected in pid %v (%s)", pid, getProcessCmdLine(pid))
				}
				continue
			case uint32(unix.SIGCHLD):
				if *debug == true {
					log.Error("SIGCHLD detected pid %v (%s)", pid, getProcessCmdLine(pid))
				}
				continue
			case uint32(unix.SIGSTOP):
				if *debug == true {
					log.Error("SIGSTOP detected pid %v (%s)", pid, getProcessCmdLine(pid))
				}
				continue
			case uint32(unix.SIGSEGV):
				if *debug == true {
					log.Error("SIGSEGV detected pid %v (%s)", pid, getProcessCmdLine(pid))
				}
				err = syscall.Kill(pid, 9)
				if err != nil {
					log.Error("kill: %v", err)
					os.Exit(1)
				}
				delete(children, pid)
				continue
			default:
				y := s.StopSignal()
				if *debug == true {
					log.Error("Child stopped for unknown reasons pid %v status %v signal %i (%s)", pid, s, y, getProcessCmdLine(pid))
				}
				continue
			}
		}

		if train == true {
			var u *user.User
			var e error
			u, e = user.Current()
			var resolvedpath = ""

			if e != nil {
				log.Error("user.Current(): %v", e)
			}

			if *trainingoutput != "" {
				resolvedpath = *trainingoutput
			} else {
				if *noprofile == false {
					resolvedpath, e = fs.ResolvePathNoGlob(p.Seccomp.TrainOutput, u)
					if e != nil {
						log.Error("resolveVars(): %v", e)
					}
				} else {
					s := fmt.Sprintf("${HOME}/%s-%d.seccomp", fname(os.Args[2]), cpid)
					resolvedpath, e = fs.ResolvePathNoGlob(s, u)
				}
			}
			policyout := "execve:1\n"
			for call := range trainingset {
				done := false
				for c := range trainingargs {
					if c == call {
						for a, v := range trainingargs[c] {
							sc, _ := syscallByNum(call)
							policyout += fmt.Sprintf("%s:%s\n", sc.name, genArgs(uint(a), (v)))
							done = true
						}
					}
				}
				if done == false {
					sc, _ := syscallByNum(call)
					policyout += fmt.Sprintf("%s:1\n", sc.name)
				}
			}
			if *appendpolicy == true {
				log.Error("Not yet implemented.")
			}
			f, err := os.OpenFile(resolvedpath, os.O_CREATE|os.O_RDWR, 0600)
			if err == nil {
				_, err := f.WriteString(policyout)
				if err != nil {
					log.Error("Error writing policy file: %v", err)
				}
				err = f.Close()
				if err != nil {
					log.Error("Error closing policy file: %v", err)
				}
			} else {
				log.Error("Error opening policy file \"%s\": %v", resolvedpath, err)
			}
		}
	}
}

func genArgs(a uint, vals []uint) string {
	s := ""
	for idx, x := range vals {
		s += fmt.Sprintf(" arg%d == %d ", a, x)
		if idx < len(vals)-1 {
			s += "||"
		}
	}
	return s
}

func contains(slice []uint, val uint) bool {
	for _, x := range slice {
		if val == x {
			return true
		}
	}
	return false
}
func fname(p string) string {
	_, fname := path.Split(p)
	return fname
}
<commit_msg>If no profile, we assume that oz-seccomp is in /usr/bin as it is in SGOS.<commit_after>package seccomp

import (
	"bytes"
	"encoding/json"
	"flag"
	"fmt"
	"github.com/subgraph/oz"
	"github.com/subgraph/oz/fs"
	"golang.org/x/sys/unix"
	"io"
	"os"
	"os/exec"
	"os/user"
	"path"
	"syscall"
)

// #include "sys/ptrace.h"
import "C"

const (
	STRINGARG = iota + 1
	PTRARG
	INTARG
)

type SystemCallArgs []int

func Tracer() {

	var train = false
	var cmd string
	var cmdArgs []string
	var p *oz.Profile

	var noprofile = flag.Bool("train", false, "Training mode")
	var debug = flag.Bool("debug", false, "Debug")
	var appendpolicy = flag.Bool("append", false, "Append to existing policy if exists")
	var trainingoutput = flag.String("output", "", "Training policy output file")

	flag.Parse()

	var args = flag.Args()

	if *noprofile == true {
		train = true
		cmd = "/usr/bin/oz-seccomp"
		cmdArgs = append([]string{"-mode=train"}, args...)
	} else {
		p = new(oz.Profile)
		if err := json.NewDecoder(os.Stdin).Decode(&p); err != nil {
			log.Error("unable to decode profile data: %v", err)
			os.Exit(1)
		}
		if p.Seccomp.Mode == oz.PROFILE_SECCOMP_TRAIN {
			train = true
		}
		*debug = p.Seccomp.Debug
		cmd = args[0]
		cmdArgs = args[1:]
	}

	var cpid = 0
	done := false

	log.Info("Tracer running command (%v) arguments (%v)\n", cmd, cmdArgs)
	c := exec.Command(cmd)
	c.SysProcAttr = &syscall.SysProcAttr{Ptrace: true}
	c.Env = os.Environ()
	c.Args = append(c.Args, cmdArgs...)

	if *noprofile == false {

		pi, err := c.StdinPipe()
		if err != nil {
			fmt.Errorf("error creating stdin pipe for tracer process: %v", err)
			os.Exit(1)
		}
		jdata, err := json.Marshal(p)
		if err != nil {
			fmt.Errorf("Unable to marshal seccomp state: %+v", err)
			os.Exit(1)
		}
		io.Copy(pi, bytes.NewBuffer(jdata))
		pi.Close()
	}
	children := make(map[int]bool)
	renderFunctions := getRenderingFunctions()

	trainingset := make(map[int]bool)
	trainingargs := make(map[int]map[int][]uint)

	if err := c.Start(); err == nil {
		cpid = c.Process.Pid
		children[c.Process.Pid] = true
		var s syscall.WaitStatus
		pid, err := syscall.Wait4(-1, &s, syscall.WALL, nil)
		children[pid] = true
		if err != nil {
			log.Error("Error (wait4) err:%v pid:%i", err, pid)
		}
		log.Info("Tracing child pid: %v\n", pid)
		for done == false {
			pflags := unix.PTRACE_O_TRACESECCOMP
			pflags |= unix.PTRACE_O_TRACEFORK
			pflags |= unix.PTRACE_O_TRACEVFORK
			pflags |= unix.PTRACE_O_TRACECLONE
			pflags |= C.PTRACE_O_EXITKILL

			syscall.PtraceSetOptions(pid, pflags)
			syscall.PtraceCont(pid, 0)
			pid, err = syscall.Wait4(-1, &s, syscall.WALL, nil)
			if err != nil {
				log.Error("Error (wait4) err:%v pid:%i children:%v\n", err, pid, children)
				done = true
				continue
			}
			children[pid] = true
			if s.Exited() == true {
				delete(children, pid)
				log.Info("Child pid %v finished.\n", pid)
				if len(children) == 0 {
					done = true
				}
				continue
			}
			if s.Signaled() == true {
				log.Error("Pid signaled, pid: %v signal: %v", pid, s)
				delete(children, pid)
				continue
			}
			switch uint32(s) >> 8 {

			case uint32(unix.SIGTRAP) | (unix.PTRACE_EVENT_SECCOMP << 8):
				var regs syscall.PtraceRegs
				err = syscall.PtraceGetRegs(pid, &regs)

				if err != nil {
					log.Error("Error (ptrace): %v", err)
				}

				systemcall, err := syscallByNum(getSyscallNumber(regs))
				if err != nil {
					log.Error("Error: %v", err)
					continue
				}

				/* Render the system call invocation */

				r := getSyscallRegisterArgs(regs)
				call := ""

				if train == true {
					trainingset[getSyscallNumber(regs)] = true
					if systemcall.captureArgs != nil {
						for c, i := range systemcall.captureArgs {
							if i == 1 {
								if trainingargs[getSyscallNumber(regs)] == nil {
									trainingargs[getSyscallNumber(regs)] = make(map[int][]uint)
								}
								if contains(trainingargs[getSyscallNumber(regs)][c], uint(r[c])) == false {
									trainingargs[getSyscallNumber(regs)][c] = append(trainingargs[getSyscallNumber(regs)][c], uint(r[c]))
								}
							}
						}
					}
				}

				if f, ok := renderFunctions[getSyscallNumber(regs)]; ok {
					call, err = f(pid, r)
					if err != nil {
						log.Info("%v", err)
						continue
					}
					if *debug == true {
						call += "\n  " + renderSyscallBasic(pid, systemcall, regs)
					}
				} else {
					call = renderSyscallBasic(pid, systemcall, regs)
				}

				log.Info("seccomp hit on sandbox pid %v (%v) syscall %v (%v):\n  %s", pid, getProcessCmdLine(pid), systemcall.name, systemcall.num, call)
				continue

			case uint32(unix.SIGTRAP) | (unix.PTRACE_EVENT_EXIT << 8):
				if *debug == true {
					log.Error("Ptrace exit event detected pid %v (%s)", pid, getProcessCmdLine(pid))
				}
				delete(children, pid)
				continue

			case uint32(unix.SIGTRAP) | (unix.PTRACE_EVENT_CLONE << 8):
				newpid, err := syscall.PtraceGetEventMsg(pid)
				if err != nil {
					log.Error("PTrace event message retrieval failed: %v", err)
				}
				children[int(newpid)] = true
				if *debug == true {
					log.Error("Ptrace clone event detected pid %v (%s)", pid, getProcessCmdLine(pid))
				}
				continue
			case uint32(unix.SIGTRAP) | (unix.PTRACE_EVENT_FORK << 8):
				if *debug == true {
					log.Error("PTrace fork event detected pid %v (%s)", pid, getProcessCmdLine(pid))
				}
				newpid, err := syscall.PtraceGetEventMsg(pid)
				if err != nil {
					log.Error("PTrace event message retrieval failed: %v", err)
				}
				children[int(newpid)] = true
				continue
			case uint32(unix.SIGTRAP) | (unix.PTRACE_EVENT_VFORK << 8):
				if *debug == true {
					log.Error("Ptrace vfork event detected pid %v (%s)", pid, getProcessCmdLine(pid))
				}
				newpid, err := syscall.PtraceGetEventMsg(pid)
				if err != nil {
					log.Error("PTrace event message retrieval failed: %v", err)
				}
				children[int(newpid)] = true
				continue
			case uint32(unix.SIGTRAP) | (unix.PTRACE_EVENT_VFORK_DONE << 8):
				if *debug == true {
					log.Error("Ptrace vfork done event detected pid %v (%s)", pid, getProcessCmdLine(pid))
				}
				newpid, err := syscall.PtraceGetEventMsg(pid)
				if err != nil {
					log.Error("PTrace event message retrieval failed: %v", err)
				}
				children[int(newpid)] = true

				continue
			case uint32(unix.SIGTRAP) | (unix.PTRACE_EVENT_EXEC << 8):
				if *debug == true {
					log.Error("Ptrace exec event detected pid %v (%s)", pid, getProcessCmdLine(pid))
				}
				continue
			case uint32(unix.SIGTRAP) | (unix.PTRACE_EVENT_STOP << 8):
				if *debug == true {
					log.Error("Ptrace stop event detected pid %v (%s)", pid, getProcessCmdLine(pid))
				}
				continue
			case uint32(unix.SIGTRAP):
				if *debug == true {
					log.Error("SIGTRAP detected in pid %v (%s)", pid, getProcessCmdLine(pid))
				}
				continue
			case uint32(unix.SIGCHLD):
				if *debug == true {
					log.Error("SIGCHLD detected pid %v (%s)", pid, getProcessCmdLine(pid))
				}
				continue
			case uint32(unix.SIGSTOP):
				if *debug == true {
					log.Error("SIGSTOP detected pid %v (%s)", pid, getProcessCmdLine(pid))
				}
				continue
			case uint32(unix.SIGSEGV):
				if *debug == true {
					log.Error("SIGSEGV detected pid %v (%s)", pid, getProcessCmdLine(pid))
				}
				err = syscall.Kill(pid, 9)
				if err != nil {
					log.Error("kill: %v", err)
					os.Exit(1)
				}
				delete(children, pid)
				continue
			default:
				y := s.StopSignal()
				if *debug == true {
					log.Error("Child stopped for unknown reasons pid %v status %v signal %i (%s)", pid, s, y, getProcessCmdLine(pid))
				}
				continue
			}
		}

		if train == true {
			var u *user.User
			var e error
			u, e = user.Current()
			var resolvedpath = ""

			if e != nil {
				log.Error("user.Current(): %v", e)
			}

			if *trainingoutput != "" {
				resolvedpath = *trainingoutput
			} else {
				if *noprofile == false {
					resolvedpath, e = fs.ResolvePathNoGlob(p.Seccomp.TrainOutput, u)
					if e != nil {
						log.Error("resolveVars(): %v", e)
					}
				} else {
					s := fmt.Sprintf("${HOME}/%s-%d.seccomp", fname(os.Args[2]), cpid)
					resolvedpath, e = fs.ResolvePathNoGlob(s, u)
				}
			}
			policyout := "execve:1\n"
			for call := range trainingset {
				done := false
				for c := range trainingargs {
					if c == call {
						for a, v := range trainingargs[c] {
							sc, _ := syscallByNum(call)
							policyout += fmt.Sprintf("%s:%s\n", sc.name, genArgs(uint(a), (v)))
							done = true
						}
					}
				}
				if done == false {
					sc, _ := syscallByNum(call)
					policyout += fmt.Sprintf("%s:1\n", sc.name)
				}
			}
			if *appendpolicy == true {
				log.Error("Not yet implemented.")
			}
			f, err := os.OpenFile(resolvedpath, os.O_CREATE|os.O_RDWR, 0600)
			if err == nil {
				_, err := f.WriteString(policyout)
				if err != nil {
					log.Error("Error writing policy file: %v", err)
				}
				err = f.Close()
				if err != nil {
					log.Error("Error closing policy file: %v", err)
				}
			} else {
				log.Error("Error opening policy file \"%s\": %v", resolvedpath, err)
			}
		}
	}
}

func genArgs(a uint, vals []uint) string {
	s := ""
	for idx, x := range vals {
		s += fmt.Sprintf(" arg%d == %d ", a, x)
		if idx < len(vals)-1 {
			s += "||"
		}
	}
	return s
}

func contains(slice []uint, val uint) bool {
	for _, x := range slice {
		if val == x {
			return true
		}
	}
	return false
}
func fname(p string) string {
	_, fname := path.Split(p)
	return fname
}
<|endoftext|>


<commit_before>package rpc // import "collectd.org/rpc"

import (
	"io"

	pb "collectd.org/rpc/proto"
	"google.golang.org/grpc"
	"google.golang.org/grpc/codes"
)

// RegisterServer registers the implementation srv with the gRPC instance s.
func RegisterServer(s *grpc.Server, srv Interface) {
	pb.RegisterCollectdServer(s, &server{
		srv: srv,
	})
}

// server implements pb.CollectdServer using srv.
type server struct {
	srv Interface
}

// DispatchValues reads ValueLists from stream and calls the Write()
// implementation on each one.
func (wrap *server) DispatchValues(stream pb.Collectd_DispatchValuesServer) error {
	for {
		req, err := stream.Recv()
		if err == io.EOF {
			break
		}
		if err != nil {
			return err
		}

		vl, err := UnmarshalValueList(req.GetValueList())
		if err != nil {
			return err
		}

		// TODO(octo): pass stream.Context() to srv.Write() once the interface allows that.
		if err := wrap.srv.Write(*vl); err != nil {
			return grpc.Errorf(codes.Internal, "Write(%v): %v", vl, err)
		}
	}

	return stream.SendAndClose(&pb.DispatchValuesResponse{})
}

// QueryValues calls the Query() implementation and streams all ValueLists from
// the channel back to the client.
func (wrap *server) QueryValues(req *pb.QueryValuesRequest, stream pb.Collectd_QueryValuesServer) error {
	id := UnmarshalIdentifier(req.GetIdentifier())

	ch, err := wrap.srv.Query(stream.Context(), id)
	if err != nil {
		return grpc.Errorf(codes.Internal, "Query(%v): %v", id, err)
	}

	for vl := range ch {
		pbVL, err := MarshalValueList(vl)
		if err != nil {
			return err
		}

		res := &pb.QueryValuesResponse{
			ValueList: pbVL,
		}
		if err := stream.Send(res); err != nil {
			return err
		}
	}

	return nil
}
<commit_msg>Package rpc: Embed Interface in the server struct.<commit_after>package rpc // import "collectd.org/rpc"

import (
	"io"

	pb "collectd.org/rpc/proto"
	"google.golang.org/grpc"
	"google.golang.org/grpc/codes"
)

// RegisterServer registers the implementation srv with the gRPC instance s.
func RegisterServer(s *grpc.Server, srv Interface) {
	pb.RegisterCollectdServer(s, &server{
		Interface: srv,
	})
}

// server implements pb.CollectdServer using srv.
type server struct {
	Interface
}

// DispatchValues reads ValueLists from stream and calls the Write()
// implementation on each one.
func (s *server) DispatchValues(stream pb.Collectd_DispatchValuesServer) error {
	for {
		req, err := stream.Recv()
		if err == io.EOF {
			break
		}
		if err != nil {
			return err
		}

		vl, err := UnmarshalValueList(req.GetValueList())
		if err != nil {
			return err
		}

		// TODO(octo): pass stream.Context() to srv.Write() once the interface allows that.
		if err := s.Write(*vl); err != nil {
			return grpc.Errorf(codes.Internal, "Write(%v): %v", vl, err)
		}
	}

	return stream.SendAndClose(&pb.DispatchValuesResponse{})
}

// QueryValues calls the Query() implementation and streams all ValueLists from
// the channel back to the client.
func (s *server) QueryValues(req *pb.QueryValuesRequest, stream pb.Collectd_QueryValuesServer) error {
	id := UnmarshalIdentifier(req.GetIdentifier())

	ch, err := s.Query(stream.Context(), id)
	if err != nil {
		return grpc.Errorf(codes.Internal, "Query(%v): %v", id, err)
	}

	for vl := range ch {
		pbVL, err := MarshalValueList(vl)
		if err != nil {
			return err
		}

		res := &pb.QueryValuesResponse{
			ValueList: pbVL,
		}
		if err := stream.Send(res); err != nil {
			return err
		}
	}

	return nil
}
<|endoftext|>


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

// +build windows

package clipboard

import (
	"runtime"
	"syscall"
	"time"
	"unsafe"
)

const (
	cfUnicodetext = 13
	gmemMoveable  = 0x0002
)

var (
	user32                     = syscall.MustLoadDLL("user32")
	isClipboardFormatAvailable = user32.MustFindProc("IsClipboardFormatAvailable")
	openClipboard              = user32.MustFindProc("OpenClipboard")
	closeClipboard             = user32.MustFindProc("CloseClipboard")
	emptyClipboard             = user32.MustFindProc("EmptyClipboard")
	getClipboardData           = user32.MustFindProc("GetClipboardData")
	setClipboardData           = user32.MustFindProc("SetClipboardData")

	kernel32     = syscall.NewLazyDLL("kernel32")
	globalAlloc  = kernel32.NewProc("GlobalAlloc")
	globalFree   = kernel32.NewProc("GlobalFree")
	globalLock   = kernel32.NewProc("GlobalLock")
	globalUnlock = kernel32.NewProc("GlobalUnlock")
	lstrcpy      = kernel32.NewProc("lstrcpyW")
)

// waitOpenClipboard opens the clipboard, waiting for up to a second to do so.
func waitOpenClipboard() error {
	started := time.Now()
	limit := started.Add(time.Second)
	var r uintptr
	var err error
	for time.Now().Before(limit) {
		r, _, err = openClipboard.Call(0)
		if r != 0 {
			return nil
		}
		time.Sleep(time.Millisecond)
	}
	return err
}

func readAll() (string, error) {
	// LockOSThread ensure that the whole method will keep executing on the same thread from begin to end (it actually locks the goroutine thread attribution).
	// Otherwise if the goroutine switch thread during execution (which is a common practice), the OpenClipboard and CloseClipboard will happen on two different threads, and it will result in a clipboard deadlock.
	runtime.LockOSThread()
	defer runtime.UnlockOSThread()
	if formatAvailable, _, err := isClipboardFormatAvailable.Call(cfUnicodetext); formatAvailable == 0 {
		return "", err
	}
	err := waitOpenClipboard()
	if err != nil {
		return "", err
	}
	defer closeClipboard.Call()

	h, _, err := getClipboardData.Call(cfUnicodetext)
	if h == 0 {
		return "", err
	}

	l, _, err := globalLock.Call(h)
	if l == 0 {
		return "", err
	}

	text := syscall.UTF16ToString((*[1 << 20]uint16)(unsafe.Pointer(l))[:])

	r, _, err := globalUnlock.Call(h)
	if r == 0 {
		return "", err
	}

	return text, nil
}

func writeAll(text string) error {
	err := waitOpenClipboard()
	if err != nil {
		return err
	}
	defer closeClipboard.Call()

	r, _, err := emptyClipboard.Call(0)
	if r == 0 {
		return err
	}

	data := syscall.StringToUTF16(text)

	// "If the hMem parameter identifies a memory object, the object must have
	// been allocated using the function with the GMEM_MOVEABLE flag."
	h, _, err := globalAlloc.Call(gmemMoveable, uintptr(len(data)*int(unsafe.Sizeof(data[0]))))
	if h == 0 {
		return err
	}
	defer func() {
		if h != 0 {
			globalFree.Call(h)
		}
	}()

	l, _, err := globalLock.Call(h)
	if l == 0 {
		return err
	}

	r, _, err = lstrcpy.Call(l, uintptr(unsafe.Pointer(&data[0])))
	if r == 0 {
		return err
	}

	r, _, err = globalUnlock.Call(h)
	if r == 0 {
		if err.(syscall.Errno) != 0 {
			return err
		}
	}

	r, _, err = setClipboardData.Call(cfUnicodetext, h)
	if r == 0 {
		return err
	}
	h = 0 // suppress deferred cleanup
	return nil
}
<commit_msg>Fix deadlock on writeAll & return error on failed to close<commit_after>// Copyright 2013 @atotto. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// +build windows

package clipboard

import (
	"runtime"
	"syscall"
	"time"
	"unsafe"
)

const (
	cfUnicodetext = 13
	gmemMoveable  = 0x0002
)

var (
	user32                     = syscall.MustLoadDLL("user32")
	isClipboardFormatAvailable = user32.MustFindProc("IsClipboardFormatAvailable")
	openClipboard              = user32.MustFindProc("OpenClipboard")
	closeClipboard             = user32.MustFindProc("CloseClipboard")
	emptyClipboard             = user32.MustFindProc("EmptyClipboard")
	getClipboardData           = user32.MustFindProc("GetClipboardData")
	setClipboardData           = user32.MustFindProc("SetClipboardData")

	kernel32     = syscall.NewLazyDLL("kernel32")
	globalAlloc  = kernel32.NewProc("GlobalAlloc")
	globalFree   = kernel32.NewProc("GlobalFree")
	globalLock   = kernel32.NewProc("GlobalLock")
	globalUnlock = kernel32.NewProc("GlobalUnlock")
	lstrcpy      = kernel32.NewProc("lstrcpyW")
)

// waitOpenClipboard opens the clipboard, waiting for up to a second to do so.
func waitOpenClipboard() error {
	started := time.Now()
	limit := started.Add(time.Second)
	var r uintptr
	var err error
	for time.Now().Before(limit) {
		r, _, err = openClipboard.Call(0)
		if r != 0 {
			return nil
		}
		time.Sleep(time.Millisecond)
	}
	return err
}

func readAll() (string, error) {
	// LockOSThread ensure that the whole method will keep executing on the same thread from begin to end (it actually locks the goroutine thread attribution).
	// Otherwise if the goroutine switch thread during execution (which is a common practice), the OpenClipboard and CloseClipboard will happen on two different threads, and it will result in a clipboard deadlock.
	runtime.LockOSThread()
	defer runtime.UnlockOSThread()
	if formatAvailable, _, err := isClipboardFormatAvailable.Call(cfUnicodetext); formatAvailable == 0 {
		return "", err
	}
	err := waitOpenClipboard()
	if err != nil {
		return "", err
	}

	h, _, err := getClipboardData.Call(cfUnicodetext)
	if h == 0 {
		_, _, _ = closeClipboard.Call()
		return "", err
	}

	l, _, err := globalLock.Call(h)
	if l == 0 {
		_, _, _ = closeClipboard.Call()
		return "", err
	}

	text := syscall.UTF16ToString((*[1 << 20]uint16)(unsafe.Pointer(l))[:])

	r, _, err := globalUnlock.Call(h)
	if r == 0 {
		_, _, _ = closeClipboard.Call()
		return "", err
	}

	closed, _, err := closeClipboard.Call()
	if closed == 0 {
		return "", err
	}
	return text, nil
}

func writeAll(text string) error {
	// LockOSThread ensure that the whole method will keep executing on the same thread from begin to end (it actually locks the goroutine thread attribution).
	// Otherwise if the goroutine switch thread during execution (which is a common practice), the OpenClipboard and CloseClipboard will happen on two different threads, and it will result in a clipboard deadlock.
	runtime.LockOSThread()
	defer runtime.UnlockOSThread()

	err := waitOpenClipboard()
	if err != nil {
		return err
	}

	r, _, err := emptyClipboard.Call(0)
	if r == 0 {
		_, _, _ = closeClipboard.Call()
		return err
	}

	data := syscall.StringToUTF16(text)

	// "If the hMem parameter identifies a memory object, the object must have
	// been allocated using the function with the GMEM_MOVEABLE flag."
	h, _, err := globalAlloc.Call(gmemMoveable, uintptr(len(data)*int(unsafe.Sizeof(data[0]))))
	if h == 0 {
		_, _, _ = closeClipboard.Call()
		return err
	}
	defer func() {
		if h != 0 {
			globalFree.Call(h)
		}
	}()

	l, _, err := globalLock.Call(h)
	if l == 0 {
		_, _, _ = closeClipboard.Call()
		return err
	}

	r, _, err = lstrcpy.Call(l, uintptr(unsafe.Pointer(&data[0])))
	if r == 0 {
		_, _, _ = closeClipboard.Call()
		return err
	}

	r, _, err = globalUnlock.Call(h)
	if r == 0 {
		if err.(syscall.Errno) != 0 {
			_, _, _ = closeClipboard.Call()
			return err
		}
	}

	r, _, err = setClipboardData.Call(cfUnicodetext, h)
	if r == 0 {
		_, _, _ = closeClipboard.Call()
		return err
	}
	h = 0 // suppress deferred cleanup
	closed, _, err := closeClipboard.Call()
	if closed == 0 {
		return err
	}
	return nil
}
<|endoftext|>


<commit_before>package sudoku

//GridModification is a series of CellModifications to apply to a Grid.
type GridModifcation []*CellModification

//CellModification represents a modification to be made to a given Cell in a
//grid.
type CellModification struct {
	//The cell representing the cell to modify. The cell's analog (at the same
	//row, col address) will be modified in the new grid.
	Cell Cell
	//The number to put in the cell. Negative numbers signify no changes.
	Number int
	//The excludes to proactively set. Invalid numbers will be ignored.
	//Indexes not listed will be left the same.
	ExcludesChanges map[int]bool
	//The marks to proactively set. Invalid numbers will be ignored.
	//Indexes not listed will be left the same.
	MarksChanges map[int]bool
}

//TODO: audit all uses of step/compoundstep.Apply()

//TOOD: make readOnlyCellImpl. Test if neighbors should be derived or not.
//Everything should be actual contiguous memory, no pointers (except for
//grid). Likely should make cellImpl embed a readOnlyCellImpl and only
//override items it needs to.

//TODO: make readOnlyGridImpl. Two possible approaches: a version that is
//incredibly easy to copy and then do minor tweaks. Or a version that stores a
//dictionary of cell configs, and any time you grab a Cell we look it up in
//the dict or in the ancestors' dicts.

//newCellModification returns a CellModification for the given cell that is a
//no-op.
func newCellModification(cell Cell) *CellModification {
	return &CellModification{
		Cell:            cell,
		Number:          -1,
		ExcludesChanges: make(map[int]bool),
		MarksChanges:    make(map[int]bool),
	}
}

//equivalent returns true if the other grid modification is equivalent to this one.
func (m GridModifcation) equivalent(other GridModifcation) bool {
	if len(m) != len(other) {
		return false
	}
	for i, modification := range m {
		otherModification := other[i]
		if modification.Cell.ref().String() != otherModification.Cell.ref().String() {
			return false
		}
		if modification.Number != otherModification.Number {
			return false
		}

		if len(modification.ExcludesChanges) != len(otherModification.ExcludesChanges) {
			return false
		}

		for key, val := range modification.ExcludesChanges {
			otherVal, ok := otherModification.ExcludesChanges[key]
			if !ok {
				return false
			}
			if val != otherVal {
				return false
			}
		}

		if len(modification.MarksChanges) != len(otherModification.MarksChanges) {
			return false
		}

		for key, val := range modification.MarksChanges {
			otherVal, ok := otherModification.MarksChanges[key]
			if !ok {
				return false
			}
			if val != otherVal {
				return false
			}
		}
	}
	return true
}

func (self *gridImpl) CopyWithModifications(modifications GridModifcation) Grid {

	//TODO: test this implementation deeply! Lots of crazy stuff that could go
	//wrong.

	var result *gridImpl

	//Copy in everything
	*result = *self

	cellNumberModified := false

	for _, modification := range modifications {
		cell := result.cellImpl(modification.Cell.Row(), modification.Cell.Col())

		if modification.Number >= 0 && modification.Number <= DIM {
			//cell.setNumber will handle setting all of the impossibles
			if cell.setNumber(modification.Number) {
				cellNumberModified = true
			}
		}

		for key, val := range modification.ExcludesChanges {
			//Key is 1-indexed
			key--
			cell.excluded[key] = val
		}

		for key, val := range modification.MarksChanges {
			//Key is 1-indexed
			key--
			cell.marks[key] = val
		}
	}

	if cellNumberModified {

		//At least one cell's number was modified, which means we need to fix
		//up the queue, numFilledCells, Invalid, Solved.

		filledCellsCount := 0

		for _, cell := range result.cells {
			if cell.number == 0 {
				continue
			}
			filledCellsCount++
		}

		result.filledCellsCount = filledCellsCount

		//Check if we're invalid.

		invalid := false

		for _, cell := range result.cells {
			//Make sure we have at least one possibility per cell
			foundPossibility := false
			for i := 0; i < DIM; i++ {
				if cell.impossibles[i] == 0 {
					foundPossibility = true
					break
				}
			}
			if !foundPossibility {
				invalid = true
				break
			}
		}

		if !invalid {
			//Let's do a deep check
			invalid = gridGroupsInvalid(result)
		}

		result.invalid = invalid

		if filledCellsCount == DIM*DIM && !result.invalid {
			//All cells are filled and it's not invalid, so it's solved!
			result.solved = true
		} else {
			//No way it's solved
			result.solved = false
		}

		result.theQueue.fix()
	}

	return result

}

func (self *mutableGridImpl) CopyWithModifications(modifications GridModifcation) Grid {
	//TODO: when we have an honest-to-god readonly grid impl, optimize this.
	result := self.MutableCopy()

	for _, modification := range modifications {
		cell := modification.Cell.MutableInGrid(result)

		if modification.Number >= 0 && modification.Number <= DIM {
			cell.SetNumber(modification.Number)
		}

		for key, val := range modification.ExcludesChanges {
			//setExcluded will skip invalid entries
			cell.SetExcluded(key, val)
		}

		for key, val := range modification.MarksChanges {
			//SetMark will skip invalid numbers
			cell.SetMark(key, val)
		}
	}

	return result
}
<commit_msg>Fixed a crasher when you use readonlygrid<commit_after>package sudoku

//GridModification is a series of CellModifications to apply to a Grid.
type GridModifcation []*CellModification

//CellModification represents a modification to be made to a given Cell in a
//grid.
type CellModification struct {
	//The cell representing the cell to modify. The cell's analog (at the same
	//row, col address) will be modified in the new grid.
	Cell Cell
	//The number to put in the cell. Negative numbers signify no changes.
	Number int
	//The excludes to proactively set. Invalid numbers will be ignored.
	//Indexes not listed will be left the same.
	ExcludesChanges map[int]bool
	//The marks to proactively set. Invalid numbers will be ignored.
	//Indexes not listed will be left the same.
	MarksChanges map[int]bool
}

//TODO: audit all uses of step/compoundstep.Apply()

//TOOD: make readOnlyCellImpl. Test if neighbors should be derived or not.
//Everything should be actual contiguous memory, no pointers (except for
//grid). Likely should make cellImpl embed a readOnlyCellImpl and only
//override items it needs to.

//TODO: make readOnlyGridImpl. Two possible approaches: a version that is
//incredibly easy to copy and then do minor tweaks. Or a version that stores a
//dictionary of cell configs, and any time you grab a Cell we look it up in
//the dict or in the ancestors' dicts.

//newCellModification returns a CellModification for the given cell that is a
//no-op.
func newCellModification(cell Cell) *CellModification {
	return &CellModification{
		Cell:            cell,
		Number:          -1,
		ExcludesChanges: make(map[int]bool),
		MarksChanges:    make(map[int]bool),
	}
}

//equivalent returns true if the other grid modification is equivalent to this one.
func (m GridModifcation) equivalent(other GridModifcation) bool {
	if len(m) != len(other) {
		return false
	}
	for i, modification := range m {
		otherModification := other[i]
		if modification.Cell.ref().String() != otherModification.Cell.ref().String() {
			return false
		}
		if modification.Number != otherModification.Number {
			return false
		}

		if len(modification.ExcludesChanges) != len(otherModification.ExcludesChanges) {
			return false
		}

		for key, val := range modification.ExcludesChanges {
			otherVal, ok := otherModification.ExcludesChanges[key]
			if !ok {
				return false
			}
			if val != otherVal {
				return false
			}
		}

		if len(modification.MarksChanges) != len(otherModification.MarksChanges) {
			return false
		}

		for key, val := range modification.MarksChanges {
			otherVal, ok := otherModification.MarksChanges[key]
			if !ok {
				return false
			}
			if val != otherVal {
				return false
			}
		}
	}
	return true
}

func (self *gridImpl) CopyWithModifications(modifications GridModifcation) Grid {

	//TODO: test this implementation deeply! Lots of crazy stuff that could go
	//wrong.

	result = new(gridImpl)

	//Copy in everything
	*result = *self

	cellNumberModified := false

	for _, modification := range modifications {
		cell := result.cellImpl(modification.Cell.Row(), modification.Cell.Col())

		if modification.Number >= 0 && modification.Number <= DIM {
			//cell.setNumber will handle setting all of the impossibles
			if cell.setNumber(modification.Number) {
				cellNumberModified = true
			}
		}

		for key, val := range modification.ExcludesChanges {
			//Key is 1-indexed
			key--
			cell.excluded[key] = val
		}

		for key, val := range modification.MarksChanges {
			//Key is 1-indexed
			key--
			cell.marks[key] = val
		}
	}

	if cellNumberModified {

		//At least one cell's number was modified, which means we need to fix
		//up the queue, numFilledCells, Invalid, Solved.

		filledCellsCount := 0

		for _, cell := range result.cells {
			if cell.number == 0 {
				continue
			}
			filledCellsCount++
		}

		result.filledCellsCount = filledCellsCount

		//Check if we're invalid.

		invalid := false

		for _, cell := range result.cells {
			//Make sure we have at least one possibility per cell
			foundPossibility := false
			for i := 0; i < DIM; i++ {
				if cell.impossibles[i] == 0 {
					foundPossibility = true
					break
				}
			}
			if !foundPossibility {
				invalid = true
				break
			}
		}

		if !invalid {
			//Let's do a deep check
			invalid = gridGroupsInvalid(result)
		}

		result.invalid = invalid

		if filledCellsCount == DIM*DIM && !result.invalid {
			//All cells are filled and it's not invalid, so it's solved!
			result.solved = true
		} else {
			//No way it's solved
			result.solved = false
		}

		result.theQueue.fix()
	}

	return result

}

func (self *mutableGridImpl) CopyWithModifications(modifications GridModifcation) Grid {
	//TODO: when we have an honest-to-god readonly grid impl, optimize this.
	result := self.MutableCopy()

	for _, modification := range modifications {
		cell := modification.Cell.MutableInGrid(result)

		if modification.Number >= 0 && modification.Number <= DIM {
			cell.SetNumber(modification.Number)
		}

		for key, val := range modification.ExcludesChanges {
			//setExcluded will skip invalid entries
			cell.SetExcluded(key, val)
		}

		for key, val := range modification.MarksChanges {
			//SetMark will skip invalid numbers
			cell.SetMark(key, val)
		}
	}

	return result
}
<|endoftext|>


<commit_before>package sudoku

//GridModification is a series of CellModifications to apply to a Grid.
type GridModification []*CellModification

//TODO: consider changing GridModification to be value type of CellModification.

//CellModification represents a modification to be made to a given Cell in a
//grid.
type CellModification struct {
	//The cell representing the cell to modify. The cell's analog (at the same
	//row, col address) will be modified in the new grid.
	Cell Cell
	//The number to put in the cell. Negative numbers signify no changes.
	Number int
	//The excludes to proactively set. Invalid numbers will be ignored.
	//Indexes not listed will be left the same.
	ExcludesChanges map[int]bool
	//The marks to proactively set. Invalid numbers will be ignored.
	//Indexes not listed will be left the same.
	MarksChanges map[int]bool
}

//TODO: audit all uses of step/compoundstep.Apply()

//TOOD: make readOnlyCellImpl. Test if neighbors should be derived or not.
//Everything should be actual contiguous memory, no pointers (except for
//grid). Likely should make cellImpl embed a readOnlyCellImpl and only
//override items it needs to.

//TODO: make readOnlyGridImpl. Two possible approaches: a version that is
//incredibly easy to copy and then do minor tweaks. Or a version that stores a
//dictionary of cell configs, and any time you grab a Cell we look it up in
//the dict or in the ancestors' dicts.

//newCellModification returns a CellModification for the given cell that is a
//no-op.
func newCellModification(cell Cell) *CellModification {
	return &CellModification{
		Cell:            cell,
		Number:          -1,
		ExcludesChanges: make(map[int]bool),
		MarksChanges:    make(map[int]bool),
	}
}

//normalize makes sure the GridModification is legal.
func (m GridModification) normalize() {
	for _, cellModification := range m {
		for key, _ := range cellModification.ExcludesChanges {
			if key <= 0 || key > DIM {
				delete(cellModification.ExcludesChanges, key)
			}
		}
		for key, _ := range cellModification.MarksChanges {
			if key <= 0 || key > DIM {
				delete(cellModification.MarksChanges, key)
			}
		}

		if cellModification.Number < -1 || cellModification.Number > DIM {
			cellModification.Number = -1
		}
	}

}

//equivalent returns true if the other grid modification is equivalent to this one.
func (m GridModification) equivalent(other GridModification) bool {
	if len(m) != len(other) {
		return false
	}
	for i, modification := range m {
		otherModification := other[i]
		if modification.Cell.ref().String() != otherModification.Cell.ref().String() {
			return false
		}
		if modification.Number != otherModification.Number {
			return false
		}

		if len(modification.ExcludesChanges) != len(otherModification.ExcludesChanges) {
			return false
		}

		for key, val := range modification.ExcludesChanges {
			otherVal, ok := otherModification.ExcludesChanges[key]
			if !ok {
				return false
			}
			if val != otherVal {
				return false
			}
		}

		if len(modification.MarksChanges) != len(otherModification.MarksChanges) {
			return false
		}

		for key, val := range modification.MarksChanges {
			otherVal, ok := otherModification.MarksChanges[key]
			if !ok {
				return false
			}
			if val != otherVal {
				return false
			}
		}
	}
	return true
}

func (self *gridImpl) CopyWithModifications(modifications GridModification) Grid {

	//TODO: test this implementation deeply! Lots of crazy stuff that could go
	//wrong.

	modifications.normalize()

	result := new(gridImpl)

	//Copy in everything
	*result = *self

	for i := 0; i < DIM*DIM; i++ {
		cell := &result.cells[i]
		cell.gridRef = result
	}

	result.theQueue.grid = result

	cellNumberModified := false

	for _, modification := range modifications {
		cell := result.cellImpl(modification.Cell.Row(), modification.Cell.Col())

		if modification.Number >= 0 && modification.Number <= DIM {
			//cell.setNumber will handle setting all of the impossibles
			if cell.setNumber(modification.Number) {
				cellNumberModified = true
			}
		}

		for key, val := range modification.ExcludesChanges {
			//Key is 1-indexed
			key--
			cell.excluded[key] = val
		}

		for key, val := range modification.MarksChanges {
			//Key is 1-indexed
			key--
			cell.marks[key] = val
		}
	}

	if cellNumberModified {

		//At least one cell's number was modified, which means we need to fix
		//up the queue, numFilledCells, Invalid, Solved.

		filledCellsCount := 0

		for _, cell := range result.cells {
			if cell.number == 0 {
				continue
			}
			filledCellsCount++
		}

		result.filledCellsCount = filledCellsCount

		//Check if we're invalid.

		invalid := false

		for _, cell := range result.cells {
			//Make sure we have at least one possibility per cell
			foundPossibility := false
			for i := 0; i < DIM; i++ {
				if cell.impossibles[i] == 0 {
					foundPossibility = true
					break
				}
			}
			if !foundPossibility {
				invalid = true
				break
			}
		}

		if !invalid {
			//Let's do a deep check
			invalid = gridGroupsInvalid(result)
		}

		result.invalid = invalid

		if filledCellsCount == DIM*DIM && !result.invalid {
			//All cells are filled and it's not invalid, so it's solved!
			result.solved = true
		} else {
			//No way it's solved
			result.solved = false
		}

		result.theQueue.fix()
	}

	return result

}

func (self *mutableGridImpl) CopyWithModifications(modifications GridModification) Grid {
	//TODO: when we have an honest-to-god readonly grid impl, optimize this.
	result := self.MutableCopy()

	modifications.normalize()

	for _, modification := range modifications {
		cell := modification.Cell.MutableInGrid(result)

		if modification.Number >= 0 && modification.Number <= DIM {
			cell.SetNumber(modification.Number)
		}

		for key, val := range modification.ExcludesChanges {
			//setExcluded will skip invalid entries
			cell.SetExcluded(key, val)
		}

		for key, val := range modification.MarksChanges {
			//SetMark will skip invalid numbers
			cell.SetMark(key, val)
		}
	}

	return result
}
<commit_msg>Fixed a bug that the next commit's test helped me find. In CopyWithModification, we also have to recalculate Invalid if any of the excludes change (and were calculating that wrong anyway)<commit_after>package sudoku

//GridModification is a series of CellModifications to apply to a Grid.
type GridModification []*CellModification

//TODO: consider changing GridModification to be value type of CellModification.

//CellModification represents a modification to be made to a given Cell in a
//grid.
type CellModification struct {
	//The cell representing the cell to modify. The cell's analog (at the same
	//row, col address) will be modified in the new grid.
	Cell Cell
	//The number to put in the cell. Negative numbers signify no changes.
	Number int
	//The excludes to proactively set. Invalid numbers will be ignored.
	//Indexes not listed will be left the same.
	ExcludesChanges map[int]bool
	//The marks to proactively set. Invalid numbers will be ignored.
	//Indexes not listed will be left the same.
	MarksChanges map[int]bool
}

//TODO: audit all uses of step/compoundstep.Apply()

//TOOD: make readOnlyCellImpl. Test if neighbors should be derived or not.
//Everything should be actual contiguous memory, no pointers (except for
//grid). Likely should make cellImpl embed a readOnlyCellImpl and only
//override items it needs to.

//TODO: make readOnlyGridImpl. Two possible approaches: a version that is
//incredibly easy to copy and then do minor tweaks. Or a version that stores a
//dictionary of cell configs, and any time you grab a Cell we look it up in
//the dict or in the ancestors' dicts.

//newCellModification returns a CellModification for the given cell that is a
//no-op.
func newCellModification(cell Cell) *CellModification {
	return &CellModification{
		Cell:            cell,
		Number:          -1,
		ExcludesChanges: make(map[int]bool),
		MarksChanges:    make(map[int]bool),
	}
}

//normalize makes sure the GridModification is legal.
func (m GridModification) normalize() {
	for _, cellModification := range m {
		for key, _ := range cellModification.ExcludesChanges {
			if key <= 0 || key > DIM {
				delete(cellModification.ExcludesChanges, key)
			}
		}
		for key, _ := range cellModification.MarksChanges {
			if key <= 0 || key > DIM {
				delete(cellModification.MarksChanges, key)
			}
		}

		if cellModification.Number < -1 || cellModification.Number > DIM {
			cellModification.Number = -1
		}
	}

}

//equivalent returns true if the other grid modification is equivalent to this one.
func (m GridModification) equivalent(other GridModification) bool {
	if len(m) != len(other) {
		return false
	}
	for i, modification := range m {
		otherModification := other[i]
		if modification.Cell.ref().String() != otherModification.Cell.ref().String() {
			return false
		}
		if modification.Number != otherModification.Number {
			return false
		}

		if len(modification.ExcludesChanges) != len(otherModification.ExcludesChanges) {
			return false
		}

		for key, val := range modification.ExcludesChanges {
			otherVal, ok := otherModification.ExcludesChanges[key]
			if !ok {
				return false
			}
			if val != otherVal {
				return false
			}
		}

		if len(modification.MarksChanges) != len(otherModification.MarksChanges) {
			return false
		}

		for key, val := range modification.MarksChanges {
			otherVal, ok := otherModification.MarksChanges[key]
			if !ok {
				return false
			}
			if val != otherVal {
				return false
			}
		}
	}
	return true
}

func (self *gridImpl) CopyWithModifications(modifications GridModification) Grid {

	//TODO: test this implementation deeply! Lots of crazy stuff that could go
	//wrong.

	modifications.normalize()

	result := new(gridImpl)

	//Copy in everything
	*result = *self

	for i := 0; i < DIM*DIM; i++ {
		cell := &result.cells[i]
		cell.gridRef = result
	}

	result.theQueue.grid = result

	cellNumberModified := false
	excludesModififed := false

	for _, modification := range modifications {
		cell := result.cellImpl(modification.Cell.Row(), modification.Cell.Col())

		if modification.Number >= 0 && modification.Number <= DIM {
			//cell.setNumber will handle setting all of the impossibles
			if cell.setNumber(modification.Number) {
				cellNumberModified = true
			}
		}

		for key, val := range modification.ExcludesChanges {
			//Key is 1-indexed
			key--
			if cell.excluded[key] != val {
				cell.excluded[key] = val
				excludesModififed = true
			}
		}

		for key, val := range modification.MarksChanges {
			//Key is 1-indexed
			key--
			cell.marks[key] = val
		}
	}

	filledCellsCount := 0

	if cellNumberModified {

		//At least one cell's number was modified, which means we need to fix
		//up the queue, numFilledCells, Invalid, Solved. (And some of those we
		//also need to do if any excludes were modified but no numbers were.)

		for _, cell := range result.cells {
			if cell.number == 0 {
				continue
			}
			filledCellsCount++
		}

		result.filledCellsCount = filledCellsCount

		//Check if we're invalid.

	}

	if cellNumberModified || excludesModififed {

		invalid := false

		for _, cell := range result.cells {
			//Make sure we have at least one possibility per cell
			foundPossibility := false
			for i := 1; i <= DIM; i++ {
				if cell.Possible(i) {
					foundPossibility = true
					break
				}
			}
			if !foundPossibility {
				invalid = true
				break
			}
		}

		if !invalid {
			//Let's do a deep check
			invalid = gridGroupsInvalid(result)
		}

		result.invalid = invalid

		if filledCellsCount == DIM*DIM && !result.invalid {
			//All cells are filled and it's not invalid, so it's solved!
			result.solved = true
		} else {
			//No way it's solved
			result.solved = false
		}

		result.theQueue.fix()
	}

	return result

}

func (self *mutableGridImpl) CopyWithModifications(modifications GridModification) Grid {
	//TODO: when we have an honest-to-god readonly grid impl, optimize this.
	result := self.MutableCopy()

	modifications.normalize()

	for _, modification := range modifications {
		cell := modification.Cell.MutableInGrid(result)

		if modification.Number >= 0 && modification.Number <= DIM {
			cell.SetNumber(modification.Number)
		}

		for key, val := range modification.ExcludesChanges {
			//setExcluded will skip invalid entries
			cell.SetExcluded(key, val)
		}

		for key, val := range modification.MarksChanges {
			//SetMark will skip invalid numbers
			cell.SetMark(key, val)
		}
	}

	return result
}
<|endoftext|>


<commit_before>// +build selinux,linux

package label

import (
	"strings"
	"testing"

	"github.com/opencontainers/runc/libcontainer/selinux"
)

func TestInit(t *testing.T) {
	if selinux.SelinuxEnabled() {
		var testNull []string
		plabel, mlabel, err := InitLabels(testNull)
		if err != nil {
			t.Log("InitLabels Failed")
			t.Fatal(err)
		}
		testDisabled := []string{"disable"}
		plabel, mlabel, err = InitLabels(testDisabled)
		if err != nil {
			t.Log("InitLabels Disabled Failed")
			t.Fatal(err)
		}
		if plabel != "" {
			t.Log("InitLabels Disabled Failed")
			t.Fatal()
		}
		testUser := []string{"user:user_u", "role:user_r", "type:user_t", "level:s0:c1,c15"}
		plabel, mlabel, err = InitLabels(testUser)
		if err != nil {
			t.Log("InitLabels User Failed")
			t.Fatal(err)
		}
		if plabel != "user_u:user_r:user_t:s0:c1,c15" || mlabel != "user_u:object_r:svirt_sandbox_file_t:s0:c1,c15" {
			t.Log("InitLabels User Match Failed")
			t.Log(plabel, mlabel)
			t.Fatal(err)
		}

		testBadData := []string{"user", "role:user_r", "type:user_t", "level:s0:c1,c15"}
		plabel, mlabel, err = InitLabels(testBadData)
		if err == nil {
			t.Log("InitLabels Bad Failed")
			t.Fatal(err)
		}
	}
}
func TestDuplicateLabel(t *testing.T) {
	secopt := DupSecOpt("system_u:system_r:svirt_lxc_net_t:s0:c1,c2")
	t.Log(secopt)
	for _, opt := range secopt {
		con := strings.SplitN(opt, ":", 3)
		if len(con) != 3 || con[0] != "label" {
			t.Errorf("Invalid DupSecOpt return value")
			continue
		}
		if con[1] == "user" {
			if con[2] != "system_u" {
				t.Errorf("DupSecOpt Failed user incorrect")
			}
			continue
		}
		if con[1] == "role" {
			if con[2] != "system_r" {
				t.Errorf("DupSecOpt Failed role incorrect")
			}
			continue
		}
		if con[1] == "type" {
			if con[2] != "svirt_lxc_net_t" {
				t.Errorf("DupSecOpt Failed type incorrect")
			}
			continue
		}
		if con[1] == "level" {
			if con[2] != "s0:c1,c2" {
				t.Errorf("DupSecOpt Failed level incorrect")
			}
			continue
		}
		t.Errorf("DupSecOpt Failed invalid field %q", con[1])
	}
	secopt = DisableSecOpt()
	if secopt[0] != "label:disable" {
		t.Errorf("DisableSecOpt Failed level incorrect")
	}
}
func TestRelabel(t *testing.T) {
	testdir := "/tmp/test"
	label := "system_u:system_r:svirt_sandbox_file_t:s0:c1,c2"
	if err := Relabel(testdir, "", true); err != nil {
		t.Fatal("Relabel with no label failed: %v", err)
	}
	if err := Relabel(testdir, label, true); err != nil {
		t.Fatal("Relabel shared failed: %v", err)
	}
	if err := Relabel(testdir, label, false); err != nil {
		t.Fatal("Relabel unshared failed: %v", err)
	}
	if err := Relabel("/etc", label, false); err == nil {
		t.Fatal("Relabel /etc succeeded")
	}
	if err := Relabel("/", label, false); err == nil {
		t.Fatal("Relabel / succeeded")
	}
	if err := Relabel("/usr", label, false); err == nil {
		t.Fatal("Relabel /usr succeeded")
	}
}

func TestValidate(t *testing.T) {
	if err := Validate("zZ"); err != ErrIncompatibleLabel {
		t.Fatalf("Expected incompatible error, got %v", err)
	}
	if err := Validate("Z"); err != nil {
		t.Fatal(err)
	}
	if err := Validate("z"); err != nil {
		t.Fatal(err)
	}
	if err := Validate(""); err != nil {
		t.Fatal(err)
	}
}

func TestIsShared(t *testing.T) {
	if shared := IsShared("Z"); shared {
		t.Fatal("Expected label `Z` to not be shared, got %v", shared)
	}
	if shared := IsShared("z"); !shared {
		t.Fatal("Expected label `z` to be shared, got %v", shared)
	}
	if shared := IsShared("Zz"); !shared {
		t.Fatal("Expected label `Zz` to be shared, got %v", shared)
	}

}
<commit_msg>make localtest failure with selinux enabled<commit_after>// +build selinux,linux

package label

import (
	"os"
	"strings"
	"testing"

	"github.com/opencontainers/runc/libcontainer/selinux"
)

func TestInit(t *testing.T) {
	if selinux.SelinuxEnabled() {
		var testNull []string
		plabel, mlabel, err := InitLabels(testNull)
		if err != nil {
			t.Log("InitLabels Failed")
			t.Fatal(err)
		}
		testDisabled := []string{"disable"}
		plabel, mlabel, err = InitLabels(testDisabled)
		if err != nil {
			t.Log("InitLabels Disabled Failed")
			t.Fatal(err)
		}
		if plabel != "" {
			t.Log("InitLabels Disabled Failed")
			t.Fatal()
		}
		testUser := []string{"user:user_u", "role:user_r", "type:user_t", "level:s0:c1,c15"}
		plabel, mlabel, err = InitLabels(testUser)
		if err != nil {
			t.Log("InitLabels User Failed")
			t.Fatal(err)
		}
		if plabel != "user_u:user_r:user_t:s0:c1,c15" || mlabel != "user_u:object_r:svirt_sandbox_file_t:s0:c1,c15" {
			t.Log("InitLabels User Match Failed")
			t.Log(plabel, mlabel)
			t.Fatal(err)
		}

		testBadData := []string{"user", "role:user_r", "type:user_t", "level:s0:c1,c15"}
		plabel, mlabel, err = InitLabels(testBadData)
		if err == nil {
			t.Log("InitLabels Bad Failed")
			t.Fatal(err)
		}
	}
}
func TestDuplicateLabel(t *testing.T) {
	secopt := DupSecOpt("system_u:system_r:svirt_lxc_net_t:s0:c1,c2")
	t.Log(secopt)
	for _, opt := range secopt {
		con := strings.SplitN(opt, ":", 3)
		if len(con) != 3 || con[0] != "label" {
			t.Errorf("Invalid DupSecOpt return value")
			continue
		}
		if con[1] == "user" {
			if con[2] != "system_u" {
				t.Errorf("DupSecOpt Failed user incorrect")
			}
			continue
		}
		if con[1] == "role" {
			if con[2] != "system_r" {
				t.Errorf("DupSecOpt Failed role incorrect")
			}
			continue
		}
		if con[1] == "type" {
			if con[2] != "svirt_lxc_net_t" {
				t.Errorf("DupSecOpt Failed type incorrect")
			}
			continue
		}
		if con[1] == "level" {
			if con[2] != "s0:c1,c2" {
				t.Errorf("DupSecOpt Failed level incorrect")
			}
			continue
		}
		t.Errorf("DupSecOpt Failed invalid field %q", con[1])
	}
	secopt = DisableSecOpt()
	if secopt[0] != "label:disable" {
		t.Errorf("DisableSecOpt Failed level incorrect")
	}
}
func TestRelabel(t *testing.T) {
	testdir := "/tmp/test"
	if err := os.Mkdir(testdir, 0755); err != nil {
		t.Fatal(err)
	}
	defer os.RemoveAll(testdir)
	label := "system_u:system_r:svirt_sandbox_file_t:s0:c1,c2"
	if err := Relabel(testdir, "", true); err != nil {
		t.Fatal("Relabel with no label failed: %v", err)
	}
	if err := Relabel(testdir, label, true); err != nil {
		t.Fatal("Relabel shared failed: %v", err)
	}
	if err := Relabel(testdir, label, false); err != nil {
		t.Fatal("Relabel unshared failed: %v", err)
	}
	if err := Relabel("/etc", label, false); err == nil {
		t.Fatal("Relabel /etc succeeded")
	}
	if err := Relabel("/", label, false); err == nil {
		t.Fatal("Relabel / succeeded")
	}
	if err := Relabel("/usr", label, false); err == nil {
		t.Fatal("Relabel /usr succeeded")
	}
}

func TestValidate(t *testing.T) {
	if err := Validate("zZ"); err != ErrIncompatibleLabel {
		t.Fatalf("Expected incompatible error, got %v", err)
	}
	if err := Validate("Z"); err != nil {
		t.Fatal(err)
	}
	if err := Validate("z"); err != nil {
		t.Fatal(err)
	}
	if err := Validate(""); err != nil {
		t.Fatal(err)
	}
}

func TestIsShared(t *testing.T) {
	if shared := IsShared("Z"); shared {
		t.Fatal("Expected label `Z` to not be shared, got %v", shared)
	}
	if shared := IsShared("z"); !shared {
		t.Fatal("Expected label `z` to be shared, got %v", shared)
	}
	if shared := IsShared("Zz"); !shared {
		t.Fatal("Expected label `Zz` to be shared, got %v", shared)
	}

}
<|endoftext|>