<commit_before>// Copyright 2015 Keybase, Inc. All rights reserved. Use of
// this source code is governed by the included BSD license.

package logger

import (
	"fmt"
	"os"
	"path/filepath"
	"strings"
	"sync"

	keybase1 "github.com/keybase/client/go/protocol"
	logging "github.com/keybase/go-logging"
	"golang.org/x/net/context"
)

const permDir os.FileMode = 0700

var initLoggingBackendOnce sync.Once
var logRotateMutex sync.Mutex

// CtxStandardLoggerKey is a type defining context keys used by the
// Standard logger.
type CtxStandardLoggerKey int

const (
	// CtxLogTags defines a context key that can hold a slice of context
	// keys, the value of which should be logged by a Standard logger if
	// one of those keys is seen in a context during a log call.
	CtxLogTagsKey CtxStandardLoggerKey = iota
)

type CtxLogTags map[interface{}]string

// NewContext returns a new Context that carries adds the given log
// tag mappings (context key -> display string).
func NewContextWithLogTags(
	ctx context.Context, logTagsToAdd CtxLogTags) context.Context {
	currTags, ok := LogTagsFromContext(ctx)
	if !ok {
		currTags = make(CtxLogTags)
	}
	for key, tag := range logTagsToAdd {
		currTags[key] = tag
	}
	return context.WithValue(ctx, CtxLogTagsKey, currTags)
}

// LogTagsFromContext returns the log tags being passed along with the
// given context.
func LogTagsFromContext(ctx context.Context) (CtxLogTags, bool) {
	logTags, ok := ctx.Value(CtxLogTagsKey).(CtxLogTags)
	return logTags, ok
}

type ExternalLogger interface {
	Log(level keybase1.LogLevel, format string, args []interface{})
}

type Standard struct {
	internal       *logging.Logger
	filename       string
	configureMutex sync.Mutex
	module         string

	externalLoggers      map[uint64]ExternalLogger
	externalLoggersCount uint64
	externalLogLevel     keybase1.LogLevel
	externalLoggersMutex sync.RWMutex
}

// New creates a new Standard logger for module.
func New(module string) *Standard {
	return NewWithCallDepth(module, 0)
}

// Verify Standard fully implements the Logger interface.
var _ Logger = (*Standard)(nil)

// NewWithCallDepth creates a new Standard logger for module, and when
// printing file names and line numbers, it goes extraCallDepth up the
// stack from where logger was invoked.
func NewWithCallDepth(module string, extraCallDepth int) *Standard {
	log := logging.MustGetLogger(module)
	log.ExtraCalldepth = 1 + extraCallDepth
	ret := &Standard{
		internal:             log,
		module:               module,
		externalLoggers:      make(map[uint64]ExternalLogger),
		externalLoggersCount: 0,
		externalLogLevel:     keybase1.LogLevel_INFO,
	}
	ret.initLogging()
	return ret
}

func (log *Standard) initLogging() {
	// Logging is always done to stderr. It's the responsibility of the
	// launcher (like launchd on OSX, or the autoforking code) to set up stderr
	// to point to the appropriate log file.
	initLoggingBackendOnce.Do(func() {
		logBackend := logging.NewLogBackend(os.Stderr, "", 0)
		logging.SetBackend(logBackend)
		logging.SetLevel(logging.INFO, log.module)
	})
}

func (log *Standard) prepareString(
	ctx context.Context, fmts string) string {
	if ctx == nil {
		return fmts
	}
	logTags, ok := LogTagsFromContext(ctx)
	if !ok || len(logTags) == 0 {
		return fmts
	}
	var tags []string
	for key, tag := range logTags {
		if v := ctx.Value(key); v != nil {
			tags = append(tags, fmt.Sprintf("%s=%s", tag, v))
		}
	}
	return fmts + " [tags:" + strings.Join(tags, ",") + "]"
}

func (log *Standard) Debug(fmt string, arg ...interface{}) {
	log.internal.Debug(fmt, arg...)
	log.logToExternalLoggers(keybase1.LogLevel_DEBUG, fmt, arg)
}

func (log *Standard) CDebugf(ctx context.Context, fmt string,
	arg ...interface{}) {
	if log.internal.IsEnabledFor(logging.DEBUG) {
		log.Debug(log.prepareString(ctx, fmt), arg...)
	}
}

func (log *Standard) Info(fmt string, arg ...interface{}) {
	log.internal.Info(fmt, arg...)
	log.logToExternalLoggers(keybase1.LogLevel_INFO, fmt, arg)
}

func (log *Standard) CInfof(ctx context.Context, fmt string,
	arg ...interface{}) {
	if log.internal.IsEnabledFor(logging.INFO) {
		log.Info(log.prepareString(ctx, fmt), arg...)
	}
}

func (log *Standard) Notice(fmt string, arg ...interface{}) {
	log.internal.Notice(fmt, arg...)
	log.logToExternalLoggers(keybase1.LogLevel_NOTICE, fmt, arg)
}

func (log *Standard) CNoticef(ctx context.Context, fmt string,
	arg ...interface{}) {
	if log.internal.IsEnabledFor(logging.NOTICE) {
		log.Notice(log.prepareString(ctx, fmt), arg...)
	}
}

func (log *Standard) Warning(fmt string, arg ...interface{}) {
	log.internal.Warning(fmt, arg...)
	log.logToExternalLoggers(keybase1.LogLevel_WARN, fmt, arg)
}

func (log *Standard) CWarningf(ctx context.Context, fmt string,
	arg ...interface{}) {
	if log.internal.IsEnabledFor(logging.WARNING) {
		log.Warning(log.prepareString(ctx, fmt), arg...)
	}
}

func (log *Standard) Error(fmt string, arg ...interface{}) {
	log.internal.Error(fmt, arg...)
	log.logToExternalLoggers(keybase1.LogLevel_ERROR, fmt, arg)
}

func (log *Standard) Errorf(fmt string, arg ...interface{}) {
	log.Error(fmt, arg...)
}

func (log *Standard) CErrorf(ctx context.Context, fmt string,
	arg ...interface{}) {
	if log.internal.IsEnabledFor(logging.ERROR) {
		log.Error(log.prepareString(ctx, fmt), arg...)
	}
}

func (log *Standard) Critical(fmt string, arg ...interface{}) {
	log.internal.Critical(fmt, arg...)
	log.logToExternalLoggers(keybase1.LogLevel_CRITICAL, fmt, arg)
}

func (log *Standard) CCriticalf(ctx context.Context, fmt string,
	arg ...interface{}) {
	if log.internal.IsEnabledFor(logging.CRITICAL) {
		log.Critical(log.prepareString(ctx, fmt), arg...)
	}
}

func (log *Standard) Fatalf(fmt string, arg ...interface{}) {
	log.internal.Fatalf(fmt, arg...)
	log.logToExternalLoggers(keybase1.LogLevel_FATAL, fmt, arg)
}

func (log *Standard) CFatalf(ctx context.Context, fmt string,
	arg ...interface{}) {
	log.Fatalf(log.prepareString(ctx, fmt), arg...)
}

func (log *Standard) Profile(fmts string, arg ...interface{}) {
	log.Debug(fmts, arg...)
}

func (log *Standard) Configure(style string, debug bool, filename string) {
	log.configureMutex.Lock()
	defer log.configureMutex.Unlock()

	log.filename = filename

	var logfmt string
	if debug {
		logfmt = fancyFormat
	} else {
		logfmt = defaultFormat
	}

	// Override the format above if an explicit style was specified.
	switch style {
	case "default":
		logfmt = defaultFormat // Default
	case "plain":
		logfmt = plainFormat // Plain
	case "file":
		logfmt = fileFormat // Good for logging to files
	case "fancy":
		logfmt = fancyFormat // Fancy, good for terminals with color
	}

	if debug {
		logging.SetLevel(logging.DEBUG, log.module)
	}

	logging.SetFormatter(logging.MustStringFormatter(logfmt))
}

func OpenLogFile(filename string) (name string, file *os.File, err error) {
	name = filename
	if err = MakeParentDirs(name); err != nil {
		return
	}
	file, err = os.OpenFile(name, (os.O_APPEND | os.O_WRONLY | os.O_CREATE), 0600)
	if err != nil {
		return
	}
	return
}

func FileExists(path string) (bool, error) {
	_, err := os.Stat(path)
	if err == nil {
		return true, nil
	}
	if os.IsNotExist(err) {
		return false, nil
	}
	return false, err
}

func MakeParentDirs(filename string) error {
	dir, _ := filepath.Split(filename)
	exists, err := FileExists(dir)
	if err != nil {
		return err
	}

	if !exists {
		err = os.MkdirAll(dir, permDir)
		if err != nil {
			return err
		}
	}
	return nil
}

func PickFirstError(errors ...error) error {
	for _, e := range errors {
		if e != nil {
			return e
		}
	}
	return nil
}

func (log *Standard) AddExternalLogger(externalLogger ExternalLogger) uint64 {
	log.externalLoggersMutex.Lock()
	defer log.externalLoggersMutex.Unlock()

	handle := log.externalLoggersCount
	log.externalLoggersCount++
	log.externalLoggers[handle] = externalLogger
	return handle
}

func (log *Standard) RemoveExternalLogger(handle uint64) {
	log.externalLoggersMutex.Lock()
	defer log.externalLoggersMutex.Unlock()

	delete(log.externalLoggers, handle)
}

func (log *Standard) logToExternalLoggers(level keybase1.LogLevel, format string, args []interface{}) {
	log.externalLoggersMutex.RLock()
	defer log.externalLoggersMutex.RUnlock()

	// Short circuit logs that are more verbose than the current external log
	// level.
	if level < log.externalLogLevel {
		return
	}

	for _, externalLogger := range log.externalLoggers {
		go externalLogger.Log(level, format, args)
	}
}

func (log *Standard) SetExternalLogLevel(level keybase1.LogLevel) {
	log.externalLoggersMutex.Lock()
	defer log.externalLoggersMutex.Unlock()

	log.externalLogLevel = level
}
<commit_msg>Don't use a goroutine for logging to external loggers<commit_after>// Copyright 2015 Keybase, Inc. All rights reserved. Use of
// this source code is governed by the included BSD license.

package logger

import (
	"fmt"
	"os"
	"path/filepath"
	"strings"
	"sync"

	keybase1 "github.com/keybase/client/go/protocol"
	logging "github.com/keybase/go-logging"
	"golang.org/x/net/context"
)

const permDir os.FileMode = 0700

var initLoggingBackendOnce sync.Once
var logRotateMutex sync.Mutex

// CtxStandardLoggerKey is a type defining context keys used by the
// Standard logger.
type CtxStandardLoggerKey int

const (
	// CtxLogTags defines a context key that can hold a slice of context
	// keys, the value of which should be logged by a Standard logger if
	// one of those keys is seen in a context during a log call.
	CtxLogTagsKey CtxStandardLoggerKey = iota
)

type CtxLogTags map[interface{}]string

// NewContext returns a new Context that carries adds the given log
// tag mappings (context key -> display string).
func NewContextWithLogTags(
	ctx context.Context, logTagsToAdd CtxLogTags) context.Context {
	currTags, ok := LogTagsFromContext(ctx)
	if !ok {
		currTags = make(CtxLogTags)
	}
	for key, tag := range logTagsToAdd {
		currTags[key] = tag
	}
	return context.WithValue(ctx, CtxLogTagsKey, currTags)
}

// LogTagsFromContext returns the log tags being passed along with the
// given context.
func LogTagsFromContext(ctx context.Context) (CtxLogTags, bool) {
	logTags, ok := ctx.Value(CtxLogTagsKey).(CtxLogTags)
	return logTags, ok
}

type ExternalLogger interface {
	Log(level keybase1.LogLevel, format string, args []interface{})
}

type Standard struct {
	internal       *logging.Logger
	filename       string
	configureMutex sync.Mutex
	module         string

	externalLoggers      map[uint64]ExternalLogger
	externalLoggersCount uint64
	externalLogLevel     keybase1.LogLevel
	externalLoggersMutex sync.RWMutex
}

// New creates a new Standard logger for module.
func New(module string) *Standard {
	return NewWithCallDepth(module, 0)
}

// Verify Standard fully implements the Logger interface.
var _ Logger = (*Standard)(nil)

// NewWithCallDepth creates a new Standard logger for module, and when
// printing file names and line numbers, it goes extraCallDepth up the
// stack from where logger was invoked.
func NewWithCallDepth(module string, extraCallDepth int) *Standard {
	log := logging.MustGetLogger(module)
	log.ExtraCalldepth = 1 + extraCallDepth
	ret := &Standard{
		internal:             log,
		module:               module,
		externalLoggers:      make(map[uint64]ExternalLogger),
		externalLoggersCount: 0,
		externalLogLevel:     keybase1.LogLevel_INFO,
	}
	ret.initLogging()
	return ret
}

func (log *Standard) initLogging() {
	// Logging is always done to stderr. It's the responsibility of the
	// launcher (like launchd on OSX, or the autoforking code) to set up stderr
	// to point to the appropriate log file.
	initLoggingBackendOnce.Do(func() {
		logBackend := logging.NewLogBackend(os.Stderr, "", 0)
		logging.SetBackend(logBackend)
		logging.SetLevel(logging.INFO, log.module)
	})
}

