<commit_before>package mark

import (
	"fmt"
	"regexp"
	"strings"
	"unicode/utf8"
)

// type position
type Pos int

// itemType identifies the type of lex items.
type itemType int

// Item represent a token or text string returned from the scanner
type item struct {
	typ itemType // The type of this item.
	pos Pos      // The starting position, in bytes, of this item in the input string.
	val string   // The value of this item.
}

const eof = -1 // Zero value so closed channel delivers EOF

const (
	itemError itemType = iota // Error occurred; value is text of error
	// Intersting things
	itemNewLine
	itemHTML
	// Block Elements
	itemText
	itemLineBreak
	itemHeading
	itemLHeading // Setext-style headers
	itemBlockQuote
	itemList
	itemCodeBlock
	itemGfmCodeBlock
	itemHr
	itemTable
	itemLpTable
	// Span Elements
	itemLink
	itemAutoLink
	itemGfmLink
	itemStrong
	itemItalic
	itemStrike
	itemCode
	itemImage
	itemBr
	itemPipe
	// Indentation
	itemIndent
)

var (
	reEmphasise = `^_{%[1]d}([\s\S]+?(?:_{0,}))_{%[1]d}|^\*{%[1]d}([\s\S]+?(?:\*{0,}))\*{%[1]d}`
	reGfmCode   = `^%[1]s{3,} *(\S+)? *\n([\s\S]+?)\s*%[1]s{3,}$*(?:\n+|$)`
	reLinkText  = `(?:\[[^\]]*\]|[^\[\]]|\])*`
	reLinkHref  = `\s*<?([\s\S]*?)>?(?:\s+['"]([\s\S]*?)['"])?\s*`
)

// Block Grammer
var block = map[itemType]*regexp.Regexp{
	itemHeading:   regexp.MustCompile(`^ *(#{1,6}) *([^\n]+?) *#* *(?:\n+|$)`),
	itemLHeading:  regexp.MustCompile(`^([^\n]+)\n *(=|-){2,} *(?:\n+|$)`),
	itemHr:        regexp.MustCompile(`^( *[-*_]){3,} *(?:\n+|$)`),
	itemCodeBlock: regexp.MustCompile(`^(( {4}|\t)[^-+*(\d\.)\n]+\n*)+`),
	// Backreferences is unavailable
	itemGfmCodeBlock: regexp.MustCompile(fmt.Sprintf(reGfmCode, "`") + "|" + fmt.Sprintf(reGfmCode, "~")),
	// `^(?:[*+-]|\d+\.) [\s\S]+?(?:\n|)`
	itemList: regexp.MustCompile(`^(?:[*+-]|\d+\.) +?(?:\n|)`),
	// leading-pipe table
	itemLpTable: regexp.MustCompile(`^ *\|(.+)\n *\|( *[-:]+[-| :]*)\n((?: *\|.*(?:\n|$))*)\n*`),
	itemTable:   regexp.MustCompile(`^ *(\S.*\|.*)\n *([-:]+ *\|[-| :]*)\n((?:.*\|.*(?:\n|$))*)\n*`),
}

// Inline Grammer
var span = map[itemType]*regexp.Regexp{
	itemItalic: regexp.MustCompile(fmt.Sprintf(reEmphasise, 1)),
	itemStrong: regexp.MustCompile(fmt.Sprintf(reEmphasise, 2)),
	itemStrike: regexp.MustCompile(`^~{2}([\s\S]+?)~{2}`),
	// itemMixed(e.g: ***str***, ~~*str*~~) will be part of the parser
	// or we'll lex recuresively
	itemCode: regexp.MustCompile("^`{1,2}\\s*([\\s\\S]*?[^`])\\s*`{1,2}"),
	itemBr:   regexp.MustCompile(`^ {2,}\n`),
	// Links
	itemLink:     regexp.MustCompile(fmt.Sprintf(`^!?\[(%s)\]\(%s\)`, reLinkText, reLinkHref)),
	itemAutoLink: regexp.MustCompile(`^<([^ >]+(@|:\/)[^ >]+)>`),
	itemGfmLink:  regexp.MustCompile(`^(https?:\/\/[^\s<]+[^<.,:;"')\]\s])`),
	// Image
	// TODO(Ariel): DRY
	itemImage: regexp.MustCompile(fmt.Sprintf(`^!?\[(%s)\]\(%s\)`, reLinkText, reLinkHref)),
}

// stateFn represents the state of the scanner as a function that returns the next state.
type stateFn func(*lexer) stateFn

// lexer holds the state of the scanner.
type lexer struct {
	name    string    // the name of the input; used only for error reports
	input   string    // the string being scanned
	state   stateFn   // the next lexing function to enter
	pos     Pos       // current position in the input
	start   Pos       // start position of this item
	width   Pos       // width of last rune read from input
	lastPos Pos       // position of most recent item returned by nextItem
	items   chan item // channel of scanned items
	eot     Pos       // end of table
}

// lex creates a new lexer for the input string.
func lex(name, input string) *lexer {
	l := &lexer{
		name:  name,
		input: input,
		items: make(chan item),
	}
	go l.run()
	return l
}

// run runs the state machine for the lexer.
func (l *lexer) run() {
	for l.state = lexAny; l.state != nil; {
		l.state = l.state(l)
	}
	close(l.items)
}

// next return the next rune in the input
func (l *lexer) next() rune {
	if int(l.pos) >= len(l.input) {
		l.width = 0
		return eof
	}
	r, w := utf8.DecodeRuneInString(l.input[l.pos:])
	l.width = Pos(w)
	l.pos += l.width
	return r
}

// lexAny scans non-space items.
func lexAny(l *lexer) stateFn {
	switch r := l.next(); r {
	case eof:
		return nil
	case '*', '-', '_', '+':
		p := l.peek()
		if p == '*' || p == '-' || p == '_' {
			l.backup()
			return lexHr
		} else {
			l.backup()
			return lexList
		}
	case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
		l.backup()
		return lexList
	case '>':
		l.emit(itemBlockQuote)
		return lexText
	case '#':
		l.backup()
		return lexHeading
	case ' ', '\t':
		// Should be here ?
		// TODO(Ariel): test that it's a codeBlock and not list for sure
		if block[itemCodeBlock].MatchString(l.input[l.pos-1:]) {
			l.backup()
			return lexCode
		}
		// Keep moving forward until we get all the
		// indentation size
		for ; r == l.peek(); r = l.next() {
		}
		l.emit(itemIndent)
		return lexAny
	case '`', '~':
		// if it's gfm-code
		c := l.input[l.pos : l.pos+2]
		if c == "``" || c == "~~" {
			l.backup()
			return lexGfmCode
		}
		fallthrough
	case '|':
		if m := block[itemLpTable].FindString(l.input[l.pos-1:]); m != "" {
			l.eot = l.start + Pos(len(m))
			l.emit(itemLpTable)
		}
		fallthrough
	default:
		if m := block[itemTable].FindString(l.input[l.pos-1:]); m != "" {
			l.eot = l.start + Pos(len(m)) - l.width
			l.emit(itemTable)
			// we go one step back to get the full text
			// in the lexText phase
			l.start--
		}
		l.backup()
		return lexText
	}
}

// lexHeading scans heading items.
func lexHeading(l *lexer) stateFn {
	if m := block[itemHeading].FindString(l.input[l.pos:]); m != "" {
		// Emit without the newline(\n)
		l.pos += Pos(len(m))
		// TODO(Ariel): hack, fix regexp
		if strings.HasSuffix(m, "\n") {
			l.pos--
		}
		l.emit(itemHeading)
		return lexAny
	}
	return lexText
}

// lexHr scans horizontal rules items.
func lexHr(l *lexer) stateFn {
	if block[itemHr].MatchString(l.input[l.pos:]) {
		match := block[itemHr].FindString(l.input[l.pos:])
		l.pos += Pos(len(match))
		l.emit(itemHr)
		return lexAny
	}
	return lexText
}

// lexGfmCode scans GFM code block.
func lexGfmCode(l *lexer) stateFn {
	re := block[itemGfmCodeBlock]
	if re.MatchString(l.input[l.pos:]) {
		match := re.FindString(l.input[l.pos:])
		l.pos += Pos(len(match))
		l.emit(itemGfmCodeBlock)
		return lexAny
	}
	return lexText
}

// lexCode scans code block.
func lexCode(l *lexer) stateFn {
	match := block[itemCodeBlock].FindString(l.input[l.pos:])
	l.pos += Pos(len(match))
	l.emit(itemCodeBlock)
	return lexAny
}

// lexList scans ordered and unordered lists.
func lexList(l *lexer) stateFn {
	if m := block[itemList].FindString(l.input[l.pos:]); m != "" {
		l.pos += Pos(len(m))
		l.emit(itemList)
	}
	return lexText
}

// lexText scans until eol(\n)
// We have a lot of things to do in this lextext
// for example: ignore itemBr on list/tables
// fix the text scaning etc...
func lexText(l *lexer) stateFn {
	// Drain text before emitting
	emit := func(item itemType, pos Pos) {
		if l.pos > l.start {
			l.emit(itemText)
		}
		l.pos += pos
		l.emit(item)
	}
Loop:
	for {
		switch r := l.peek(); {
		case r == eof:
			emit(eof, Pos(0))
			break Loop
		case r == '\n':
			emit(itemNewLine, l.width)
			break Loop
		case r == ' ':
			if m := span[itemBr].FindString(l.input[l.pos:]); m != "" {
				// pos - length of new-line
				emit(itemBr, Pos(len(m)))
				break
			}
			l.next()
		// if it's start as an emphasis
		case r == '_', r == '*', r == '~', r == '`':
			input := l.input[l.pos:]
			// Strong
			if m := span[itemStrong].FindString(input); m != "" {
				emit(itemStrong, Pos(len(m)))
				break
			}
			// Italic
			if m := span[itemItalic].FindString(input); m != "" {
				emit(itemItalic, Pos(len(m)))
				break
			}
			// Strike
			if m := span[itemStrike].FindString(input); m != "" {
				emit(itemStrike, Pos(len(m)))
				break
			}
			// InlineCode
			if m := span[itemCode].FindString(input); m != "" {
				emit(itemCode, Pos(len(m)))
				break
			}
			l.next()
		// itemLink, itemAutoLink, itemImage
		case r == '[', r == '<', r == '!':
			input := l.input[l.pos:]
			if m := span[itemLink].FindString(input); m != "" {
				pos := Pos(len(m))
				if r == '[' {
					emit(itemLink, pos)
				} else {
					emit(itemImage, pos)
				}
				break
			}
			if m := span[itemAutoLink].FindString(input); m != "" {
				emit(itemAutoLink, Pos(len(m)))
				break
			}
			l.next()
		case r == '|':
			if l.eot > l.pos {
				emit(itemPipe, l.width)
				break
			}
			l.next()
		default:
			input := l.input[l.pos:]
			// Test for Setext-style headers
			if m := block[itemLHeading].FindString(input); m != "" {
				emit(itemLHeading, Pos(len(m)))
				break Loop
			}
			// GfmLink
			if m := span[itemGfmLink].FindString(input); m != "" {
				emit(itemGfmLink, Pos(len(m)))
				break
			}
			l.next()
		}
	}
	return lexAny
}

// backup steps back one rune. Can only be called once per call of next.
func (l *lexer) backup() {
	l.pos -= l.width
}

// peek returns but does not consume the next rune in the input.
func (l *lexer) peek() rune {
	r := l.next()
	l.backup()
	return r
}

// emit passes an item back to the client.
func (l *lexer) emit(t itemType) {
	l.items <- item{t, l.start, l.input[l.start:l.pos]}
	l.start = l.pos
}

// lexItem return the next item token, clled by the parser.
func (l *lexer) nextItem() item {
	item := <-l.items
	l.lastPos = l.pos
	return item
}
<commit_msg>fix(lexer): heading regexp<commit_after>package mark

import (
	"fmt"
	"regexp"
	"strings"
	"unicode/utf8"
)

// type position
type Pos int

// itemType identifies the type of lex items.
type itemType int

// Item represent a token or text string returned from the scanner
type item struct {
	typ itemType // The type of this item.
	pos Pos      // The starting position, in bytes, of this item in the input string.
	val string   // The value of this item.
}

const eof = -1 // Zero value so closed channel delivers EOF

const (
	itemError itemType = iota // Error occurred; value is text of error
	// Intersting things
	itemNewLine
	itemHTML
	// Block Elements
	itemText
	itemLineBreak
	itemHeading
	itemLHeading // Setext-style headers
	itemBlockQuote
	itemList
	itemCodeBlock
	itemGfmCodeBlock
	itemHr
	itemTable
	itemLpTable
	// Span Elements
	itemLink
	itemAutoLink
	itemGfmLink
	itemStrong
	itemItalic
	itemStrike
	itemCode
	itemImage
	itemBr
	itemPipe
	// Indentation
	itemIndent
)

var (
	reEmphasise = `^_{%[1]d}([\s\S]+?(?:_{0,}))_{%[1]d}|^\*{%[1]d}([\s\S]+?(?:\*{0,}))\*{%[1]d}`
	reGfmCode   = `^%[1]s{3,} *(\S+)? *\n([\s\S]+?)\s*%[1]s{3,}$*(?:\n+|$)`
	reLinkText  = `(?:\[[^\]]*\]|[^\[\]]|\])*`
	reLinkHref  = `\s*<?([\s\S]*?)>?(?:\s+['"]([\s\S]*?)['"])?\s*`
)

// Block Grammer
var block = map[itemType]*regexp.Regexp{
	itemHeading:   regexp.MustCompile(`^ *(#{1,6}) +([^\n]+?) *#* *(?:\n+|$)`),
	itemLHeading:  regexp.MustCompile(`^([^\n]+)\n *(=|-){2,} *(?:\n+|$)`),
	itemHr:        regexp.MustCompile(`^( *[-*_]){3,} *(?:\n+|$)`),
	itemCodeBlock: regexp.MustCompile(`^(( {4}|\t)[^-+*(\d\.)\n]+\n*)+`),
	// Backreferences is unavailable
	itemGfmCodeBlock: regexp.MustCompile(fmt.Sprintf(reGfmCode, "`") + "|" + fmt.Sprintf(reGfmCode, "~")),
	// `^(?:[*+-]|\d+\.) [\s\S]+?(?:\n|)`
	itemList: regexp.MustCompile(`^(?:[*+-]|\d+\.) +?(?:\n|)`),
	// leading-pipe table
	itemLpTable: regexp.MustCompile(`^ *\|(.+)\n *\|( *[-:]+[-| :]*)\n((?: *\|.*(?:\n|$))*)\n*`),
	itemTable:   regexp.MustCompile(`^ *(\S.*\|.*)\n *([-:]+ *\|[-| :]*)\n((?:.*\|.*(?:\n|$))*)\n*`),
}