func (log *Standard) prepareString(
	ctx context.Context, fmts string) string {
	if ctx == nil {
		return fmts
	}
	logTags, ok := LogTagsFromContext(ctx)
	if !ok || len(logTags) == 0 {
		return fmts
	}
	var tags []string
	for key, tag := range logTags {
		if v := ctx.Value(key); v != nil {
			tags = append(tags, fmt.Sprintf("%s=%s", tag, v))
		}
	}
	return fmts + " [tags:" + strings.Join(tags, ",") + "]"
}

func (log *Standard) Debug(fmt string, arg ...interface{}) {
	log.internal.Debug(fmt, arg...)
	log.logToExternalLoggers(keybase1.LogLevel_DEBUG, fmt, arg)
}

func (log *Standard) CDebugf(ctx context.Context, fmt string,
	arg ...interface{}) {
	if log.internal.IsEnabledFor(logging.DEBUG) {
		log.Debug(log.prepareString(ctx, fmt), arg...)
	}
}

func (log *Standard) Info(fmt string, arg ...interface{}) {
	log.internal.Info(fmt, arg...)
	log.logToExternalLoggers(keybase1.LogLevel_INFO, fmt, arg)
}

func (log *Standard) CInfof(ctx context.Context, fmt string,
	arg ...interface{}) {
	if log.internal.IsEnabledFor(logging.INFO) {
		log.Info(log.prepareString(ctx, fmt), arg...)
	}
}

func (log *Standard) Notice(fmt string, arg ...interface{}) {
	log.internal.Notice(fmt, arg...)
	log.logToExternalLoggers(keybase1.LogLevel_NOTICE, fmt, arg)
}

func (log *Standard) CNoticef(ctx context.Context, fmt string,
	arg ...interface{}) {
	if log.internal.IsEnabledFor(logging.NOTICE) {
		log.Notice(log.prepareString(ctx, fmt), arg...)
	}
}

func (log *Standard) Warning(fmt string, arg ...interface{}) {
	log.internal.Warning(fmt, arg...)
	log.logToExternalLoggers(keybase1.LogLevel_WARN, fmt, arg)
}

func (log *Standard) CWarningf(ctx context.Context, fmt string,
	arg ...interface{}) {
	if log.internal.IsEnabledFor(logging.WARNING) {
		log.Warning(log.prepareString(ctx, fmt), arg...)
	}
}

func (log *Standard) Error(fmt string, arg ...interface{}) {
	log.internal.Error(fmt, arg...)
	log.logToExternalLoggers(keybase1.LogLevel_ERROR, fmt, arg)
}

func (log *Standard) Errorf(fmt string, arg ...interface{}) {
	log.Error(fmt, arg...)
}

func (log *Standard) CErrorf(ctx context.Context, fmt string,
	arg ...interface{}) {
	if log.internal.IsEnabledFor(logging.ERROR) {
		log.Error(log.prepareString(ctx, fmt), arg...)
	}
}

func (log *Standard) Critical(fmt string, arg ...interface{}) {
	log.internal.Critical(fmt, arg...)
	log.logToExternalLoggers(keybase1.LogLevel_CRITICAL, fmt, arg)
}

func (log *Standard) CCriticalf(ctx context.Context, fmt string,
	arg ...interface{}) {
	if log.internal.IsEnabledFor(logging.CRITICAL) {
		log.Critical(log.prepareString(ctx, fmt), arg...)
	}
}

func (log *Standard) Fatalf(fmt string, arg ...interface{}) {
	log.internal.Fatalf(fmt, arg...)
	log.logToExternalLoggers(keybase1.LogLevel_FATAL, fmt, arg)
}

func (log *Standard) CFatalf(ctx context.Context, fmt string,
	arg ...interface{}) {
	log.Fatalf(log.prepareString(ctx, fmt), arg...)
}

func (log *Standard) Profile(fmts string, arg ...interface{}) {
	log.Debug(fmts, arg...)
}

func (log *Standard) Configure(style string, debug bool, filename string) {
	log.configureMutex.Lock()
	defer log.configureMutex.Unlock()

	log.filename = filename

	var logfmt string
	if debug {
		logfmt = fancyFormat
	} else {
		logfmt = defaultFormat
	}

	// Override the format above if an explicit style was specified.
	switch style {
	case "default":
		logfmt = defaultFormat // Default
	case "plain":
		logfmt = plainFormat // Plain
	case "file":
		logfmt = fileFormat // Good for logging to files
	case "fancy":
		logfmt = fancyFormat // Fancy, good for terminals with color
	}

	if debug {
		logging.SetLevel(logging.DEBUG, log.module)
	}

	logging.SetFormatter(logging.MustStringFormatter(logfmt))
}

func OpenLogFile(filename string) (name string, file *os.File, err error) {
	name = filename
	if err = MakeParentDirs(name); err != nil {
		return
	}
	file, err = os.OpenFile(name, (os.O_APPEND | os.O_WRONLY | os.O_CREATE), 0600)
	if err != nil {
		return
	}
	return
}

func FileExists(path string) (bool, error) {
	_, err := os.Stat(path)
	if err == nil {
		return true, nil
	}
	if os.IsNotExist(err) {
		return false, nil
	}
	return false, err
}

func MakeParentDirs(filename string) error {
	dir, _ := filepath.Split(filename)
	exists, err := FileExists(dir)
	if err != nil {
		return err
	}

	if !exists {
		err = os.MkdirAll(dir, permDir)
		if err != nil {
			return err
		}
	}
	return nil
}

func PickFirstError(errors ...error) error {
	for _, e := range errors {
		if e != nil {
			return e
		}
	}
	return nil
}

func (log *Standard) AddExternalLogger(externalLogger ExternalLogger) uint64 {
	log.externalLoggersMutex.Lock()
	defer log.externalLoggersMutex.Unlock()

	handle := log.externalLoggersCount
	log.externalLoggersCount++
	log.externalLoggers[handle] = externalLogger
	return handle
}

func (log *Standard) RemoveExternalLogger(handle uint64) {
	log.externalLoggersMutex.Lock()
	defer log.externalLoggersMutex.Unlock()

	delete(log.externalLoggers, handle)
}

func (log *Standard) logToExternalLoggers(level keybase1.LogLevel, format string, args []interface{}) {
	log.externalLoggersMutex.RLock()
	defer log.externalLoggersMutex.RUnlock()

	// Short circuit logs that are more verbose than the current external log
	// level.
	if level < log.externalLogLevel {
		return
	}

	for _, externalLogger := range log.externalLoggers {
		externalLogger.Log(level, format, args)
	}
}

func (log *Standard) SetExternalLogLevel(level keybase1.LogLevel) {
	log.externalLoggersMutex.Lock()
	defer log.externalLoggersMutex.Unlock()

	log.externalLogLevel = level
}
<|endoftext|>


<commit_before>package main

import (
    "gopkg.in/yaml.v2"
    "io/ioutil"
    "fmt"
    "encoding/hex"
    "encoding/binary"
    "github.com/fuzxxl/nfc/2.0/nfc"
    "github.com/fuzxxl/freefare/0.3/freefare"
    "./keydiversification"
)

// TODO: move to a separate helper module
func string_to_aeskey(keydata_str string) (*freefare.DESFireKey, error) {
    keydata := new([16]byte)
    to_keydata, err := hex.DecodeString(keydata_str)
    if err != nil {
        key := freefare.NewDESFireAESKey(*keydata, 0)
        return key, err
    }
    copy(keydata[0:], to_keydata)
    key := freefare.NewDESFireAESKey(*keydata, 0)
    return key,nil
}

func bytes_to_aeskey(source []byte) (*freefare.DESFireKey) {
    keydata := new([16]byte)
    copy(keydata[0:], source)
    key := freefare.NewDESFireAESKey(*keydata, 0)
    return key
}

func string_to_byte(source string) (byte, error) {
    bytearray, err := hex.DecodeString(source)
    if err != nil {
        return 0x0, err
    }
    return bytearray[0], nil
}

func applicationsettings(accesskey byte, frozen, req_auth_fileops, req_auth_dir, allow_master_key_chg bool) byte {
    ret := byte(0)
    ret |= accesskey << 4
    if (frozen) {
        ret |= 1 << 3
    }
    if (req_auth_fileops) {
        ret |= 1 << 2
    }
    if (req_auth_dir) {
        ret |= 1 << 1;
    }
    if (allow_master_key_chg) {
        ret |= 1;
    }
    return ret
}

func main() {
    keys_data, err := ioutil.ReadFile("keys.yaml")
    if err != nil {
        panic(err)
    }

    keymap := make(map[interface{}]interface{});
    err = yaml.Unmarshal([]byte(keys_data), &keymap);
    if err != nil {
        panic(err)
    }

    apps_data, err := ioutil.ReadFile("apps.yaml")
    if err != nil {
        panic(err)
    }

    appmap := make(map[interface{}]interface{});
    err = yaml.Unmarshal([]byte(apps_data), &appmap);
    if err != nil {
        panic(err)
    }

    // Application-id from config
    aidbytes, err := hex.DecodeString(appmap["hacklab_acl"].(map[interface{}]interface{})["aid"].(string))
    if err != nil {
        panic(err)
    }
    aidint, n := binary.Uvarint(aidbytes)
    if n <= 0 {
        panic(fmt.Sprintf("binary.Uvarint returned %d", n))
    }
    aid := freefare.NewDESFireAid(uint32(aidint))
    //fmt.Println(aid)
    // Needed for diversification
    sysid, err := hex.DecodeString(appmap["hacklab_acl"].(map[interface{}]interface{})["sysid"].(string))
    if err != nil {
        panic(err)
    }

    // Key id numbers from config
    uid_read_key_id, err := string_to_byte(appmap["hacklab_acl"].(map[interface{}]interface{})["uid_read_key_id"].(string))
    if err != nil {
        panic(err)
    }
    acl_read_key_id, err := string_to_byte(appmap["hacklab_acl"].(map[interface{}]interface{})["acl_read_key_id"].(string))
    if err != nil {
        panic(err)
    }
    acl_write_key_id, err := string_to_byte(appmap["hacklab_acl"].(map[interface{}]interface{})["acl_write_key_id"].(string))
    if err != nil {
        panic(err)
    }
    prov_key_id, err := string_to_byte(appmap["hacklab_acl"].(map[interface{}]interface{})["provisioning_key_id"].(string))
    if err != nil {
        panic(err)
    }

    // Defaul (null) key
    nullkeydata := new([8]byte)
    defaultkey := freefare.NewDESFireDESKey(*nullkeydata)

    nullkeydata16 := new([16]byte)
    defaultkey_aes := freefare.NewDESFireAESKey(*nullkeydata16, 0)

    // New card master key
    new_master_key, err := string_to_aeskey(keymap["card_master"].(string))
    if err != nil {
        panic(err)
    }
    //fmt.Println(new_master_key)

    // The static app key to read UID
    uid_read_key, err := string_to_aeskey(keymap["uid_read_key"].(string))
    if err != nil {
        panic(err)
    }
    //fmt.Println(uid_read_key)

    // Bases for the diversified keys
    prov_key_base, err := hex.DecodeString(keymap["prov_master"].(string))
    if err != nil {
        panic(err)
    }
    acl_read_base, err := hex.DecodeString(keymap["acl_read_key"].(string))
    if err != nil {
        panic(err)
    }
    acl_write_base, err := hex.DecodeString(keymap["acl_write_key"].(string))
    if err != nil {
        panic(err)
    }

    // Open device and get tags list
    d, err := nfc.Open("");
    if err != nil {
        panic(err)
    }

    tags, err := freefare.GetTags(d);
    if err != nil {
        panic(err)
    }

    // Initialize each tag with our app
    for i := 0; i < len(tags); i++ {
        tag := tags[i]
        fmt.Println(tag.String(), tag.UID())

        // Skip non desfire tags
        if (tag.Type() != freefare.DESFire) {
            fmt.Println("Skipped");
            continue
        }

        desfiretag := tag.(freefare.DESFireTag)

        // Connect to this tag
        fmt.Println("Connecting");
        error := desfiretag.Connect()
        if error != nil {
            panic(error)
        }
        fmt.Println("Done");

        fmt.Println("Authenticating");
        error = desfiretag.Authenticate(0,*defaultkey)
        if error != nil {
            fmt.Println("Failed, trying agin with new key")
            error = desfiretag.Authenticate(0,*new_master_key)
            if error != nil {
                panic(error)
            }
            fmt.Println("Changing key back to default")
            error = desfiretag.ChangeKey(0,  *defaultkey, *new_master_key);
            if error != nil {
                panic(error)
            }
            fmt.Println("Re-auth with default key")
            error = desfiretag.Authenticate(0,*defaultkey)
            if error != nil {
                panic(error)
            }
            fmt.Println("Disabling random id")
            error = desfiretag.SetConfiguration(false, false)
            if error != nil {
                panic(error)
            }
            fmt.Println("Formatting (to get a clean state)")
            error = desfiretag.FormatPICC()
            if error != nil {
                panic(error)
            }
            return
        }
        fmt.Println("Done");

        // Get card real UID
        realuid_str, error := desfiretag.CardUID()
        if error != nil {
            panic(error)
        }
        realuid, error := hex.DecodeString(realuid_str);
        if error != nil {
            panic(error)
        }
        //fmt.Println("realuid:", hex.EncodeToString(realuid));

        // Calculate the diversified keys
        prov_key_bytes, err := keydiversification.AES128(prov_key_base, aidbytes, realuid, sysid)
        if err != nil {
            panic(err)
        }
        prov_key := bytes_to_aeskey(prov_key_bytes)
        acl_read_bytes, err := keydiversification.AES128(acl_read_base, aidbytes, realuid, sysid)
        if err != nil {
            panic(err)
        }
        acl_read_key := bytes_to_aeskey(acl_read_bytes)
        acl_write_bytes, err := keydiversification.AES128(acl_write_base, aidbytes, realuid, sysid)
        if err != nil {
            panic(err)
        }
        acl_write_key := bytes_to_aeskey(acl_write_bytes)

        // Start working...
        fmt.Println("Changing default master key");
        error = desfiretag.ChangeKey(0, *new_master_key, *defaultkey);
        if error != nil {
            panic(error)
        }
        fmt.Println("Done");

        fmt.Println("Creating application");
        // Settings are: only master key may change other keys, configuration is not locked, authentication required for everything, AMK change allowed
        error = desfiretag.CreateApplication(aid, applicationsettings(0x0, false, true, true, true), freefare.CryptoAES | 6);
        if error != nil {
            panic(error)
        }
        fmt.Println("Done");

        fmt.Println("Selecting application");
        error = desfiretag.SelectApplication(aid);
        if error != nil {
            panic(error)
        }
        fmt.Println("Done");

        fmt.Println("Re-auth with null AES key")
        error = desfiretag.Authenticate(prov_key_id,*defaultkey_aes)
        if error != nil {
            panic(error)
        }

        fmt.Println("Changing provisioning key");
        error = desfiretag.ChangeKey(prov_key_id, *prov_key, *defaultkey_aes);
        if error != nil {
            panic(error)
        }
        fmt.Println("Done");

        fmt.Println("Re-auth with provisioning key")
        error = desfiretag.Authenticate(prov_key_id,*prov_key)
        if error != nil {
            panic(error)
        }

        fmt.Println("Changing ACL reading key");
        error = desfiretag.ChangeKey(acl_read_key_id, *acl_read_key, *defaultkey_aes);
        if error != nil {
            panic(error)
        }
        fmt.Println("Done");

        fmt.Println("Changing ACL writing key");
        error = desfiretag.ChangeKey(acl_write_key_id, *acl_write_key, *defaultkey_aes);
        if error != nil {
            panic(error)
        }
        fmt.Println("Done");

        fmt.Println("Changing static UID reading key");
        error = desfiretag.ChangeKey(uid_read_key_id, *uid_read_key, *defaultkey_aes);
        if error != nil {
            panic(error)
        }
        fmt.Println("Done");

        fmt.Println("Creating ACL data file");
        error = desfiretag.CreateDataFile(0, freefare.Enciphered, freefare.MakeDESFireAccessRights(acl_read_key_id, acl_write_key_id, prov_key_id, prov_key_id), 8, false)
        if error != nil {
            panic(error)
        }
        fmt.Println("Done");

        /**
         * TODO: check later if this works
        fmt.Println("Creating ACL backup file");
        error = desfiretag.CreateDataFile(0, freefare.Enciphered, freefare.MakeDESFireAccessRights(acl_read_key_id, acl_write_key_id, prov_key_id, prov_key_id), 8, true)
        if error != nil {
            panic(error)
        }
        fmt.Println("Done");
         */

        /**
         * Only needed when working with backup files
        // Not sure if this is actually needed
        fmt.Println("Committing");
        error = desfiretag.CommitTransaction()
        if error != nil {
            panic(error)
        }
        fmt.Println("Done");
         */

        /**
         * Enable this only when 100% everything else works perfectly
        fmt.Println("Enabling random ID");
        error = desfiretag.SetConfiguration(false, true)
        if error != nil {
            panic(error)
        }
        fmt.Println("Done");
         */

        fmt.Println("Disconnecting");
        error = desfiretag.Disconnect()
        if error != nil {
            panic(error)
        }
        fmt.Println("Done");
    }

}<commit_msg>I hope this creates a backed up data file<commit_after>package main