// Inline Grammer
var span = map[itemType]*regexp.Regexp{
	itemItalic: regexp.MustCompile(fmt.Sprintf(reEmphasise, 1)),
	itemStrong: regexp.MustCompile(fmt.Sprintf(reEmphasise, 2)),
	itemStrike: regexp.MustCompile(`^~{2}([\s\S]+?)~{2}`),
	// itemMixed(e.g: ***str***, ~~*str*~~) will be part of the parser
	// or we'll lex recuresively
	itemCode: regexp.MustCompile("^`{1,2}\\s*([\\s\\S]*?[^`])\\s*`{1,2}"),
	itemBr:   regexp.MustCompile(`^ {2,}\n`),
	// Links
	itemLink:     regexp.MustCompile(fmt.Sprintf(`^!?\[(%s)\]\(%s\)`, reLinkText, reLinkHref)),
	itemAutoLink: regexp.MustCompile(`^<([^ >]+(@|:\/)[^ >]+)>`),
	itemGfmLink:  regexp.MustCompile(`^(https?:\/\/[^\s<]+[^<.,:;"')\]\s])`),
	// Image
	// TODO(Ariel): DRY
	itemImage: regexp.MustCompile(fmt.Sprintf(`^!?\[(%s)\]\(%s\)`, reLinkText, reLinkHref)),
}

// stateFn represents the state of the scanner as a function that returns the next state.
type stateFn func(*lexer) stateFn

// lexer holds the state of the scanner.
type lexer struct {
	name    string    // the name of the input; used only for error reports
	input   string    // the string being scanned
	state   stateFn   // the next lexing function to enter
	pos     Pos       // current position in the input
	start   Pos       // start position of this item
	width   Pos       // width of last rune read from input
	lastPos Pos       // position of most recent item returned by nextItem
	items   chan item // channel of scanned items
	eot     Pos       // end of table
}

// lex creates a new lexer for the input string.
func lex(name, input string) *lexer {
	l := &lexer{
		name:  name,
		input: input,
		items: make(chan item),
	}
	go l.run()
	return l
}

// run runs the state machine for the lexer.
func (l *lexer) run() {
	for l.state = lexAny; l.state != nil; {
		l.state = l.state(l)
	}
	close(l.items)
}

// next return the next rune in the input
func (l *lexer) next() rune {
	if int(l.pos) >= len(l.input) {
		l.width = 0
		return eof
	}
	r, w := utf8.DecodeRuneInString(l.input[l.pos:])
	l.width = Pos(w)
	l.pos += l.width
	return r
}

// lexAny scans non-space items.
func lexAny(l *lexer) stateFn {
	switch r := l.next(); r {
	case eof:
		return nil
	case '*', '-', '_', '+':
		p := l.peek()
		if p == '*' || p == '-' || p == '_' {
			l.backup()
			return lexHr
		} else {
			l.backup()
			return lexList
		}
	case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
		l.backup()
		return lexList
	case '>':
		l.emit(itemBlockQuote)
		return lexText
	case '#':
		l.backup()
		return lexHeading
	case ' ', '\t':
		// Should be here ?
		// TODO(Ariel): test that it's a codeBlock and not list for sure
		if block[itemCodeBlock].MatchString(l.input[l.pos-1:]) {
			l.backup()
			return lexCode
		}
		// Keep moving forward until we get all the
		// indentation size
		for ; r == l.peek(); r = l.next() {
		}
		l.emit(itemIndent)
		return lexAny
	case '`', '~':
		// if it's gfm-code
		c := l.input[l.pos : l.pos+2]
		if c == "``" || c == "~~" {
			l.backup()
			return lexGfmCode
		}
		fallthrough
	case '|':
		if m := block[itemLpTable].FindString(l.input[l.pos-1:]); m != "" {
			l.eot = l.start + Pos(len(m))
			l.emit(itemLpTable)
		}
		fallthrough
	default:
		if m := block[itemTable].FindString(l.input[l.pos-1:]); m != "" {
			l.eot = l.start + Pos(len(m)) - l.width
			l.emit(itemTable)
			// we go one step back to get the full text
			// in the lexText phase
			l.start--
		}
		l.backup()
		return lexText
	}
}

// lexHeading scans heading items.
func lexHeading(l *lexer) stateFn {
	if m := block[itemHeading].FindString(l.input[l.pos:]); m != "" {
		// Emit without the newline(\n)
		l.pos += Pos(len(m))
		// TODO(Ariel): hack, fix regexp
		if strings.HasSuffix(m, "\n") {
			l.pos--
		}
		l.emit(itemHeading)
		return lexAny
	}
	return lexText
}

// lexHr scans horizontal rules items.
func lexHr(l *lexer) stateFn {
	if block[itemHr].MatchString(l.input[l.pos:]) {
		match := block[itemHr].FindString(l.input[l.pos:])
		l.pos += Pos(len(match))
		l.emit(itemHr)
		return lexAny
	}
	return lexText
}

// lexGfmCode scans GFM code block.
func lexGfmCode(l *lexer) stateFn {
	re := block[itemGfmCodeBlock]
	if re.MatchString(l.input[l.pos:]) {
		match := re.FindString(l.input[l.pos:])
		l.pos += Pos(len(match))
		l.emit(itemGfmCodeBlock)
		return lexAny
	}
	return lexText
}

// lexCode scans code block.
func lexCode(l *lexer) stateFn {
	match := block[itemCodeBlock].FindString(l.input[l.pos:])
	l.pos += Pos(len(match))
	l.emit(itemCodeBlock)
	return lexAny
}

// lexList scans ordered and unordered lists.
func lexList(l *lexer) stateFn {
	if m := block[itemList].FindString(l.input[l.pos:]); m != "" {
		l.pos += Pos(len(m))
		l.emit(itemList)
	}
	return lexText
}

// lexText scans until eol(\n)
// We have a lot of things to do in this lextext
// for example: ignore itemBr on list/tables
// fix the text scaning etc...
func lexText(l *lexer) stateFn {
	// Drain text before emitting
	emit := func(item itemType, pos Pos) {
		if l.pos > l.start {
			l.emit(itemText)
		}
		l.pos += pos
		l.emit(item)
	}
Loop:
	for {
		switch r := l.peek(); {
		case r == eof:
			emit(eof, Pos(0))
			break Loop
		case r == '\n':
			emit(itemNewLine, l.width)
			break Loop
		case r == ' ':
			if m := span[itemBr].FindString(l.input[l.pos:]); m != "" {
				// pos - length of new-line
				emit(itemBr, Pos(len(m)))
				break
			}
			l.next()
		// if it's start as an emphasis
		case r == '_', r == '*', r == '~', r == '`':
			input := l.input[l.pos:]
			// Strong
			if m := span[itemStrong].FindString(input); m != "" {
				emit(itemStrong, Pos(len(m)))
				break
			}
			// Italic
			if m := span[itemItalic].FindString(input); m != "" {
				emit(itemItalic, Pos(len(m)))
				break
			}
			// Strike
			if m := span[itemStrike].FindString(input); m != "" {
				emit(itemStrike, Pos(len(m)))
				break
			}
			// InlineCode
			if m := span[itemCode].FindString(input); m != "" {
				emit(itemCode, Pos(len(m)))
				break
			}
			l.next()
		// itemLink, itemAutoLink, itemImage
		case r == '[', r == '<', r == '!':
			input := l.input[l.pos:]
			if m := span[itemLink].FindString(input); m != "" {
				pos := Pos(len(m))
				if r == '[' {
					emit(itemLink, pos)
				} else {
					emit(itemImage, pos)
				}
				break
			}
			if m := span[itemAutoLink].FindString(input); m != "" {
				emit(itemAutoLink, Pos(len(m)))
				break
			}
			l.next()
		case r == '|':
			if l.eot > l.pos {
				emit(itemPipe, l.width)
				break
			}
			l.next()
		default:
			input := l.input[l.pos:]
			// Test for Setext-style headers
			if m := block[itemLHeading].FindString(input); m != "" {
				emit(itemLHeading, Pos(len(m)))
				break Loop
			}
			// GfmLink
			if m := span[itemGfmLink].FindString(input); m != "" {
				emit(itemGfmLink, Pos(len(m)))
				break
			}
			l.next()
		}
	}
	return lexAny
}

// backup steps back one rune. Can only be called once per call of next.
func (l *lexer) backup() {
	l.pos -= l.width
}

// peek returns but does not consume the next rune in the input.
func (l *lexer) peek() rune {
	r := l.next()
	l.backup()
	return r
}

// emit passes an item back to the client.
func (l *lexer) emit(t itemType) {
	l.items <- item{t, l.start, l.input[l.start:l.pos]}
	l.start = l.pos
}

// lexItem return the next item token, clled by the parser.
func (l *lexer) nextItem() item {
	item := <-l.items
	l.lastPos = l.pos
	return item
}
<|endoftext|>


<commit_before>// +build linux

package lxc

import (
	"bufio"
	"fmt"
	"io/ioutil"
	"math/rand"
	"os"
	"path"
	"strings"
	"testing"
	"time"

	"github.com/docker/docker/daemon/execdriver"
	nativeTemplate "github.com/docker/docker/daemon/execdriver/native/template"
	"github.com/docker/libcontainer/configs"
	"github.com/syndtr/gocapability/capability"
)

func TestLXCConfig(t *testing.T) {
	root, err := ioutil.TempDir("", "TestLXCConfig")
	if err != nil {
		t.Fatal(err)
	}
	defer os.RemoveAll(root)

	os.MkdirAll(path.Join(root, "containers", "1"), 0777)

	// Memory is allocated randomly for testing
	rand.Seed(time.Now().UTC().UnixNano())
	var (
		memMin = 33554432
		memMax = 536870912
		mem    = memMin + rand.Intn(memMax-memMin)
		cpuMin = 100
		cpuMax = 10000
		cpu    = cpuMin + rand.Intn(cpuMax-cpuMin)
	)

	driver, err := NewDriver(root, root, "", false)
	if err != nil {
		t.Fatal(err)
	}
	command := &execdriver.Command{
		ID: "1",
		Resources: &execdriver.Resources{
			Memory:    int64(mem),
			CpuShares: int64(cpu),
		},
		Network: &execdriver.Network{
			Mtu:       1500,
			Interface: nil,
		},
		AllowedDevices: make([]*configs.Device, 0),
		ProcessConfig:  execdriver.ProcessConfig{},
	}
	p, err := driver.generateLXCConfig(command)
	if err != nil {
		t.Fatal(err)
	}
	grepFile(t, p,
		fmt.Sprintf("lxc.cgroup.memory.limit_in_bytes = %d", mem))

	grepFile(t, p,
		fmt.Sprintf("lxc.cgroup.memory.memsw.limit_in_bytes = %d", mem*2))
}

func TestCustomLxcConfig(t *testing.T) {
	root, err := ioutil.TempDir("", "TestCustomLxcConfig")
	if err != nil {
		t.Fatal(err)
	}
	defer os.RemoveAll(root)

	os.MkdirAll(path.Join(root, "containers", "1"), 0777)

	driver, err := NewDriver(root, root, "", false)
	if err != nil {
		t.Fatal(err)
	}
	processConfig := execdriver.ProcessConfig{
		Privileged: false,
	}
	command := &execdriver.Command{
		ID: "1",
		LxcConfig: []string{
			"lxc.utsname = docker",
			"lxc.cgroup.cpuset.cpus = 0,1",
		},
		Network: &execdriver.Network{
			Mtu:       1500,
			Interface: nil,
		},
		ProcessConfig: processConfig,
	}

	p, err := driver.generateLXCConfig(command)
	if err != nil {
		t.Fatal(err)
	}

	grepFile(t, p, "lxc.utsname = docker")
	grepFile(t, p, "lxc.cgroup.cpuset.cpus = 0,1")
}

func grepFile(t *testing.T, path string, pattern string) {
	grepFileWithReverse(t, path, pattern, false)
}

func grepFileWithReverse(t *testing.T, path string, pattern string, inverseGrep bool) {
	f, err := os.Open(path)
	if err != nil {
		t.Fatal(err)
	}
	defer f.Close()
	r := bufio.NewReader(f)
	var (
		line string
	)
	err = nil
	for err == nil {
		line, err = r.ReadString('\n')
		if strings.Contains(line, pattern) == true {
			if inverseGrep {
				t.Fatalf("grepFile: pattern \"%s\" found in \"%s\"", pattern, path)
			}
			return
		}
	}
	if inverseGrep {
		return
	}
	t.Fatalf("grepFile: pattern \"%s\" not found in \"%s\"", pattern, path)
}

func TestEscapeFstabSpaces(t *testing.T) {
	var testInputs = map[string]string{
		" ":                      "\\040",
		"":                       "",
		"/double  space":         "/double\\040\\040space",
		"/some long test string": "/some\\040long\\040test\\040string",
		"/var/lib/docker":        "/var/lib/docker",
		" leading":               "\\040leading",
		"trailing ":              "trailing\\040",
	}
	for in, exp := range testInputs {
		if out := escapeFstabSpaces(in); exp != out {
			t.Logf("Expected %s got %s", exp, out)
			t.Fail()
		}
	}
}

func TestIsDirectory(t *testing.T) {
	tempDir, err := ioutil.TempDir("", "TestIsDir")
	if err != nil {
		t.Fatal(err)
	}
	defer os.RemoveAll(tempDir)

	tempFile, err := ioutil.TempFile(tempDir, "TestIsDirFile")
	if err != nil {
		t.Fatal(err)
	}

	if isDirectory(tempDir) != "dir" {
		t.Logf("Could not identify %s as a directory", tempDir)
		t.Fail()
	}

	if isDirectory(tempFile.Name()) != "file" {
		t.Logf("Could not identify %s as a file", tempFile.Name())
		t.Fail()
	}
}