import (
    "gopkg.in/yaml.v2"
    "io/ioutil"
    "fmt"
    "encoding/hex"
    "encoding/binary"
    "github.com/fuzxxl/nfc/2.0/nfc"
    "github.com/fuzxxl/freefare/0.3/freefare"
    "./keydiversification"
)

// TODO: move to a separate helper module
func string_to_aeskey(keydata_str string) (*freefare.DESFireKey, error) {
    keydata := new([16]byte)
    to_keydata, err := hex.DecodeString(keydata_str)
    if err != nil {
        key := freefare.NewDESFireAESKey(*keydata, 0)
        return key, err
    }
    copy(keydata[0:], to_keydata)
    key := freefare.NewDESFireAESKey(*keydata, 0)
    return key,nil
}

func bytes_to_aeskey(source []byte) (*freefare.DESFireKey) {
    keydata := new([16]byte)
    copy(keydata[0:], source)
    key := freefare.NewDESFireAESKey(*keydata, 0)
    return key
}

func string_to_byte(source string) (byte, error) {
    bytearray, err := hex.DecodeString(source)
    if err != nil {
        return 0x0, err
    }
    return bytearray[0], nil
}

func applicationsettings(accesskey byte, frozen, req_auth_fileops, req_auth_dir, allow_master_key_chg bool) byte {
    ret := byte(0)
    ret |= accesskey << 4
    if (frozen) {
        ret |= 1 << 3
    }
    if (req_auth_fileops) {
        ret |= 1 << 2
    }
    if (req_auth_dir) {
        ret |= 1 << 1;
    }
    if (allow_master_key_chg) {
        ret |= 1;
    }
    return ret
}

func main() {
    keys_data, err := ioutil.ReadFile("keys.yaml")
    if err != nil {
        panic(err)
    }

    keymap := make(map[interface{}]interface{});
    err = yaml.Unmarshal([]byte(keys_data), &keymap);
    if err != nil {
        panic(err)
    }

    apps_data, err := ioutil.ReadFile("apps.yaml")
    if err != nil {
        panic(err)
    }

    appmap := make(map[interface{}]interface{});
    err = yaml.Unmarshal([]byte(apps_data), &appmap);
    if err != nil {
        panic(err)
    }

    // Application-id from config
    aidbytes, err := hex.DecodeString(appmap["hacklab_acl"].(map[interface{}]interface{})["aid"].(string))
    if err != nil {
        panic(err)
    }
    aidint, n := binary.Uvarint(aidbytes)
    if n <= 0 {
        panic(fmt.Sprintf("binary.Uvarint returned %d", n))
    }
    aid := freefare.NewDESFireAid(uint32(aidint))
    //fmt.Println(aid)
    // Needed for diversification
    sysid, err := hex.DecodeString(appmap["hacklab_acl"].(map[interface{}]interface{})["sysid"].(string))
    if err != nil {
        panic(err)
    }

    // Key id numbers from config
    uid_read_key_id, err := string_to_byte(appmap["hacklab_acl"].(map[interface{}]interface{})["uid_read_key_id"].(string))
    if err != nil {
        panic(err)
    }
    acl_read_key_id, err := string_to_byte(appmap["hacklab_acl"].(map[interface{}]interface{})["acl_read_key_id"].(string))
    if err != nil {
        panic(err)
    }
    acl_write_key_id, err := string_to_byte(appmap["hacklab_acl"].(map[interface{}]interface{})["acl_write_key_id"].(string))
    if err != nil {
        panic(err)
    }
    prov_key_id, err := string_to_byte(appmap["hacklab_acl"].(map[interface{}]interface{})["provisioning_key_id"].(string))
    if err != nil {
        panic(err)
    }

    // Defaul (null) key
    nullkeydata := new([8]byte)
    defaultkey := freefare.NewDESFireDESKey(*nullkeydata)

    nullkeydata16 := new([16]byte)
    defaultkey_aes := freefare.NewDESFireAESKey(*nullkeydata16, 0)

    // New card master key
    new_master_key, err := string_to_aeskey(keymap["card_master"].(string))
    if err != nil {
        panic(err)
    }
    //fmt.Println(new_master_key)

    // The static app key to read UID
    uid_read_key, err := string_to_aeskey(keymap["uid_read_key"].(string))
    if err != nil {
        panic(err)
    }
    //fmt.Println(uid_read_key)

    // Bases for the diversified keys
    prov_key_base, err := hex.DecodeString(keymap["prov_master"].(string))
    if err != nil {
        panic(err)
    }
    acl_read_base, err := hex.DecodeString(keymap["acl_read_key"].(string))
    if err != nil {
        panic(err)
    }
    acl_write_base, err := hex.DecodeString(keymap["acl_write_key"].(string))
    if err != nil {
        panic(err)
    }

    // Open device and get tags list
    d, err := nfc.Open("");
    if err != nil {
        panic(err)
    }

    tags, err := freefare.GetTags(d);
    if err != nil {
        panic(err)
    }

    // Initialize each tag with our app
    for i := 0; i < len(tags); i++ {
        tag := tags[i]
        fmt.Println(tag.String(), tag.UID())

        // Skip non desfire tags
        if (tag.Type() != freefare.DESFire) {
            fmt.Println("Skipped");
            continue
        }

        desfiretag := tag.(freefare.DESFireTag)

        // Connect to this tag
        fmt.Println("Connecting");
        error := desfiretag.Connect()
        if error != nil {
            panic(error)
        }
        fmt.Println("Done");

        fmt.Println("Authenticating");
        error = desfiretag.Authenticate(0,*defaultkey)
        if error != nil {
            fmt.Println("Failed, trying agin with new key")
            error = desfiretag.Authenticate(0,*new_master_key)
            if error != nil {
                panic(error)
            }
            fmt.Println("Changing key back to default")
            error = desfiretag.ChangeKey(0,  *defaultkey, *new_master_key);
            if error != nil {
                panic(error)
            }
            fmt.Println("Re-auth with default key")
            error = desfiretag.Authenticate(0,*defaultkey)
            if error != nil {
                panic(error)
            }
            fmt.Println("Disabling random id")
            error = desfiretag.SetConfiguration(false, false)
            if error != nil {
                panic(error)
            }
            fmt.Println("Formatting (to get a clean state)")
            error = desfiretag.FormatPICC()
            if error != nil {
                panic(error)
            }
            return
        }
        fmt.Println("Done");

        // Get card real UID
        realuid_str, error := desfiretag.CardUID()
        if error != nil {
            panic(error)
        }
        realuid, error := hex.DecodeString(realuid_str);
        if error != nil {
            panic(error)
        }
        //fmt.Println("realuid:", hex.EncodeToString(realuid));

        // Calculate the diversified keys
        prov_key_bytes, err := keydiversification.AES128(prov_key_base, aidbytes, realuid, sysid)
        if err != nil {
            panic(err)
        }
        prov_key := bytes_to_aeskey(prov_key_bytes)
        acl_read_bytes, err := keydiversification.AES128(acl_read_base, aidbytes, realuid, sysid)
        if err != nil {
            panic(err)
        }
        acl_read_key := bytes_to_aeskey(acl_read_bytes)
        acl_write_bytes, err := keydiversification.AES128(acl_write_base, aidbytes, realuid, sysid)
        if err != nil {
            panic(err)
        }
        acl_write_key := bytes_to_aeskey(acl_write_bytes)

        // Start working...
        fmt.Println("Changing default master key");
        error = desfiretag.ChangeKey(0, *new_master_key, *defaultkey);
        if error != nil {
            panic(error)
        }
        fmt.Println("Done");

        fmt.Println("Creating application");
        // Settings are: only master key may change other keys, configuration is not locked, authentication required for everything, AMK change allowed
        error = desfiretag.CreateApplication(aid, applicationsettings(0x0, false, true, true, true), freefare.CryptoAES | 6);
        if error != nil {
            panic(error)
        }
        fmt.Println("Done");

        fmt.Println("Selecting application");
        error = desfiretag.SelectApplication(aid);
        if error != nil {
            panic(error)
        }
        fmt.Println("Done");

        fmt.Println("Re-auth with null AES key")
        error = desfiretag.Authenticate(prov_key_id,*defaultkey_aes)
        if error != nil {
            panic(error)
        }

        fmt.Println("Changing provisioning key");
        error = desfiretag.ChangeKey(prov_key_id, *prov_key, *defaultkey_aes);
        if error != nil {
            panic(error)
        }
        fmt.Println("Done");

        fmt.Println("Re-auth with provisioning key")
        error = desfiretag.Authenticate(prov_key_id,*prov_key)
        if error != nil {
            panic(error)
        }

        fmt.Println("Changing ACL reading key");
        error = desfiretag.ChangeKey(acl_read_key_id, *acl_read_key, *defaultkey_aes);
        if error != nil {
            panic(error)
        }
        fmt.Println("Done");

        fmt.Println("Changing ACL writing key");
        error = desfiretag.ChangeKey(acl_write_key_id, *acl_write_key, *defaultkey_aes);
        if error != nil {
            panic(error)
        }
        fmt.Println("Done");

        fmt.Println("Changing static UID reading key");
        error = desfiretag.ChangeKey(uid_read_key_id, *uid_read_key, *defaultkey_aes);
        if error != nil {
            panic(error)
        }
        fmt.Println("Done");

        fmt.Println("Creating ACL data file");
        error = desfiretag.CreateDataFile(0, freefare.Enciphered, freefare.MakeDESFireAccessRights(acl_read_key_id, acl_write_key_id, prov_key_id, prov_key_id), 8, true)
        if error != nil {
            panic(error)
        }
        fmt.Println("Done");

        /**
         * Only needed when working with backup files
        // Not sure if this is actually needed
        fmt.Println("Committing");
        error = desfiretag.CommitTransaction()
        if error != nil {
            panic(error)
        }
        fmt.Println("Done");
         */

        /**
         * Enable this only when 100% everything else works perfectly
        fmt.Println("Enabling random ID");
        error = desfiretag.SetConfiguration(false, true)
        if error != nil {
            panic(error)
        }
        fmt.Println("Done");
         */

        fmt.Println("Disconnecting");
        error = desfiretag.Disconnect()
        if error != nil {
            panic(error)
        }
        fmt.Println("Done");
    }

}<|endoftext|>


<commit_before>package statuschart

import (
	"fmt"
	"github.com/burke/ttyutils"
	slog "github.com/burke/zeus/go/shinylog"
	"strings"
	"time"

	"github.com/burke/zeus/go/processtree"
	"os"
)

const (
	lineT = "{yellow}├── "
	lineL = "{yellow}└── "
	lineI = "{yellow}│   "
	lineX = "{yellow}    "
)

func ttyStart(tree *processtree.ProcessTree, done, quit chan bool) {
	go func() {
		scw := &StringChannelWriter{make(chan string, 10)}
		slog.DefaultLogger = slog.NewShinyLogger(scw, scw)

		termios, err := ttyutils.NoEcho(uintptr(os.Stdout.Fd()))
		if err != nil {
			theChart.terminalSupported = false
		}

		ticker := time.Tick(1000 * time.Millisecond)
		for {
			select {
			case <-quit:
				ttyutils.RestoreTerminalState(uintptr(os.Stdout.Fd()), termios)
				done <- true
				return
			case <-ticker:
				theChart.draw()
			case output := <-scw.Notif:
				theChart.L.Lock()
				if theChart.drawnInitial {
					print(output)
				}
				theChart.extraOutput += output
				theChart.L.Unlock()
				theChart.draw()
			case <-tree.StateChanged:
				theChart.draw()
			case <-theChart.update:
				theChart.draw()
			}
		}
	}()
}

func (s *StatusChart) draw() {
	s.L.Lock()
	defer s.L.Unlock()

	if s.drawnInitial {
		lengthOfOutput := s.lengthOfOutput()
		numberOfOutputLines := s.numberOfSlaves + len(s.Commands) + lengthOfOutput + 3
		fmt.Printf("\033[%dA", numberOfOutputLines)
	} else {
		s.drawnInitial = true
	}

	log := theChart.directLogger

	log.Colorized("\x1b[4m{green}[ready] {red}[crashed] {blue}[running] {magenta}[connecting] {yellow}[waiting]\033[K")
	s.drawSubtree(s.RootSlave, "", "")

	log.Colorized("\033[K\n\x1b[4mAvailable Commands: {yellow}[waiting] {red}[crashed] {green}[ready]\033[K")
	s.drawCommands()
	output := strings.Replace(s.extraOutput, "\n", "\033[K\n", -1)
	fmt.Printf(output)
}

func (s *StatusChart) lengthOfOutput() int {
	ts, err := ttyutils.Winsize(os.Stdout)
	if err != nil {
		// This can happen when the output is redirected to a device
		// that blows up on the ioctl Winsize uses. We don't care about fancy drawing in this case.
		return 0
	}
	width := int(ts.Columns)
	if width == 0 { // output has been redirected
		return 0
	}

	lines := strings.Split(s.extraOutput, "\n")

	numLines := 0
	for _, line := range lines {
		n := (len(line) + width - 1) / width
		if n == 0 {
			n = 1
		}
		numLines += n
	}

	return numLines - 1
}

func (s *StatusChart) drawCommands() {
	for _, command := range s.Commands {
		state := command.Parent.State

		alia := strings.Join(command.Aliases, ", ")
		var aliasPart string
		if len(alia) > 0 {
			aliasPart = " (alias: " + alia + ")"
		}
		text := "zeus " + command.Name + aliasPart
		reset := "\033[K"

		log := theChart.directLogger

		switch state {
		case processtree.SReady:
			log.Green(text + reset)
		case processtree.SCrashed:
			log.Red(text + " {yellow}[run to see backtrace]" + reset)
		default:
			log.Yellow(text + reset)
		}
	}
}

func (s *StatusChart) drawSubtree(node *processtree.SlaveNode, myIndentation, childIndentation string) {
	printStateInfo(myIndentation, node.Name, node.State, false, true)

	for i, slave := range node.Slaves {
		if i == len(node.Slaves)-1 {
			s.drawSubtree(slave, childIndentation+lineL, childIndentation+lineX)
		} else {
			s.drawSubtree(slave, childIndentation+lineT, childIndentation+lineI)
		}
	}
}

type StringChannelWriter struct {
	Notif chan string
}

func (s *StringChannelWriter) Write(o []byte) (int, error) {
	s.Notif <- string(o)
	return len(o), nil
}
<commit_msg>Don't update the statuschart every second; only on changes [fixes #333]<commit_after>package statuschart

import (
	"fmt"
	"github.com/burke/ttyutils"
	slog "github.com/burke/zeus/go/shinylog"
	"strings"

	"github.com/burke/zeus/go/processtree"
	"os"
)

const (
	lineT = "{yellow}├── "
	lineL = "{yellow}└── "
	lineI = "{yellow}│   "
	lineX = "{yellow}    "
)

func ttyStart(tree *processtree.ProcessTree, done, quit chan bool) {
	go func() {
		scw := &StringChannelWriter{make(chan string, 10)}
		slog.DefaultLogger = slog.NewShinyLogger(scw, scw)

		termios, err := ttyutils.NoEcho(uintptr(os.Stdout.Fd()))
		if err != nil {
			theChart.terminalSupported = false
		}

		for {
			select {
			case <-quit:
				ttyutils.RestoreTerminalState(uintptr(os.Stdout.Fd()), termios)
				done <- true
				return
			case output := <-scw.Notif:
				theChart.L.Lock()
				if theChart.drawnInitial {
					print(output)
				}
				theChart.extraOutput += output
				theChart.L.Unlock()
				theChart.draw()
			case <-tree.StateChanged:
				theChart.draw()
			case <-theChart.update:
				theChart.draw()
			}
		}
	}()
}

func (s *StatusChart) draw() {
	s.L.Lock()
	defer s.L.Unlock()

	if s.drawnInitial {
		lengthOfOutput := s.lengthOfOutput()
		numberOfOutputLines := s.numberOfSlaves + len(s.Commands) + lengthOfOutput + 3
		fmt.Printf("\033[%dA", numberOfOutputLines)
	} else {
		s.drawnInitial = true
	}

	log := theChart.directLogger

	log.Colorized("\x1b[4m{green}[ready] {red}[crashed] {blue}[running] {magenta}[connecting] {yellow}[waiting]\033[K")
	s.drawSubtree(s.RootSlave, "", "")

	log.Colorized("\033[K\n\x1b[4mAvailable Commands: {yellow}[waiting] {red}[crashed] {green}[ready]\033[K")
	s.drawCommands()
	output := strings.Replace(s.extraOutput, "\n", "\033[K\n", -1)
	fmt.Printf(output)
}

func (s *StatusChart) lengthOfOutput() int {
	ts, err := ttyutils.Winsize(os.Stdout)
	if err != nil {
		// This can happen when the output is redirected to a device
		// that blows up on the ioctl Winsize uses. We don't care about fancy drawing in this case.
		return 0
	}
	width := int(ts.Columns)
	if width == 0 { // output has been redirected
		return 0
	}

	lines := strings.Split(s.extraOutput, "\n")

	numLines := 0
	for _, line := range lines {
		n := (len(line) + width - 1) / width
		if n == 0 {
			n = 1
		}
		numLines += n
	}

	return numLines - 1
}

func (s *StatusChart) drawCommands() {
	for _, command := range s.Commands {
		state := command.Parent.State

		alia := strings.Join(command.Aliases, ", ")
		var aliasPart string
		if len(alia) > 0 {
			aliasPart = " (alias: " + alia + ")"
		}
		text := "zeus " + command.Name + aliasPart
		reset := "\033[K"

		log := theChart.directLogger

		switch state {
		case processtree.SReady:
			log.Green(text + reset)
		case processtree.SCrashed:
			log.Red(text + " {yellow}[run to see backtrace]" + reset)
		default:
			log.Yellow(text + reset)
		}
	}
}

func (s *StatusChart) drawSubtree(node *processtree.SlaveNode, myIndentation, childIndentation string) {
	printStateInfo(myIndentation, node.Name, node.State, false, true)

	for i, slave := range node.Slaves {
		if i == len(node.Slaves)-1 {
			s.drawSubtree(slave, childIndentation+lineL, childIndentation+lineX)
		} else {
			s.drawSubtree(slave, childIndentation+lineT, childIndentation+lineI)
		}
	}
}

type StringChannelWriter struct {
	Notif chan string
}

func (s *StringChannelWriter) Write(o []byte) (int, error) {
	s.Notif <- string(o)
	return len(o), nil
}
<|endoftext|>


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

package types

import (
	"container/heap"
	"fmt"
)

// initOrder computes the Info.InitOrder for package variables.
func (check *Checker) initOrder() {
	// An InitOrder may already have been computed if a package is
	// built from several calls to (*Checker).Files.  Clear it.
	check.Info.InitOrder = check.Info.InitOrder[:0]

	// compute the object dependency graph and
	// initialize a priority queue with the list
	// of graph nodes
	pq := nodeQueue(dependencyGraph(check.objMap))
	heap.Init(&pq)

	const debug = false
	if debug {
		fmt.Printf("package %s: object dependency graph\n", check.pkg.Name())
		for _, n := range pq {
			for _, o := range n.out {
				fmt.Printf("\t%s -> %s\n", n.obj.Name(), o.obj.Name())
			}
		}
		fmt.Println()
		fmt.Printf("package %s: initialization order\n", check.pkg.Name())
	}

	// determine initialization order by removing the highest priority node
	// (the one with the fewest dependencies) and its edges from the graph,
	// repeatedly, until there are no nodes left.
	// In a valid Go program, those nodes always have zero dependencies (after
	// removing all incoming dependencies), otherwise there are initialization
	// cycles.
	mark := 0
	emitted := make(map[*declInfo]bool)
	for len(pq) > 0 {
		// get the next node
		n := heap.Pop(&pq).(*objNode)

		// if n still depends on other nodes, we have a cycle
		if n.in > 0 {
			mark++ // mark nodes using a different value each time
			cycle := findPath(n, n, mark)
			if i := valIndex(cycle); i >= 0 {
				check.reportCycle(cycle, i)
			}
			// ok to continue, but the variable initialization order
			// will be incorrect at this point since it assumes no
			// cycle errors
		}

		// reduce dependency count of all dependent nodes
		// and update priority queue
		for _, out := range n.out {
			out.in--
			heap.Fix(&pq, out.index)
		}

		// record the init order for variables with initializers only
		v, _ := n.obj.(*Var)
		info := check.objMap[v]
		if v == nil || !info.hasInitializer() {
			continue
		}

		// n:1 variable declarations such as: a, b = f()
		// introduce a node for each lhs variable (here: a, b);
		// but they all have the same initializer - emit only
		// one, for the first variable seen
		if emitted[info] {
			continue // initializer already emitted, if any
		}
		emitted[info] = true

		infoLhs := info.lhs // possibly nil (see declInfo.lhs field comment)
		if infoLhs == nil {
			infoLhs = []*Var{v}
		}
		init := &Initializer{infoLhs, info.init}
		check.Info.InitOrder = append(check.Info.InitOrder, init)

		if debug {
			fmt.Printf("\t%s\n", init)
		}
	}

	if debug {
		fmt.Println()
	}
}

// findPath returns the (reversed) list of nodes z, ... c, b, a,
// such that there is a path (list of edges) from a to z.
// If there is no such path, the result is nil.
// Nodes marked with the value mark are considered "visited";
// unvisited nodes are marked during the graph search.
func findPath(a, z *objNode, mark int) []*objNode {
	if a.mark == mark {
		return nil // node already seen
	}
	a.mark = mark

	for _, n := range a.out {
		if n == z {
			return []*objNode{z}
		}
		if P := findPath(n, z, mark); P != nil {
			return append(P, n)
		}
	}

	return nil
}

// valIndex returns the index of the first constant or variable in a,
// if any; or a value < 0.
func valIndex(a []*objNode) int {
	for i, n := range a {
		switch n.obj.(type) {
		case *Const, *Var:
			return i
		}
	}
	return -1
}

// reportCycle reports an error for the cycle starting at i.
func (check *Checker) reportCycle(cycle []*objNode, i int) {
	obj := cycle[i].obj
	check.errorf(obj.Pos(), "initialization cycle for %s", obj.Name())
	// print cycle
	for range cycle {
		check.errorf(obj.Pos(), "\t%s refers to", obj.Name()) // secondary error, \t indented
		i++
		if i >= len(cycle) {
			i = 0
		}
		obj = cycle[i].obj
	}
	check.errorf(obj.Pos(), "\t%s", obj.Name())
}