func TestCustomLxcConfigMounts(t *testing.T) {
	root, err := ioutil.TempDir("", "TestCustomLxcConfig")
	if err != nil {
		t.Fatal(err)
	}
	defer os.RemoveAll(root)
	tempDir, err := ioutil.TempDir("", "TestIsDir")
	if err != nil {
		t.Fatal(err)
	}
	defer os.RemoveAll(tempDir)

	tempFile, err := ioutil.TempFile(tempDir, "TestIsDirFile")
	if err != nil {
		t.Fatal(err)
	}
	os.MkdirAll(path.Join(root, "containers", "1"), 0777)

	driver, err := NewDriver(root, root, "", false)
	if err != nil {
		t.Fatal(err)
	}
	processConfig := execdriver.ProcessConfig{
		Privileged: false,
	}
	mounts := []execdriver.Mount{
		{
			Source:      tempDir,
			Destination: tempDir,
			Writable:    false,
			Private:     true,
		},
		{
			Source:      tempFile.Name(),
			Destination: tempFile.Name(),
			Writable:    true,
			Private:     true,
		},
	}
	command := &execdriver.Command{
		ID: "1",
		LxcConfig: []string{
			"lxc.utsname = docker",
			"lxc.cgroup.cpuset.cpus = 0,1",
		},
		Network: &execdriver.Network{
			Mtu:       1500,
			Interface: nil,
		},
		Mounts:        mounts,
		ProcessConfig: processConfig,
	}

	p, err := driver.generateLXCConfig(command)
	if err != nil {
		t.Fatal(err)
	}

	grepFile(t, p, "lxc.utsname = docker")
	grepFile(t, p, "lxc.cgroup.cpuset.cpus = 0,1")

	grepFile(t, p, fmt.Sprintf("lxc.mount.entry = %s %s none rbind,ro,create=%s 0 0", tempDir, "/"+tempDir, "dir"))
	grepFile(t, p, fmt.Sprintf("lxc.mount.entry = %s %s none rbind,rw,create=%s 0 0", tempFile.Name(), "/"+tempFile.Name(), "file"))
}

func TestCustomLxcConfigMisc(t *testing.T) {
	root, err := ioutil.TempDir("", "TestCustomLxcConfig")
	if err != nil {
		t.Fatal(err)
	}
	defer os.RemoveAll(root)
	os.MkdirAll(path.Join(root, "containers", "1"), 0777)
	driver, err := NewDriver(root, root, "", true)

	if err != nil {
		t.Fatal(err)
	}
	processConfig := execdriver.ProcessConfig{
		Privileged: false,
	}

	processConfig.Env = []string{"HOSTNAME=testhost"}
	command := &execdriver.Command{
		ID: "1",
		LxcConfig: []string{
			"lxc.cgroup.cpuset.cpus = 0,1",
		},
		Network: &execdriver.Network{
			Mtu: 1500,
			Interface: &execdriver.NetworkInterface{
				Gateway:     "10.10.10.1",
				IPAddress:   "10.10.10.10",
				IPPrefixLen: 24,
				Bridge:      "docker0",
			},
		},
		ProcessConfig:   processConfig,
		CapAdd:          []string{"net_admin", "syslog"},
		CapDrop:         []string{"kill", "mknod"},
		AppArmorProfile: "lxc-container-default-with-nesting",
	}

	p, err := driver.generateLXCConfig(command)
	if err != nil {
		t.Fatal(err)
	}
	// network
	grepFile(t, p, "lxc.network.type = veth")
	grepFile(t, p, "lxc.network.link = docker0")
	grepFile(t, p, "lxc.network.name = eth0")
	grepFile(t, p, "lxc.network.ipv4 = 10.10.10.10/24")
	grepFile(t, p, "lxc.network.ipv4.gateway = 10.10.10.1")
	grepFile(t, p, "lxc.network.flags = up")
	grepFile(t, p, "lxc.aa_profile = lxc-container-default-with-nesting")
	// hostname
	grepFile(t, p, "lxc.utsname = testhost")
	grepFile(t, p, "lxc.cgroup.cpuset.cpus = 0,1")
	container := nativeTemplate.New()
	for _, cap := range container.Capabilities {
		realCap := execdriver.GetCapability(cap)
		numCap := fmt.Sprintf("%d", realCap.Value)
		if cap != "MKNOD" && cap != "KILL" {
			grepFile(t, p, fmt.Sprintf("lxc.cap.keep = %s", numCap))
		}
	}

	grepFileWithReverse(t, p, fmt.Sprintf("lxc.cap.keep = %d", capability.CAP_KILL), true)
	grepFileWithReverse(t, p, fmt.Sprintf("lxc.cap.keep = %d", capability.CAP_MKNOD), true)
}

func TestCustomLxcConfigMiscOverride(t *testing.T) {
	root, err := ioutil.TempDir("", "TestCustomLxcConfig")
	if err != nil {
		t.Fatal(err)
	}
	defer os.RemoveAll(root)
	os.MkdirAll(path.Join(root, "containers", "1"), 0777)
	driver, err := NewDriver(root, root, "", false)
	if err != nil {
		t.Fatal(err)
	}
	processConfig := execdriver.ProcessConfig{
		Privileged: false,
	}

	processConfig.Env = []string{"HOSTNAME=testhost"}
	command := &execdriver.Command{
		ID: "1",
		LxcConfig: []string{
			"lxc.cgroup.cpuset.cpus = 0,1",
			"lxc.network.ipv4 = 172.0.0.1",
		},
		Network: &execdriver.Network{
			Mtu: 1500,
			Interface: &execdriver.NetworkInterface{
				Gateway:     "10.10.10.1",
				IPAddress:   "10.10.10.10",
				IPPrefixLen: 24,
				Bridge:      "docker0",
			},
		},
		ProcessConfig: processConfig,
		CapAdd:        []string{"NET_ADMIN", "SYSLOG"},
		CapDrop:       []string{"KILL", "MKNOD"},
	}

	p, err := driver.generateLXCConfig(command)
	if err != nil {
		t.Fatal(err)
	}
	// network
	grepFile(t, p, "lxc.network.type = veth")
	grepFile(t, p, "lxc.network.link = docker0")
	grepFile(t, p, "lxc.network.name = eth0")
	grepFile(t, p, "lxc.network.ipv4 = 172.0.0.1")
	grepFile(t, p, "lxc.network.ipv4.gateway = 10.10.10.1")
	grepFile(t, p, "lxc.network.flags = up")

	// hostname
	grepFile(t, p, "lxc.utsname = testhost")
	grepFile(t, p, "lxc.cgroup.cpuset.cpus = 0,1")
	container := nativeTemplate.New()
	for _, cap := range container.Capabilities {
		realCap := execdriver.GetCapability(cap)
		numCap := fmt.Sprintf("%d", realCap.Value)
		if cap != "MKNOD" && cap != "KILL" {
			grepFile(t, p, fmt.Sprintf("lxc.cap.keep = %s", numCap))
		}
	}
	grepFileWithReverse(t, p, fmt.Sprintf("lxc.cap.keep = %d", capability.CAP_KILL), true)
	grepFileWithReverse(t, p, fmt.Sprintf("lxc.cap.keep = %d", capability.CAP_MKNOD), true)
}
<commit_msg>execdriver/lxc: use local rand.Random in test<commit_after>// +build linux

package lxc

import (
	"bufio"
	"fmt"
	"io/ioutil"
	"math/rand"
	"os"
	"path"
	"strings"
	"testing"
	"time"

	"github.com/docker/docker/daemon/execdriver"
	nativeTemplate "github.com/docker/docker/daemon/execdriver/native/template"
	"github.com/docker/libcontainer/configs"
	"github.com/syndtr/gocapability/capability"
)

func TestLXCConfig(t *testing.T) {
	root, err := ioutil.TempDir("", "TestLXCConfig")
	if err != nil {
		t.Fatal(err)
	}
	defer os.RemoveAll(root)

	os.MkdirAll(path.Join(root, "containers", "1"), 0777)

	// Memory is allocated randomly for testing
	r := rand.New(rand.NewSource(time.Now().UTC().UnixNano()))
	var (
		memMin = 33554432
		memMax = 536870912
		mem    = memMin + r.Intn(memMax-memMin)
		cpuMin = 100
		cpuMax = 10000
		cpu    = cpuMin + r.Intn(cpuMax-cpuMin)
	)

	driver, err := NewDriver(root, root, "", false)
	if err != nil {
		t.Fatal(err)
	}
	command := &execdriver.Command{
		ID: "1",
		Resources: &execdriver.Resources{
			Memory:    int64(mem),
			CpuShares: int64(cpu),
		},
		Network: &execdriver.Network{
			Mtu:       1500,
			Interface: nil,
		},
		AllowedDevices: make([]*configs.Device, 0),
		ProcessConfig:  execdriver.ProcessConfig{},
	}
	p, err := driver.generateLXCConfig(command)
	if err != nil {
		t.Fatal(err)
	}
	grepFile(t, p,
		fmt.Sprintf("lxc.cgroup.memory.limit_in_bytes = %d", mem))

	grepFile(t, p,
		fmt.Sprintf("lxc.cgroup.memory.memsw.limit_in_bytes = %d", mem*2))
}

func TestCustomLxcConfig(t *testing.T) {
	root, err := ioutil.TempDir("", "TestCustomLxcConfig")
	if err != nil {
		t.Fatal(err)
	}
	defer os.RemoveAll(root)

	os.MkdirAll(path.Join(root, "containers", "1"), 0777)

	driver, err := NewDriver(root, root, "", false)
	if err != nil {
		t.Fatal(err)
	}
	processConfig := execdriver.ProcessConfig{
		Privileged: false,
	}
	command := &execdriver.Command{
		ID: "1",
		LxcConfig: []string{
			"lxc.utsname = docker",
			"lxc.cgroup.cpuset.cpus = 0,1",
		},
		Network: &execdriver.Network{
			Mtu:       1500,
			Interface: nil,
		},
		ProcessConfig: processConfig,
	}

	p, err := driver.generateLXCConfig(command)
	if err != nil {
		t.Fatal(err)
	}

	grepFile(t, p, "lxc.utsname = docker")
	grepFile(t, p, "lxc.cgroup.cpuset.cpus = 0,1")
}

func grepFile(t *testing.T, path string, pattern string) {
	grepFileWithReverse(t, path, pattern, false)
}

func grepFileWithReverse(t *testing.T, path string, pattern string, inverseGrep bool) {
	f, err := os.Open(path)
	if err != nil {
		t.Fatal(err)
	}
	defer f.Close()
	r := bufio.NewReader(f)
	var (
		line string
	)
	err = nil
	for err == nil {
		line, err = r.ReadString('\n')
		if strings.Contains(line, pattern) == true {
			if inverseGrep {
				t.Fatalf("grepFile: pattern \"%s\" found in \"%s\"", pattern, path)
			}
			return
		}
	}
	if inverseGrep {
		return
	}
	t.Fatalf("grepFile: pattern \"%s\" not found in \"%s\"", pattern, path)
}

func TestEscapeFstabSpaces(t *testing.T) {
	var testInputs = map[string]string{
		" ":                      "\\040",
		"":                       "",
		"/double  space":         "/double\\040\\040space",
		"/some long test string": "/some\\040long\\040test\\040string",
		"/var/lib/docker":        "/var/lib/docker",
		" leading":               "\\040leading",
		"trailing ":              "trailing\\040",
	}
	for in, exp := range testInputs {
		if out := escapeFstabSpaces(in); exp != out {
			t.Logf("Expected %s got %s", exp, out)
			t.Fail()
		}
	}
}

func TestIsDirectory(t *testing.T) {
	tempDir, err := ioutil.TempDir("", "TestIsDir")
	if err != nil {
		t.Fatal(err)
	}
	defer os.RemoveAll(tempDir)

	tempFile, err := ioutil.TempFile(tempDir, "TestIsDirFile")
	if err != nil {
		t.Fatal(err)
	}

	if isDirectory(tempDir) != "dir" {
		t.Logf("Could not identify %s as a directory", tempDir)
		t.Fail()
	}

	if isDirectory(tempFile.Name()) != "file" {
		t.Logf("Could not identify %s as a file", tempFile.Name())
		t.Fail()
	}
}

func TestCustomLxcConfigMounts(t *testing.T) {
	root, err := ioutil.TempDir("", "TestCustomLxcConfig")
	if err != nil {
		t.Fatal(err)
	}
	defer os.RemoveAll(root)
	tempDir, err := ioutil.TempDir("", "TestIsDir")
	if err != nil {
		t.Fatal(err)
	}
	defer os.RemoveAll(tempDir)

	tempFile, err := ioutil.TempFile(tempDir, "TestIsDirFile")
	if err != nil {
		t.Fatal(err)
	}
	os.MkdirAll(path.Join(root, "containers", "1"), 0777)

	driver, err := NewDriver(root, root, "", false)
	if err != nil {
		t.Fatal(err)
	}
	processConfig := execdriver.ProcessConfig{
		Privileged: false,
	}
	mounts := []execdriver.Mount{
		{
			Source:      tempDir,
			Destination: tempDir,
			Writable:    false,
			Private:     true,
		},
		{
			Source:      tempFile.Name(),
			Destination: tempFile.Name(),
			Writable:    true,
			Private:     true,
		},
	}
	command := &execdriver.Command{
		ID: "1",
		LxcConfig: []string{
			"lxc.utsname = docker",
			"lxc.cgroup.cpuset.cpus = 0,1",
		},
		Network: &execdriver.Network{
			Mtu:       1500,
			Interface: nil,
		},
		Mounts:        mounts,
		ProcessConfig: processConfig,
	}

	p, err := driver.generateLXCConfig(command)
	if err != nil {
		t.Fatal(err)
	}

	grepFile(t, p, "lxc.utsname = docker")
	grepFile(t, p, "lxc.cgroup.cpuset.cpus = 0,1")

	grepFile(t, p, fmt.Sprintf("lxc.mount.entry = %s %s none rbind,ro,create=%s 0 0", tempDir, "/"+tempDir, "dir"))
	grepFile(t, p, fmt.Sprintf("lxc.mount.entry = %s %s none rbind,rw,create=%s 0 0", tempFile.Name(), "/"+tempFile.Name(), "file"))
}