// An objNode represents a node in the object dependency graph.
// Each node b in a.out represents an edge a->b indicating that
// b depends on a.
// Nodes may be marked for cycle detection. A node n is marked
// if n.mark corresponds to the current mark value.
type objNode struct {
	obj   Object     // object represented by this node
	in    int        // number of nodes this node depends on
	out   []*objNode // list of nodes that depend on this node
	index int        // node index in list of nodes
	mark  int        // for cycle detection
}

// dependencyGraph computes the transposed object dependency graph
// from the given objMap. The transposed graph is returned as a list
// of nodes; an edge d->n indicates that node n depends on node d.
func dependencyGraph(objMap map[Object]*declInfo) []*objNode {
	// M maps each object to its corresponding node
	M := make(map[Object]*objNode, len(objMap))
	for obj := range objMap {
		M[obj] = &objNode{obj: obj}
	}

	// G is the graph of nodes n
	G := make([]*objNode, len(M))
	i := 0
	for obj, n := range M {
		deps := objMap[obj].deps
		n.in = len(deps)
		for d := range deps {
			d := M[d]                // node n depends on node d
			d.out = append(d.out, n) // add edge d->n
		}

		G[i] = n
		n.index = i
		i++
	}

	return G
}

// nodeQueue implements the container/heap interface;
// a nodeQueue may be used as a priority queue.
type nodeQueue []*objNode

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

func (a nodeQueue) Swap(i, j int) {
	x, y := a[i], a[j]
	a[i], a[j] = y, x
	x.index, y.index = j, i
}

func (a nodeQueue) Less(i, j int) bool {
	x, y := a[i], a[j]
	// nodes are prioritized by number of incoming dependencies (1st key)
	// and source order (2nd key)
	return x.in < y.in || x.in == y.in && x.obj.order() < y.obj.order()
}

func (a *nodeQueue) Push(x interface{}) {
	panic("unreachable")
}

func (a *nodeQueue) Pop() interface{} {
	n := len(*a)
	x := (*a)[n-1]
	x.index = -1 // for safety
	*a = (*a)[:n-1]
	return x
}
<commit_msg>go/types: revert gofmt -s change to permit building with 1.3<commit_after>// Copyright 2014 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package types

import (
	"container/heap"
	"fmt"
)

// initOrder computes the Info.InitOrder for package variables.
func (check *Checker) initOrder() {
	// An InitOrder may already have been computed if a package is
	// built from several calls to (*Checker).Files.  Clear it.
	check.Info.InitOrder = check.Info.InitOrder[:0]

	// compute the object dependency graph and
	// initialize a priority queue with the list
	// of graph nodes
	pq := nodeQueue(dependencyGraph(check.objMap))
	heap.Init(&pq)

	const debug = false
	if debug {
		fmt.Printf("package %s: object dependency graph\n", check.pkg.Name())
		for _, n := range pq {
			for _, o := range n.out {
				fmt.Printf("\t%s -> %s\n", n.obj.Name(), o.obj.Name())
			}
		}
		fmt.Println()
		fmt.Printf("package %s: initialization order\n", check.pkg.Name())
	}

	// determine initialization order by removing the highest priority node
	// (the one with the fewest dependencies) and its edges from the graph,
	// repeatedly, until there are no nodes left.
	// In a valid Go program, those nodes always have zero dependencies (after
	// removing all incoming dependencies), otherwise there are initialization
	// cycles.
	mark := 0
	emitted := make(map[*declInfo]bool)
	for len(pq) > 0 {
		// get the next node
		n := heap.Pop(&pq).(*objNode)

		// if n still depends on other nodes, we have a cycle
		if n.in > 0 {
			mark++ // mark nodes using a different value each time
			cycle := findPath(n, n, mark)
			if i := valIndex(cycle); i >= 0 {
				check.reportCycle(cycle, i)
			}
			// ok to continue, but the variable initialization order
			// will be incorrect at this point since it assumes no
			// cycle errors
		}

		// reduce dependency count of all dependent nodes
		// and update priority queue
		for _, out := range n.out {
			out.in--
			heap.Fix(&pq, out.index)
		}

		// record the init order for variables with initializers only
		v, _ := n.obj.(*Var)
		info := check.objMap[v]
		if v == nil || !info.hasInitializer() {
			continue
		}

		// n:1 variable declarations such as: a, b = f()
		// introduce a node for each lhs variable (here: a, b);
		// but they all have the same initializer - emit only
		// one, for the first variable seen
		if emitted[info] {
			continue // initializer already emitted, if any
		}
		emitted[info] = true

		infoLhs := info.lhs // possibly nil (see declInfo.lhs field comment)
		if infoLhs == nil {
			infoLhs = []*Var{v}
		}
		init := &Initializer{infoLhs, info.init}
		check.Info.InitOrder = append(check.Info.InitOrder, init)

		if debug {
			fmt.Printf("\t%s\n", init)
		}
	}

	if debug {
		fmt.Println()
	}
}

// findPath returns the (reversed) list of nodes z, ... c, b, a,
// such that there is a path (list of edges) from a to z.
// If there is no such path, the result is nil.
// Nodes marked with the value mark are considered "visited";
// unvisited nodes are marked during the graph search.
func findPath(a, z *objNode, mark int) []*objNode {
	if a.mark == mark {
		return nil // node already seen
	}
	a.mark = mark

	for _, n := range a.out {
		if n == z {
			return []*objNode{z}
		}
		if P := findPath(n, z, mark); P != nil {
			return append(P, n)
		}
	}

	return nil
}

// valIndex returns the index of the first constant or variable in a,
// if any; or a value < 0.
func valIndex(a []*objNode) int {
	for i, n := range a {
		switch n.obj.(type) {
		case *Const, *Var:
			return i
		}
	}
	return -1
}

// reportCycle reports an error for the cycle starting at i.
func (check *Checker) reportCycle(cycle []*objNode, i int) {
	obj := cycle[i].obj
	check.errorf(obj.Pos(), "initialization cycle for %s", obj.Name())
	// print cycle
	for _ = range cycle {
		check.errorf(obj.Pos(), "\t%s refers to", obj.Name()) // secondary error, \t indented
		i++
		if i >= len(cycle) {
			i = 0
		}
		obj = cycle[i].obj
	}
	check.errorf(obj.Pos(), "\t%s", obj.Name())
}

// An objNode represents a node in the object dependency graph.
// Each node b in a.out represents an edge a->b indicating that
// b depends on a.
// Nodes may be marked for cycle detection. A node n is marked
// if n.mark corresponds to the current mark value.
type objNode struct {
	obj   Object     // object represented by this node
	in    int        // number of nodes this node depends on
	out   []*objNode // list of nodes that depend on this node
	index int        // node index in list of nodes
	mark  int        // for cycle detection
}

// dependencyGraph computes the transposed object dependency graph
// from the given objMap. The transposed graph is returned as a list
// of nodes; an edge d->n indicates that node n depends on node d.
func dependencyGraph(objMap map[Object]*declInfo) []*objNode {
	// M maps each object to its corresponding node
	M := make(map[Object]*objNode, len(objMap))
	for obj := range objMap {
		M[obj] = &objNode{obj: obj}
	}

	// G is the graph of nodes n
	G := make([]*objNode, len(M))
	i := 0
	for obj, n := range M {
		deps := objMap[obj].deps
		n.in = len(deps)
		for d := range deps {
			d := M[d]                // node n depends on node d
			d.out = append(d.out, n) // add edge d->n
		}

		G[i] = n
		n.index = i
		i++
	}

	return G
}

// nodeQueue implements the container/heap interface;
// a nodeQueue may be used as a priority queue.
type nodeQueue []*objNode

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

func (a nodeQueue) Swap(i, j int) {
	x, y := a[i], a[j]
	a[i], a[j] = y, x
	x.index, y.index = j, i
}

func (a nodeQueue) Less(i, j int) bool {
	x, y := a[i], a[j]
	// nodes are prioritized by number of incoming dependencies (1st key)
	// and source order (2nd key)
	return x.in < y.in || x.in == y.in && x.obj.order() < y.obj.order()
}

func (a *nodeQueue) Push(x interface{}) {
	panic("unreachable")
}

func (a *nodeQueue) Pop() interface{} {
	n := len(*a)
	x := (*a)[n-1]
	x.index = -1 // for safety
	*a = (*a)[:n-1]
	return x
}
<|endoftext|>


<commit_before>package gqt_test

import (
	"bytes"
	"fmt"
	"io"
	"io/ioutil"
	"os"
	"os/exec"
	"path/filepath"
	"runtime"
	"strconv"
	"strings"
	"time"

	"code.cloudfoundry.org/garden"
	"code.cloudfoundry.org/guardian/gqt/runner"
	"code.cloudfoundry.org/guardian/kawasaki/iptables"
	"code.cloudfoundry.org/guardian/pkg/locksmith"
	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
	"github.com/onsi/gomega/gexec"

	"encoding/json"
	"testing"
)

var ginkgoIO = garden.ProcessIO{Stdout: GinkgoWriter, Stderr: GinkgoWriter}

var config runner.GdnRunnerConfig
var binaries runner.Binaries

// the unprivileged user is baked into the cfgarden/garden-ci-ubuntu image
var unprivilegedUID = uint32(5000)
var unprivilegedGID = uint32(5000)

var gqtStartTime time.Time

var defaultTestRootFS string

func TestGqt(t *testing.T) {
	RegisterFailHandler(Fail)

	SynchronizedBeforeSuite(func() []byte {
		var err error
		binaries = runner.Binaries{}

		binaries.Tar = os.Getenv("GARDEN_TAR_PATH")

		binaries.Gdn, err = gexec.Build("code.cloudfoundry.org/guardian/cmd/gdn", "-tags", "daemon", "-race", "-ldflags", "-extldflags '-static'")
		Expect(err).NotTo(HaveOccurred())

		binaries.NetworkPlugin, err = gexec.Build("code.cloudfoundry.org/guardian/gqt/cmd/fake_network_plugin")
		Expect(err).NotTo(HaveOccurred())

		binaries.ImagePlugin, err = gexec.Build("code.cloudfoundry.org/guardian/gqt/cmd/fake_image_plugin")
		Expect(err).NotTo(HaveOccurred())

		binaries.PrivilegedImagePlugin = fmt.Sprintf("%s-priv", binaries.ImagePlugin)
		Expect(copyFile(binaries.ImagePlugin, binaries.PrivilegedImagePlugin)).To(Succeed())

		binaries.RuntimePlugin, err = gexec.Build("code.cloudfoundry.org/guardian/gqt/cmd/fake_runtime_plugin")
		Expect(err).NotTo(HaveOccurred())

		binaries.NoopPlugin, err = gexec.Build("code.cloudfoundry.org/guardian/gqt/cmd/noop_plugin")
		Expect(err).NotTo(HaveOccurred())

		if runtime.GOOS == "linux" {
			binaries.ExecRunner, err = gexec.Build("code.cloudfoundry.org/guardian/cmd/dadoo")
			Expect(err).NotTo(HaveOccurred())

			binaries.Socket2me, err = gexec.Build("code.cloudfoundry.org/guardian/cmd/socket2me")
			Expect(err).NotTo(HaveOccurred())

			cmd := exec.Command("make")
			runCommandInDir(cmd, "../rundmc/nstar")
			binaries.NSTar = "../rundmc/nstar/nstar"

			cmd = exec.Command("gcc", "-static", "-o", "init", "init.c")
			runCommandInDir(cmd, "../cmd/init")
			binaries.Init = "../cmd/init/init"
		}

		data, err := json.Marshal(binaries)
		Expect(err).NotTo(HaveOccurred())

		return data
	}, func(data []byte) {
		Expect(json.Unmarshal(data, &binaries)).To(Succeed())
		defaultTestRootFS = os.Getenv("GARDEN_TEST_ROOTFS")
	})

	SynchronizedAfterSuite(func() {}, func() {
		gexec.CleanupBuildArtifacts()
	})

	BeforeEach(func() {
		if defaultTestRootFS == "" {
			Skip("No Garden RootFS")
		}

		// chmod all the artifacts
		Expect(os.Chmod(filepath.Join(binaries.Gdn, "..", ".."), 0755)).To(Succeed())
		filepath.Walk(filepath.Join(binaries.Gdn, "..", ".."), func(path string, info os.FileInfo, err error) error {
			Expect(err).NotTo(HaveOccurred())
			Expect(os.Chmod(path, 0755)).To(Succeed())
			return nil
		})

		config = defaultConfig()
	})

	AfterEach(func() {
		// Windows worker is not containerised and therefore the test needs to take care to delete the temporary folder
		if runtime.GOOS == "windows" {
			Expect(os.RemoveAll(config.TmpDir)).To(Succeed())
		}
	})

	SetDefaultEventuallyTimeout(5 * time.Second)
	RunSpecs(t, "GQT Suite")
}

func runCommandInDir(cmd *exec.Cmd, workingDir string) {
	cmd.Dir = workingDir
	cmd.Stdout = GinkgoWriter
	cmd.Stderr = GinkgoWriter
	Expect(cmd.Run()).To(Succeed())
}

func defaultConfig() runner.GdnRunnerConfig {
	cfg := runner.DefaultGdnRunnerConfig()
	cfg.DefaultRootFS = defaultTestRootFS
	cfg.GdnBin = binaries.Gdn
	cfg.Socket2meBin = binaries.Socket2me
	cfg.ExecRunnerBin = binaries.ExecRunner
	cfg.InitBin = binaries.Init
	cfg.TarBin = binaries.Tar
	cfg.NSTarBin = binaries.NSTar

	return cfg
}

func restartGarden(client *runner.RunningGarden, config runner.GdnRunnerConfig) *runner.RunningGarden {
	Expect(client.Ping()).To(Succeed(), "tried to restart garden while it was not running")
	Expect(client.Stop()).To(Succeed())
	return runner.Start(config)
}

func runIPTables(ipTablesArgs ...string) ([]byte, error) {
	lock, err := locksmith.NewFileSystem().Lock(iptables.LockKey)
	if err != nil {
		return nil, err
	}
	defer lock.Unlock()

	outBuffer := bytes.NewBuffer([]byte{})
	errBuffer := bytes.NewBuffer([]byte{})
	cmd := exec.Command("iptables", append([]string{"-w"}, ipTablesArgs...)...)
	cmd.Stdout = outBuffer
	cmd.Stderr = errBuffer
	err = cmd.Run()

	fmt.Fprintln(GinkgoWriter, outBuffer.String())
	fmt.Fprintln(GinkgoWriter, errBuffer.String())
	return outBuffer.Bytes(), err
}

// returns the n'th ASCII character starting from 'a' through 'z'
// E.g. nodeToString(1) = a, nodeToString(2) = b, etc ...
func nodeToString(ginkgoNode int) string {
	r := 'a' + ginkgoNode - 1
	Expect(r).To(BeNumerically(">=", 'a'))
	Expect(r).To(BeNumerically("<=", 'z'))
	return string(r)
}

func createPeaRoootfs(tmpDir string) string {
	Expect(exec.Command("cp", "-a", defaultTestRootFS, tmpDir).Run()).To(Succeed())
	Expect(os.Chmod(tmpDir, 0777)).To(Succeed())
	peaRootfs := filepath.Join(tmpDir, "rootfs")
	Expect(exec.Command("chown", "-R", "4294967294:4294967294", peaRootfs).Run()).To(Succeed())
	Expect(ioutil.WriteFile(filepath.Join(peaRootfs, "ima-pea"), []byte("pea!"), 0644)).To(Succeed())
	return peaRootfs
}

func intptr(i int) *int {
	return &i
}

func uint64ptr(i uint64) *uint64 {
	return &i
}

func uint32ptr(i uint32) *uint32 {
	return &i
}

func boolptr(b bool) *bool {
	return &b
}

func idToStr(id uint32) string {
	return strconv.FormatUint(uint64(id), 10)
}

func readFile(path string) string {
	content, err := ioutil.ReadFile(path)
	Expect(err).NotTo(HaveOccurred())
	return string(content)
}

func copyFile(srcPath, dstPath string) error {
	dirPath := filepath.Dir(dstPath)
	if err := os.MkdirAll(dirPath, 0777); err != nil {
		return err
	}

	reader, err := os.Open(srcPath)
	if err != nil {
		return err
	}
	writer, err := os.Create(dstPath)
	if err != nil {
		reader.Close()
		return err
	}

	if _, err := io.Copy(writer, reader); err != nil {
		writer.Close()
		reader.Close()
		return err
	}

	writer.Close()
	reader.Close()

	return os.Chmod(writer.Name(), 0777)
}

func getCurrentCGroup() string {
	currentCgroup, err := exec.Command("sh", "-c", "cat /proc/self/cgroup | head -1 | awk -F ':' '{print $3}'").CombinedOutput()
	Expect(err).NotTo(HaveOccurred())
	return strings.TrimSpace(string(currentCgroup))
}

func getCurrentCGroupPath(cgroupsRoot, subsystem, tag string, privileged bool) string {
	parentCgroup := "garden"
	if tag != "" {
		parentCgroup = fmt.Sprintf("garden-%s", tag)
	}

	// We always use the cgroup root for privileged containers, regardless of
	// tag.
	if privileged {
		parentCgroup = ""
	}

	return filepath.Join(cgroupsRoot, subsystem, getCurrentCGroup(), parentCgroup)
}

func removeSocket() {
	_, err := os.Stat(config.BindSocket)
	if err == nil {
		Expect(os.Remove(config.BindSocket)).To(Succeed())
	} else if !os.IsNotExist(err) {
		Expect(err).NotTo(HaveOccurred())
	}
}
<commit_msg>Only compile gdn with -race if env var is set<commit_after>package gqt_test

import (
	"bytes"
	"fmt"
	"io"
	"io/ioutil"
	"os"
	"os/exec"
	"path/filepath"
	"runtime"
	"strconv"
	"strings"
	"time"

	"code.cloudfoundry.org/garden"
	"code.cloudfoundry.org/guardian/gqt/runner"
	"code.cloudfoundry.org/guardian/kawasaki/iptables"
	"code.cloudfoundry.org/guardian/pkg/locksmith"
	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
	"github.com/onsi/gomega/gexec"

	"encoding/json"
	"testing"
)

var ginkgoIO = garden.ProcessIO{Stdout: GinkgoWriter, Stderr: GinkgoWriter}

var config runner.GdnRunnerConfig
var binaries runner.Binaries

// the unprivileged user is baked into the cfgarden/garden-ci-ubuntu image
var unprivilegedUID = uint32(5000)
var unprivilegedGID = uint32(5000)

var gqtStartTime time.Time

var defaultTestRootFS string

func TestGqt(t *testing.T) {
	RegisterFailHandler(Fail)

	SynchronizedBeforeSuite(func() []byte {
		var err error
		binaries = runner.Binaries{}

		binaries.Tar = os.Getenv("GARDEN_TAR_PATH")

		gdnBuildArgs := []string{"-tags", "daemon", "-ldflags", "-extldflags '-static'"}
		if os.Getenv("RACE_DETECTION") != "" {
			gdnBuildArgs = append(gdnBuildArgs, "-race")
		}
		binaries.Gdn, err = gexec.Build("code.cloudfoundry.org/guardian/cmd/gdn", gdnBuildArgs...)
		Expect(err).NotTo(HaveOccurred())

		binaries.NetworkPlugin, err = gexec.Build("code.cloudfoundry.org/guardian/gqt/cmd/fake_network_plugin")
		Expect(err).NotTo(HaveOccurred())

		binaries.ImagePlugin, err = gexec.Build("code.cloudfoundry.org/guardian/gqt/cmd/fake_image_plugin")
		Expect(err).NotTo(HaveOccurred())

		binaries.PrivilegedImagePlugin = fmt.Sprintf("%s-priv", binaries.ImagePlugin)
		Expect(copyFile(binaries.ImagePlugin, binaries.PrivilegedImagePlugin)).To(Succeed())

		binaries.RuntimePlugin, err = gexec.Build("code.cloudfoundry.org/guardian/gqt/cmd/fake_runtime_plugin")
		Expect(err).NotTo(HaveOccurred())

		binaries.NoopPlugin, err = gexec.Build("code.cloudfoundry.org/guardian/gqt/cmd/noop_plugin")
		Expect(err).NotTo(HaveOccurred())

		if runtime.GOOS == "linux" {
			binaries.ExecRunner, err = gexec.Build("code.cloudfoundry.org/guardian/cmd/dadoo")
			Expect(err).NotTo(HaveOccurred())

			binaries.Socket2me, err = gexec.Build("code.cloudfoundry.org/guardian/cmd/socket2me")
			Expect(err).NotTo(HaveOccurred())

			cmd := exec.Command("make")
			runCommandInDir(cmd, "../rundmc/nstar")
			binaries.NSTar = "../rundmc/nstar/nstar"

			cmd = exec.Command("gcc", "-static", "-o", "init", "init.c")
			runCommandInDir(cmd, "../cmd/init")
			binaries.Init = "../cmd/init/init"
		}

		data, err := json.Marshal(binaries)
		Expect(err).NotTo(HaveOccurred())

		return data
	}, func(data []byte) {
		Expect(json.Unmarshal(data, &binaries)).To(Succeed())
		defaultTestRootFS = os.Getenv("GARDEN_TEST_ROOTFS")
	})

	SynchronizedAfterSuite(func() {}, func() {
		gexec.CleanupBuildArtifacts()
	})

	BeforeEach(func() {
		if defaultTestRootFS == "" {
			Skip("No Garden RootFS")
		}

		// chmod all the artifacts
		Expect(os.Chmod(filepath.Join(binaries.Gdn, "..", ".."), 0755)).To(Succeed())
		filepath.Walk(filepath.Join(binaries.Gdn, "..", ".."), func(path string, info os.FileInfo, err error) error {
			Expect(err).NotTo(HaveOccurred())
			Expect(os.Chmod(path, 0755)).To(Succeed())
			return nil
		})

		config = defaultConfig()
	})

	AfterEach(func() {
		// Windows worker is not containerised and therefore the test needs to take care to delete the temporary folder
		if runtime.GOOS == "windows" {
			Expect(os.RemoveAll(config.TmpDir)).To(Succeed())
		}
	})

	SetDefaultEventuallyTimeout(5 * time.Second)
	RunSpecs(t, "GQT Suite")
}

func runCommandInDir(cmd *exec.Cmd, workingDir string) {
	cmd.Dir = workingDir
	cmd.Stdout = GinkgoWriter
	cmd.Stderr = GinkgoWriter
	Expect(cmd.Run()).To(Succeed())
}

func defaultConfig() runner.GdnRunnerConfig {
	cfg := runner.DefaultGdnRunnerConfig()
	cfg.DefaultRootFS = defaultTestRootFS
	cfg.GdnBin = binaries.Gdn
	cfg.Socket2meBin = binaries.Socket2me
	cfg.ExecRunnerBin = binaries.ExecRunner
	cfg.InitBin = binaries.Init
	cfg.TarBin = binaries.Tar
	cfg.NSTarBin = binaries.NSTar

	return cfg
}

func restartGarden(client *runner.RunningGarden, config runner.GdnRunnerConfig) *runner.RunningGarden {
	Expect(client.Ping()).To(Succeed(), "tried to restart garden while it was not running")
	Expect(client.Stop()).To(Succeed())
	return runner.Start(config)
}

func runIPTables(ipTablesArgs ...string) ([]byte, error) {
	lock, err := locksmith.NewFileSystem().Lock(iptables.LockKey)
	if err != nil {
		return nil, err
	}
	defer lock.Unlock()

	outBuffer := bytes.NewBuffer([]byte{})
	errBuffer := bytes.NewBuffer([]byte{})
	cmd := exec.Command("iptables", append([]string{"-w"}, ipTablesArgs...)...)
	cmd.Stdout = outBuffer
	cmd.Stderr = errBuffer
	err = cmd.Run()

	fmt.Fprintln(GinkgoWriter, outBuffer.String())
	fmt.Fprintln(GinkgoWriter, errBuffer.String())
	return outBuffer.Bytes(), err
}

// returns the n'th ASCII character starting from 'a' through 'z'
// E.g. nodeToString(1) = a, nodeToString(2) = b, etc ...
func nodeToString(ginkgoNode int) string {
	r := 'a' + ginkgoNode - 1
	Expect(r).To(BeNumerically(">=", 'a'))
	Expect(r).To(BeNumerically("<=", 'z'))
	return string(r)
}

func createPeaRoootfs(tmpDir string) string {
	Expect(exec.Command("cp", "-a", defaultTestRootFS, tmpDir).Run()).To(Succeed())
	Expect(os.Chmod(tmpDir, 0777)).To(Succeed())
	peaRootfs := filepath.Join(tmpDir, "rootfs")
	Expect(exec.Command("chown", "-R", "4294967294:4294967294", peaRootfs).Run()).To(Succeed())
	Expect(ioutil.WriteFile(filepath.Join(peaRootfs, "ima-pea"), []byte("pea!"), 0644)).To(Succeed())
	return peaRootfs
}

func intptr(i int) *int {
	return &i
}

func uint64ptr(i uint64) *uint64 {
	return &i
}

func uint32ptr(i uint32) *uint32 {
	return &i
}

func boolptr(b bool) *bool {
	return &b
}

func idToStr(id uint32) string {
	return strconv.FormatUint(uint64(id), 10)
}

func readFile(path string) string {
	content, err := ioutil.ReadFile(path)
	Expect(err).NotTo(HaveOccurred())
	return string(content)
}

func copyFile(srcPath, dstPath string) error {
	dirPath := filepath.Dir(dstPath)
	if err := os.MkdirAll(dirPath, 0777); err != nil {
		return err
	}

	reader, err := os.Open(srcPath)
	if err != nil {
		return err
	}
	writer, err := os.Create(dstPath)
	if err != nil {
		reader.Close()
		return err
	}

	if _, err := io.Copy(writer, reader); err != nil {
		writer.Close()
		reader.Close()
		return err
	}

	writer.Close()
	reader.Close()

	return os.Chmod(writer.Name(), 0777)
}

func getCurrentCGroup() string {
	currentCgroup, err := exec.Command("sh", "-c", "cat /proc/self/cgroup | head -1 | awk -F ':' '{print $3}'").CombinedOutput()
	Expect(err).NotTo(HaveOccurred())
	return strings.TrimSpace(string(currentCgroup))
}