func TestCustomLxcConfigMisc(t *testing.T) {
	root, err := ioutil.TempDir("", "TestCustomLxcConfig")
	if err != nil {
		t.Fatal(err)
	}
	defer os.RemoveAll(root)
	os.MkdirAll(path.Join(root, "containers", "1"), 0777)
	driver, err := NewDriver(root, root, "", true)

	if err != nil {
		t.Fatal(err)
	}
	processConfig := execdriver.ProcessConfig{
		Privileged: false,
	}

	processConfig.Env = []string{"HOSTNAME=testhost"}
	command := &execdriver.Command{
		ID: "1",
		LxcConfig: []string{
			"lxc.cgroup.cpuset.cpus = 0,1",
		},
		Network: &execdriver.Network{
			Mtu: 1500,
			Interface: &execdriver.NetworkInterface{
				Gateway:     "10.10.10.1",
				IPAddress:   "10.10.10.10",
				IPPrefixLen: 24,
				Bridge:      "docker0",
			},
		},
		ProcessConfig:   processConfig,
		CapAdd:          []string{"net_admin", "syslog"},
		CapDrop:         []string{"kill", "mknod"},
		AppArmorProfile: "lxc-container-default-with-nesting",
	}

	p, err := driver.generateLXCConfig(command)
	if err != nil {
		t.Fatal(err)
	}
	// network
	grepFile(t, p, "lxc.network.type = veth")
	grepFile(t, p, "lxc.network.link = docker0")
	grepFile(t, p, "lxc.network.name = eth0")
	grepFile(t, p, "lxc.network.ipv4 = 10.10.10.10/24")
	grepFile(t, p, "lxc.network.ipv4.gateway = 10.10.10.1")
	grepFile(t, p, "lxc.network.flags = up")
	grepFile(t, p, "lxc.aa_profile = lxc-container-default-with-nesting")
	// hostname
	grepFile(t, p, "lxc.utsname = testhost")
	grepFile(t, p, "lxc.cgroup.cpuset.cpus = 0,1")
	container := nativeTemplate.New()
	for _, cap := range container.Capabilities {
		realCap := execdriver.GetCapability(cap)
		numCap := fmt.Sprintf("%d", realCap.Value)
		if cap != "MKNOD" && cap != "KILL" {
			grepFile(t, p, fmt.Sprintf("lxc.cap.keep = %s", numCap))
		}
	}

	grepFileWithReverse(t, p, fmt.Sprintf("lxc.cap.keep = %d", capability.CAP_KILL), true)
	grepFileWithReverse(t, p, fmt.Sprintf("lxc.cap.keep = %d", capability.CAP_MKNOD), true)
}

func TestCustomLxcConfigMiscOverride(t *testing.T) {
	root, err := ioutil.TempDir("", "TestCustomLxcConfig")
	if err != nil {
		t.Fatal(err)
	}
	defer os.RemoveAll(root)
	os.MkdirAll(path.Join(root, "containers", "1"), 0777)
	driver, err := NewDriver(root, root, "", false)
	if err != nil {
		t.Fatal(err)
	}
	processConfig := execdriver.ProcessConfig{
		Privileged: false,
	}

	processConfig.Env = []string{"HOSTNAME=testhost"}
	command := &execdriver.Command{
		ID: "1",
		LxcConfig: []string{
			"lxc.cgroup.cpuset.cpus = 0,1",
			"lxc.network.ipv4 = 172.0.0.1",
		},
		Network: &execdriver.Network{
			Mtu: 1500,
			Interface: &execdriver.NetworkInterface{
				Gateway:     "10.10.10.1",
				IPAddress:   "10.10.10.10",
				IPPrefixLen: 24,
				Bridge:      "docker0",
			},
		},
		ProcessConfig: processConfig,
		CapAdd:        []string{"NET_ADMIN", "SYSLOG"},
		CapDrop:       []string{"KILL", "MKNOD"},
	}

	p, err := driver.generateLXCConfig(command)
	if err != nil {
		t.Fatal(err)
	}
	// network
	grepFile(t, p, "lxc.network.type = veth")
	grepFile(t, p, "lxc.network.link = docker0")
	grepFile(t, p, "lxc.network.name = eth0")
	grepFile(t, p, "lxc.network.ipv4 = 172.0.0.1")
	grepFile(t, p, "lxc.network.ipv4.gateway = 10.10.10.1")
	grepFile(t, p, "lxc.network.flags = up")

	// hostname
	grepFile(t, p, "lxc.utsname = testhost")
	grepFile(t, p, "lxc.cgroup.cpuset.cpus = 0,1")
	container := nativeTemplate.New()
	for _, cap := range container.Capabilities {
		realCap := execdriver.GetCapability(cap)
		numCap := fmt.Sprintf("%d", realCap.Value)
		if cap != "MKNOD" && cap != "KILL" {
			grepFile(t, p, fmt.Sprintf("lxc.cap.keep = %s", numCap))
		}
	}
	grepFileWithReverse(t, p, fmt.Sprintf("lxc.cap.keep = %d", capability.CAP_KILL), true)
	grepFileWithReverse(t, p, fmt.Sprintf("lxc.cap.keep = %d", capability.CAP_MKNOD), true)
}
<|endoftext|>


<commit_before>// +build linux

package overlayutils // import "github.com/docker/docker/daemon/graphdriver/overlayutils"

import (
	"fmt"
	"io/ioutil"
	"os"
	"path"
	"path/filepath"

	"github.com/docker/docker/daemon/graphdriver"
	"github.com/pkg/errors"
	"github.com/sirupsen/logrus"
	"golang.org/x/sys/unix"
)

// ErrDTypeNotSupported denotes that the backing filesystem doesn't support d_type.
func ErrDTypeNotSupported(driver, backingFs string) error {
	msg := fmt.Sprintf("%s: the backing %s filesystem is formatted without d_type support, which leads to incorrect behavior.", driver, backingFs)
	if backingFs == "xfs" {
		msg += " Reformat the filesystem with ftype=1 to enable d_type support."
	}

	if backingFs == "extfs" {
		msg += " Reformat the filesystem (or use tune2fs) with -O filetype flag to enable d_type support."
	}

	msg += " Backing filesystems without d_type support are not supported."

	return graphdriver.NotSupportedError(msg)
}

// SupportsOverlay checks if the system supports overlay filesystem
// by performing an actual overlay mount.
//
// checkMultipleLowers parameter enables check for multiple lowerdirs,
// which is required for the overlay2 driver.
func SupportsOverlay(d string, checkMultipleLowers bool) error {
	td, err := ioutil.TempDir(d, "check-overlayfs-support")
	if err != nil {
		return err
	}
	defer func() {
		if err := os.RemoveAll(td); err != nil {
			logrus.Warnf("Failed to remove check directory %v: %v", td, err)
		}
	}()

	for _, dir := range []string{"lower1", "lower2", "upper", "work", "merged"} {
		if err := os.Mkdir(filepath.Join(td, dir), 0755); err != nil {
			return err
		}
	}

	mnt := filepath.Join(td, "merged")
	lowerDir := path.Join(td, "lower2")
	if checkMultipleLowers {
		lowerDir += ":" + path.Join(td, "lower1")
	}
	opts := fmt.Sprintf("lowerdir=%s,upperdir=%s,workdir=%s", lowerDir, path.Join(td, "upper"), path.Join(td, "work"))
	if err := unix.Mount("overlay", mnt, "overlay", 0, opts); err != nil {
		return errors.Wrap(err, "failed to mount overlay")
	}
	if err := unix.Unmount(mnt, 0); err != nil {
		logrus.Warnf("Failed to unmount check directory %v: %v", mnt, err)
	}
	return nil
}
<commit_msg>rootless: disable overlay2 if running with SELinux<commit_after>// +build linux

package overlayutils // import "github.com/docker/docker/daemon/graphdriver/overlayutils"

import (
	"fmt"
	"io/ioutil"
	"os"
	"path"
	"path/filepath"

	"github.com/docker/docker/daemon/graphdriver"
	"github.com/pkg/errors"
	"github.com/sirupsen/logrus"
	"golang.org/x/sys/unix"
)

// ErrDTypeNotSupported denotes that the backing filesystem doesn't support d_type.
func ErrDTypeNotSupported(driver, backingFs string) error {
	msg := fmt.Sprintf("%s: the backing %s filesystem is formatted without d_type support, which leads to incorrect behavior.", driver, backingFs)
	if backingFs == "xfs" {
		msg += " Reformat the filesystem with ftype=1 to enable d_type support."
	}

	if backingFs == "extfs" {
		msg += " Reformat the filesystem (or use tune2fs) with -O filetype flag to enable d_type support."
	}

	msg += " Backing filesystems without d_type support are not supported."

	return graphdriver.NotSupportedError(msg)
}

// SupportsOverlay checks if the system supports overlay filesystem
// by performing an actual overlay mount.
//
// checkMultipleLowers parameter enables check for multiple lowerdirs,
// which is required for the overlay2 driver.
func SupportsOverlay(d string, checkMultipleLowers bool) error {
	// We can't rely on go-selinux.GetEnabled() to detect whether SELinux is enabled,
	// because RootlessKit doesn't mount /sys/fs/selinux in the child: https://github.com/rootless-containers/rootlesskit/issues/94
	// So we check $_DOCKERD_ROOTLESS_SELINUX, which is set by dockerd-rootless.sh .
	if os.Getenv("_DOCKERD_ROOTLESS_SELINUX") == "1" {
		// Kernel 5.11 introduced support for rootless overlayfs, but incompatible with SELinux,
		// so fallback to fuse-overlayfs.
		// https://github.com/moby/moby/issues/42333
		return errors.New("overlay is not supported for Rootless with SELinux")
	}

	td, err := ioutil.TempDir(d, "check-overlayfs-support")
	if err != nil {
		return err
	}
	defer func() {
		if err := os.RemoveAll(td); err != nil {
			logrus.Warnf("Failed to remove check directory %v: %v", td, err)
		}
	}()

	for _, dir := range []string{"lower1", "lower2", "upper", "work", "merged"} {
		if err := os.Mkdir(filepath.Join(td, dir), 0755); err != nil {
			return err
		}
	}

	mnt := filepath.Join(td, "merged")
	lowerDir := path.Join(td, "lower2")
	if checkMultipleLowers {
		lowerDir += ":" + path.Join(td, "lower1")
	}
	opts := fmt.Sprintf("lowerdir=%s,upperdir=%s,workdir=%s", lowerDir, path.Join(td, "upper"), path.Join(td, "work"))
	if err := unix.Mount("overlay", mnt, "overlay", 0, opts); err != nil {
		return errors.Wrap(err, "failed to mount overlay")
	}
	if err := unix.Unmount(mnt, 0); err != nil {
		logrus.Warnf("Failed to unmount check directory %v: %v", mnt, err)
	}
	return nil
}
<|endoftext|>


<commit_before>// Copyright 2015 Davis Webb
// Copyright 2015 Luke Shumaker

package backend_test

import (
	. "periwinkle/backend"
	"strings"
	"testing"
)

func TestNewUser(t *testing.T) {
	conf := CreateTempDB()

	user := NewUser(conf.DB, "JohnDoe", "password", "johndoe@purdue.edu")

	switch {
	case !strings.EqualFold(user.ID, "JohnDoe"):
		t.Error("User ID was not properly set to.")
	case user.FullName != "":
		t.Error("User name was not properly set.")
	case user.Addresses[0].Address != "johndoe@purdue.edu":
		t.Error("User address was not preperly set.")
	}

	conf.DB.Close()
}

func TestGetUserByID(t *testing.T) {
	conf := CreateTempDB()

	user := NewUser(conf.DB, "JohnDoe", "password", "johndoe@purdue.edu")

	o := GetUserByID(conf.DB, user.ID)

	switch {
	case o == nil:
		t.Error("GetUserByID() returned nil")
	case !strings.EqualFold(user.ID, o.ID):
		t.Error("GetUserByID() returned a user with a different ID")
	}

	conf.DB.Close()
}

func TestNewUserAddress(t *testing.T) {
	conf := CreateTempDB()

	user := NewUser(conf.DB, "JohnDoe", "password", "johndoe@purdue.edu")

	newAddr := NewUserAddress(conf.DB, user.ID, "email", "johndoe2@purdue.edu", false)

	switch {
	case newAddr.Address != "johndoe2@purdue.edu":
		t.Error("Error adding new email to user in NewUserAddress()")
	case newAddr.Medium != "email":
		t.Error("Error assigning medium type in NewUserAddress()")
	}

	newAddr = NewUserAddress(conf.DB, user.ID, "sms", "7655555555", false)

	switch {
	case newAddr.Address != "7655555555":
		t.Error("Error adding new sms to user in NewUserAddress()")
	case newAddr.Medium != "sms":
		t.Error("Error assigning medium type in NewUserAddress()")
	}

	conf.DB.Close()
}

func TestGetUserByAddress(t *testing.T) {
	conf := CreateTempDB()

	user := NewUser(conf.DB, "JohnDoe", "password", "johndoe@purdue.edu")

	o := GetUserByAddress(conf.DB, "email", user.Addresses[0].Address)
	if strings.Compare(user.ID, o.ID) != 0 {
		t.Error("Error in GetUserByAdress()")
	}

	conf.DB.Close()
}

// func TestSetPassword(t *testing.T) {
// 	t.Error("TODO")
// }

// func TestCheckPassword(t *testing.T) {
// 	t.Error("TODO")
// }

// func TestGetAddressByUserAndMedium(t *testing.T) {
// 	addr := GetAddressByUserAndMedium(conf.DB, user.ID, "email")

// 	switch {
// 	case addr == nil:
// 		t.Error("GetAddressByUserAndMedium() returned nil")
// 	case addr.Address != user.Addresses[0].Address:
// 		t.Error("Addresses do not match: " + user.Addresses[0].Address + " != " + addr.Address)
// 	}
// 	conf.DB.Close()
// }

func TestGetUserSubscriptions(t *testing.T) {

	conf := CreateTempDB()

	waste := NewUser(conf.DB, "JohnDoe", "password", "johndoe@purdue.edu")

	user := GetUserByID(conf.DB, waste.ID)

	subs := user.GetUserSubscriptions(conf.DB)

	if subs == nil {
		t.Error("GetUserSubscriptions returned nil")
	}
}
<commit_msg>Minor fix<commit_after>// Copyright 2015 Davis Webb
// Copyright 2015 Luke Shumaker

package backend_test

import (
	. "periwinkle/backend"
	"strings"
	"testing"
)

func TestNewUser(t *testing.T) {
	conf := CreateTempDB()

	user := NewUser(conf.DB, "JohnDoe", "password", "johndoe@purdue.edu")

	switch {
	case !strings.EqualFold(user.ID, "JohnDoe"):
		t.Error("User ID was not properly set to.")
	case user.FullName != "":
		t.Error("User name was not properly set.")
	case user.Addresses[0].Address != "johndoe@purdue.edu":
		t.Error("User address was not preperly set.")
	}

	conf.DB.Close()
}

func TestGetUserByID(t *testing.T) {
	conf := CreateTempDB()

	user := NewUser(conf.DB, "JohnDoe", "password", "johndoe@purdue.edu")

	o := GetUserByID(conf.DB, user.ID)

	switch {
	case o == nil:
		t.Error("GetUserByID() returned nil")
	case !strings.EqualFold(user.ID, o.ID):
		t.Error("GetUserByID() returned a user with a different ID")
	}

	conf.DB.Close()
}