func getCurrentCGroupPath(cgroupsRoot, subsystem, tag string, privileged bool) string {
	parentCgroup := "garden"
	if tag != "" {
		parentCgroup = fmt.Sprintf("garden-%s", tag)
	}

	// We always use the cgroup root for privileged containers, regardless of
	// tag.
	if privileged {
		parentCgroup = ""
	}

	return filepath.Join(cgroupsRoot, subsystem, getCurrentCGroup(), parentCgroup)
}

func removeSocket() {
	_, err := os.Stat(config.BindSocket)
	if err == nil {
		Expect(os.Remove(config.BindSocket)).To(Succeed())
	} else if !os.IsNotExist(err) {
		Expect(err).NotTo(HaveOccurred())
	}
}
<|endoftext|>


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

package adb

import (
	"context"
	"fmt"
	"strconv"
	"strings"
	"sync"
	"time"

	"github.com/google/gapid/core/app"
	"github.com/google/gapid/core/event/task"
	"github.com/google/gapid/core/fault"
	"github.com/google/gapid/core/log"
	"github.com/google/gapid/core/os/android"
	"github.com/google/gapid/core/os/device"
	"github.com/google/gapid/core/os/device/bind"
	"github.com/google/gapid/core/os/shell"
)

const (
	// ErrNoDeviceList May be returned if the adb fails to return a device list when asked.
	ErrNoDeviceList = fault.Const("Device list not returned")
	// ErrInvalidDeviceList May be returned if the device list could not be parsed.
	ErrInvalidDeviceList = fault.Const("Could not parse device list")
	// ErrInvalidStatus May be returned if the status string is not a known status.
	ErrInvalidStatus = fault.Const("Invalid status string")
	// Frequency at which to print scan errors.
	printScanErrorsEveryNSeconds = 120
	// Global settings for opting to use prerelease driver.
	prereleaseDriverSettingVariable = "game_driver_prerelease_opt_in_apps"
)

var (
	// Each of the devInfoProviders are called each time a new device is found.
	// External packages can use this to add additional information to the
	// device.
	devInfoProviders      []DeviceInfoProvider
	devInfoProvidersMutex sync.Mutex

	// cache is a map of device serials to fully resolved bindings.
	cache      = map[string]*binding{}
	cacheMutex sync.Mutex // Guards cache.

	// Registry of all the discovered devices.
	registry = bind.NewRegistry()
)

// DeviceInfoProvider is a function that adds additional information to a
// Device.
type DeviceInfoProvider func(ctx context.Context, d Device) error

// RegisterDeviceInfoProvider registers f to be called to add additional
// information to a newly discovered Android device.
func RegisterDeviceInfoProvider(f DeviceInfoProvider) {
	devInfoProvidersMutex.Lock()
	defer devInfoProvidersMutex.Unlock()
	devInfoProviders = append(devInfoProviders, f)
}

// Monitor updates the registry with devices that are added and removed at the
// specified interval. Monitor returns once the context is cancelled.
func Monitor(ctx context.Context, r *bind.Registry, interval time.Duration) error {
	unlisten := registry.Listen(bind.NewDeviceListener(r.AddDevice, r.RemoveDevice))
	defer unlisten()

	for _, d := range registry.Devices() {
		r.AddDevice(ctx, d)
	}

	var lastErrorPrinted time.Time
	for {
		if err := scanDevices(ctx); err != nil {
			if time.Since(lastErrorPrinted).Seconds() > printScanErrorsEveryNSeconds {
				log.E(ctx, "Couldn't scan devices: %v", err)
				lastErrorPrinted = time.Now()
			}
		} else {
			lastErrorPrinted = time.Time{}
		}

		select {
		case <-task.ShouldStop(ctx):
			return nil
		case <-time.After(interval):
		}
	}
}

// Devices returns the list of attached Android devices.
func Devices(ctx context.Context) (DeviceList, error) {
	if err := scanDevices(ctx); err != nil {
		return nil, err
	}
	devs := registry.Devices()
	out := make(DeviceList, len(devs))
	for i, d := range devs {
		out[i] = d.(Device)
	}
	return out, nil
}

func SetupPrereleaseDriver(ctx context.Context, d Device, p *android.InstalledPackage) (app.Cleanup, error) {
	oldOptinApps, err := d.SystemSetting(ctx, "global", prereleaseDriverSettingVariable)
	if err != nil {
		return nil, log.Err(ctx, err, "Failed to get prerelease driver opt in apps.")
	}
	if strings.Contains(oldOptinApps, p.Name) {
		return nil, nil
	}
	newOptinApps := oldOptinApps + "," + p.Name
	// TODO(b/145893290) Check whether application has developer driver enabled once b/145893290 is fixed.
	if err := d.SetSystemSetting(ctx, "global", prereleaseDriverSettingVariable, newOptinApps); err != nil {
		return nil, log.Errf(ctx, err, "Failed to set up prerelease driver for app: %v.", p.Name)
	}
	return func(ctx context.Context) {
		d.SetSystemSetting(ctx, "global", prereleaseDriverSettingVariable, oldOptinApps)
	}, nil
}

func newDevice(ctx context.Context, serial string, status bind.Status) (*binding, error) {
	d := &binding{
		Simple: bind.Simple{
			To: &device.Instance{
				Serial:        serial,
				Configuration: &device.Configuration{},
			},
			LastStatus: status,
		},
	}

	// Lookup the basic hardware information
	if res, err := d.SystemProperty(ctx, "ro.build.product"); err == nil {
		d.To.Configuration.Hardware = &device.Hardware{
			Name: strings.TrimSpace(res),
		}
	}

	// Early bail out if we cannot get device information
	if d.To.Configuration.Hardware == nil {
		return nil, log.Errf(ctx, nil, "Cannot get device information")
	}

	// Collect the operating system version
	if version, err := d.SystemProperty(ctx, "ro.build.version.release"); err == nil {
		var major, minor, point int32
		fmt.Sscanf(version, "%d.%d.%d", &major, &minor, &point)
		d.To.Configuration.OS = device.AndroidOS(major, minor, point)
	}

	// Collect the API version
	if version, err := d.SystemProperty(ctx, "ro.build.version.sdk"); err == nil {
		v, _ := strconv.Atoi(version)
		// preview_sdk is used to determine the version for the next OS release
		// Until the official release, new OS releases will use the same sdk
		// version as the previous OS while setting the preview_sdk
		if preview, err := d.SystemProperty(ctx, "ro.build.version.preview_sdk"); err == nil {
			p, _ := strconv.Atoi(preview)
			v += p
		}
		d.To.Configuration.OS.APIVersion = int32(v)
	}

	if description, err := d.SystemProperty(ctx, "ro.build.description"); err == nil {
		d.To.Configuration.OS.Build = strings.TrimSpace(description)
	}

	// Check which abis the device says it supports
	d.To.Configuration.ABIs = d.To.Configuration.ABIs[:0]

	seen := map[string]bool{}
	for _, prop := range []string{
		"ro.product.cpu.abilist",
		"ro.product.cpu.abi",
		"ro.product.cpu.abi2",
	} {
		abis, _ := d.SystemProperty(ctx, prop)
		if strings.TrimSpace(abis) == "" {
			continue
		}
		for _, abi := range strings.Split(abis, ",") {
			if seen[abi] {
				continue
			}
			d.To.Configuration.ABIs = append(d.To.Configuration.ABIs, device.ABIByName(abi))
			seen[abi] = true
		}
	}

	// Make sure Perfetto daemons are running.
	if err := d.EnsurePerfettoPersistent(ctx); err != nil {
		log.W(ctx, "Failed to signal Perfetto services to start", err)
	}

	// Run device info providers only if the API is supported
	if d.To.Configuration.OS != nil && d.To.Configuration.OS.APIVersion >= device.AndroidMinimalSupportedAPIVersion {
		devInfoProvidersMutex.Lock()
		defer devInfoProvidersMutex.Unlock()
		for _, f := range devInfoProviders {
			if err := f(ctx, d); err != nil {
				return nil, err
			}
		}
	}

	// Query device Perfetto service state
	if perfettoCapability, err := d.QueryPerfettoServiceState(ctx); err == nil {
		d.To.Configuration.PerfettoCapability = perfettoCapability
	}

	// Query device ANGLE support
	if anglePackage, err := d.QueryAnglePackageName(ctx); err == nil {
		d.To.Configuration.AnglePackage = anglePackage
	}

	// Query infos related to the Vulkan driver
	if d.To.Configuration.GetDrivers() != nil && d.To.Configuration.GetDrivers().GetVulkan() != nil {

		// If the VkRenderStagesProducer layer exist, we assume the render stages producer is
		// implemented in the layer.
		for _, l := range d.To.Configuration.GetDrivers().GetVulkan().GetLayers() {
			if l.Name == "VkRenderStagesProducer" {
				capability := d.To.Configuration.PerfettoCapability
				if capability == nil {
					capability = &device.PerfettoCapability{
						GpuProfiling: &device.GPUProfiling{},
					}
					d.To.Configuration.PerfettoCapability = capability
				}
				gpu := capability.GpuProfiling
				gpu.HasRenderStageProducerLayer = true
				gpu.HasRenderStage = true
				break
			}
		}

		if version, err := d.DriverVersionCode(ctx); err == nil {
			d.To.Configuration.Drivers.Vulkan.Version = strconv.Itoa(version)
		}
	}

	if d.Instance().GetName() == "" {
		d.Instance().Name = d.To.Configuration.Hardware.Name
	}
	if i := d.Instance(); i.ID == nil || allZero(i.ID.Data) {
		// Generate an identifier for the device based on its details.
		i.GenID()
	}

	return d, nil
}

func allZero(bytes []byte) bool {
	for _, b := range bytes {
		if b != 0 {
			return true
		}
	}
	return false
}

// scanDevices returns the list of attached Android devices.
func scanDevices(ctx context.Context) error {
	exe, err := adb()
	if err != nil {
		return log.Err(ctx, err, "")
	}
	stdout, err := shell.Command(exe.System(), "devices").Call(ctx)
	if err != nil {
		return err
	}
	parsed, err := parseDevices(ctx, stdout)
	if err != nil {
		return err
	}

	cacheMutex.Lock()
	defer cacheMutex.Unlock()

	for serial, status := range parsed {
		cached, ok := cache[serial]
		if !ok || status != cached.Status(ctx) {
			device, err := newDevice(ctx, serial, status)
			if err != nil {
				return err
			}
			if ok {
				registry.RemoveDevice(ctx, cached)
			}
			cache[serial] = device
			registry.AddDevice(ctx, device)
		}
	}

	// Remove cached results for removed devices.
	for serial, cached := range cache {
		if _, found := parsed[serial]; !found {
			delete(cache, serial)
			registry.RemoveDevice(ctx, cached)
		}
	}

	return nil
}

func parseDevices(ctx context.Context, out string) (map[string]bind.Status, error) {
	a := strings.SplitAfter(out, "List of devices attached")
	if len(a) != 2 {
		return nil, ErrNoDeviceList
	}
	lines := strings.Split(a[1], "\n")
	devices := make(map[string]bind.Status, len(lines))
	for _, line := range lines {
		if strings.HasPrefix(line, "adb server version") && strings.HasSuffix(line, "killing...") {
			continue // adb server version (36) doesn't match this client (35); killing...
		}
		if strings.HasPrefix(line, "*") {
			continue // For example, "* daemon started successfully *"
		}
		fields := strings.Fields(line)
		switch len(fields) {
		case 0:
			continue
		case 2:
			serial, status := fields[0], fields[1]
			switch status {
			case "unknown":
				devices[serial] = bind.Status_Unknown
			case "offline":
				devices[serial] = bind.Status_Offline
			case "device":
				devices[serial] = bind.Status_Online
			case "unauthorized":
				devices[serial] = bind.Status_Unauthorized
			default:
				return nil, log.Errf(ctx, ErrInvalidStatus, "value: %v", status)
			}
		default:
			return nil, ErrInvalidDeviceList
		}
	}
	return devices, nil
}

// NativeBridgeABI returns the native ABI for the given emulated ABI for the
// device by consulting the ro.dalvik.vm.isa.<emulated_isa>=<native_isa>
// system properties.
func (b *binding) NativeBridgeABI(ctx context.Context, emulated *device.ABI) *device.ABI {
	isa := abiToISA(emulated)
	if isa == "" {
		return emulated
	}
	isa, err := b.SystemProperty(ctx, "ro.dalvik.vm.isa."+isa)
	if err != nil {
		return emulated
	}
	native := isaToABI(isa)
	if native == nil {
		return emulated
	}
	return native
}

func (b *binding) IsLocal(ctx context.Context) (bool, error) {
	return true, nil
}

var abiToISAs = []struct {
	abi *device.ABI
	isa string
}{
	// {device.Architecture_ARMEABI, "arm"},
	{device.AndroidARMv7a, "arm"},
	{device.AndroidARM64v8a, "arm64"},
	{device.AndroidMIPS, "mips"},
	{device.AndroidMIPS64, "mips64"},
	{device.AndroidX86, "x86"},
	{device.AndroidX86_64, "x86_64"},
}

func abiToISA(abi *device.ABI) string {
	for _, e := range abiToISAs {
		if e.abi.Architecture == abi.Architecture {
			return e.isa
		}
	}
	return ""
}

func isaToABI(isa string) *device.ABI {
	for _, e := range abiToISAs {
		if e.isa == isa {
			return e.abi
		}
	}
	return nil
}
<commit_msg>Update UGD opt-in settings property. (#487)<commit_after>// Copyright (C) 2017 Google Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package adb

import (
	"context"
	"fmt"
	"strconv"
	"strings"
	"sync"
	"time"

	"github.com/google/gapid/core/app"
	"github.com/google/gapid/core/event/task"
	"github.com/google/gapid/core/fault"
	"github.com/google/gapid/core/log"
	"github.com/google/gapid/core/os/android"
	"github.com/google/gapid/core/os/device"
	"github.com/google/gapid/core/os/device/bind"
	"github.com/google/gapid/core/os/shell"
)

const (
	// ErrNoDeviceList May be returned if the adb fails to return a device list when asked.
	ErrNoDeviceList = fault.Const("Device list not returned")
	// ErrInvalidDeviceList May be returned if the device list could not be parsed.
	ErrInvalidDeviceList = fault.Const("Could not parse device list")
	// ErrInvalidStatus May be returned if the status string is not a known status.
	ErrInvalidStatus = fault.Const("Invalid status string")
	// Frequency at which to print scan errors.
	printScanErrorsEveryNSeconds = 120
	// Global settings for opting to use prerelease driver.
	oldDeveloperDriverSettingVariable = "game_driver_prerelease_opt_in_apps"
	developerDriverSettingVariable    = "updatable_driver_prerelease_opt_in_apps"
)

var (
	// Each of the devInfoProviders are called each time a new device is found.
	// External packages can use this to add additional information to the
	// device.
	devInfoProviders      []DeviceInfoProvider
	devInfoProvidersMutex sync.Mutex

	// cache is a map of device serials to fully resolved bindings.
	cache      = map[string]*binding{}
	cacheMutex sync.Mutex // Guards cache.

	// Registry of all the discovered devices.
	registry = bind.NewRegistry()
)

// DeviceInfoProvider is a function that adds additional information to a
// Device.
type DeviceInfoProvider func(ctx context.Context, d Device) error

// RegisterDeviceInfoProvider registers f to be called to add additional
// information to a newly discovered Android device.
func RegisterDeviceInfoProvider(f DeviceInfoProvider) {
	devInfoProvidersMutex.Lock()
	defer devInfoProvidersMutex.Unlock()
	devInfoProviders = append(devInfoProviders, f)
}

// Monitor updates the registry with devices that are added and removed at the
// specified interval. Monitor returns once the context is cancelled.
func Monitor(ctx context.Context, r *bind.Registry, interval time.Duration) error {
	unlisten := registry.Listen(bind.NewDeviceListener(r.AddDevice, r.RemoveDevice))
	defer unlisten()

	for _, d := range registry.Devices() {
		r.AddDevice(ctx, d)
	}

	var lastErrorPrinted time.Time
	for {
		if err := scanDevices(ctx); err != nil {
			if time.Since(lastErrorPrinted).Seconds() > printScanErrorsEveryNSeconds {
				log.E(ctx, "Couldn't scan devices: %v", err)
				lastErrorPrinted = time.Now()
			}
		} else {
			lastErrorPrinted = time.Time{}
		}

		select {
		case <-task.ShouldStop(ctx):
			return nil
		case <-time.After(interval):
		}
	}
}

// Devices returns the list of attached Android devices.
func Devices(ctx context.Context) (DeviceList, error) {
	if err := scanDevices(ctx); err != nil {
		return nil, err
	}
	devs := registry.Devices()
	out := make(DeviceList, len(devs))
	for i, d := range devs {
		out[i] = d.(Device)
	}
	return out, nil
}

func SetupPrereleaseDriver(ctx context.Context, d Device, p *android.InstalledPackage) (app.Cleanup, error) {
	settingVariable := developerDriverSettingVariable
	if d.Instance().GetConfiguration().GetOS().GetAPIVersion() <= 30 {
		settingVariable = oldDeveloperDriverSettingVariable
	}

	oldOptinApps, err := d.SystemSetting(ctx, "global", settingVariable)
	if err != nil {
		return nil, log.Err(ctx, err, "Failed to get prerelease driver opt in apps.")
	}
	if strings.Contains(oldOptinApps, p.Name) {
		return nil, nil
	}
	newOptinApps := oldOptinApps + "," + p.Name
	// TODO(b/145893290) Check whether application has developer driver enabled once b/145893290 is fixed.
	if err := d.SetSystemSetting(ctx, "global", settingVariable, newOptinApps); err != nil {
		return nil, log.Errf(ctx, err, "Failed to set up prerelease driver for app: %v.", p.Name)
	}
	return func(ctx context.Context) {
		d.SetSystemSetting(ctx, "global", settingVariable, oldOptinApps)
	}, nil
}

func newDevice(ctx context.Context, serial string, status bind.Status) (*binding, error) {
	d := &binding{
		Simple: bind.Simple{
			To: &device.Instance{
				Serial:        serial,
				Configuration: &device.Configuration{},
			},
			LastStatus: status,
		},
	}

	// Lookup the basic hardware information
	if res, err := d.SystemProperty(ctx, "ro.build.product"); err == nil {
		d.To.Configuration.Hardware = &device.Hardware{
			Name: strings.TrimSpace(res),
		}
	}

	// Early bail out if we cannot get device information
	if d.To.Configuration.Hardware == nil {
		return nil, log.Errf(ctx, nil, "Cannot get device information")
	}

	// Collect the operating system version
	if version, err := d.SystemProperty(ctx, "ro.build.version.release"); err == nil {
		var major, minor, point int32
		fmt.Sscanf(version, "%d.%d.%d", &major, &minor, &point)
		d.To.Configuration.OS = device.AndroidOS(major, minor, point)
	}

	// Collect the API version
	if version, err := d.SystemProperty(ctx, "ro.build.version.sdk"); err == nil {
		v, _ := strconv.Atoi(version)
		// preview_sdk is used to determine the version for the next OS release
		// Until the official release, new OS releases will use the same sdk
		// version as the previous OS while setting the preview_sdk
		if preview, err := d.SystemProperty(ctx, "ro.build.version.preview_sdk"); err == nil {
			p, _ := strconv.Atoi(preview)
			v += p
		}
		d.To.Configuration.OS.APIVersion = int32(v)
	}

	if description, err := d.SystemProperty(ctx, "ro.build.description"); err == nil {
		d.To.Configuration.OS.Build = strings.TrimSpace(description)
	}

	// Check which abis the device says it supports
	d.To.Configuration.ABIs = d.To.Configuration.ABIs[:0]

	seen := map[string]bool{}
	for _, prop := range []string{
		"ro.product.cpu.abilist",
		"ro.product.cpu.abi",
		"ro.product.cpu.abi2",
	} {
		abis, _ := d.SystemProperty(ctx, prop)
		if strings.TrimSpace(abis) == "" {
			continue
		}
		for _, abi := range strings.Split(abis, ",") {
			if seen[abi] {
				continue
			}
			d.To.Configuration.ABIs = append(d.To.Configuration.ABIs, device.ABIByName(abi))
			seen[abi] = true
		}
	}

	// Make sure Perfetto daemons are running.
	if err := d.EnsurePerfettoPersistent(ctx); err != nil {
		log.W(ctx, "Failed to signal Perfetto services to start", err)
	}

	// Run device info providers only if the API is supported
	if d.To.Configuration.OS != nil && d.To.Configuration.OS.APIVersion >= device.AndroidMinimalSupportedAPIVersion {
		devInfoProvidersMutex.Lock()
		defer devInfoProvidersMutex.Unlock()
		for _, f := range devInfoProviders {
			if err := f(ctx, d); err != nil {
				return nil, err
			}
		}
	}

	// Query device Perfetto service state
	if perfettoCapability, err := d.QueryPerfettoServiceState(ctx); err == nil {
		d.To.Configuration.PerfettoCapability = perfettoCapability
	}

	// Query device ANGLE support
	if anglePackage, err := d.QueryAnglePackageName(ctx); err == nil {
		d.To.Configuration.AnglePackage = anglePackage
	}

	// Query infos related to the Vulkan driver
	if d.To.Configuration.GetDrivers() != nil && d.To.Configuration.GetDrivers().GetVulkan() != nil {

		// If the VkRenderStagesProducer layer exist, we assume the render stages producer is
		// implemented in the layer.
		for _, l := range d.To.Configuration.GetDrivers().GetVulkan().GetLayers() {
			if l.Name == "VkRenderStagesProducer" {
				capability := d.To.Configuration.PerfettoCapability
				if capability == nil {
					capability = &device.PerfettoCapability{
						GpuProfiling: &device.GPUProfiling{},
					}
					d.To.Configuration.PerfettoCapability = capability
				}
				gpu := capability.GpuProfiling
				gpu.HasRenderStageProducerLayer = true
				gpu.HasRenderStage = true
				break
			}
		}

		if version, err := d.DriverVersionCode(ctx); err == nil {
			d.To.Configuration.Drivers.Vulkan.Version = strconv.Itoa(version)
		}
	}

	if d.Instance().GetName() == "" {
		d.Instance().Name = d.To.Configuration.Hardware.Name
	}
	if i := d.Instance(); i.ID == nil || allZero(i.ID.Data) {
		// Generate an identifier for the device based on its details.
		i.GenID()
	}

	return d, nil
}

func allZero(bytes []byte) bool {
	for _, b := range bytes {
		if b != 0 {
			return true
		}
	}
	return false
}

// scanDevices returns the list of attached Android devices.
func scanDevices(ctx context.Context) error {
	exe, err := adb()
	if err != nil {
		return log.Err(ctx, err, "")
	}
	stdout, err := shell.Command(exe.System(), "devices").Call(ctx)
	if err != nil {
		return err
	}
	parsed, err := parseDevices(ctx, stdout)
	if err != nil {
		return err
	}

	cacheMutex.Lock()
	defer cacheMutex.Unlock()

	for serial, status := range parsed {
		cached, ok := cache[serial]
		if !ok || status != cached.Status(ctx) {
			device, err := newDevice(ctx, serial, status)
			if err != nil {
				return err
			}
			if ok {
				registry.RemoveDevice(ctx, cached)
			}
			cache[serial] = device
			registry.AddDevice(ctx, device)
		}
	}

	// Remove cached results for removed devices.
	for serial, cached := range cache {
		if _, found := parsed[serial]; !found {
			delete(cache, serial)
			registry.RemoveDevice(ctx, cached)
		}
	}

	return nil
}

func parseDevices(ctx context.Context, out string) (map[string]bind.Status, error) {
	a := strings.SplitAfter(out, "List of devices attached")
	if len(a) != 2 {
		return nil, ErrNoDeviceList
	}
	lines := strings.Split(a[1], "\n")
	devices := make(map[string]bind.Status, len(lines))
	for _, line := range lines {
		if strings.HasPrefix(line, "adb server version") && strings.HasSuffix(line, "killing...") {
			continue // adb server version (36) doesn't match this client (35); killing...
		}
		if strings.HasPrefix(line, "*") {
			continue // For example, "* daemon started successfully *"
		}
		fields := strings.Fields(line)
		switch len(fields) {
		case 0:
			continue
		case 2:
			serial, status := fields[0], fields[1]
			switch status {
			case "unknown":
				devices[serial] = bind.Status_Unknown
			case "offline":
				devices[serial] = bind.Status_Offline
			case "device":
				devices[serial] = bind.Status_Online
			case "unauthorized":
				devices[serial] = bind.Status_Unauthorized
			default:
				return nil, log.Errf(ctx, ErrInvalidStatus, "value: %v", status)
			}
		default:
			return nil, ErrInvalidDeviceList
		}
	}
	return devices, nil
}

// NativeBridgeABI returns the native ABI for the given emulated ABI for the
// device by consulting the ro.dalvik.vm.isa.<emulated_isa>=<native_isa>
// system properties.
func (b *binding) NativeBridgeABI(ctx context.Context, emulated *device.ABI) *device.ABI {
	isa := abiToISA(emulated)
	if isa == "" {
		return emulated
	}
	isa, err := b.SystemProperty(ctx, "ro.dalvik.vm.isa."+isa)
	if err != nil {
		return emulated
	}
	native := isaToABI(isa)
	if native == nil {
		return emulated
	}
	return native
}

func (b *binding) IsLocal(ctx context.Context) (bool, error) {
	return true, nil
}

var abiToISAs = []struct {
	abi *device.ABI
	isa string
}{
	// {device.Architecture_ARMEABI, "arm"},
	{device.AndroidARMv7a, "arm"},
	{device.AndroidARM64v8a, "arm64"},
	{device.AndroidMIPS, "mips"},
	{device.AndroidMIPS64, "mips64"},
	{device.AndroidX86, "x86"},
	{device.AndroidX86_64, "x86_64"},
}

func abiToISA(abi *device.ABI) string {
	for _, e := range abiToISAs {
		if e.abi.Architecture == abi.Architecture {
			return e.isa
		}
	}
	return ""
}

func isaToABI(isa string) *device.ABI {
	for _, e := range abiToISAs {
		if e.isa == isa {
			return e.abi
		}
	}
	return nil
}
<|endoftext|>