func TestNewUserAddress(t *testing.T) {
	conf := CreateTempDB()

	user := NewUser(conf.DB, "JohnDoe", "password", "johndoe@purdue.edu")

	newAddr := NewUserAddress(conf.DB, user.ID, "email", "johndoe2@purdue.edu", false)

	switch {
	case newAddr.Address != "johndoe2@purdue.edu":
		t.Error("Error adding new email to user in NewUserAddress()")
	case newAddr.Medium != "email":
		t.Error("Error assigning medium type in NewUserAddress()")
	}

	newAddr = NewUserAddress(conf.DB, user.ID, "sms", "7655555555", false)

	switch {
	case newAddr.Address != "7655555555":
		t.Error("Error adding new sms to user in NewUserAddress()")
	case newAddr.Medium != "sms":
		t.Error("Error assigning medium type in NewUserAddress()")
	}

	conf.DB.Close()
}

func TestGetUserByAddress(t *testing.T) {
	conf := CreateTempDB()

	user := NewUser(conf.DB, "JohnDoe", "password", "johndoe@purdue.edu")

	o := GetUserByAddress(conf.DB, "email", user.Addresses[0].Address)
	if !strings.EqualFold(user.ID, o.ID) {
		t.Error("Error in GetUserByAdress()")
	}

	conf.DB.Close()
}

// func TestSetPassword(t *testing.T) {
// 	t.Error("TODO")
// }

// func TestCheckPassword(t *testing.T) {
// 	t.Error("TODO")
// }

// func TestGetAddressByUserAndMedium(t *testing.T) {
// 	addr := GetAddressByUserAndMedium(conf.DB, user.ID, "email")

// 	switch {
// 	case addr == nil:
// 		t.Error("GetAddressByUserAndMedium() returned nil")
// 	case addr.Address != user.Addresses[0].Address:
// 		t.Error("Addresses do not match: " + user.Addresses[0].Address + " != " + addr.Address)
// 	}
// 	conf.DB.Close()
// }

func TestGetUserSubscriptions(t *testing.T) {

	conf := CreateTempDB()

	waste := NewUser(conf.DB, "JohnDoe", "password", "johndoe@purdue.edu")

	user := GetUserByID(conf.DB, waste.ID)

	subs := user.GetUserSubscriptions(conf.DB)

	if subs == nil {
		t.Error("GetUserSubscriptions returned nil")
	}
}
<|endoftext|>


<commit_before>// Copyright 2009 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 gosym

import (
	"debug/elf"
	"os"
	"os/exec"
	"runtime"
	"strings"
	"testing"
)

var pclinetestBinary string

func dotest() bool {
	// For now, only works on ELF platforms.
	if runtime.GOOS != "linux" || runtime.GOARCH != "amd64" {
		return false
	}
	if pclinetestBinary != "" {
		return true
	}
	// This command builds pclinetest from pclinetest.asm;
	// the resulting binary looks like it was built from pclinetest.s,
	// but we have renamed it to keep it away from the go tool.
	pclinetestBinary = os.TempDir() + "/pclinetest"
	cmd := exec.Command("sh", "-c", "go tool 6a pclinetest.asm && go tool 6l -E main -o "+pclinetestBinary+" pclinetest.6")
	if err := cmd.Run(); err != nil {
		panic(err)
	}
	return true
}

func getTable(t *testing.T) *Table {
	f, tab := crack(os.Args[0], t)
	f.Close()
	return tab
}

func crack(file string, t *testing.T) (*elf.File, *Table) {
	// Open self
	f, err := elf.Open(file)
	if err != nil {
		t.Fatal(err)
	}
	return parse(file, f, t)
}

func parse(file string, f *elf.File, t *testing.T) (*elf.File, *Table) {
	symdat, err := f.Section(".gosymtab").Data()
	if err != nil {
		f.Close()
		t.Fatalf("reading %s gosymtab: %v", file, err)
	}
	pclndat, err := f.Section(".gopclntab").Data()
	if err != nil {
		f.Close()
		t.Fatalf("reading %s gopclntab: %v", file, err)
	}

	pcln := NewLineTable(pclndat, f.Section(".text").Addr)
	tab, err := NewTable(symdat, pcln)
	if err != nil {
		f.Close()
		t.Fatalf("parsing %s gosymtab: %v", file, err)
	}

	return f, tab
}

var goarch = os.Getenv("O")

func TestLineFromAline(t *testing.T) {
	if !dotest() {
		return
	}

	tab := getTable(t)

	// Find the sym package
	pkg := tab.LookupFunc("debug/gosym.TestLineFromAline").Obj
	if pkg == nil {
		t.Fatalf("nil pkg")
	}

	// Walk every absolute line and ensure that we hit every
	// source line monotonically
	lastline := make(map[string]int)
	final := -1
	for i := 0; i < 10000; i++ {
		path, line := pkg.lineFromAline(i)
		// Check for end of object
		if path == "" {
			if final == -1 {
				final = i - 1
			}
			continue
		} else if final != -1 {
			t.Fatalf("reached end of package at absolute line %d, but absolute line %d mapped to %s:%d", final, i, path, line)
		}
		// It's okay to see files multiple times (e.g., sys.a)
		if line == 1 {
			lastline[path] = 1
			continue
		}
		// Check that the is the next line in path
		ll, ok := lastline[path]
		if !ok {
			t.Errorf("file %s starts on line %d", path, line)
		} else if line != ll+1 {
			t.Errorf("expected next line of file %s to be %d, got %d", path, ll+1, line)
		}
		lastline[path] = line
	}
	if final == -1 {
		t.Errorf("never reached end of object")
	}
}

func TestLineAline(t *testing.T) {
	if !dotest() {
		return
	}

	tab := getTable(t)

	for _, o := range tab.Files {
		// A source file can appear multiple times in a
		// object.  alineFromLine will always return alines in
		// the first file, so track which lines we've seen.
		found := make(map[string]int)
		for i := 0; i < 1000; i++ {
			path, line := o.lineFromAline(i)
			if path == "" {
				break
			}

			// cgo files are full of 'Z' symbols, which we don't handle
			if len(path) > 4 && path[len(path)-4:] == ".cgo" {
				continue
			}

			if minline, ok := found[path]; path != "" && ok {
				if minline >= line {
					// We've already covered this file
					continue
				}
			}
			found[path] = line

			a, err := o.alineFromLine(path, line)
			if err != nil {
				t.Errorf("absolute line %d in object %s maps to %s:%d, but mapping that back gives error %s", i, o.Paths[0].Name, path, line, err)
			} else if a != i {
				t.Errorf("absolute line %d in object %s maps to %s:%d, which maps back to absolute line %d\n", i, o.Paths[0].Name, path, line, a)
			}
		}
	}
}

func TestPCLine(t *testing.T) {
	if !dotest() {
		return
	}

	f, tab := crack(pclinetestBinary, t)
	text := f.Section(".text")
	textdat, err := text.Data()
	if err != nil {
		t.Fatalf("reading .text: %v", err)
	}

	// Test PCToLine
	sym := tab.LookupFunc("linefrompc")
	wantLine := 0
	for pc := sym.Entry; pc < sym.End; pc++ {
		file, line, fn := tab.PCToLine(pc)
		off := pc - text.Addr // TODO(rsc): should not need off; bug in 8g
		wantLine += int(textdat[off])
		t.Logf("off is %d", off)
		if fn == nil {
			t.Errorf("failed to get line of PC %#x", pc)
		} else if !strings.HasSuffix(file, "pclinetest.s") {
			t.Errorf("expected %s (%s) at PC %#x, got %s (%s)", "pclinetest.s", sym.Name, pc, file, fn.Name)
		} else if line != wantLine || fn != sym {
			t.Errorf("expected :%d (%s) at PC %#x, got :%d (%s)", wantLine, sym.Name, pc, line, fn.Name)
		}
	}

	// Test LineToPC
	sym = tab.LookupFunc("pcfromline")
	lookupline := -1
	wantLine = 0
	off := uint64(0) // TODO(rsc): should not need off; bug in 8g
	for pc := sym.Value; pc < sym.End; pc += 2 + uint64(textdat[off]) {
		file, line, fn := tab.PCToLine(pc)
		off = pc - text.Addr
		wantLine += int(textdat[off])
		if line != wantLine {
			t.Errorf("expected line %d at PC %#x in pcfromline, got %d", wantLine, pc, line)
			off = pc + 1 - text.Addr
			continue
		}
		if lookupline == -1 {
			lookupline = line
		}
		for ; lookupline <= line; lookupline++ {
			pc2, fn2, err := tab.LineToPC(file, lookupline)
			if lookupline != line {
				// Should be nothing on this line
				if err == nil {
					t.Errorf("expected no PC at line %d, got %#x (%s)", lookupline, pc2, fn2.Name)
				}
			} else if err != nil {
				t.Errorf("failed to get PC of line %d: %s", lookupline, err)
			} else if pc != pc2 {
				t.Errorf("expected PC %#x (%s) at line %d, got PC %#x (%s)", pc, fn.Name, line, pc2, fn2.Name)
			}
		}
		off = pc + 1 - text.Addr
	}
}
<commit_msg>debug/gosym: dump 6a/6l output to process stdout/stderr so we can see failures.<commit_after>// Copyright 2009 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 gosym

import (
	"debug/elf"
	"os"
	"os/exec"
	"runtime"
	"strings"
	"testing"
)

var pclinetestBinary string

func dotest() bool {
	// For now, only works on ELF platforms.
	if runtime.GOOS != "linux" || runtime.GOARCH != "amd64" {
		return false
	}
	if pclinetestBinary != "" {
		return true
	}
	// This command builds pclinetest from pclinetest.asm;
	// the resulting binary looks like it was built from pclinetest.s,
	// but we have renamed it to keep it away from the go tool.
	pclinetestBinary = os.TempDir() + "/pclinetest"
	cmd := exec.Command("sh", "-c", "go tool 6a pclinetest.asm && go tool 6l -E main -o "+pclinetestBinary+" pclinetest.6")
	cmd.Stdout = os.Stdout
	cmd.Stderr = os.Stderr
	if err := cmd.Run(); err != nil {
		panic(err)
	}
	return true
}

func getTable(t *testing.T) *Table {
	f, tab := crack(os.Args[0], t)
	f.Close()
	return tab
}

func crack(file string, t *testing.T) (*elf.File, *Table) {
	// Open self
	f, err := elf.Open(file)
	if err != nil {
		t.Fatal(err)
	}
	return parse(file, f, t)
}

func parse(file string, f *elf.File, t *testing.T) (*elf.File, *Table) {
	symdat, err := f.Section(".gosymtab").Data()
	if err != nil {
		f.Close()
		t.Fatalf("reading %s gosymtab: %v", file, err)
	}
	pclndat, err := f.Section(".gopclntab").Data()
	if err != nil {
		f.Close()
		t.Fatalf("reading %s gopclntab: %v", file, err)
	}

	pcln := NewLineTable(pclndat, f.Section(".text").Addr)
	tab, err := NewTable(symdat, pcln)
	if err != nil {
		f.Close()
		t.Fatalf("parsing %s gosymtab: %v", file, err)
	}

	return f, tab
}

var goarch = os.Getenv("O")

func TestLineFromAline(t *testing.T) {
	if !dotest() {
		return
	}

	tab := getTable(t)

	// Find the sym package
	pkg := tab.LookupFunc("debug/gosym.TestLineFromAline").Obj
	if pkg == nil {
		t.Fatalf("nil pkg")
	}

	// Walk every absolute line and ensure that we hit every
	// source line monotonically
	lastline := make(map[string]int)
	final := -1
	for i := 0; i < 10000; i++ {
		path, line := pkg.lineFromAline(i)
		// Check for end of object
		if path == "" {
			if final == -1 {
				final = i - 1
			}
			continue
		} else if final != -1 {
			t.Fatalf("reached end of package at absolute line %d, but absolute line %d mapped to %s:%d", final, i, path, line)
		}
		// It's okay to see files multiple times (e.g., sys.a)
		if line == 1 {
			lastline[path] = 1
			continue
		}
		// Check that the is the next line in path
		ll, ok := lastline[path]
		if !ok {
			t.Errorf("file %s starts on line %d", path, line)
		} else if line != ll+1 {
			t.Errorf("expected next line of file %s to be %d, got %d", path, ll+1, line)
		}
		lastline[path] = line
	}
	if final == -1 {
		t.Errorf("never reached end of object")
	}
}

func TestLineAline(t *testing.T) {
	if !dotest() {
		return
	}

	tab := getTable(t)

	for _, o := range tab.Files {
		// A source file can appear multiple times in a
		// object.  alineFromLine will always return alines in
		// the first file, so track which lines we've seen.
		found := make(map[string]int)
		for i := 0; i < 1000; i++ {
			path, line := o.lineFromAline(i)
			if path == "" {
				break
			}

			// cgo files are full of 'Z' symbols, which we don't handle
			if len(path) > 4 && path[len(path)-4:] == ".cgo" {
				continue
			}

			if minline, ok := found[path]; path != "" && ok {
				if minline >= line {
					// We've already covered this file
					continue
				}
			}
			found[path] = line

			a, err := o.alineFromLine(path, line)
			if err != nil {
				t.Errorf("absolute line %d in object %s maps to %s:%d, but mapping that back gives error %s", i, o.Paths[0].Name, path, line, err)
			} else if a != i {
				t.Errorf("absolute line %d in object %s maps to %s:%d, which maps back to absolute line %d\n", i, o.Paths[0].Name, path, line, a)
			}
		}
	}
}

func TestPCLine(t *testing.T) {
	if !dotest() {
		return
	}

	f, tab := crack(pclinetestBinary, t)
	text := f.Section(".text")
	textdat, err := text.Data()
	if err != nil {
		t.Fatalf("reading .text: %v", err)
	}

	// Test PCToLine
	sym := tab.LookupFunc("linefrompc")
	wantLine := 0
	for pc := sym.Entry; pc < sym.End; pc++ {
		file, line, fn := tab.PCToLine(pc)
		off := pc - text.Addr // TODO(rsc): should not need off; bug in 8g
		wantLine += int(textdat[off])
		t.Logf("off is %d", off)
		if fn == nil {
			t.Errorf("failed to get line of PC %#x", pc)
		} else if !strings.HasSuffix(file, "pclinetest.s") {
			t.Errorf("expected %s (%s) at PC %#x, got %s (%s)", "pclinetest.s", sym.Name, pc, file, fn.Name)
		} else if line != wantLine || fn != sym {
			t.Errorf("expected :%d (%s) at PC %#x, got :%d (%s)", wantLine, sym.Name, pc, line, fn.Name)
		}
	}

	// Test LineToPC
	sym = tab.LookupFunc("pcfromline")
	lookupline := -1
	wantLine = 0
	off := uint64(0) // TODO(rsc): should not need off; bug in 8g
	for pc := sym.Value; pc < sym.End; pc += 2 + uint64(textdat[off]) {
		file, line, fn := tab.PCToLine(pc)
		off = pc - text.Addr
		wantLine += int(textdat[off])
		if line != wantLine {
			t.Errorf("expected line %d at PC %#x in pcfromline, got %d", wantLine, pc, line)
			off = pc + 1 - text.Addr
			continue
		}
		if lookupline == -1 {
			lookupline = line
		}
		for ; lookupline <= line; lookupline++ {
			pc2, fn2, err := tab.LineToPC(file, lookupline)
			if lookupline != line {
				// Should be nothing on this line
				if err == nil {
					t.Errorf("expected no PC at line %d, got %#x (%s)", lookupline, pc2, fn2.Name)
				}
			} else if err != nil {
				t.Errorf("failed to get PC of line %d: %s", lookupline, err)
			} else if pc != pc2 {
				t.Errorf("expected PC %#x (%s) at line %d, got PC %#x (%s)", pc, fn.Name, line, pc2, fn2.Name)
			}
		}
		off = pc + 1 - text.Addr
	}
}
<|endoftext|>


<commit_before>// Copyright 2009 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 gosym

import (
	"debug/elf"
	"os"
	"testing"
	"syscall"
)

func dotest() bool {
	// For now, only works on ELF platforms.
	return syscall.OS == "linux" && os.Getenv("GOARCH") == "amd64"
}

func getTable(t *testing.T) *Table {
	f, tab := crack(os.Args[0], t)
	f.Close()
	return tab
}

func crack(file string, t *testing.T) (*elf.File, *Table) {
	// Open self
	f, err := elf.Open(file)
	if err != nil {
		t.Fatal(err)
	}
	return parse(file, f, t)
}

func parse(file string, f *elf.File, t *testing.T) (*elf.File, *Table) {
	symdat, err := f.Section(".gosymtab").Data()
	if err != nil {
		f.Close()
		t.Fatalf("reading %s gosymtab: %v", file, err)
	}
	pclndat, err := f.Section(".gopclntab").Data()
	if err != nil {
		f.Close()
		t.Fatalf("reading %s gopclntab: %v", file, err)
	}

	pcln := NewLineTable(pclndat, f.Section(".text").Addr)
	tab, err := NewTable(symdat, pcln)
	if err != nil {
		f.Close()
		t.Fatalf("parsing %s gosymtab: %v", file, err)
	}

	return f, tab
}

var goarch = os.Getenv("O")

func TestLineFromAline(t *testing.T) {
	if !dotest() {
		return
	}

	tab := getTable(t)

	// Find the sym package
	pkg := tab.LookupFunc("debug/gosym.TestLineFromAline").Obj
	if pkg == nil {
		t.Fatalf("nil pkg")
	}

	// Walk every absolute line and ensure that we hit every
	// source line monotonically
	lastline := make(map[string]int)
	final := -1
	for i := 0; i < 10000; i++ {
		path, line := pkg.lineFromAline(i)
		// Check for end of object
		if path == "" {
			if final == -1 {
				final = i - 1
			}
			continue
		} else if final != -1 {
			t.Fatalf("reached end of package at absolute line %d, but absolute line %d mapped to %s:%d", final, i, path, line)
		}
		// It's okay to see files multiple times (e.g., sys.a)
		if line == 1 {
			lastline[path] = 1
			continue
		}
		// Check that the is the next line in path
		ll, ok := lastline[path]
		if !ok {
			t.Errorf("file %s starts on line %d", path, line)
		} else if line != ll+1 {
			t.Errorf("expected next line of file %s to be %d, got %d", path, ll+1, line)
		}
		lastline[path] = line
	}
	if final == -1 {
		t.Errorf("never reached end of object")
	}
}

func TestLineAline(t *testing.T) {
	if !dotest() {
		return
	}

	tab := getTable(t)

	for _, o := range tab.Files {
		// A source file can appear multiple times in a
		// object.  alineFromLine will always return alines in
		// the first file, so track which lines we've seen.
		found := make(map[string]int)
		for i := 0; i < 1000; i++ {
			path, line := o.lineFromAline(i)
			if path == "" {
				break
			}

			// cgo files are full of 'Z' symbols, which we don't handle
			if len(path) > 4 && path[len(path)-4:] == ".cgo" {
				continue
			}

			if minline, ok := found[path]; path != "" && ok {
				if minline >= line {
					// We've already covered this file
					continue
				}
			}
			found[path] = line

			a, err := o.alineFromLine(path, line)
			if err != nil {
				t.Errorf("absolute line %d in object %s maps to %s:%d, but mapping that back gives error %s", i, o.Paths[0].Name, path, line, err)
			} else if a != i {
				t.Errorf("absolute line %d in object %s maps to %s:%d, which maps back to absolute line %d\n", i, o.Paths[0].Name, path, line, a)
			}
		}
	}
}

// gotest: if [ "$(uname)-$(uname -m)" = Linux-x86_64 ]; then
// gotest:    mkdir -p _test && $AS pclinetest.s && $LD -E main -o _test/pclinetest pclinetest.$O
// gotest: fi
func TestPCLine(t *testing.T) {
	if !dotest() {
		return
	}

	f, tab := crack("_test/pclinetest", t)
	text := f.Section(".text")
	textdat, err := text.Data()
	if err != nil {
		t.Fatalf("reading .text: %v", err)
	}

	// Test PCToLine
	sym := tab.LookupFunc("linefrompc")
	wantLine := 0
	for pc := sym.Entry; pc < sym.End; pc++ {
		file, line, fn := tab.PCToLine(pc)
		off := pc - text.Addr // TODO(rsc): should not need off; bug in 8g
		wantLine += int(textdat[off])
		if fn == nil {
			t.Errorf("failed to get line of PC %#x", pc)
		} else if len(file) < 12 || file[len(file)-12:] != "pclinetest.s" || line != wantLine || fn != sym {
			t.Errorf("expected %s:%d (%s) at PC %#x, got %s:%d (%s)", "pclinetest.s", wantLine, sym.Name, pc, file, line, fn.Name)
		}
	}

	// Test LineToPC
	sym = tab.LookupFunc("pcfromline")
	lookupline := -1
	wantLine = 0
	off := uint64(0) // TODO(rsc): should not need off; bug in 8g
	for pc := sym.Value; pc < sym.End; pc += 2 + uint64(textdat[off]) {
		file, line, fn := tab.PCToLine(pc)
		off = pc - text.Addr
		wantLine += int(textdat[off])
		if line != wantLine {
			t.Errorf("expected line %d at PC %#x in pcfromline, got %d", wantLine, pc, line)
			off = pc + 1 - text.Addr
			continue
		}
		if lookupline == -1 {
			lookupline = line
		}
		for ; lookupline <= line; lookupline++ {
			pc2, fn2, err := tab.LineToPC(file, lookupline)
			if lookupline != line {
				// Should be nothing on this line
				if err == nil {
					t.Errorf("expected no PC at line %d, got %#x (%s)", lookupline, pc2, fn2.Name)
				}
			} else if err != nil {
				t.Errorf("failed to get PC of line %d: %s", lookupline, err)
			} else if pc != pc2 {
				t.Errorf("expected PC %#x (%s) at line %d, got PC %#x (%s)", pc, fn.Name, line, pc2, fn2.Name)
			}
		}
		off = pc + 1 - text.Addr
	}
}
<commit_msg>debug/gosym: do not run when cross-compiling<commit_after>// Copyright 2009 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 gosym

import (
	"debug/elf"
	"os"
	"testing"
	"syscall"
)

func dotest() bool {
	// For now, only works on ELF platforms.
	return syscall.OS == "linux" && os.Getenv("GOARCH") == "amd64"
}

func getTable(t *testing.T) *Table {
	f, tab := crack(os.Args[0], t)
	f.Close()
	return tab
}

func crack(file string, t *testing.T) (*elf.File, *Table) {
	// Open self
	f, err := elf.Open(file)
	if err != nil {
		t.Fatal(err)
	}
	return parse(file, f, t)
}

func parse(file string, f *elf.File, t *testing.T) (*elf.File, *Table) {
	symdat, err := f.Section(".gosymtab").Data()
	if err != nil {
		f.Close()
		t.Fatalf("reading %s gosymtab: %v", file, err)
	}
	pclndat, err := f.Section(".gopclntab").Data()
	if err != nil {
		f.Close()
		t.Fatalf("reading %s gopclntab: %v", file, err)
	}

	pcln := NewLineTable(pclndat, f.Section(".text").Addr)
	tab, err := NewTable(symdat, pcln)
	if err != nil {
		f.Close()
		t.Fatalf("parsing %s gosymtab: %v", file, err)
	}

	return f, tab
}

var goarch = os.Getenv("O")

func TestLineFromAline(t *testing.T) {
	if !dotest() {
		return
	}

	tab := getTable(t)

	// Find the sym package
	pkg := tab.LookupFunc("debug/gosym.TestLineFromAline").Obj
	if pkg == nil {
		t.Fatalf("nil pkg")
	}

	// Walk every absolute line and ensure that we hit every
	// source line monotonically
	lastline := make(map[string]int)
	final := -1
	for i := 0; i < 10000; i++ {
		path, line := pkg.lineFromAline(i)
		// Check for end of object
		if path == "" {
			if final == -1 {
				final = i - 1
			}
			continue
		} else if final != -1 {
			t.Fatalf("reached end of package at absolute line %d, but absolute line %d mapped to %s:%d", final, i, path, line)
		}
		// It's okay to see files multiple times (e.g., sys.a)
		if line == 1 {
			lastline[path] = 1
			continue
		}
		// Check that the is the next line in path
		ll, ok := lastline[path]
		if !ok {
			t.Errorf("file %s starts on line %d", path, line)
		} else if line != ll+1 {
			t.Errorf("expected next line of file %s to be %d, got %d", path, ll+1, line)
		}
		lastline[path] = line
	}
	if final == -1 {
		t.Errorf("never reached end of object")
	}
}

func TestLineAline(t *testing.T) {
	if !dotest() {
		return
	}

	tab := getTable(t)

	for _, o := range tab.Files {
		// A source file can appear multiple times in a
		// object.  alineFromLine will always return alines in
		// the first file, so track which lines we've seen.
		found := make(map[string]int)
		for i := 0; i < 1000; i++ {
			path, line := o.lineFromAline(i)
			if path == "" {
				break
			}

			// cgo files are full of 'Z' symbols, which we don't handle
			if len(path) > 4 && path[len(path)-4:] == ".cgo" {
				continue
			}

			if minline, ok := found[path]; path != "" && ok {
				if minline >= line {
					// We've already covered this file
					continue
				}
			}
			found[path] = line

			a, err := o.alineFromLine(path, line)
			if err != nil {
				t.Errorf("absolute line %d in object %s maps to %s:%d, but mapping that back gives error %s", i, o.Paths[0].Name, path, line, err)
			} else if a != i {
				t.Errorf("absolute line %d in object %s maps to %s:%d, which maps back to absolute line %d\n", i, o.Paths[0].Name, path, line, a)
			}
		}
	}
}

// gotest: if [ "$(uname)-$(uname -m)" = Linux-x86_64 -a "$GOARCH" = amd64 ]; then
// gotest:    mkdir -p _test && $AS pclinetest.s && $LD -E main -o _test/pclinetest pclinetest.$O
// gotest: fi
func TestPCLine(t *testing.T) {
	if !dotest() {
		return
	}

	f, tab := crack("_test/pclinetest", t)
	text := f.Section(".text")
	textdat, err := text.Data()
	if err != nil {
		t.Fatalf("reading .text: %v", err)
	}

	// Test PCToLine
	sym := tab.LookupFunc("linefrompc")
	wantLine := 0
	for pc := sym.Entry; pc < sym.End; pc++ {
		file, line, fn := tab.PCToLine(pc)
		off := pc - text.Addr // TODO(rsc): should not need off; bug in 8g
		wantLine += int(textdat[off])
		if fn == nil {
			t.Errorf("failed to get line of PC %#x", pc)
		} else if len(file) < 12 || file[len(file)-12:] != "pclinetest.s" || line != wantLine || fn != sym {
			t.Errorf("expected %s:%d (%s) at PC %#x, got %s:%d (%s)", "pclinetest.s", wantLine, sym.Name, pc, file, line, fn.Name)
		}
	}

	// Test LineToPC
	sym = tab.LookupFunc("pcfromline")
	lookupline := -1
	wantLine = 0
	off := uint64(0) // TODO(rsc): should not need off; bug in 8g
	for pc := sym.Value; pc < sym.End; pc += 2 + uint64(textdat[off]) {
		file, line, fn := tab.PCToLine(pc)
		off = pc - text.Addr
		wantLine += int(textdat[off])
		if line != wantLine {
			t.Errorf("expected line %d at PC %#x in pcfromline, got %d", wantLine, pc, line)
			off = pc + 1 - text.Addr
			continue
		}
		if lookupline == -1 {
			lookupline = line
		}
		for ; lookupline <= line; lookupline++ {
			pc2, fn2, err := tab.LineToPC(file, lookupline)
			if lookupline != line {
				// Should be nothing on this line
				if err == nil {
					t.Errorf("expected no PC at line %d, got %#x (%s)", lookupline, pc2, fn2.Name)
				}
			} else if err != nil {
				t.Errorf("failed to get PC of line %d: %s", lookupline, err)
			} else if pc != pc2 {
				t.Errorf("expected PC %#x (%s) at line %d, got PC %#x (%s)", pc, fn.Name, line, pc2, fn2.Name)
			}
		}
		off = pc + 1 - text.Addr
	}
}
<|endoftext|>


<commit_before>// Copyright 2009 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 gosym

import (
	"debug/elf"
	"fmt"
	"io/ioutil"
	"os"
	"os/exec"
	"path/filepath"
	"runtime"
	"strings"
	"testing"
)

var (
	pclineTempDir    string
	pclinetestBinary string
)

func dotest(self bool) bool {
	// For now, only works on amd64 platforms.
	if runtime.GOARCH != "amd64" {
		return false
	}
	// Self test reads test binary; only works on Linux.
	if self && runtime.GOOS != "linux" {
		return false
	}
	// Command below expects "sh", so Unix.
	if runtime.GOOS == "windows" || runtime.GOOS == "plan9" {
		return false
	}
	if pclinetestBinary != "" {
		return true
	}
	var err error
	pclineTempDir, err = ioutil.TempDir("", "pclinetest")
	if err != nil {
		panic(err)
	}
	if strings.Contains(pclineTempDir, " ") {
		panic("unexpected space in tempdir")
	}
	// This command builds pclinetest from pclinetest.asm;
	// the resulting binary looks like it was built from pclinetest.s,
	// but we have renamed it to keep it away from the go tool.
	pclinetestBinary = filepath.Join(pclineTempDir, "pclinetest")
	command := fmt.Sprintf("go tool 6a -o %s.6 pclinetest.asm && go tool 6l -H linux -E main -o %s %s.6",
		pclinetestBinary, pclinetestBinary, pclinetestBinary)
	cmd := exec.Command("sh", "-c", command)
	if runtime.GOOS == "akaros" {
		cmd = exec.Command("/bin/ash", "-c", command)
	}
	cmd.Stdout = os.Stdout
	cmd.Stderr = os.Stderr
	if err := cmd.Run(); err != nil {
		panic(err)
	}
	return true
}

func endtest() {
	if pclineTempDir != "" {
		os.RemoveAll(pclineTempDir)
		pclineTempDir = ""
		pclinetestBinary = ""
	}
}

func getTable(t *testing.T) *Table {
	f, tab := crack(os.Args[0], t)
	f.Close()
	return tab
}

func crack(file string, t *testing.T) (*elf.File, *Table) {
	// Open self
	f, err := elf.Open(file)
	if err != nil {
		t.Fatal(err)
	}
	return parse(file, f, t)
}

func parse(file string, f *elf.File, t *testing.T) (*elf.File, *Table) {
	symdat, err := f.Section(".gosymtab").Data()
	if err != nil {
		f.Close()
		t.Fatalf("reading %s gosymtab: %v", file, err)
	}
	pclndat, err := f.Section(".gopclntab").Data()
	if err != nil {
		f.Close()
		t.Fatalf("reading %s gopclntab: %v", file, err)
	}

	pcln := NewLineTable(pclndat, f.Section(".text").Addr)
	tab, err := NewTable(symdat, pcln)
	if err != nil {
		f.Close()
		t.Fatalf("parsing %s gosymtab: %v", file, err)
	}

	return f, tab
}

var goarch = os.Getenv("O")

func TestLineFromAline(t *testing.T) {
	if !dotest(true) {
		return
	}
	defer endtest()

	tab := getTable(t)
	if tab.go12line != nil {
		// aline's don't exist in the Go 1.2 table.
		t.Skip("not relevant to Go 1.2 symbol table")
	}

	// Find the sym package
	pkg := tab.LookupFunc("debug/gosym.TestLineFromAline").Obj
	if pkg == nil {
		t.Fatalf("nil pkg")
	}

	// Walk every absolute line and ensure that we hit every
	// source line monotonically
	lastline := make(map[string]int)
	final := -1
	for i := 0; i < 10000; i++ {
		path, line := pkg.lineFromAline(i)
		// Check for end of object
		if path == "" {
			if final == -1 {
				final = i - 1
			}
			continue
		} else if final != -1 {
			t.Fatalf("reached end of package at absolute line %d, but absolute line %d mapped to %s:%d", final, i, path, line)
		}
		// It's okay to see files multiple times (e.g., sys.a)
		if line == 1 {
			lastline[path] = 1
			continue
		}
		// Check that the is the next line in path
		ll, ok := lastline[path]
		if !ok {
			t.Errorf("file %s starts on line %d", path, line)
		} else if line != ll+1 {
			t.Fatalf("expected next line of file %s to be %d, got %d", path, ll+1, line)
		}
		lastline[path] = line
	}
	if final == -1 {
		t.Errorf("never reached end of object")
	}
}

func TestLineAline(t *testing.T) {
	if !dotest(true) {
		return
	}
	defer endtest()

	tab := getTable(t)
	if tab.go12line != nil {
		// aline's don't exist in the Go 1.2 table.
		t.Skip("not relevant to Go 1.2 symbol table")
	}

	for _, o := range tab.Files {
		// A source file can appear multiple times in a
		// object.  alineFromLine will always return alines in
		// the first file, so track which lines we've seen.
		found := make(map[string]int)
		for i := 0; i < 1000; i++ {
			path, line := o.lineFromAline(i)
			if path == "" {
				break
			}

			// cgo files are full of 'Z' symbols, which we don't handle
			if len(path) > 4 && path[len(path)-4:] == ".cgo" {
				continue
			}

			if minline, ok := found[path]; path != "" && ok {
				if minline >= line {
					// We've already covered this file
					continue
				}
			}
			found[path] = line

			a, err := o.alineFromLine(path, line)
			if err != nil {
				t.Errorf("absolute line %d in object %s maps to %s:%d, but mapping that back gives error %s", i, o.Paths[0].Name, path, line, err)
			} else if a != i {
				t.Errorf("absolute line %d in object %s maps to %s:%d, which maps back to absolute line %d\n", i, o.Paths[0].Name, path, line, a)
			}
		}
	}
}

func TestPCLine(t *testing.T) {
	if !dotest(false) {
		return
	}
	defer endtest()

	f, tab := crack(pclinetestBinary, t)
	text := f.Section(".text")
	textdat, err := text.Data()
	if err != nil {
		t.Fatalf("reading .text: %v", err)
	}

	// Test PCToLine
	sym := tab.LookupFunc("linefrompc")
	wantLine := 0
	for pc := sym.Entry; pc < sym.End; pc++ {
		off := pc - text.Addr // TODO(rsc): should not need off; bug in 8g
		if textdat[off] == 255 {
			break
		}
		wantLine += int(textdat[off])
		t.Logf("off is %d %#x (max %d)", off, textdat[off], sym.End-pc)
		file, line, fn := tab.PCToLine(pc)
		if fn == nil {
			t.Errorf("failed to get line of PC %#x", pc)
		} else if !strings.HasSuffix(file, "pclinetest.asm") || line != wantLine || fn != sym {
			t.Errorf("PCToLine(%#x) = %s:%d (%s), want %s:%d (%s)", pc, file, line, fn.Name, "pclinetest.asm", wantLine, sym.Name)
		}
	}

	// Test LineToPC
	sym = tab.LookupFunc("pcfromline")
	lookupline := -1
	wantLine = 0
	off := uint64(0) // TODO(rsc): should not need off; bug in 8g
	for pc := sym.Value; pc < sym.End; pc += 2 + uint64(textdat[off]) {
		file, line, fn := tab.PCToLine(pc)
		off = pc - text.Addr
		if textdat[off] == 255 {
			break
		}
		wantLine += int(textdat[off])
		if line != wantLine {
			t.Errorf("expected line %d at PC %#x in pcfromline, got %d", wantLine, pc, line)
			off = pc + 1 - text.Addr
			continue
		}
		if lookupline == -1 {
			lookupline = line
		}
		for ; lookupline <= line; lookupline++ {
			pc2, fn2, err := tab.LineToPC(file, lookupline)
			if lookupline != line {
				// Should be nothing on this line
				if err == nil {
					t.Errorf("expected no PC at line %d, got %#x (%s)", lookupline, pc2, fn2.Name)
				}
			} else if err != nil {
				t.Errorf("failed to get PC of line %d: %s", lookupline, err)
			} else if pc != pc2 {
				t.Errorf("expected PC %#x (%s) at line %d, got PC %#x (%s)", pc, fn.Name, line, pc2, fn2.Name)
			}
		}
		off = pc + 1 - text.Addr
	}
}
<commit_msg>Add exception for akaros in debug/gosysm<commit_after>// Copyright 2009 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 gosym

import (
	"debug/elf"
	"fmt"
	"io/ioutil"
	"os"
	"os/exec"
	"path/filepath"
	"runtime"
	"strings"
	"testing"
)

var (
	pclineTempDir    string
	pclinetestBinary string
)

func dotest(self bool) bool {
	// For now, only works on amd64 platforms.
	if runtime.GOARCH != "amd64" {
		return false
	}
	// Self test reads test binary; only works on Linux.
	if self && runtime.GOOS != "linux" {
		return false
	}
	// Command below expects "sh", so Unix.
	if runtime.GOOS == "windows" || runtime.GOOS == "plan9" || runtime.GOOS == "akaros" {
		return false
	}
	if pclinetestBinary != "" {
		return true
	}
	var err error
	pclineTempDir, err = ioutil.TempDir("", "pclinetest")
	if err != nil {
		panic(err)
	}
	if strings.Contains(pclineTempDir, " ") {
		panic("unexpected space in tempdir")
	}
	// This command builds pclinetest from pclinetest.asm;
	// the resulting binary looks like it was built from pclinetest.s,
	// but we have renamed it to keep it away from the go tool.
	pclinetestBinary = filepath.Join(pclineTempDir, "pclinetest")
	command := fmt.Sprintf("go tool 6a -o %s.6 pclinetest.asm && go tool 6l -H linux -E main -o %s %s.6",
		pclinetestBinary, pclinetestBinary, pclinetestBinary)
	cmd := exec.Command("sh", "-c", command)
	cmd.Stdout = os.Stdout
	cmd.Stderr = os.Stderr
	if err := cmd.Run(); err != nil {
		panic(err)
	}
	return true
}

func endtest() {
	if pclineTempDir != "" {
		os.RemoveAll(pclineTempDir)
		pclineTempDir = ""
		pclinetestBinary = ""
	}
}

func getTable(t *testing.T) *Table {
	f, tab := crack(os.Args[0], t)
	f.Close()
	return tab
}

func crack(file string, t *testing.T) (*elf.File, *Table) {
	// Open self
	f, err := elf.Open(file)
	if err != nil {
		t.Fatal(err)
	}
	return parse(file, f, t)
}

func parse(file string, f *elf.File, t *testing.T) (*elf.File, *Table) {
	symdat, err := f.Section(".gosymtab").Data()
	if err != nil {
		f.Close()
		t.Fatalf("reading %s gosymtab: %v", file, err)
	}
	pclndat, err := f.Section(".gopclntab").Data()
	if err != nil {
		f.Close()
		t.Fatalf("reading %s gopclntab: %v", file, err)
	}

	pcln := NewLineTable(pclndat, f.Section(".text").Addr)
	tab, err := NewTable(symdat, pcln)
	if err != nil {
		f.Close()
		t.Fatalf("parsing %s gosymtab: %v", file, err)
	}

	return f, tab
}

var goarch = os.Getenv("O")

func TestLineFromAline(t *testing.T) {
	if !dotest(true) {
		return
	}
	defer endtest()

	tab := getTable(t)
	if tab.go12line != nil {
		// aline's don't exist in the Go 1.2 table.
		t.Skip("not relevant to Go 1.2 symbol table")
	}

	// Find the sym package
	pkg := tab.LookupFunc("debug/gosym.TestLineFromAline").Obj
	if pkg == nil {
		t.Fatalf("nil pkg")
	}

	// Walk every absolute line and ensure that we hit every
	// source line monotonically
	lastline := make(map[string]int)
	final := -1
	for i := 0; i < 10000; i++ {
		path, line := pkg.lineFromAline(i)
		// Check for end of object
		if path == "" {
			if final == -1 {
				final = i - 1
			}
			continue
		} else if final != -1 {
			t.Fatalf("reached end of package at absolute line %d, but absolute line %d mapped to %s:%d", final, i, path, line)
		}
		// It's okay to see files multiple times (e.g., sys.a)
		if line == 1 {
			lastline[path] = 1
			continue
		}
		// Check that the is the next line in path
		ll, ok := lastline[path]
		if !ok {
			t.Errorf("file %s starts on line %d", path, line)
		} else if line != ll+1 {
			t.Fatalf("expected next line of file %s to be %d, got %d", path, ll+1, line)
		}
		lastline[path] = line
	}
	if final == -1 {
		t.Errorf("never reached end of object")
	}
}

func TestLineAline(t *testing.T) {
	if !dotest(true) {
		return
	}
	defer endtest()

	tab := getTable(t)
	if tab.go12line != nil {
		// aline's don't exist in the Go 1.2 table.
		t.Skip("not relevant to Go 1.2 symbol table")
	}

	for _, o := range tab.Files {
		// A source file can appear multiple times in a
		// object.  alineFromLine will always return alines in
		// the first file, so track which lines we've seen.
		found := make(map[string]int)
		for i := 0; i < 1000; i++ {
			path, line := o.lineFromAline(i)
			if path == "" {
				break
			}

			// cgo files are full of 'Z' symbols, which we don't handle
			if len(path) > 4 && path[len(path)-4:] == ".cgo" {
				continue
			}

			if minline, ok := found[path]; path != "" && ok {
				if minline >= line {
					// We've already covered this file
					continue
				}
			}
			found[path] = line

			a, err := o.alineFromLine(path, line)
			if err != nil {
				t.Errorf("absolute line %d in object %s maps to %s:%d, but mapping that back gives error %s", i, o.Paths[0].Name, path, line, err)
			} else if a != i {
				t.Errorf("absolute line %d in object %s maps to %s:%d, which maps back to absolute line %d\n", i, o.Paths[0].Name, path, line, a)
			}
		}
	}
}

func TestPCLine(t *testing.T) {
	if !dotest(false) {
		return
	}
	defer endtest()

	f, tab := crack(pclinetestBinary, t)
	text := f.Section(".text")
	textdat, err := text.Data()
	if err != nil {
		t.Fatalf("reading .text: %v", err)
	}

	// Test PCToLine
	sym := tab.LookupFunc("linefrompc")
	wantLine := 0
	for pc := sym.Entry; pc < sym.End; pc++ {
		off := pc - text.Addr // TODO(rsc): should not need off; bug in 8g
		if textdat[off] == 255 {
			break
		}
		wantLine += int(textdat[off])
		t.Logf("off is %d %#x (max %d)", off, textdat[off], sym.End-pc)
		file, line, fn := tab.PCToLine(pc)
		if fn == nil {
			t.Errorf("failed to get line of PC %#x", pc)
		} else if !strings.HasSuffix(file, "pclinetest.asm") || line != wantLine || fn != sym {
			t.Errorf("PCToLine(%#x) = %s:%d (%s), want %s:%d (%s)", pc, file, line, fn.Name, "pclinetest.asm", wantLine, sym.Name)
		}
	}

	// Test LineToPC
	sym = tab.LookupFunc("pcfromline")
	lookupline := -1
	wantLine = 0
	off := uint64(0) // TODO(rsc): should not need off; bug in 8g
	for pc := sym.Value; pc < sym.End; pc += 2 + uint64(textdat[off]) {
		file, line, fn := tab.PCToLine(pc)
		off = pc - text.Addr
		if textdat[off] == 255 {
			break
		}
		wantLine += int(textdat[off])
		if line != wantLine {
			t.Errorf("expected line %d at PC %#x in pcfromline, got %d", wantLine, pc, line)
			off = pc + 1 - text.Addr
			continue
		}
		if lookupline == -1 {
			lookupline = line
		}
		for ; lookupline <= line; lookupline++ {
			pc2, fn2, err := tab.LineToPC(file, lookupline)
			if lookupline != line {
				// Should be nothing on this line
				if err == nil {
					t.Errorf("expected no PC at line %d, got %#x (%s)", lookupline, pc2, fn2.Name)
				}
			} else if err != nil {
				t.Errorf("failed to get PC of line %d: %s", lookupline, err)
			} else if pc != pc2 {
				t.Errorf("expected PC %#x (%s) at line %d, got PC %#x (%s)", pc, fn.Name, line, pc2, fn2.Name)
			}
		}
		off = pc + 1 - text.Addr
	}
}
<|endoftext|>


<commit_before>// godefs -gsyscall types_linux.c

// MACHINE GENERATED - DO NOT EDIT.

package syscall

// Constants
const (
	sizeofPtr               = 0x4
	sizeofShort             = 0x2
	sizeofInt               = 0x4
	sizeofLong              = 0x4
	sizeofLongLong          = 0x8
	PathMax                 = 0x1000
	SizeofSockaddrInet4     = 0x10
	SizeofSockaddrInet6     = 0x1c
	SizeofSockaddrAny       = 0x70
	SizeofSockaddrUnix      = 0x6e
	SizeofSockaddrLinklayer = 0x14
	SizeofLinger            = 0x8
	SizeofMsghdr            = 0x1c
	SizeofCmsghdr           = 0xc
	SizeofUcred             = 0xc
	SizeofInotifyEvent      = 0x10
)

// Types

type _C_short int16

type _C_int int32

type _C_long int32

type _C_long_long int64

type Timespec struct {
	Sec  int32
	Nsec int32
}

type Timeval struct {
	Sec  int32
	Usec int32
}

type Timex struct {
	Modes     uint32
	Offset    int32
	Freq      int32
	Maxerror  int32
	Esterror  int32
	Status    int32
	Constant  int32
	Precision int32
	Tolerance int32
	Time      Timeval
	Tick      int32
	Ppsfreq   int32
	Jitter    int32
	Shift     int32
	Stabil    int32
	Jitcnt    int32
	Calcnt    int32
	Errcnt    int32
	Stbcnt    int32
	Tai       int32
	Pad0      int32
	Pad1      int32
	Pad2      int32
	Pad3      int32
	Pad4      int32
	Pad5      int32
	Pad6      int32
	Pad7      int32
	Pad8      int32
	Pad9      int32
	Pad10     int32
}

type Time_t int32

type Tms struct {
	Utime  int32
	Stime  int32
	Cutime int32
	Cstime int32
}

type Utimbuf struct {
	Actime  int32
	Modtime int32
}

type Rusage struct {
	Utime    Timeval
	Stime    Timeval
	Maxrss   int32
	Ixrss    int32
	Idrss    int32
	Isrss    int32
	Minflt   int32
	Majflt   int32
	Nswap    int32
	Inblock  int32
	Oublock  int32
	Msgsnd   int32
	Msgrcv   int32
	Nsignals int32
	Nvcsw    int32
	Nivcsw   int32
}

type Rlimit struct {
	Cur uint64
	Max uint64
}

type _Gid_t uint32

type Stat_t struct {
	Dev       uint64
	X__pad1   uint16
	Pad0      [2]byte
	X__st_ino uint32
	Mode      uint32
	Nlink     uint32
	Uid       uint32
	Gid       uint32
	Rdev      uint64
	X__pad2   uint16
	Pad1      [6]byte
	Size      int64
	Blksize   int32
	Pad2      [4]byte
	Blocks    int64
	Atim      Timespec
	Mtim      Timespec
	Ctim      Timespec
	Ino       uint64
}

type Statfs_t struct {
	Type    int32
	Bsize   int32
	Blocks  uint64
	Bfree   uint64
	Bavail  uint64
	Files   uint64
	Ffree   uint64
	Fsid    [8]byte /* __fsid_t */
	Namelen int32
	Frsize  int32
	Spare   [5]int32
	Pad0    [4]byte
}

type Dirent struct {
	Ino    uint64
	Off    int64
	Reclen uint16
	Type   uint8
	Name   [256]uint8
	Pad0   [5]byte
}

type RawSockaddrInet4 struct {
	Family uint16
	Port   uint16
	Addr   [4]byte /* in_addr */
	Zero   [8]uint8
}

type RawSockaddrInet6 struct {
	Family   uint16
	Port     uint16
	Flowinfo uint32
	Addr     [16]byte /* in6_addr */
	Scope_id uint32
}

type RawSockaddrUnix struct {
	Family uint16
	Path   [108]uint8
}

type RawSockaddrLinklayer struct {
	Family   uint16
	Protocol uint16
	Ifindex  int32
	Hatype   uint16
	Pkttype  uint8
	Halen    uint8
	Addr     [8]uint8
}

type RawSockaddr struct {
	Family uint16
	Data   [14]uint8
}

type RawSockaddrAny struct {
	Addr RawSockaddr
	Pad  [96]uint8
}

type _Socklen uint32

type Linger struct {
	Onoff  int32
	Linger int32
}

type Iovec struct {
	Base *byte
	Len  uint32
}

type Msghdr struct {
	Name       *byte
	Namelen    uint32
	Iov        *Iovec
	Iovlen     uint32
	Control    *byte
	Controllen uint32
	Flags      int32
}

type Cmsghdr struct {
	Len   uint32
	Level int32
	Type  int32
}

type Ucred struct {
	Pid int32
	Uid uint32
	Gid uint32
}

type InotifyEvent struct {
	Wd     int32
	Mask   uint32
	Cookie uint32
	Len    uint32
}

type PtraceRegs struct{}

type PtraceRegs struct{}

type FdSet struct {
	Bits [32]int32
}

type Sysinfo_t struct {
	Uptime    int32
	Loads     [3]uint32
	Totalram  uint32
	Freeram   uint32
	Sharedram uint32
	Bufferram uint32
	Totalswap uint32
	Freeswap  uint32
	Procs     uint16
	Pad       uint16
	Totalhigh uint32
	Freehigh  uint32
	Unit      uint32
	X_f       [8]uint8
}

type Utsname struct {
	Sysname    [65]uint8
	Nodename   [65]uint8
	Release    [65]uint8
	Version    [65]uint8
	Machine    [65]uint8
	Domainname [65]uint8
}

type Ustat_t struct {
	Tfree  int32
	Tinode uint32
	Fname  [6]uint8
	Fpack  [6]uint8
}

type EpollEvent struct {
	Events uint32
	Fd     int32
	Pad    int32
}
<commit_msg>arm: fix syscall build again<commit_after>// godefs -gsyscall types_linux.c

// MACHINE GENERATED - DO NOT EDIT.

// Manual corrections: UGH
//	remove duplicate PtraceRegs type
//	change RawSockaddrUnix field to Path [108]int8 (was uint8()

package syscall

// Constants
const (
	sizeofPtr               = 0x4
	sizeofShort             = 0x2
	sizeofInt               = 0x4
	sizeofLong              = 0x4
	sizeofLongLong          = 0x8
	PathMax                 = 0x1000
	SizeofSockaddrInet4     = 0x10
	SizeofSockaddrInet6     = 0x1c
	SizeofSockaddrAny       = 0x70
	SizeofSockaddrUnix      = 0x6e
	SizeofSockaddrLinklayer = 0x14
	SizeofLinger            = 0x8
	SizeofMsghdr            = 0x1c
	SizeofCmsghdr           = 0xc
	SizeofUcred             = 0xc
	SizeofInotifyEvent      = 0x10
)

// Types

type _C_short int16

type _C_int int32

type _C_long int32

type _C_long_long int64

type Timespec struct {
	Sec  int32
	Nsec int32
}

type Timeval struct {
	Sec  int32
	Usec int32
}

type Timex struct {
	Modes     uint32
	Offset    int32
	Freq      int32
	Maxerror  int32
	Esterror  int32
	Status    int32
	Constant  int32
	Precision int32
	Tolerance int32
	Time      Timeval
	Tick      int32
	Ppsfreq   int32
	Jitter    int32
	Shift     int32
	Stabil    int32
	Jitcnt    int32
	Calcnt    int32
	Errcnt    int32
	Stbcnt    int32
	Tai       int32
	Pad0      int32
	Pad1      int32
	Pad2      int32
	Pad3      int32
	Pad4      int32
	Pad5      int32
	Pad6      int32
	Pad7      int32
	Pad8      int32
	Pad9      int32
	Pad10     int32
}

type Time_t int32

type Tms struct {
	Utime  int32
	Stime  int32
	Cutime int32
	Cstime int32
}

type Utimbuf struct {
	Actime  int32
	Modtime int32
}

type Rusage struct {
	Utime    Timeval
	Stime    Timeval
	Maxrss   int32
	Ixrss    int32
	Idrss    int32
	Isrss    int32
	Minflt   int32
	Majflt   int32
	Nswap    int32
	Inblock  int32
	Oublock  int32
	Msgsnd   int32
	Msgrcv   int32
	Nsignals int32
	Nvcsw    int32
	Nivcsw   int32
}

type Rlimit struct {
	Cur uint64
	Max uint64
}

type _Gid_t uint32

type Stat_t struct {
	Dev       uint64
	X__pad1   uint16
	Pad0      [2]byte
	X__st_ino uint32
	Mode      uint32
	Nlink     uint32
	Uid       uint32
	Gid       uint32
	Rdev      uint64
	X__pad2   uint16
	Pad1      [6]byte
	Size      int64
	Blksize   int32
	Pad2      [4]byte
	Blocks    int64
	Atim      Timespec
	Mtim      Timespec
	Ctim      Timespec
	Ino       uint64
}

type Statfs_t struct {
	Type    int32
	Bsize   int32
	Blocks  uint64
	Bfree   uint64
	Bavail  uint64
	Files   uint64
	Ffree   uint64
	Fsid    [8]byte /* __fsid_t */
	Namelen int32
	Frsize  int32
	Spare   [5]int32
	Pad0    [4]byte
}

type Dirent struct {
	Ino    uint64
	Off    int64
	Reclen uint16
	Type   uint8
	Name   [256]uint8
	Pad0   [5]byte
}

type RawSockaddrInet4 struct {
	Family uint16
	Port   uint16
	Addr   [4]byte /* in_addr */
	Zero   [8]uint8
}

type RawSockaddrInet6 struct {
	Family   uint16
	Port     uint16
	Flowinfo uint32
	Addr     [16]byte /* in6_addr */
	Scope_id uint32
}

type RawSockaddrUnix struct {
	Family uint16
	Path   [108]int8
}

type RawSockaddrLinklayer struct {
	Family   uint16
	Protocol uint16
	Ifindex  int32
	Hatype   uint16
	Pkttype  uint8
	Halen    uint8
	Addr     [8]uint8
}

type RawSockaddr struct {
	Family uint16
	Data   [14]uint8
}

type RawSockaddrAny struct {
	Addr RawSockaddr
	Pad  [96]uint8
}

type _Socklen uint32

type Linger struct {
	Onoff  int32
	Linger int32
}

type Iovec struct {
	Base *byte
	Len  uint32
}

type Msghdr struct {
	Name       *byte
	Namelen    uint32
	Iov        *Iovec
	Iovlen     uint32
	Control    *byte
	Controllen uint32
	Flags      int32
}

type Cmsghdr struct {
	Len   uint32
	Level int32
	Type  int32
}

type Ucred struct {
	Pid int32
	Uid uint32
	Gid uint32
}

type InotifyEvent struct {
	Wd     int32
	Mask   uint32
	Cookie uint32
	Len    uint32
}

type PtraceRegs struct{}

type FdSet struct {
	Bits [32]int32
}

type Sysinfo_t struct {
	Uptime    int32
	Loads     [3]uint32
	Totalram  uint32
	Freeram   uint32
	Sharedram uint32
	Bufferram uint32
	Totalswap uint32
	Freeswap  uint32
	Procs     uint16
	Pad       uint16
	Totalhigh uint32
	Freehigh  uint32
	Unit      uint32
	X_f       [8]uint8
}

type Utsname struct {
	Sysname    [65]uint8
	Nodename   [65]uint8
	Release    [65]uint8
	Version    [65]uint8
	Machine    [65]uint8
	Domainname [65]uint8
}

type Ustat_t struct {
	Tfree  int32
	Tinode uint32
	Fname  [6]uint8
	Fpack  [6]uint8
}

type EpollEvent struct {
	Events uint32
	Fd     int32
	Pad    int32
}
<|endoftext|>


<commit_before>package s3

import (
	"fmt"

	"github.com/pachyderm/pachyderm/src/client"
)

type ClientFactory interface {
	Client(authToken string) (*client.APIClient, error)
}

type LocalClientFactory struct {
	port uint16
}

func NewLocalClientFactory(port uint16) *LocalClientFactory {
	return &LocalClientFactory{
		port: port,
	}
}

func (f *LocalClientFactory) Client(authToken string) (*client.APIClient, error) {
	pc, err := client.NewFromAddress(fmt.Sprintf("localhost:%d", f.port))
	if err != nil {
		return nil, err
	}
	if authToken != "" {
		pc.SetAuthToken(authToken)
	}
	return pc, nil
}
<commit_msg>ClientFactory comments<commit_after>package s3

import (
	"fmt"

	"github.com/pachyderm/pachyderm/src/client"
)

// ClientFactory implementors provide a way for the s3gateway to instantiate
// and configure a request-scoped client.
type ClientFactory interface {
	// Client creates a pachyderm client.
	Client(authToken string) (*client.APIClient, error)
}

// LocalClientFactory creates clients that connect to localhost on a
// configurable port.
type LocalClientFactory struct {
	port uint16
}

// NewLocalClientFactory creates a new LocalClientFactory, using the given
// port.
func NewLocalClientFactory(port uint16) *LocalClientFactory {
	return &LocalClientFactory{
		port: port,
	}
}

// Client creates a pachyderm client.
func (f *LocalClientFactory) Client(authToken string) (*client.APIClient, error) {
	pc, err := client.NewFromAddress(fmt.Sprintf("localhost:%d", f.port))
	if err != nil {
		return nil, err
	}
	if authToken != "" {
		pc.SetAuthToken(authToken)
	}
	return pc, nil
}
<|endoftext|>